KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > metadata > XmlFileLoader


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.metadata;
23
24 import org.jboss.deployment.DeploymentException;
25 import org.jboss.logging.Logger;
26 import org.jboss.util.xml.JBossEntityResolver;
27 import org.w3c.dom.Document JavaDoc;
28 import org.xml.sax.ErrorHandler JavaDoc;
29 import org.xml.sax.InputSource JavaDoc;
30 import org.xml.sax.SAXException JavaDoc;
31 import org.xml.sax.SAXParseException JavaDoc;
32
33 import javax.xml.parsers.DocumentBuilder JavaDoc;
34 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.InputStream JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.net.URLClassLoader JavaDoc;
39
40 /** XmlFileLoader class is used to read ejb-jar.xml, standardjboss.xml, jboss.xml
41  * files, process them using DTDs and create ApplicationMetaData object for
42  * future use. It also provides the local entity resolver for the JBoss
43  * specific DTDs.
44  *
45  * @author <a HREF="mailto:bill@burkecentral.com">Bill Burke</a>
46  * @author <a HREF="mailto:sebastien.alborini@m4x.org">Sebastien Alborini</a>
47  * @author <a HREF="mailto:WolfgangWerner@gmx.net">Wolfgang Werner</a>
48  * @author <a HREF="mailto:Darius.D@jbees.com">Darius Davidavicius</a>
49  * @author <a HREF="mailto:scott.stark@jboss.org">Scott Stark</a>
50  * @author <a HREF="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>.
51  * @version $Revision: 37459 $
52  */

