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