001 package com.sptci.echo2;
002
003 import java.io.File;
004 import java.io.FileOutputStream;
005 import java.io.IOException;
006
007 import java.util.List;
008 import java.util.Map;
009
010 import org.jdom.Attribute;
011 import org.jdom.DocType;
012 import org.jdom.Document;
013 import org.jdom.Element;
014 import org.jdom.JDOMException;
015 import org.jdom.input.SAXBuilder;
016 import org.jdom.output.Format;
017 import org.jdom.output.XMLOutputter;
018 import org.jdom.xpath.XPath;
019
020 /**
021 * A JDO meta-data generator. This is a generic generator that does
022 * not apply any JDO vendor specific extensions. Sub-classes may be
023 * developed that apply vendor specific extensions.
024 *
025 * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
026 * @author Rakesh Vidyadharan 2006-02-08
027 * @version $Id: JDOMetaDataGenerator.java,v 1.4 2006/02/15 17:22:56 rakesh Exp $
028 */
029 public class JDOMetaDataGenerator
030 {
031 /**
032 * The name of the class for which the meta-data is to be generated.
033 */
034 protected String name;
035
036 /**
037 * The name of the package to which the class belongs.
038 */
039 protected String packageName;
040
041 /**
042 * The fields available in the class for which meta-data is to be
043 * generated.
044 */
045 protected Map<String, String> fields;
046
047 /**
048 * Default constructor. No special actions required.
049 */
050 protected JDOMetaDataGenerator() {}
051
052 /**
053 * Create a new instance of the class using the specified values.
054 *
055 * @param name The {@link #name} value to set.
056 * @param packageName The {@link #packageName} value to set.
057 * @param fields The {@link #fields} value to set.
058 */
059 public JDOMetaDataGenerator ( String name, String packageName,
060 Map<String, String> fields )
061 {
062 super();
063 this.name = name;
064 this.packageName = packageName;
065 this.fields = fields;
066 }
067
068 /**
069 * Generate the JDO meta-data file for a JDO JavaBean.
070 *
071 * <p>Uses JDOM and Jaxen for parsing an existing meta-data file
072 * and for creating or updating the file.</p>
073 *
074 * @see #updateFile
075 * @see #generateFile
076 * @throws JDOMException If errors are encountered while fetching
077 * the element.
078 * @throws IOException If errors are encountered while writing to
079 * the meta-data file.
080 */
081 public void generate() throws JDOMException, IOException
082 {
083 File file = new File( "package.jdo" );
084
085 if ( file.exists() )
086 {
087 updateFile( file );
088 }
089 else
090 {
091 generateFile( file );
092 }
093 }
094
095 /**
096 * Generate a new meta-data file with the meta-data for the {@link
097 * #name} JDO object.
098 *
099 * @see #writeFile
100 * @param file The file to generate
101 * @throws JDOMException If errors are encountered while fetching
102 * the element.
103 * @throws IOException If errors are encountered while writing to
104 * the meta-data file.
105 */
106 protected void generateFile( File file )
107 throws JDOMException, IOException
108 {
109 DocType docType = new DocType(
110 "jdo",
111 "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN",
112 "http://java.sun.com/dtd/jdo_1_0.dtd" );
113
114 Document document = new Document( new Element( "jdo" ), docType );
115 document.getRootElement().addContent( generateMetaData() );
116 document.getRootElement().addContent( generateEchoPackage() );
117 writeFile ( file, document );
118 }
119
120 /**
121 * Generate the meta-data elements and attributes for the JDO object
122 * represented by {@link #name}.
123 *
124 * @see #generateSourcePackage
125 * @see #generateSource
126 * @return Element The element that represents the JDO object.
127 */
128 protected Element generateMetaData()
129 {
130 Element element = generateSourcePackage();
131 element.addContent( generateSource() );
132
133 return element;
134 }
135
136 /**
137 * Generate the package ({@link #packageName}) element for the class
138 * represented by {@link #name}.
139 *
140 * @return Element The element representing the package.
141 */
142 protected Element generateSourcePackage()
143 {
144 Element element = new Element( "package" );
145 element.setAttribute( "name", packageName );
146
147 return element;
148 }
149
150 /**
151 * Generate the element for the class represented by {@link #name}.
152 *
153 * @return Element The element representing the class.
154 */
155 protected Element generateSource()
156 {
157 Element element = new Element( "class" );
158 element.setAttribute( "name", name );
159
160 Element hash = new Element( "field" );
161 hash.setAttribute( "name", "hash" );
162 element.addContent( hash );
163
164 for ( Map.Entry<String, String> entry : fields.entrySet() )
165 {
166 Element field = new Element( "field" );
167 field.setAttribute( "name", entry.getKey() );
168 element.addContent( field );
169
170 if ( entry.getValue().contains( "List<ListItem>" ) )
171 {
172 Element child = new Element( "collection" );
173 child.setAttribute( "element-type", "com.sptci.echo2.ListItem" );
174 field.addContent( child );
175 }
176 if ( entry.getValue().contains( "Map<String, Boolean>" ) )
177 {
178 Element child = new Element( "map" );
179 child.setAttribute( "key-type", "java.lang.String" );
180 child.setAttribute( "value-type", "java.lang.Boolean" );
181 field.addContent( child );
182 }
183 }
184
185 return element;
186 }
187
188 /**
189 * Generate the meta-data elements and attributes for the
190 * <code>com.sptci.echo2</code> package.
191 *
192 * @see #generateListItem
193 * @return Element The element that represents the meta-data for
194 * the package.
195 */
196 protected Element generateEchoPackage()
197 {
198 Element element = new Element( "package" );
199 element.setAttribute( "name", "com.sptci.echo2" );
200 element.addContent( generateListItem() );
201
202 return element;
203 }
204
205 /**
206 * Write the specified XML document to the specified file.
207 *
208 * @param file The file to write to.
209 * @param document The document to write.
210 * @throws JDOMException If errors are encountered while fetching
211 * the element.
212 * @throws IOException If errors are encountered while writing to
213 * the meta-data file.
214 */
215 protected void writeFile( File file, Document document )
216 throws JDOMException, IOException
217 {
218 FileOutputStream out = new FileOutputStream( file );
219 Format format = Format.getPrettyFormat();
220 format.setLineSeparator( System.getProperty( "line.separator" ) );
221 format.setIndent( " " );
222
223 XMLOutputter outputter = new XMLOutputter( format );
224 outputter.output( document, out );
225 out.flush();
226 out.close();
227 }
228
229 /**
230 * Add the meta-data for the {@link #name} JDO object to the
231 * existing meta-data file.
232 *
233 * @see #fetchSourcePackage
234 * @see #generateMetaData
235 * @see #fetchSource
236 * @see #generateSource
237 * @see #fetchEchoPackage
238 * @see #fetchListItem
239 * @see #generateEchoPackage
240 * @see #generateListItem
241 * @see #writeFile
242 * @param file The file to update.
243 * @throws JDOMException If errors are encountered while fetching
244 * the element.
245 * @throws IOException If errors are encountered while writing to
246 * the meta-data file.
247 */
248 protected void updateFile( File file )
249 throws JDOMException, IOException
250 {
251 SAXBuilder builder = new SAXBuilder();
252 Document document = builder.build( file );
253
254 Element sourcePackage = fetchSourcePackage( document );
255 if ( sourcePackage == null )
256 {
257 document.getRootElement().addContent( generateMetaData() );
258 }
259 else if ( fetchSource( document ) == null )
260 {
261 sourcePackage.addContent( generateSource() );
262 }
263
264 Element echo = fetchEchoPackage( document );
265 if ( echo == null )
266 {
267 document.getRootElement().addContent( generateEchoPackage() );
268 }
269 else
270 {
271 if ( fetchListItem( document ) == null )
272 {
273 echo.addContent( generateListItem() );
274 }
275 }
276
277 writeFile( file, document );
278 }
279
280 /**
281 * Fetch the element (if it exists) for the package definition for
282 * {@link #packageName}.
283 *
284 * @param document The document from which to fetch the element.
285 * @return Element The appropriate element.
286 * @throws JDOMException If errors are encountered while fetching
287 * the element.
288 */
289 protected Element fetchSourcePackage( Document document )
290 throws JDOMException
291 {
292 XPath xpath = XPath.newInstance(
293 "/jdo/package[@name = '" + packageName + "']" );
294 return ( (Element) xpath.selectSingleNode( document ) );
295 }
296
297 /**
298 * Fetch the element (if it exists) that represents the class
299 * representing {@link #name}.
300 *
301 * @param document The document from which to fetch the element.
302 * @return Element The appropriate element.
303 * @throws JDOMException If errors are encountered while fetching
304 * the element.
305 */
306 protected Element fetchSource( Document document )
307 throws JDOMException
308 {
309 XPath xpath = XPath.newInstance(
310 "/jdo/package[@name = '" + packageName + "']/class[@name = '" + name + "']" );
311 return ( (Element) xpath.selectSingleNode( document ) );
312 }
313
314 /**
315 * Fetch the element (if it exists) for the package definition for
316 * <code>com.sptci.echo2</code>.
317 *
318 * @param document The document from which to fetch the element.
319 * @return Element The appropriate element.
320 * @throws JDOMException If errors are encountered while fetching
321 * the element.
322 */
323 protected Element fetchEchoPackage( Document document )
324 throws JDOMException
325 {
326 XPath xpath = XPath.newInstance(
327 "/jdo/package[@name = 'com.sptci.echo2']" );
328 return ( (Element) xpath.selectSingleNode( document ) );
329 }
330
331 /**
332 * Fetch the element (if it exists) for the class definition for
333 * <code>com.sptci.echo2.ListItem</code>.
334 *
335 * @param document The document from which to fetch the element.
336 * @return Element The appropriate element.
337 * @throws JDOMException If errors are encountered while fetching
338 * the element.
339 */
340 protected Element fetchListItem( Document document )
341 throws JDOMException
342 {
343 XPath xpath = XPath.newInstance(
344 "/jdo/package[@name = 'com.sptci.echo2']/class[@name = 'ListItem']" );
345 return ( (Element) xpath.selectSingleNode( document ) );
346 }
347
348 /**
349 * Generate the meta-data for the {@link ListItem} class.
350 *
351 * @return Element The element that represents the meta-data for
352 * the class.
353 */
354 protected Element generateListItem()
355 {
356 Element element = new Element( "class" );
357 element.setAttribute( "name", "ListItem" );
358
359 Element field1 = new Element( "field" );
360 field1.setAttribute( "name", "value" );
361 field1.setAttribute( "null-value", "exception" );
362 element.addContent( field1 );
363
364 Element field2 = new Element( "field" );
365 field2.setAttribute( "name", "selected" );
366 field2.setAttribute( "null-value", "exception" );
367 element.addContent( field2 );
368
369 return element;
370 }
371 }