View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * This file was originally developed by Keith Visco during the course of employment at Intalio Inc.
34   * All portions of this file developed by Keith Visco after Jan 19 2005 are Copyright (C) 2005 Keith
35   * Visco. All Rights Reserved.
36   *
37   * $Id$
38   */
39  package org.exolab.castor.builder;
40  
41  import java.util.Collections;
42  import java.util.Enumeration;
43  import java.util.HashMap;
44  import java.util.Hashtable;
45  import java.util.Map;
46  import java.util.Properties;
47  import java.util.Vector;
48  
49  import org.exolab.castor.builder.util.ClassInfoResolverImpl;
50  import org.exolab.castor.mapping.xml.MappingRoot;
51  import org.exolab.castor.util.dialog.ConsoleDialog;
52  import org.exolab.castor.util.dialog.Dialog;
53  import org.exolab.castor.xml.schema.Annotated;
54  import org.exolab.castor.xml.schema.Schema;
55  import org.exolab.javasource.JClass;
56  
57  /**
58   * A class for maintaining state for the SourceGenerator.
59   *
60   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
61   * @version $Revision$ $Date: 2005-06-22 22:13:21 -0600 (Wed, 22 Jun 2005) $
62   */
63  public final class SGStateInfo extends ClassInfoResolverImpl {
64  
65    /** An empty Enumeration to be returned whenever we need an empty Enumeration. */
66    private static final Enumeration<String> EMPTY_ENUMERATION = Collections.emptyEnumeration();
67    /** The SourceGenerator is still generating source. */
68    public static final int NORMAL_STATUS = 0;
69    /** The SourceGenerator has been stopped by an error or by the user. */
70    public static final int STOP_STATUS = 1;
71  
72    /** The in memory mapping files for each package. */
73    private Hashtable<String, MappingRoot> _mappings = null;
74    /** The in memory package listings for each package. */
75    private Hashtable<String, Properties> _packageListings = null;
76  
77    /** The package used when creating new classes. */
78    private String _packageName;
79  
80    /** Keeps track of which JClass files have been processed. */
81    private Vector<JClass> _processed = null;
82    /** true if existing source files should not be silently overwritten. */
83    private boolean _promptForOverwrite = true;
84    /** The schema we are generating source code for. */
85    private Schema _schema = null;
86    /** true if non-fatal warnings should be suppressed. */
87    private boolean _suppressNonFatalWarnings = false;
88    /** true if source generation should provide verbose output on its progress. */
89    private boolean _verbose = false;
90    /** The SourceFactory state. */
91    private FactoryState _currentFactoryState = null;
92    /** This class allows user interaction when Castor wants to ask a question. */
93    private Dialog _dialog = null;
94    /** The source generator whose state we track. */
95    private SourceGenerator _sgen = null;
96    /** Current status of the source generator. */
97    private int _status = NORMAL_STATUS;
98    /** Maps annotations to generated source code. */
99    private Map<Annotated, JClass[]> _sourcesByComponent = new HashMap<Annotated, JClass[]>();
100 
101   /**
102    * A cache of already generated classes (by their class name).
103    */
104   private Map<String, JClass> _sourcesByName = new HashMap<String, JClass>();
105 
106   /**
107    * A cache of already generated classes (as part of an imported schema), keyed by their class
108    * name.
109    */
110   private Map<String, JClass> _importedSourcesByName = new HashMap<String, JClass>();
111 
112   /**
113    * Creates a new SGStateInfo.
114    *
115    * @param schema the Schema to generate source for
116    * @param sgen the SourceGenerator instance
117    */
118   protected SGStateInfo(final Schema schema, final SourceGenerator sgen) {
119     super();
120     _schema = schema;
121     _packageName = "";
122     _processed = new Vector<JClass>();
123     _dialog = new ConsoleDialog();
124     _sgen = sgen;
125   }
126 
127   /**
128    * Get package used when creating new classes.
129    * 
130    * @return Package used when creating new classes.
131    */
132   public String getPackageName() {
133     return _packageName;
134   }
135 
136   /**
137    * Set package used when creating new classes.
138    * 
139    * @param packageName Package used when creating new classes.
140    */
141   protected void setPackageName(final String packageName) {
142     _packageName = packageName;
143   }
144 
145   /**
146    * Binds the given Annotated structure with its generated source classes.
147    *
148    * @param annotated the Annotated structure to add JClass bindings for
149    * @param classes the JClass[] to bind
150    */
151   public void bindSourceCode(final Annotated annotated, final JClass[] classes) {
152     _sourcesByComponent.put(annotated, classes);
153     for (JClass jClass : classes) {
154       if (jClass != null) {
155         _sourcesByName.put(jClass.getName(), jClass);
156       }
157     }
158   } // -- bindSourceCode
159 
160   /**
161    * Stores generated sources as processed within an imported schema.
162    * 
163    * @param importedSourcesByName Generated sources as processed within an imported schema.
164    */
165   public void storeImportedSourcesByName(final Map<String, JClass> importedSourcesByName) {
166     _importedSourcesByName.putAll(importedSourcesByName);
167   } // -- storeImportedSourcesByName
168 
169   /**
170    * Returns the processed JClass with the given name. If no such JClass has been marked as
171    * processed, null is returned.
172    *
173    * @param className the JClass name to check against
174    * @return the JClass with the given name
175    */
176   JClass getProcessed(final String className) {
177     for (JClass jClass : _processed) {
178       if (jClass.getName().equals(className)) {
179         return jClass;
180       }
181     }
182     return null;
183   } // -- getProcessed
184 
185   /**
186    * Returns the array of JClass for the given Annotated structure or null if no bindings have been
187    * specified for the given Structure.
188    *
189    * @param annotated the Annotated structure to search
190    * @return the JClass array
191    */
192   public JClass[] getSourceCode(final Annotated annotated) {
193     return _sourcesByComponent.get(annotated);
194   } // -- getSourceCode
195 
196   /**
197    * Returns the JClass with the given name or null if no bindings have been specified for a JClass
198    * with the name.
199    *
200    * @param className the name of the JClass
201    * @return the JClass if found
202    */
203   public JClass getSourceCode(final String className) {
204     return _sourcesByName.get(className);
205   } // -- getSourceCode
206 
207   /**
208    * Returns the JClass with the given name or null if no bindings have been specified for a JClass
209    * with the name. This method consults with JClass instances imported through a Schema import
210    * only.
211    *
212    * @param className the name of the JClass
213    * @return the (imported) JClass if found
214    */
215   public JClass getImportedSourceCode(final String className) {
216     return _importedSourcesByName.get(className);
217   } // -- getImportedSourceCode
218 
219 
220   /**
221    * Returns the Mapping file associated with the given filename.
222    *
223    * @param filename The filename to search for a Mapping File association
224    * @return the Mapping file.
225    */
226   public MappingRoot getMapping(final String filename) {
227     if (_mappings != null && filename != null) {
228       return _mappings.get(filename);
229     }
230     return null;
231   } // -- getMapping
232 
233   /**
234    * Returns the CDRFile (Properties file) associated with the given filename.
235    *
236    * @param filename filename of the CDR file to be processed
237    * @return the Properties file.
238    */
239   public Properties getCDRFile(final String filename) {
240     if (_packageListings != null && filename != null) {
241       return _packageListings.get(filename);
242     }
243     return null;
244   }
245 
246   /**
247    * Returns the set of CDR file names.
248    *
249    * @return the set of CDR file names.
250    */
251   public Enumeration<String> getCDRFilenames() {
252     if (_packageListings == null) {
253       return EMPTY_ENUMERATION;
254     }
255     return _packageListings.keys();
256   } // -- getCDRFilenames
257 
258   /**
259    * Returns the set of mapping filenames.
260    *
261    * @return the set of mapping filenames.
262    */
263   public Enumeration<String> getMappingFilenames() {
264     if (_mappings == null) {
265       return EMPTY_ENUMERATION;
266     }
267     return _mappings.keys();
268   } // -- getMappingFilenames
269 
270   /**
271    * Returns the current status.
272    *
273    * @return the current status.
274    */
275   public int getStatusCode() {
276     return _status;
277   } // -- getStatusCode
278 
279   /**
280    * Marks the given JClass as having been processed.
281    *
282    * @param jClass the JClass to mark as having been processed.
283    */
284   void markAsProcessed(final JClass jClass) {
285     // String className = jClass.getName();
286     if (!_processed.contains(jClass)) {
287       _processed.add(jClass);
288     }
289   } // -- markAsProcessed
290 
291   /**
292    * Returns true if the given JClass has been marked as processed.
293    *
294    * @param jClass the JClass to check for being marked as processed
295    * @return true if the given JClass has been marked as processed.
296    */
297   boolean processed(final JClass jClass) {
298     return _processed.contains(jClass);
299   } // -- processed
300 
301   /**
302    * Returns true if a JClass with the given name has been marked as processed.
303    *
304    * @param className the JClass name to check against
305    * @return true if a JClass with the given name has been marked as processed
306    */
307   boolean processed(final String className) {
308     for (JClass jClass : _processed) {
309       if (jClass.getName().equals(className)) {
310         return true;
311       }
312     }
313     return false;
314   } // -- processed
315 
316   /**
317    * Returns true if existing source files should be prompted before being overwritten.
318    *
319    * @return true if existing source files should be prompted before being overwritten
320    */
321   boolean promptForOverwrite() {
322     return _promptForOverwrite;
323   } // -- promptForOverwrite
324 
325   /**
326    * Sets whether or not existing source files should be silently overwritten or whether the user
327    * should be prompted first.
328    *
329    * @param promptForOverwrite true if existing files should not be silently overwritten.
330    */
331   void setPromptForOverwrite(final boolean promptForOverwrite) {
332     this._promptForOverwrite = promptForOverwrite;
333   } // -- setPromptForOverwrite
334 
335   /**
336    * Returns a reference to the schema for which we are generating source.
337    * 
338    * @return a reference to the schema for which we are generating source.
339    */
340   Schema getSchema() {
341     return _schema;
342   } // -- getSchema
343 
344   /**
345    * Returns the SourceGenerator instance being used.
346    * 
347    * @return the SourceGenerator instance being used.
348    */
349   public SourceGenerator getSourceGenerator() {
350     return _sgen;
351   } // -- getSourceGenerator
352 
353   /**
354    * Returns true if non-fatal warnings should be suppressed.
355    * 
356    * @return true if non-fatal warnings should be suppressed.
357    */
358   public boolean getSuppressNonFatalWarnings() {
359     return _suppressNonFatalWarnings;
360   }
361 
362   /**
363    * Sets whether non-fatal warnings should be supporessed.
364    * 
365    * @param suppressNonFatalWarnings true if non-fatal warnings should be supporessed
366    */
367   void setSuppressNonFatalWarnings(final boolean suppressNonFatalWarnings) {
368     _suppressNonFatalWarnings = suppressNonFatalWarnings;
369   }
370 
371   /**
372    * Sets the CDR (ClassDescriptorResolver) file associated with the given filename.
373    *
374    * @param filename the filename associated with the CDR file
375    * @param props the Properties file
376    */
377   public void setCDRFile(final String filename, final Properties props) {
378     if (filename == null) {
379       String err = "The argument 'filename' must not be null.";
380       throw new IllegalArgumentException(err);
381     }
382 
383     if (_packageListings == null) {
384       _packageListings = new Hashtable<String, Properties>();
385     }
386 
387     if (props == null) {
388       _packageListings.remove(filename);
389     } else {
390       _packageListings.put(filename, props);
391     }
392   } // -- setCDRFile
393 
394   /**
395    * Sets the Mapping file associated with the given filename.
396    *
397    * @param filename the filename associated with the Mapping
398    * @param mapping the MappingRoot
399    */
400   public void setMapping(final String filename, final MappingRoot mapping) {
401     if (filename == null) {
402       String err = "The argument 'filename' must not be null.";
403       throw new IllegalArgumentException(err);
404     }
405 
406     if (_mappings == null) {
407       _mappings = new Hashtable<String, MappingRoot>();
408     }
409 
410     if (mapping == null) {
411       _mappings.remove(filename);
412     } else {
413       _mappings.put(filename, mapping);
414     }
415   } // -- setMapping
416 
417   /**
418    * Returns the Dialog used for interacting with the user.
419    *
420    * @return the Dialog, or null if none has been set.
421    */
422   public Dialog getDialog() {
423     return _dialog;
424   } // -- getConsoleDialog
425 
426   /**
427    * Sets the Dialog used for interacting with the user.
428    *
429    * @param dialog the Dialog to use
430    */
431   void setDialog(final Dialog dialog) {
432     _dialog = dialog;
433   } // -- setDialog
434 
435   // /**
436   // * Sets the XMLBindingComponent that this SGStateInfo is working on.
437   // */
438   // void setXMLBindingComponent(XMLBindingComponent compo) {
439   // _bindingComponent = compo;
440   // }
441   //
442   // /**
443   // * Returns the XMLBindingComponent this SGStateInfo is working on.
444   // *
445   // * @return the XMLBindingComponent this SGStateInfo is working on.
446   // */
447   // XMLBindingComponent getXMLBindingComponent() {
448   // return _bindingComponent;
449   // }
450 
451   /**
452    * Sets the current status code to the given one.
453    *
454    * @param status the new status code
455    */
456   public void setStatusCode(final int status) {
457     _status = status;
458   } // -- setStatusCode
459 
460   /**
461    * Sets whether or not the source code generator prints additional messages during generating
462    * source code.
463    *
464    * @param verbose a boolean, when true indicates to print additional messages
465    */
466   void setVerbose(final boolean verbose) {
467     this._verbose = verbose;
468   } // -- setVerbose
469 
470   /**
471    * Returns the value of the verbose flag. A true value indicates that additional messages may be
472    * printed during processing.
473    *
474    * @return the value of the verbose flag.
475    */
476   public boolean verbose() {
477     return this._verbose;
478   } // -- verbose
479 
480   /**
481    * Returns the current FactoryState that holds information about the classes being generated.
482    *
483    * @return the current FactoryState
484    */
485   public FactoryState getCurrentFactoryState() {
486     return _currentFactoryState;
487   }
488 
489   /**
490    * Sets the current FactoryState.
491    * 
492    * @param state the current FactoryState
493    * @see #getCurrentFactoryState
494    */
495   public void setCurrentFactoryState(final FactoryState state) {
496     _currentFactoryState = state;
497   }
498 
499   // protected JClass getJClass(String name) {
500   // if (name == null) return null;
501   // JClass jClass = (JClass)classTypes.get(name);
502   //
503   // if (jClass == null) {
504   // jClass = new JClass(name);
505   // classTypes.put(name, jClass);
506   // }
507   // return jClass;
508   // }
509 
510   /**
511    * Returns the sources as generated through XML schema imports.
512    * 
513    * @return the sources as generated through XML schema imports.
514    */
515   public Map<String, JClass> getImportedSourcesByName() {
516     return _importedSourcesByName;
517   }
518 
519   /**
520    * Returns the sources as generated through XML schema imports.
521    * 
522    * @return the sources as generated through XML schema imports.
523    */
524   public Map<String, JClass> getSourcesByName() {
525     return _sourcesByName;
526   }
527 
528 }