View Javadoc

1   package org.codehaus.modello.plugin.java;
2   
3   /*
4    * Copyright (c) 2004, Codehaus.org
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy of
7    * this software and associated documentation files (the "Software"), to deal in
8    * the Software without restriction, including without limitation the rights to
9    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10   * of the Software, and to permit persons to whom the Software is furnished to do
11   * so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  
25  import java.io.File;
26  import java.io.IOException;
27  import java.io.OutputStream;
28  import java.io.Writer;
29  import java.text.DateFormat;
30  import java.text.ParseException;
31  import java.text.SimpleDateFormat;
32  import java.util.ArrayList;
33  import java.util.Date;
34  import java.util.List;
35  import java.util.Locale;
36  import java.util.Properties;
37  
38  import org.codehaus.modello.ModelloException;
39  import org.codehaus.modello.ModelloParameterConstants;
40  import org.codehaus.modello.model.BaseElement;
41  import org.codehaus.modello.model.Model;
42  import org.codehaus.modello.model.ModelAssociation;
43  import org.codehaus.modello.model.ModelClass;
44  import org.codehaus.modello.model.ModelDefault;
45  import org.codehaus.modello.model.ModelField;
46  import org.codehaus.modello.model.ModelInterface;
47  import org.codehaus.modello.model.ModelType;
48  import org.codehaus.modello.plugin.AbstractModelloGenerator;
49  import org.codehaus.modello.plugin.java.javasource.JClass;
50  import org.codehaus.modello.plugin.java.javasource.JComment;
51  import org.codehaus.modello.plugin.java.javasource.JInterface;
52  import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
53  import org.codehaus.modello.plugin.java.javasource.JStructure;
54  import org.codehaus.modello.plugin.java.metadata.JavaClassMetadata;
55  import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
56  import org.codehaus.modello.plugin.java.metadata.JavaModelMetadata;
57  import org.codehaus.modello.plugin.model.ModelClassMetadata;
58  import org.codehaus.plexus.util.StringUtils;
59  import org.codehaus.plexus.util.WriterFactory;
60  
61  /**
62   * AbstractJavaModelloGenerator - similar in scope to {@link AbstractModelloGenerator} but with features that
63   * java generators can use.
64   *
65   * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
66   */
67  public abstract class AbstractJavaModelloGenerator
68      extends AbstractModelloGenerator
69  {
70      protected boolean useJava5 = false;
71  
72      protected boolean domAsXpp3 = true;
73  
74      protected void initialize( Model model, Properties parameters )
75          throws ModelloException
76      {
77          super.initialize( model, parameters );
78  
79          useJava5 = Boolean.valueOf( getParameter( parameters, ModelloParameterConstants.USE_JAVA5, "false" ) );
80  
81          domAsXpp3 = !"false".equals( parameters.getProperty( ModelloParameterConstants.DOM_AS_XPP3 ) );
82      }
83  
84      /**
85       * Create a new java source file writer, with configured encoding.
86       *
87       * @param packageName the package of the source file to create
88       * @param className the class of the source file to create
89       * @return a JSourceWriter with configured encoding
90       * @throws IOException
91       */
92      protected JSourceWriter newJSourceWriter( String packageName, String className )
93          throws IOException
94      {
95          String directory = packageName.replace( '.', File.separatorChar );
96  
97          File f = new File( new File( getOutputDirectory(), directory ), className + ".java" );
98  
99          if ( !f.getParentFile().exists() )
100         {
101             f.getParentFile().mkdirs();
102         }
103 
104         OutputStream os = getBuildContext().newFileOutputStream( f );
105 
106         Writer writer = ( getEncoding() == null ) ? WriterFactory.newPlatformWriter( os )
107                         : WriterFactory.newWriter( os, getEncoding() );
108 
109         return new JSourceWriter( writer );
110     }
111 
112     private JComment getHeaderComment()
113     {
114         JComment comment = new JComment();
115         comment.setComment( getHeader() );
116         return comment;
117     }
118 
119     protected void initHeader( JClass clazz )
120     {
121         clazz.setHeader( getHeaderComment() );
122     }
123 
124     protected void initHeader( JInterface interfaze )
125     {
126         interfaze.setHeader( getHeaderComment() );
127     }
128 
129     protected void suppressAllWarnings( Model objectModel, JStructure structure )
130     {
131         JavaModelMetadata javaModelMetadata = (JavaModelMetadata) objectModel.getMetadata( JavaModelMetadata.ID );
132 
133         if ( useJava5 && javaModelMetadata.isSuppressAllWarnings() )
134         {
135             structure.appendAnnotation( "@SuppressWarnings( \"all\" )" );
136         }
137     }
138 
139     protected void addModelImports( JClass jClass, BaseElement baseElem )
140         throws ModelloException
141     {
142         String basePackageName = null;
143         if ( baseElem instanceof ModelType )
144         {
145             basePackageName = ( (ModelType) baseElem ).getPackageName( isPackageWithVersion(), getGeneratedVersion() );
146         }
147 
148         // import interfaces
149         for ( ModelInterface modelInterface : getModel().getInterfaces( getGeneratedVersion() ) )
150         {
151             addModelImport( jClass, modelInterface, basePackageName );
152         }
153 
154         // import classes
155         for ( ModelClass modelClass : getClasses( getModel() ) )
156         {
157             addModelImport( jClass, modelClass, basePackageName );
158         }
159     }
160 
161     private void addModelImport( JClass jClass, ModelType modelType, String basePackageName )
162     {
163         String packageName = modelType.getPackageName( isPackageWithVersion(), getGeneratedVersion() );
164 
165         if ( !packageName.equals( basePackageName ) )
166         {
167             jClass.addImport( packageName + '.' + modelType.getName() );
168         }
169     }
170 
171     protected String getPrefix( JavaFieldMetadata javaFieldMetadata )
172     {
173         return javaFieldMetadata.isBooleanGetter() ? "is" : "get";
174     }
175 
176     protected String getDefaultValue( ModelAssociation association )
177     {
178         String value = association.getDefaultValue();
179 
180         if ( useJava5 )
181         {
182             value = StringUtils.replaceOnce( StringUtils.replaceOnce( value, "/*", "" ), "*/", "" );
183         }
184 
185         return value;
186     }
187 
188     protected static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS";
189 
190     protected String getJavaDefaultValue( ModelField modelField )
191         throws ModelloException
192     {
193         String type = modelField.getType();
194         String value = modelField.getDefaultValue();
195 
196         if ( "String".equals( type ) )
197         {
198             return '"' + escapeStringLiteral( value ) + '"';
199         }
200         else if ( "char".equals( type ) )
201         {
202             return '\'' + escapeStringLiteral( value ) + '\'';
203         }
204         else if ( "long".equals( type ) )
205         {
206             return value + 'L';
207         }
208         else if ( "float".equals( type ) )
209         {
210             return value + 'f';
211         }
212         else if ( "Date".equals( type ) )
213         {
214             DateFormat format = new SimpleDateFormat( DEFAULT_DATE_FORMAT, Locale.US );
215             try
216             {
217                 Date date = format.parse( value );
218                 return "new java.util.Date( " + date.getTime() + "L )";
219             }
220             catch ( ParseException pe )
221             {
222                 throw new ModelloException( "Unparseable default date: " + value, pe );
223             }
224         }
225         else if ( value != null && value.length() > 0 )
226         {
227             if ( "Character".equals( type ) && !value.contains( type ) )
228             {
229                 return newPrimitiveWrapper( type, "'" + escapeStringLiteral( value ) + "'", useJava5 );
230             }
231             else if ( "Boolean".equals( type ) && !value.contains( type ) )
232             {
233                 return newPrimitiveWrapper( type, value, true );
234             }
235             else if ( "Byte".equals( type ) && !value.contains( type ) )
236             {
237                 return newPrimitiveWrapper( type, "(byte) " + value, useJava5 );
238             }
239             else if ( "Short".equals( type ) && !value.contains( type ) )
240             {
241                 return newPrimitiveWrapper( type, "(short) " + value, useJava5 );
242             }
243             else if ( "Integer".equals( type ) && !value.contains( type ) )
244             {
245                 return newPrimitiveWrapper( type, value, useJava5 );
246             }
247             else if ( "Long".equals( type ) && !value.contains( type ) )
248             {
249                 return newPrimitiveWrapper( type, value + 'L', useJava5 );
250             }
251             else if ( "Float".equals( type ) && !value.contains( type ) )
252             {
253                 return newPrimitiveWrapper( type, value + 'f', useJava5 );
254             }
255             else if ( "Double".equals( type ) && !value.contains( type ) )
256             {
257                 return newPrimitiveWrapper( type, value, useJava5 );
258             }
259         }
260 
261         return value;
262     }
263 
264     private String newPrimitiveWrapper( String type, String value, boolean useJava5 )
265     {
266         if ( useJava5 )
267         {
268             return type + ".valueOf( " + value + " )";
269         }
270         else
271         {
272             return "new " + type + "( " + value + " )";
273         }
274     }
275 
276     private String escapeStringLiteral( String str )
277     {
278         StringBuilder buffer = new StringBuilder( str.length() + 32 );
279 
280         for ( int i = 0, n = str.length(); i < n; i++ )
281         {
282             char c = str.charAt( i );
283             switch ( c )
284             {
285                 case '\0':
286                     buffer.append( "\\0" );
287                     break;
288                 case '\t':
289                     buffer.append( "\\t" );
290                     break;
291                 case '\r':
292                     buffer.append( "\\r" );
293                     break;
294                 case '\n':
295                     buffer.append( "\\n" );
296                     break;
297                 case '\\':
298                     buffer.append( "\\\\" );
299                     break;
300                 default:
301                     buffer.append( c );
302             }
303         }
304 
305         return buffer.toString();
306     }
307 
308     protected String getValueChecker( String type, String value, ModelField field )
309         throws ModelloException
310     {
311         String retVal;
312         if ( "boolean".equals( type ) || "double".equals( type ) || "float".equals( type ) || "int".equals( type )
313             || "long".equals( type ) || "short".equals( type ) || "byte".equals( type ) || "char".equals( type ) )
314         {
315             retVal = "if ( " + value + " != " + getJavaDefaultValue( field ) + " )";
316         }
317         else if ( ModelDefault.LIST.equals( type ) || ModelDefault.SET.equals( type )
318             || ModelDefault.MAP.equals( type ) || ModelDefault.PROPERTIES.equals( type ) )
319         {
320             retVal = "if ( ( " + value + " != null ) && ( " + value + ".size() > 0 ) )";
321         }
322         else if ( "String".equals( type ) && field.getDefaultValue() != null )
323         {
324             retVal = "if ( ( " + value + " != null ) && !" + value + ".equals( \"" + field.getDefaultValue() + "\" ) )";
325         }
326         else if ( "Date".equals( type ) && field.getDefaultValue() != null )
327         {
328             retVal = "if ( ( " + value + " != null ) && !" + value + ".equals( " + getJavaDefaultValue( field ) + " ) )";
329         }
330         else
331         {
332             retVal = "if ( " + value + " != null )";
333         }
334         return retVal;
335     }
336 
337     protected List<ModelClass> getClasses( Model model )
338     {
339         List<ModelClass> modelClasses = new ArrayList<ModelClass>();
340 
341         for ( ModelClass modelClass : model.getClasses( getGeneratedVersion() ) )
342         {
343             if ( isRelevant( modelClass ) )
344             {
345                 modelClasses.add( modelClass );
346             }
347         }
348 
349         return modelClasses;
350     }
351 
352     protected boolean isRelevant( ModelClass modelClass )
353     {
354         return isJavaEnabled( modelClass ) && !isTrackingSupport( modelClass );
355     }
356 
357     protected boolean isJavaEnabled( ModelClass modelClass )
358     {
359         JavaClassMetadata javaClassMetadata = (JavaClassMetadata) modelClass.getMetadata( JavaClassMetadata.ID );
360         return javaClassMetadata.isEnabled();
361     }
362 
363     protected boolean isTrackingSupport( ModelClass modelClass )
364     {
365         ModelClassMetadata modelClassMetadata = (ModelClassMetadata) modelClass.getMetadata( ModelClassMetadata.ID );
366         if ( StringUtils.isNotEmpty( modelClassMetadata.getLocationTracker() ) )
367         {
368             return true;
369         }
370         if ( StringUtils.isNotEmpty( modelClassMetadata.getSourceTracker() ) )
371         {
372             return true;
373         }
374         return false;
375     }
376 
377 }