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 }