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