1 /*
2 * Copyright 2005 Werner Guttmann
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.exolab.castor.builder.factory;
17
18 import java.util.Enumeration;
19
20 import org.castor.xml.JavaNaming;
21 import org.exolab.castor.builder.BuilderConfiguration;
22 import org.exolab.castor.builder.GroupNaming;
23 import org.exolab.castor.builder.SourceGenerator;
24 import org.exolab.castor.xml.schema.Annotated;
25 import org.exolab.castor.xml.schema.Annotation;
26 import org.exolab.castor.xml.schema.AttributeDecl;
27 import org.exolab.castor.xml.schema.Documentation;
28 import org.exolab.castor.xml.schema.ElementDecl;
29 import org.exolab.castor.xml.schema.Structure;
30
31 /**
32 * This class defines a base type for the source generator code factory classes.
33 *
34 * @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner Guttmann</a>
35 * @version $Revision: 6287 $ $Date: $
36 */
37 public class BaseFactory {
38
39 /** The BuilderConfiguration instance, for callbacks to obtain certain
40 * configured properties. */
41 private final BuilderConfiguration _config;
42
43 /** The type factory. */
44 private final FieldInfoFactory _infoFactory;
45
46 /** A GroupNaming helper class used to named anonymous groups. */
47 private GroupNaming _groupNaming = null;
48
49 /**
50 * The calling instance of {@link SourceGenerator}.
51 */
52 private SourceGenerator _sourceGenerator;
53
54 /**
55 * Creates an instance of this class.
56 * @param config XML code generator configuration
57 * @param infoFactory the FieldInfoFactory to use
58 * @param groupNaming Group naming scheme to be used.
59 * @param sourceGenerator The calling source generator.
60 */
61 public BaseFactory(final BuilderConfiguration config,
62 final FieldInfoFactory infoFactory,
63 final GroupNaming groupNaming,
64 final SourceGenerator sourceGenerator) {
65 if (config == null) {
66 String err = "The 'BuilderConfiguration' argument must not be null.";
67 throw new IllegalArgumentException(err);
68 }
69 _config = config;
70
71 if (infoFactory == null) {
72 if (getConfig().useOldFieldNaming()) {
73 this._infoFactory = new FieldInfoFactory();
74 } else {
75 this._infoFactory = new FieldInfoFactory(false);
76 }
77 } else {
78 this._infoFactory = infoFactory;
79 }
80 _groupNaming = groupNaming;
81 _sourceGenerator = sourceGenerator;
82 }
83
84 /**
85 * Get BuilderConfiguration instance, for callbacks to obtain certain configured properties.
86 *
87 * @return BuilderConfiguration instance.
88 */
89 protected final BuilderConfiguration getConfig() {
90 return _config;
91 }
92
93 /**
94 * Get type factory.
95 *
96 * @return Type factory.
97 */
98 protected final FieldInfoFactory getInfoFactory() {
99 return _infoFactory;
100 }
101
102 /**
103 * Normalizes the given string for use in comments.
104 *
105 * @param value
106 * the String to normalize
107 * @return the given string, normalized, for use in comments.
108 */
109 protected final String normalize(final String value) {
110 if (value == null) {
111 return null;
112 }
113
114 char[] chars = value.toCharArray();
115 char[] newChars = new char[chars.length * 2];
116 int count = 0;
117 int i = 0;
118 boolean skip = false;
119
120 while (i < chars.length) {
121 char ch = chars[i++];
122
123 if ((ch == ' ') || (ch == '\t')) {
124 if ((!skip) && (count != 0)) {
125 newChars[count++] = ' ';
126 }
127 skip = true;
128 } else if (ch == '*') {
129 if (i < chars.length && chars[i] == '/') {
130 newChars[count++] = ch;
131 newChars[count++] = '\\';
132 }
133 } else {
134 if (count == 0) {
135 //-- ignore new lines only if count == 0
136 if ((ch == '\r') || (ch == '\n')) {
137 continue;
138 }
139 }
140 newChars[count++] = ch;
141 skip = false;
142 }
143 }
144 return new String(newChars, 0, count);
145 }
146
147 /**
148 * Returns the group naming helper class for naming nested anonymous groups.
149 *
150 * @return the group naming helper class for naming nested anonymous groups.
151 */
152 public final GroupNaming getGroupNaming() {
153 return _groupNaming;
154 }
155
156 /**
157 * Sets the group naming helper class for naming nested anonymous groups.
158 * @param groupNaming the group naming helper class for naming nested anonymous groups.
159 */
160 public final void setGroupNaming(final GroupNaming groupNaming) {
161 _groupNaming = groupNaming;
162 }
163
164 /**
165 * Returns the calling {@link SourceGenerator} instance.
166 * @return the calling source generator
167 */
168 protected SourceGenerator getSourceGenerator() {
169 return _sourceGenerator;
170 }
171
172 /**
173 * Creates and returns a Javadoc comment from the given annotations.
174 * @param annotated The {@link Annotated} instance holding annotations.
175 * @return The Javadoc comment created from the annotations.
176 */
177 protected String createComment(final Annotated annotated) {
178 //-- process annotations
179 Enumeration<Annotation> enumeration = annotated.getAnnotations();
180 if (enumeration.hasMoreElements()) {
181 //-- just use first annotation
182 return createComment(enumeration.nextElement());
183 }
184 //-- there were no annotations...try possible references
185 switch(annotated.getStructureType()) {
186 case Structure.ELEMENT:
187 ElementDecl elem = (ElementDecl) annotated;
188 if (elem.isReference()) {
189 return createComment(elem.getReference());
190 }
191 break;
192 case Structure.ATTRIBUTE:
193 AttributeDecl att = (AttributeDecl) annotated;
194 if (att.isReference()) {
195 return createComment(att.getReference());
196 }
197 break;
198 default:
199 break;
200 }
201 return null;
202 } //-- createComment
203
204 /**
205 * Creates and returns a Javadoc comment from a given {@link Annotation}.
206 * @param annotation The {@link Annotation} instance to be used for comment creation.
207 * @return The Javdoc comment assembled from the AnnotationItem instance
208 */
209 private String createComment(final Annotation annotation) {
210 if (annotation == null) {
211 return null;
212 }
213
214 Enumeration<Documentation> enumeration = annotation.getDocumentation();
215 if (enumeration.hasMoreElements()) {
216 //-- just use first <info>
217 Documentation documentation = enumeration.nextElement();
218 return normalize(documentation.getContent());
219 }
220 return null;
221 }
222
223 /**
224 * Creates Comments from Schema annotations.
225 * @param annotated the Annotated structure to process
226 * @return the generated comment.
227 *
228 */
229 // TODO: refactor to avoid duplication with createComment() methods
230 protected String extractCommentsFromAnnotations(final Annotated annotated) {
231 //-- process annotations
232 Enumeration<Annotation> enumeration = annotated.getAnnotations();
233 if (enumeration.hasMoreElements()) {
234 StringBuilder comment = new StringBuilder();
235 while (enumeration.hasMoreElements()) {
236 Annotation ann = enumeration.nextElement();
237 Enumeration<Documentation> documentations = ann.getDocumentation();
238 while (documentations.hasMoreElements()) {
239 Documentation documentation = documentations.nextElement();
240 String content = documentation.getContent();
241 if (content != null) {
242 comment.append(content);
243 }
244 }
245 }
246 return normalize(comment.toString());
247 }
248 return null;
249 }
250
251 /**
252 * To get the {@link JavaNaming} to be used.
253 * @return {@link JavaNaming} instance to be used
254 * @since 1.1.3
255 */
256 public final JavaNaming getJavaNaming() {
257 return _config.getJavaNaming();
258 }
259 }