001: /**********************************************************************
002: Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: 2004 Kikuchi Kousuke - org.jpox.enhancer.conf.MetaDataParser
017: 2004 Andy Jefferson - added class and field custom object creation facility
018: 2004 Andy Jefferson - updated resolve entity to use Ralf Ullrich suggestion
019: 2004 Marco Schulze (NightLabs.de) - added safety checks for missing local dtd files
020: 2004 Marco Schulze (NightLabs.de) - added special handling of SAXException
021: ...
022: **********************************************************************/package org.jpox.metadata.xml;
023:
024: import java.io.FileInputStream;
025: import java.io.InputStream;
026: import java.net.URL;
027:
028: import javax.xml.parsers.SAXParser;
029: import javax.xml.parsers.SAXParserFactory;
030:
031: import org.jpox.exceptions.JPOXException;
032: import org.jpox.exceptions.JPOXUserException;
033: import org.jpox.metadata.InvalidMetaDataException;
034: import org.jpox.metadata.MetaData;
035: import org.jpox.metadata.MetaDataManager;
036: import org.jpox.util.EntityResolverFactory;
037: import org.jpox.util.JPOXLogger;
038: import org.jpox.util.JavaUtils;
039: import org.jpox.util.Localiser;
040: import org.jpox.util.StringUtils;
041: import org.xml.sax.EntityResolver;
042: import org.xml.sax.SAXException;
043: import org.xml.sax.helpers.DefaultHandler;
044:
045: /**
046: * Class to provide the parsing framework for parsing metadata files.
047: * This will support parsing of any metadata files where the resultant object is
048: * derived from org.jpox.metadata.MetaData, so can be used on JDO files, ORM files,
049: * JDOQUERY files, JPA files, or "persistence.xml" files. Can be used for any future
050: * metadata files too.
051: * <P>
052: * Provides 3 different entry points depending on whether the caller has a URL,
053: * a file, or an InputStream.
054: * </P>
055: *
056: * @since 1.1
057: * @version $Revision: 1.1 $
058: */
059: public class MetaDataParser extends DefaultHandler {
060: /** Localiser for messages */
061: protected static Localiser LOCALISER = Localiser
062: .getInstance("org.jpox.metadata.Localisation");
063:
064: /** MetaData manager. */
065: protected final MetaDataManager mgr;
066:
067: /** Whether to validate while parsing. */
068: protected final boolean validate;
069:
070: /** SAXParser being used. */
071: SAXParser parser = null;
072:
073: /**
074: * Constructor.
075: * @param mgr MetaDataManager
076: * @param validate Whether to validate while parsing
077: */
078: public MetaDataParser(MetaDataManager mgr, boolean validate) {
079: this .mgr = mgr;
080: this .validate = validate;
081: }
082:
083: /**
084: * Method to parse a MetaData file given the URL of the file.
085: * @param url Url of the metadata file
086: * @param handlerName Name of the handler plugin to use when parsing
087: * @return The MetaData for this file
088: * @throws JPOXException thrown if error occurred
089: */
090: public MetaData parseMetaDataURL(URL url, String handlerName) {
091: if (url == null) {
092: String msg = LOCALISER.msg("044031");
093: JPOXLogger.METADATA.error(msg);
094: throw new JPOXException(msg);
095: }
096:
097: InputStream in = null;
098: try {
099: in = url.openStream();
100: } catch (Exception ignore) {
101: }
102: if (in == null) {
103: try {
104: in = new FileInputStream(StringUtils
105: .getFileForFilename(url.getFile()));
106: } catch (Exception ignore) {
107: }
108: }
109: if (in == null) {
110: JPOXLogger.METADATA.error(LOCALISER.msg("044032", url
111: .toString()));
112: throw new JPOXException(LOCALISER.msg("044032", url
113: .toString()));
114: }
115:
116: // Parse the file
117: return parseMetaDataStream(in, url.toString(), handlerName);
118: }
119:
120: /**
121: * Method to parse a MetaData file given the filename.
122: * @param fileName Name of the file
123: * @param handlerName Name of the handler plugin to use when parsing
124: * @return The MetaData for this file
125: * @throws JPOXException if error occurred
126: */
127: public MetaData parseMetaDataFile(String fileName,
128: String handlerName) {
129: InputStream in = null;
130: try {
131: in = new URL(fileName).openStream();
132: } catch (Exception ignore) {
133: //do nothing
134: }
135: if (in == null) {
136: try {
137: in = new FileInputStream(StringUtils
138: .getFileForFilename(fileName));
139: } catch (Exception ignore) {
140: //do nothing
141: }
142: }
143: if (in == null) {
144: JPOXLogger.ENHANCER
145: .error(LOCALISER.msg("044032", fileName));
146: throw new JPOXException(LOCALISER.msg("044032", fileName));
147: }
148:
149: // Parse the file
150: return parseMetaDataStream(in, fileName, handlerName);
151: }
152:
153: /**
154: * Method to parse a MetaData file given an InputStream.
155: * @param in input stream
156: * @param filename Name of the file (if applicable)
157: * @param handlerName Name of the handler plugin to use when parsing
158: * @return The MetaData for this file
159: * @throws JPOXException thrown if error occurred
160: */
161: public MetaData parseMetaDataStream(InputStream in,
162: String filename, String handlerName) {
163: if (in == null) {
164: throw new NullPointerException("input stream is null");
165: }
166:
167: if (JPOXLogger.METADATA.isDebugEnabled()) {
168: JPOXLogger.METADATA.debug(LOCALISER.msg("044030", filename,
169: handlerName, validate ? "true" : "false"));
170: }
171: try {
172: if (parser == null) {
173: // Create a SAXParser (use JDK parser for now)
174: SAXParserFactory factory = SAXParserFactory
175: .newInstance();
176: factory.setValidating(validate);
177: factory.setNamespaceAware(validate);
178: if (validate) {
179: // Xerces (if in CLASSPATH) needs this for validation (of XSD)
180: try {
181: factory
182: .setFeature(
183: "http://apache.org/xml/features/validation/schema",
184: true);
185: } catch (Exception e) {
186: }
187: }
188:
189: parser = factory.newSAXParser();
190: }
191:
192: // Generate the default handler to process the metadata
193:
194: DefaultHandler handler = null;
195: EntityResolver entityResolver = null;
196: try {
197: entityResolver = EntityResolverFactory.getInstance(mgr
198: .getOMFContext().getPluginManager(),
199: handlerName);
200: if (entityResolver != null) {
201: parser.getXMLReader().setEntityResolver(
202: entityResolver);
203: }
204: Class[] argTypes = new Class[] { MetaDataManager.class,
205: String.class, EntityResolver.class };
206: Object[] argValues = new Object[] { mgr, filename,
207: entityResolver };
208:
209: handler = (DefaultHandler) mgr.getOMFContext()
210: .getPluginManager().createExecutableExtension(
211: "org.jpox.metadata_handler", "name",
212: handlerName, "class-name", argTypes,
213: argValues);
214: if (handler == null) {
215: // Plugin of this name not found
216: throw new JPOXUserException(LOCALISER.msg("044028",
217: handlerName)).setFatal();
218: }
219: } catch (Exception e) {
220: String msg = LOCALISER.msg("044029", handlerName, e
221: .getMessage());
222: throw new JPOXException(msg, e);
223: }
224:
225: // Parse the metadata
226: parser.parse(in, handler);
227:
228: // Return the FileMetaData that has been parsed
229: return ((AbstractMetaDataHandler) handler).getMetaData();
230: } catch (JPOXException e) {
231: throw e;
232: } catch (Exception e) {
233: Throwable cause = e;
234: if (e instanceof SAXException) {
235: SAXException se = (SAXException) e;
236: cause = se.getException();
237: }
238: if (JavaUtils.isJRE1_4OrAbove()) {
239: cause = e.getCause() == null ? cause : e.getCause();
240: }
241:
242: JPOXLogger.METADATA.error(LOCALISER.msg("044040", filename,
243: cause));
244: if (cause instanceof InvalidMetaDataException) {
245: throw (InvalidMetaDataException) cause;
246: } else {
247: String message = LOCALISER.msg("044033", e);
248: throw new JPOXException(message, cause);
249: }
250: } finally {
251: try {
252: in.close();
253: } catch (Exception ignore) {
254: // Do nothing
255: }
256: }
257: }
258: }
|