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