View Javadoc
1 package xdoclet.plugins; 2 3 import xdoclet.Plugin; 4 import xdoclet.XDocletException; 5 import xdoclet.util.ClasspathManager; 6 import xdoclet.util.FileUtils; 7 import xdoclet.util.betwixt.BetwixtConfigurer; 8 import xdoclet.sdk.xgg.XGGPojo; 9 import xdoclet.sdk.xgg.betwixt.BeanReaderSerializer; 10 11 import java.io.File; 12 import java.io.FileWriter; 13 import java.io.Writer; 14 import java.io.IOException; 15 import java.io.ObjectInputStream; 16 import java.io.InputStream; 17 import java.io.Reader; 18 import java.io.InputStreamReader; 19 import java.beans.IntrospectionException; 20 import java.util.Collection; 21 import java.net.URL; 22 23 import org.apache.commons.betwixt.io.BeanWriter; 24 import org.apache.commons.betwixt.io.BeanReader; 25 import org.apache.commons.betwixt.XMLIntrospector; 26 import org.apache.commons.logging.LogFactory; 27 import org.xml.sax.SAXException; 28 29 /*** 30 * <p> 31 * Plugin backed by <a href="http://jakarta.apache.org/commons/betwixt/">Betwixt</a>. 32 * This plugin is used as a base class for plugins using beans generated by 33 * {@link xdoclet.sdk.xgg.XGGPlugin}. 34 * </p> 35 * <p> 36 * The plugin developer only has to implement one of the <code>populate</code> 37 * methods (which one depending on whether the plugin is intended to be used in 38 * one file or multiple files mode). 39 * </p> 40 * <p> 41 * The implemented populate method should cast the root bean to the class 42 * that is passed to the constructor and populate the bean with sub-beans, 43 * using the metaData that's passes to the same populate method. The metaData 44 * should also be cast to the appropriate type, like {@link xjavadoc.XClass} 45 * or whatever metadata type the plugin expects to be fed with. 46 * </p> 47 * 48 * @bean.class name="betwixt" 49 * displayName="Betwixt Plugin" 50 * shortDescription="A plugin that generates XML with Betwixt" 51 * 52 * @bean.icon color16="betwixt16.gif" 53 * 54 * @author <a href="mailto:aslak.hellesoy at netcom.no">Aslak Hellesøy</a> 55 * @version $Revision: 1.8 $ 56 */ 57 public abstract class BetwixtPlugin extends Plugin { 58 public static final String SERIALIZED_BEANREADER = "BeanReader.ser"; 59 60 private final Class _rootClass; 61 62 // The BeanReader used to read in merge files 63 private BeanReader _beanReader; 64 65 /*** 66 * Sets the version. 67 * @param version DTD/XSD version. 68 * 69 * @bean.property 70 * shortDescription="Name of DTD or XSD file." 71 * displayName="Version" 72 * default="true" 73 */ 74 public void setVersion(String version) { 75 XGGPojo.setVersion(version); 76 } 77 78 protected BetwixtPlugin( Class rootClass ) { 79 _rootClass = rootClass; 80 81 /* 82 TODO This doesn't work yet. 83 BeanReader isn't properly serialised with all rules, 84 and changes are probably needed in Digester to make it work. 85 */ 86 //_beanReader = readBeanReader(); 87 88 // TODO this is temporary till we get the above to work 89 File root = FileUtils.getRoot( getClass() ); 90 System.out.println("CREATING BEANREADER"); 91 _beanReader = BeanReaderSerializer.createBeanReader( root, null); 92 System.out.println("DONE CREATING BEANREADER"); 93 } 94 95 /*** 96 * Reads a serialised XMLBeanInfoRegistry that will be used 97 * by both BeanReader and BeanWriter. The serialised XMLBeanInfoRegistry 98 * is packaged during build time. The reason why we're doing it this 99 * way is that the construction of an XMLBeanInfoRegistry can be a 100 * lengthy operation. 101 * 102 * @throws IllegalStateException if the registry couldn't be read. 103 */ 104 private BeanReader readBeanReader() throws IllegalStateException { 105 BeanReader result = null; 106 try { 107 // We expect to find beans in a subpackage called xml. That's 108 // where XGG should generate the beans. 109 InputStream serialisedRegistry = getClass().getResourceAsStream( "xml/" + SERIALIZED_BEANREADER); 110 ObjectInputStream ois = new ObjectInputStream(serialisedRegistry); 111 return (BeanReader) ois.readObject(); 112 } catch( IOException e ) { 113 LogFactory.getLog(BetwixtPlugin.class).warn("NON FATAL: Couldn't read XMLBeanInfoRegistry : " + e.getMessage() ); 114 // throw new IllegalStateException( e.getMessage() ); 115 } catch( ClassNotFoundException e ) { 116 LogFactory.getLog(BetwixtPlugin.class).warn("NON FATAL: Couldn't read XMLBeanInfoRegistry : " + e.getMessage() ); 117 // throw new IllegalStateException( e.getMessage() ); 118 } catch( Exception e ) { 119 LogFactory.getLog(BetwixtPlugin.class).warn("NON FATAL: Couldn't read XMLBeanInfoRegistry : " + e.getMessage() ); 120 // throw new IllegalStateException( e.getMessage() ); 121 } 122 return result; 123 } 124 125 /*** 126 * <p> 127 * Parses an XML stream into a bean. This method can be used by subclasses 128 * to merge in additional content. The result should be cast to the 129 * expected Bean class. 130 * </p> 131 * <p> 132 * The stream will be sought for on the classpath, and the mergeFile 133 * should be a relative path. 134 * </p> 135 * 136 * @param mergeFile a relative path to a resource containing XML. 137 * @return a Java Bean, or null if the mergeFile wasn't found. 138 * @throws XDocletException if the file can't be properly parsed. 139 */ 140 protected final Object parse( String mergeFile ) throws XDocletException { 141 if( mergeFile == null ) { 142 throw new XDocletException( "mergeFile can't be null" ); 143 } 144 URL url = getXDoclet().getClasspathManager().getResource( mergeFile ); 145 if( url == null ) { 146 String classpath = getXDoclet().getClasspathManager().getClasspath(); 147 String niceClasspath = ClasspathManager.getNiceClasspath( classpath ); 148 // TODO: only info here 149 LogFactory.getLog(BetwixtPlugin.class).error( "Couldn't find " + mergeFile + " on classpath:" + niceClasspath ); 150 return null; 151 } else { 152 return parse( url ); 153 } 154 } 155 156 private final Object parse( URL url ) throws XDocletException { 157 if( url == null ) { 158 throw new XDocletException( "url can't be null" ); 159 } 160 try { 161 return parse( new InputStreamReader( url.openStream() ), url.toExternalForm() ); 162 } catch( IOException e ) { 163 LogFactory.getLog(BetwixtPlugin.class).error("Couldn't parse " + url.toExternalForm()); 164 throw new XDocletException( e ); 165 } 166 } 167 168 /*** 169 * @todo Send the content through Jelly before sending it to Betwixt. 170 */ 171 private final Object parse( Reader in, String location ) throws XDocletException { 172 try { 173 System.out.println("********************************* PARSING MERGE FILE " + location); 174 Object result = _beanReader.parse( in ); 175 System.out.println("################################# DONE PARSING MERGE FILE " + location); 176 return result; 177 } catch( IOException e ) { 178 LogFactory.getLog(BetwixtPlugin.class).error("Couldn't parse " + location); 179 throw new XDocletException( e ); 180 } catch( SAXException e ) { 181 LogFactory.getLog(BetwixtPlugin.class).error("Couldn't parse " + location); 182 throw new XDocletException( e ); 183 } 184 } 185 186 protected final void generate(File file, Object metaData) throws IOException, XDocletException { 187 XGGPojo root = createRoot(); 188 populate(root, metaData); 189 generate( file, root ); 190 } 191 192 protected final void generate(File file, Collection metaData) throws IOException, XDocletException { 193 XGGPojo root = createRoot(); 194 populate(root, metaData); 195 generate( file, root ); 196 } 197 198 private final void generate( File file, XGGPojo root ) throws IOException, XDocletException { 199 Writer writer = new FileWriter(file); 200 BeanWriter beanWriter = new BeanWriter(writer); 201 if( _beanReader != null ) { 202 beanWriter.setXMLIntrospector( _beanReader.getXMLIntrospector() ); 203 } else { 204 XMLIntrospector introspector = new XMLIntrospector(); 205 BetwixtConfigurer.configureIntrospector( introspector, null ); 206 } 207 208 try { 209 beanWriter.setIndent(" "); 210 beanWriter.setEndOfLine(System.getProperty("line.separator")); 211 beanWriter.writeXmlDeclaration("<?xml version=\"1.0\" encoding=\"" + getEncoding() + "\"?>"); 212 beanWriter.write(root); 213 beanWriter.flush(); 214 writer.flush(); 215 writer.close(); 216 } catch (IOException e) { 217 throw e; 218 } catch (SAXException e) { 219 LogFactory.getLog(BetwixtPlugin.class).error("Failed to write XML", e); 220 throw new XDocletException( e ); 221 } catch (IntrospectionException e) { 222 LogFactory.getLog(BetwixtPlugin.class).error("Failed to write XML", e); 223 throw new XDocletException( e ); 224 } 225 } 226 227 /*** 228 * Populates the XML tree. 229 * @param root Object representing the root element in the XML. 230 * @param metaData data that can be used to populate the XML tree. 231 * @throws XDocletException if population fails. 232 */ 233 protected void populate(XGGPojo root, Object metaData) throws XDocletException { 234 throw new UnsupportedOperationException("This method should be implemented in " + getClass().getName() ); 235 } 236 237 /*** 238 * Populates the XML tree. 239 * @param root Object representing the root element in the XML. 240 * @param metaData data that can be used to populate the XML tree. 241 * @throws XDocletException if population fails. 242 */ 243 protected void populate(XGGPojo root, Collection metaData) throws XDocletException { 244 throw new UnsupportedOperationException("This method should be implemented in " + getClass().getName() ); 245 } 246 247 private XGGPojo createRoot() { 248 try { 249 return (XGGPojo) _rootClass.newInstance(); 250 } catch (Exception e) { 251 LogFactory.getLog(BetwixtPlugin.class).error("Failed to instantiate a new XGGPojo: " + _rootClass.getName(), e ); 252 throw new IllegalArgumentException("Can't instantiate with " + _rootClass.getName() ); 253 } 254 } 255 }

This page was automatically generated by Maven