001 package com.sptci.echo2;
002
003 import java.io.FileNotFoundException;
004 import java.io.IOException;
005
006 import java.util.Date;
007 import java.util.Formatter;
008 import java.util.List;
009 import java.util.Map;
010
011 import java.text.SimpleDateFormat;
012
013 import org.jdom.JDOMException;
014
015 import org.rakeshv.utils.StringUtilities;
016
017 /**
018 * A JDO JavaBean generator. In addition to generating the source file
019 * as implemented in {@link ModelGenerator}, generates an additional
020 * <code>Factory</code> class to implement interactions with the JDO
021 * datastore, and a default JDO metadata file.
022 *
023 * <p>The following shows the invocation semantics for this class:</p>
024 * <pre>
025 * java -classpath <path to classes>:sptecho.jar:<path to Echo2_App.jar>:<path to jdom>:<path to jaxen> \
026 * com.sptci.echo2.JDOModelGenerator \
027 * <fully qualified name of UI class>
028 * </pre>
029 *
030 * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
031 * @author Rakesh Vidyadharan 2006-02-08
032 * @version $Id: JDOModelGenerator.java,v 1.3 2006/02/15 17:23:32 rakesh Exp $
033 * @see JDOMetaDataGenerator
034 */
035 public class JDOModelGenerator extends ModelGenerator
036 {
037 /**
038 * Delegates to the super-class constructor.
039 *
040 * @param name The fully qualified name of the class. Example:
041 * <code>com.sptci.demo.InputForm</code>.
042 * @throws ClassNotFoundException If the class corresponding to the
043 * <code>name</code> cannot be found in the classpath.
044 */
045 public JDOModelGenerator( String name ) throws ClassNotFoundException
046 {
047 super( name );
048 }
049
050 /**
051 * Over-ridden to generate the factory class source and metadata file
052 * in addition to the JavaBean source.
053 *
054 * @see #addInstanceCallbacks
055 * @see #generateFactory
056 * @see #generateMetaData
057 * @throws Exception If errors are encountered while generating
058 * the source file.
059 */
060 @Override
061 public void generate() throws Exception
062 {
063 addInstanceCallbacks();
064 generateFactory();
065 generateMetaData();
066 }
067
068 /**
069 * Add <code>InstanceCallbacks</code> support to the JDO JavaBean.
070 * Write the modified source code back to the source file.
071 *
072 * @see ModelGenerator#generate
073 * @throws Exception If errors are encountered while writing to
074 * the file.
075 */
076 protected void addInstanceCallbacks() throws Exception
077 {
078 super.generate();
079 StringBuilder builder = new StringBuilder(
080 StringUtilities.fromFile( name + ".java" ) );
081
082 StringBuilder callback = new StringBuilder( 32 );
083 Formatter formatter = new Formatter( callback );
084 formatter.format( "import javax.jdo.InstanceCallbacks;%n" );
085
086 int index = builder.indexOf( "import" );
087 builder.insert( index, callback.toString() );
088
089 String impl = "implements ";
090 index = builder.indexOf( impl ) + impl.length();
091 builder.insert( index, "InstanceCallbacks, " );
092 StringUtilities.toFile( builder.toString(), name + ".java" );
093 }
094
095 /**
096 * Generate the methods for the JavaBean.
097 *
098 * @see ModelGenerator#generateMethods
099 * @return String The source code for the methods to be included in
100 * the JavaBean.
101 */
102 @Override
103 protected String generateMethods()
104 {
105 StringBuilder builder = new StringBuilder( super.generateMethods() );
106 Formatter formatter = new Formatter( builder );
107
108 formatter.format( "%n /**%n" );
109 formatter.format( " * Called after the values are loaded from the%n" );
110 formatter.format( " * data store into this instance.%n" );
111 formatter.format( " * InstanceCallbacks method implementation. No actions required%n" );
112 formatter.format( " * by default.%n" );
113 formatter.format( " */%n" );
114 formatter.format( " public void jdoPostLoad() {}%n%n" );
115
116 formatter.format( " /**%n" );
117 formatter.format( " * Called before the values are stored from this instance%n" );
118 formatter.format( " * to the data store.%n" );
119 formatter.format( " * InstanceCallbacks method implementation.%n" );
120 formatter.format( " * Pre-calculate {@link #hash} using {@link #hashCode}.%n" );
121 formatter.format( " */%n" );
122 formatter.format( " public void jdoPreStore()%n" );
123 formatter.format( " {%n" );
124 formatter.format( " hash = hashCode();%n" );
125 formatter.format( " }%n%n" );
126
127 formatter.format( " /**%n" );
128 formatter.format( " * Called before the values in the instance are cleared.%n" );
129 formatter.format( " * InstanceCallbacks method implementation. No actions required%n" );
130 formatter.format( " * by default.%n" );
131 formatter.format( " */%n" );
132 formatter.format( " public void jdoPreClear() {}%n%n" );
133
134 formatter.format( " /**%n" );
135 formatter.format( " * Called before the instance is deleted.%n" );
136 formatter.format( " * InstanceCallbacks method implementation. No actions required%n" );
137 formatter.format( " * by default.%n" );
138 formatter.format( " */%n" );
139 formatter.format( " public void jdoPreDelete() {}%n" );
140
141 return builder.toString();
142 }
143
144 /**
145 * Generate a <code>Factory</code> class that handles interactions
146 * between the JDO JavaBean objects and the JDO datastore.
147 *
148 * @see #generateFactoryInitialisers
149 * @see #generateSaveMethod
150 * @see #generateFactoryMethods
151 * @throws IOException If errors are encountered while writing the
152 * generated source file.
153 */
154 protected void generateFactory() throws IOException
155 {
156 StringBuilder builder = new StringBuilder( 8192 );
157 Formatter formatter = new Formatter( builder );
158 String factoryName = name + "Factory";
159
160 formatter.format( "package %s;%n%n", source.getPackage().getName() );
161 formatter.format( "import java.io.Serializable;%n" );
162 formatter.format( "import java.util.ArrayList;%n" );
163 formatter.format( "import java.util.Collection;%n" );
164 formatter.format( "import java.util.logging.Logger;%n" );
165
166 formatter.format( "%n" );
167 formatter.format( "import javax.jdo.JDOHelper;%n" );
168 formatter.format( "import javax.jdo.PersistenceManager;%n" );
169 formatter.format( "import javax.jdo.Query;%n" );
170
171 formatter.format( "%n" );
172 formatter.format( "import com.sptci.jdo.PersistenceManagerFactory;%n" );
173 formatter.format( "%n" );
174
175 formatter.format( "/**%n" );
176 formatter.format( " * A factory class for abstracting interactions between the%n" );
177 formatter.format(
178 " * {@link %s} JDO JavaBean and the JDO data store.%n",
179 name );
180 formatter.format( " *%n" );
181 formatter.format( " * @author %s %s%n", getClass().getName(),
182 ( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ssZ" ) ).format( new Date() ) );
183 formatter.format( " * @version $Id: JDOModelGenerator.java,v 1.3 2006/02/15 17:23:32 rakesh Exp $%n" );
184 formatter.format( " */%n" );
185 formatter.format( "public class %s%n", factoryName );
186 formatter.format( " implements Serializable%n" );
187 formatter.format( "{%n" );
188
189 builder.append( generateFactoryInitialisers() );
190 builder.append( generateSaveMethod() );
191 builder.append( generateDeleteMethod() );
192 builder.append( generateFactoryMethods() );
193
194 formatter.format( "}%n" );
195
196
197 StringUtilities.toFile( builder.toString(), factoryName + ".java" );
198 }
199
200 /**
201 * Generate the initialiser methods for the factory class.
202 *
203 * @return String The source code for the initialisers.
204 */
205 protected String generateFactoryInitialisers()
206 {
207 StringBuilder builder = new StringBuilder( 8192 );
208 Formatter formatter = new Formatter( builder );
209 String factoryName = name + "Factory";
210
211 formatter.format( " /**%n" );
212 formatter.format( " * The singleton instance of the class.%n" );
213 formatter.format( " */%n" );
214 formatter.format( " private static final %s singleton =%n",
215 factoryName );
216 formatter.format( " new %s();%n%n", factoryName );
217
218 formatter.format( " /**%n" );
219 formatter.format( " * The logger used to log errors/warnings to.%n" );
220 formatter.format( " */%n" );
221 formatter.format( " private static final Logger logger =%n" );
222 formatter.format( " Logger.getLogger( \"%s.%s\" );%n%n",
223 source.getPackage().getName(), factoryName );
224
225 formatter.format( " /**%n" );
226 formatter.format( " * Default constructor. Cannot be instantiated.%n" );
227 formatter.format( " */%n" );
228 formatter.format( " protected %s() {}%n%n", factoryName );
229
230 formatter.format( " /**%n" );
231 formatter.format( " * Return the singleton instance of the class.%n" );
232 formatter.format( " *%n" );
233 formatter.format( " * @return %s The {@link #singleton} instance.%n",
234 factoryName );
235 formatter.format( " */%n" );
236 formatter.format( " public static final %s getInstance()%n",
237 factoryName );
238 formatter.format( " {%n" );
239 formatter.format( " return singleton;%n" );
240 formatter.format( " }%n%n" );
241
242 return builder.toString();
243 }
244
245 /**
246 * Generate the <code>save</code> method that will be used to save
247 * a JDO JavaBean to the JDO data store.
248 *
249 * @return String The source code for the save method.
250 */
251 protected String generateSaveMethod()
252 {
253 StringBuilder builder = new StringBuilder( 1024 );
254 Formatter formatter = new Formatter( builder );
255
256 String fieldName = name.substring( 0, 1 ).toLowerCase() +
257 name.substring( 1 );
258 formatter.format( " /**%n" );
259 formatter.format(
260 " * Save the specified instance of {@link %s}%n",
261 name );
262 formatter.format( " * to the JDO data store.%n" );
263 formatter.format( " *%n" );
264 formatter.format( " * @param %s The instance to persist to%n",
265 fieldName );
266 formatter.format( " * the data store.%n" );
267 formatter.format( " */%n" );
268 formatter.format( " public void save( %s %s )%n", name, fieldName );
269 formatter.format( " {%n" );
270 formatter.format( " PersistenceManager persistenceManager = null;%n" );
271 formatter.format( " boolean active = false;%n%n" );
272
273 formatter.format( " try%n" );
274 formatter.format( " {%n" );
275 formatter.format( " persistenceManager =%n" );
276 formatter.format( " JDOHelper.getPersistenceManager( %s );%n", fieldName );
277 formatter.format( " if ( persistenceManager == null )%n" );
278 formatter.format( " {%n" );
279 formatter.format( " persistenceManager =%n" );
280 formatter.format( " PersistenceManagerFactory.getPersistenceManager();%n" );
281 formatter.format( " }%n" );
282 formatter.format( " active = persistenceManager.currentTransaction().isActive();%n%n" );
283
284 formatter.format( " if ( ! active )%n" );
285 formatter.format( " {%n" );
286 formatter.format( " persistenceManager.currentTransaction().begin();%n" );
287 formatter.format( " }%n%n" );
288
289 formatter.format( " if ( ! JDOHelper.isPersistent( %s ) )%n",
290 fieldName );
291 formatter.format( " {%n" );
292 formatter.format( " persistenceManager.makePersistent( %s );%n",
293 fieldName );
294 formatter.format( " }%n%n" );
295
296 formatter.format( " if ( ! active )%n" );
297 formatter.format( " {%n" );
298 formatter.format( " persistenceManager.currentTransaction().commit();%n" );
299 formatter.format( " }%n" );
300
301 formatter.format( " }%n" );
302 formatter.format( " finally%n" );
303 formatter.format( " {%n" );
304 formatter.format( " if ( ! active && persistenceManager.currentTransaction().isActive() )%n" );
305 formatter.format( " {%n" );
306 formatter.format( " persistenceManager.currentTransaction().rollback();%n" );
307 formatter.format( " logger.severe( \"Unknown problem. Rollling back transaction.\" );%n" );
308 formatter.format( " }%n" );
309 formatter.format( " }%n" );
310
311 formatter.format( " }%n%n" );
312
313 return builder.toString();
314 }
315
316 /**
317 * Generate the <code>delete</code> method that will be used to delete
318 * a JDO JavaBean to the JDO data store.
319 *
320 * @return String The source code for the save method.
321 */
322 protected String generateDeleteMethod()
323 {
324 StringBuilder builder = new StringBuilder( 1024 );
325 Formatter formatter = new Formatter( builder );
326
327 String fieldName = name.substring( 0, 1 ).toLowerCase() +
328 name.substring( 1 );
329 formatter.format( " /**%n" );
330 formatter.format(
331 " * Delete the specified instance of {@link %s}%n",
332 name );
333 formatter.format( " * from the JDO data store.%n" );
334 formatter.format( " *%n" );
335 formatter.format( " * @param %s The instance to delete from%n",
336 fieldName );
337 formatter.format( " * the data store.%n" );
338 formatter.format( " */%n" );
339 formatter.format( " public void delete( %s %s )%n", name, fieldName );
340 formatter.format( " {%n" );
341 formatter.format( " PersistenceManager persistenceManager = null;%n" );
342 formatter.format( " boolean active = false;%n%n" );
343
344 formatter.format( " try%n" );
345 formatter.format( " {%n" );
346 formatter.format( " persistenceManager =%n" );
347 formatter.format( " JDOHelper.getPersistenceManager( %s );%n", fieldName );
348 formatter.format( " active = persistenceManager.currentTransaction().isActive();%n%n" );
349
350 formatter.format( " if ( ! active )%n" );
351 formatter.format( " {%n" );
352 formatter.format( " persistenceManager.currentTransaction().begin();%n" );
353 formatter.format( " }%n%n" );
354
355 formatter.format( " if ( JDOHelper.isPersistent( %s ) )%n",
356 fieldName );
357 formatter.format( " {%n" );
358 formatter.format( " persistenceManager.deletePersistent( %s );%n",
359 fieldName );
360 formatter.format( " }%n%n" );
361
362 formatter.format( " if ( ! active )%n" );
363 formatter.format( " {%n" );
364 formatter.format( " persistenceManager.currentTransaction().commit();%n" );
365 formatter.format( " }%n" );
366
367 formatter.format( " }%n" );
368 formatter.format( " finally%n" );
369 formatter.format( " {%n" );
370 formatter.format( " if ( ! active && persistenceManager.currentTransaction().isActive() )%n" );
371 formatter.format( " {%n" );
372 formatter.format( " persistenceManager.currentTransaction().rollback();%n" );
373 formatter.format( " logger.severe( \"Unknown problem. Rollling back transaction.\" );%n" );
374 formatter.format( " }%n" );
375 formatter.format( " }%n" );
376
377 formatter.format( " }%n%n" );
378
379 return builder.toString();
380 }
381
382 /**
383 * Generate additional factory methods for fetching the JDO
384 * JavaBean instances from the JDO data store.
385 *
386 * @return String The source code for the factory methods.
387 */
388 protected String generateFactoryMethods()
389 {
390 StringBuilder builder = new StringBuilder( 2046 );
391 Formatter formatter = new Formatter( builder );
392
393 formatter.format( " /**%n" );
394 formatter.format( " * Return all the instance of {@link %s}%n",
395 name );
396 formatter.format( " * from the JDO data store.%n" );
397 formatter.format( " *%n" );
398 formatter.format( " * @return Collection An <code>ArrayList</code> of all the instances.%n" );
399 formatter.format( " */%n" );
400 formatter.format( " @SuppressWarnings(value={\"unchecked\"})%n" );
401 formatter.format( " public final Collection<%s> fetchAll()%n",
402 name );
403 formatter.format( " {%n" );
404
405 formatter.format( " Collection<%s> collection = new ArrayList<%s>();%n",
406 name, name );
407 formatter.format( " PersistenceManager persistenceManager =%n" );
408 formatter.format( " PersistenceManagerFactory.getPersistenceManager();%n" );
409 formatter.format( " Query query = null;%n" );
410 formatter.format( " try%n" );
411 formatter.format( " {%n" );
412 formatter.format(
413 " query = persistenceManager.newQuery( %s.class );%n",
414 name );
415 formatter.format(
416 " collection.addAll( (Collection<%s>) query.execute() );%n",
417 name );
418 formatter.format( " }%n" );
419 formatter.format( " finally%n" );
420 formatter.format( " {%n" );
421 formatter.format( " query.closeAll();%n" );
422 formatter.format( " }%n" );
423 formatter.format( "%n return collection;%n%n" );
424 formatter.format( " }%n%n" );
425
426 return builder.toString();
427 }
428
429 /**
430 * Generate the JDO meta-data file for the JDO JavaBean.
431 *
432 * <p>Uses JDOM and Jaxen for parsing an existing meta-data file
433 * and for creating or updating the file.</p>
434 *
435 * @see JDOMetaDataGenerator#generate
436 * @throws JDOMException If errors are encountered while fetching
437 * the element.
438 * @throws IOException If errors are encountered while writing to
439 * the meta-data file.
440 */
441 protected void generateMetaData()
442 throws JDOMException, IOException
443 {
444 JDOMetaDataGenerator generator = new JDOMetaDataGenerator( name,
445 source.getPackage().getName(), fields );
446 generator.generate();
447 }
448
449 /**
450 * Main method.
451 */
452 public static void main( String[] args )
453 {
454 if ( args.length != 1 )
455 {
456 System.err.println(
457 "Usage: java -classpath <classpath> com.sptci.echo2.JDOModelGenerator <UI class>" );
458 System.exit( 2 );
459 }
460 else
461 {
462 try
463 {
464 JDOModelGenerator generator = new JDOModelGenerator( args[0] );
465 generator.generate();
466 }
467 catch ( Throwable t )
468 {
469 t.printStackTrace();
470 System.exit( 1 );
471 }
472 }
473
474 System.exit( 0 );
475 }
476 }