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