53 public class XmlFileLoader
54 {
55    // Constants -----------------------------------------------------
56

57    // Attributes ----------------------------------------------------
58
private static boolean defaultValidateDTDs = false;
59    private static Logger log = Logger.getLogger(XmlFileLoader.class);
60    private URLClassLoader JavaDoc classLoader;
61    private ApplicationMetaData metaData;
62    private boolean validateDTDs;
63    
64    // Static --------------------------------------------------------
65
public static boolean getDefaultValidateDTDs()
66    {
67       return defaultValidateDTDs;
68    }
69    
70    public static void setDefaultValidateDTDs(boolean validate)
71    {
72       defaultValidateDTDs = validate;
73    }
74    
75    
76    // Constructors --------------------------------------------------
77
public XmlFileLoader()
78    {
79       this(defaultValidateDTDs);
80    }
81    
82    public XmlFileLoader(boolean validateDTDs)
83    {
84       this.validateDTDs = validateDTDs;
85    }
86    
87    // Public --------------------------------------------------------
88
public ApplicationMetaData getMetaData()
89    {
90       return metaData;
91    }
92    
93    /**
94     * Set the class loader
95     */

96    public void setClassLoader(URLClassLoader JavaDoc cl)
97    {
98       classLoader = cl;
99    }
100    
101    /**
102     * Gets the class loader
103     *
104     * @return ClassLoader - the class loader
105     */

106    public ClassLoader JavaDoc getClassLoader()
107    {
108       return classLoader;
109    }
110    
111    
112    /** Get the flag indicating that ejb-jar.dtd, jboss.dtd &
113     * jboss-web.dtd conforming documents should be validated
114     * against the DTD.
115     */

116    public boolean getValidateDTDs()
117    {
118       return validateDTDs;
119    }
120    
121    /** Set the flag indicating that ejb-jar.dtd, jboss.dtd &
122     * jboss-web.dtd conforming documents should be validated
123     * against the DTD.
124     */

125    public void setValidateDTDs(boolean validate)
126    {
127       this.validateDTDs = validate;
128    }
129    
130    /**
131     * Creates the ApplicationMetaData.
132     * The configuration files are found in the classLoader when not explicitly given as
133     * the alternativeDD.
134     *
135     * The default jboss.xml and jaws.xml files are always read first, then we override
136     * the defaults if the user provides them
137     *
138     * @param alternativeDD a URL to the alternative DD given in application.xml
139     */

140    public ApplicationMetaData load(URL JavaDoc alternativeDD) throws Exception JavaDoc
141    {
142       URL JavaDoc ejbjarUrl = null;
143       if (alternativeDD != null)
144       {
145          log.debug("Using alternativeDD: " + alternativeDD);
146          ejbjarUrl = alternativeDD;
147       }
148       else
149       {
150          ejbjarUrl = getClassLoader().getResource("META-INF/ejb-jar.xml");
151       }
152
153       if (ejbjarUrl == null)
154       {
155          throw new DeploymentException("no ejb-jar.xml found");
156       }
157
158       // create the metadata
159
metaData = new ApplicationMetaData();
160       metaData.setResourceClassLoader(classLoader);
161
162       Document JavaDoc ejbjarDocument = getDocumentFromURL(ejbjarUrl);
163       
164       // the url may be used to report errors
165
metaData.setUrl(ejbjarUrl);
166       metaData.importEjbJarXml(ejbjarDocument.getDocumentElement());
167       
168       // Load jbossdefault.xml from the default classLoader
169
// we always load defaults first
170
// we use the context classloader, because this guy has to know where
171
// this file is
172
URL JavaDoc defaultJbossUrl = Thread.currentThread().getContextClassLoader().getResource("standardjboss.xml");
173       if (defaultJbossUrl == null)
174       {
175          throw new DeploymentException("no standardjboss.xml found");
176       }
177
178       Document JavaDoc defaultJbossDocument = null;
179       try
180       {
181          defaultJbossDocument = getDocumentFromURL(defaultJbossUrl);
182          metaData.setUrl(defaultJbossUrl);
183          metaData.importJbossXml(defaultJbossDocument.getDocumentElement());
184       }
185       catch (Exception JavaDoc ex)
186       {
187          log.error("failed to load standardjboss.xml. There could be a syntax error.", ex);
188          throw ex;
189       }
190       
191       // Load jboss.xml
192
// if this file is provided, then we override the defaults
193
try
194       {
195          URL JavaDoc jbossUrl = getClassLoader().getResource("META-INF/jboss.xml");
196          if (jbossUrl != null)
197          {
198             Document JavaDoc jbossDocument = getDocumentFromURL(jbossUrl);
199             metaData.setUrl(jbossUrl);
200             metaData.importJbossXml(jbossDocument.getDocumentElement());
201          }
202       }
203       catch (Exception JavaDoc ex)
204       {
205          log.error("failed to load jboss.xml. There could be a syntax error.", ex);
206          throw ex;
207       }
208       
209       return metaData;
210    }
211
212    /** Invokes getDocument(url, defaultValidateDTDs)
213     *
214     */

215    public static Document JavaDoc getDocument(URL JavaDoc url) throws DeploymentException
216    {
217       return getDocument(url, defaultValidateDTDs);
218    }
219    
220    /** Get the xml file from the URL and parse it into a Document object.
221     * Calls new XmlFileLoader(validateDTDs).getDocumentFromURL(url);
222     * @param url the URL from which the xml doc is to be obtained.
223     * @return Document
224     */

225    public static Document JavaDoc getDocument(URL JavaDoc url, boolean validateDTDs) throws DeploymentException
226    {
227       XmlFileLoader loader = new XmlFileLoader(validateDTDs);
228       return loader.getDocumentFromURL(url);
229    }
230    
231    /** Get the xml file from the URL and parse it into a Document object.
232     * Calls getDocument(new InputSource(url.openStream()), url.getPath())
233     * with the InputSource.SystemId set to url.toExternalForm().
234     *
235     * @param url the URL from which the xml doc is to be obtained.
236     * @return Document
237     */

238    public Document JavaDoc getDocumentFromURL(URL JavaDoc url) throws DeploymentException
239    {
240       InputStream JavaDoc is = null;
241       try
242       {
243          is = url.openStream();
244          return getDocument(is, url.toExternalForm());
245       }
246       catch (IOException JavaDoc e)
247       {
248          throw new DeploymentException("Failed to obtain xml doc from URL", e);
249       }
250    }
251
252    /** Parses the xml document in is to create a DOM Document. DTD validation
253     * is enabled if validateDTDs is true and we install an EntityResolver and
254     * ErrorHandler to resolve J2EE DTDs and handle errors. We also create an
255     * InputSource for the InputStream and set the SystemId URI to the inPath
256     * value. This allows relative entity references to be resolved against the
257     * inPath URI. The is argument will be closed.
258     *
259     * @param is the InputStream containing the xml descriptor to parse
260     * @param inPath the path information for the xml doc. This is used as the
261     * InputSource SystemId URI for resolving relative entity references.
262     * @return Document
263     */

264    public Document JavaDoc getDocument(InputStream JavaDoc is, String JavaDoc inPath)
265       throws DeploymentException
266    {
267       InputSource JavaDoc is2 = new InputSource JavaDoc(is);
268       is2.setSystemId(inPath);
269       Document JavaDoc doc = null;
270       try
271       {
272          doc = getDocument(is2, inPath);
273       }
274       finally
275       {
276          // close the InputStream to get around "too many open files" errors
277
// with large heaps
278
try
279          {
280             if( is != null )
281               is.close();
282          }
283          catch (Exception JavaDoc e)
284          {
285             // ignore
286
}
287       }
288       return doc;
289    }
290
291    /** Parses the xml document in is to create a DOM Document. DTD validation
292     * is enabled if validateDTDs is true and we install an EntityResolver and
293     * ErrorHandler to resolve J2EE DTDs and handle errors. We also create an
294     * InputSource for the InputStream and set the SystemId URI to the inPath
295     * value. This allows relative entity references to be resolved against the
296     * inPath URI.
297     *
298     * @param is the InputSource containing the xml descriptor to parse
299     * @param inPath the path information for the xml doc. This is used for
300     * only for error reporting.
301     * @return Document
302     */

303    public Document JavaDoc getDocument(InputSource JavaDoc is, String JavaDoc inPath)
304       throws DeploymentException
305    {
306       try
307       {
308          DocumentBuilderFactory JavaDoc docBuilderFactory = DocumentBuilderFactory.newInstance();
309
310          // Enable DTD validation based on our validateDTDs flag
311
docBuilderFactory.setValidating(validateDTDs);
312          // make the parser namespace-aware in case we deal
313
// with ejb2.1 descriptors, will not break dtd parsing in any way
314
// in which case there would be just a default namespace
315
docBuilderFactory.setNamespaceAware(true);
316          // this will (along JAXP in conjunction with
317
// validation+namespace-awareness) enable xml schema checking.
318
// Will currently fail because some J2EE1.4/W3C schemas
319
// are still lacking.
320
//docBuilderFactory.setAttribute
321
// ("http://java.sun.com/xml/jaxp/properties/schemaLanguage","http://www.w3.org/2001/XMLSchema");
322
DocumentBuilder JavaDoc docBuilder = docBuilderFactory.newDocumentBuilder();
323          JBossEntityResolver lr = new JBossEntityResolver();
324          LocalErrorHandler eh = new LocalErrorHandler( inPath, lr );
325          docBuilder.setEntityResolver(lr);
326          docBuilder.setErrorHandler(eh );
327
328          Document JavaDoc doc = docBuilder.parse(is);
329          if(validateDTDs && eh.hadError())
330          {
331             throw new DeploymentException("Invalid XML: file=" + inPath, eh.getException());
332          }
333          return doc;
334       }
335       catch (DeploymentException e)
336       {
337          throw e;
338       }
339       catch (SAXParseException JavaDoc e)
340       {
341          String JavaDoc msg = "Invalid XML: file=" + inPath+"@"+e.getColumnNumber()+":"+e.getLineNumber();
342          throw new DeploymentException(msg, e);
343       }
344       catch (SAXException JavaDoc e)
345       {
346          throw new DeploymentException("Invalid XML: file=" + inPath, e);
347       }
348       catch (Exception JavaDoc e)
349       {
350          throw new DeploymentException("Invalid XML: file=" + inPath, e);
351       }
352    }
353    
354    // Package protected ---------------------------------------------
355

356    // Protected -----------------------------------------------------
357

358    // Private -------------------------------------------------------
359

360    // Inner classes -------------------------------------------------
361

362    /** Local error handler for entity resolver to DocumentBuilder parser.
363     * Error is printed to output just if DTD was detected in the XML file.
364     * If DTD was not found in XML file it is assumed that the EJB builder
365     * doesn't want to use DTD validation. Validation may have been enabled via
366     * validateDTDs flag so we look to the isEntityResolved() function in the LocalResolver
367     * and reject errors if DTD not used.
368     **/

369    private static class LocalErrorHandler implements ErrorHandler JavaDoc
370    {
371       // The xml file being parsed
372
private String JavaDoc theFileName;
373       private JBossEntityResolver localResolver;
374       private boolean error;
375       private SAXParseException JavaDoc exception;
376       
377       public LocalErrorHandler( String JavaDoc inFileName, JBossEntityResolver localResolver )
378       {
379          this.theFileName = inFileName;
380          this.localResolver = localResolver;
381          this.error = false;
382       }
383       
384       public void error(SAXParseException JavaDoc exception)
385       {
386          this.exception = exception;
387          if ( localResolver.isEntityResolved() )
388          {
389             this.error = true;
390             log.error("XmlFileLoader: File "
391             + theFileName
392             + " process error. Line: "
393             + String.valueOf(exception.getLineNumber())
394             + ". Error message: "
395             + exception.getMessage()
396             );
397          }//end if
398
}
399
400       public void fatalError(SAXParseException JavaDoc exception)
401       {
402          this.exception = exception;
403          if ( localResolver.isEntityResolved() )
404          {
405             this.error = true;
406             log.error("XmlFileLoader: File "
407             + theFileName
408             + " process fatal error. Line: "
409             + String.valueOf(exception.getLineNumber())
410             + ". Error message: "
411             + exception.getMessage()
412             );
413          }//end if
414
}
415       
416       public void warning(SAXParseException JavaDoc exception)
417       {
418          this.exception = exception;
419          if ( localResolver.isEntityResolved() )
420          {
421             this.error = true;
422             log.error("XmlFileLoader: File "
423             + theFileName
424             + " process warning. Line: "
425             + String.valueOf(exception.getLineNumber())
426             + ". Error message: "
427             + exception.getMessage()
428             );
429          }//end if
430
}
431
432       public SAXParseException JavaDoc getException()
433       {
434          return exception;
435       }
436
437       public boolean hadError()
438       {
439          return error;
440       }
441    }// end class LocalErrorHandler
442
}
443
Popular Tags