001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.lib.meta;
020:
021: import java.security.AccessController;
022:
023: import org.apache.commons.lang.StringUtils;
024: import org.apache.openjpa.lib.util.J2DoPrivHelper;
025: import org.apache.openjpa.lib.util.Localizer;
026: import org.xml.sax.Attributes;
027: import org.xml.sax.SAXException;
028: import serp.util.Strings;
029:
030: /**
031: * Custom SAX parser used by the system to quickly parse metadata files
032: * for classes.
033: *
034: * @author Abe White
035: * @nojavadoc
036: */
037: public class CFMetaDataParser extends XMLMetaDataParser {
038:
039: static final String[] PACKAGES = new String[] { "java.lang.",
040: "java.util.", "java.math." };
041: private static final Localizer _loc = Localizer
042: .forPackage(CFMetaDataParser.class);
043:
044: // the current package and class being parsed
045: private String _package = null;
046: private String _class = null;
047:
048: public CFMetaDataParser() {
049: setParseText(false);
050: }
051:
052: /**
053: * The name of the package element. Defaults to "package".
054: */
055: protected boolean isPackageElementName(String name) {
056: return "package".equals(name);
057: }
058:
059: /**
060: * The attribute of the package element that holds the name, or null to
061: * use the element text. Defaults to "name".
062: */
063: protected String getPackageAttributeName() {
064: return "name";
065: }
066:
067: /**
068: * The depth of the package element. Defaults to 1.
069: */
070: protected int getPackageElementDepth() {
071: return 1;
072: }
073:
074: /**
075: * The name of the class element. Defaults to "class".
076: */
077: protected boolean isClassElementName(String name) {
078: return "class".equals(name);
079: }
080:
081: /**
082: * The attribute of the class element that holds the name, or null to
083: * use the element text. Defaults to "name".
084: */
085: protected String getClassAttributeName() {
086: return "name";
087: }
088:
089: /**
090: * The depth of the class element. Defaults to 2.
091: */
092: protected int getClassElementDepth() {
093: return 2;
094: }
095:
096: protected boolean startElement(String name, Attributes attrs)
097: throws SAXException {
098: // skip root element
099: int depth = currentDepth();
100: if (depth == 0)
101: return true;
102:
103: try {
104: if (depth == getPackageElementDepth()
105: && isPackageElementName(name))
106: return startPackage(name, attrs);
107: if (depth == getClassElementDepth()
108: && isClassElementName(name))
109: return startClass(name, attrs);
110: if (depth > getClassElementDepth() && _class != null
111: && getClassAttributeName() != null)
112: return startClassElement(name, attrs);
113: if (depth > getPackageElementDepth() && _package != null
114: && getPackageAttributeName() != null)
115: return startPackageElement(name, attrs);
116: return startSystemElement(name, attrs);
117: } catch (SAXException se) {
118: throw se;
119: } catch (NullPointerException npe) {
120: throw getException(_loc.get("parse-error", name), npe);
121: }
122: }
123:
124: protected void endElement(String name) throws SAXException {
125: // skip root element
126: int depth = currentDepth();
127: if (depth == 0)
128: return;
129:
130: try {
131: if (depth == getPackageElementDepth()
132: && isPackageElementName(name))
133: endPackage(name);
134: else if (depth == getClassElementDepth()
135: && isClassElementName(name))
136: endClass(name);
137: else if (depth > getClassElementDepth() && _class != null
138: && getClassAttributeName() != null)
139: endClassElement(name);
140: else if (depth > getPackageElementDepth()
141: && _package != null
142: && getPackageAttributeName() != null)
143: endPackageElement(name);
144: else
145: endSystemElement(name);
146: } catch (SAXException se) {
147: throw se;
148: } catch (NullPointerException npe) {
149: throw getException(_loc.get("parse-error", name), npe);
150: }
151: }
152:
153: /**
154: * Start a package. Parses out package attribute by default.
155: * Return false to skip package element and its contents.
156: */
157: protected boolean startPackage(String elem, Attributes attrs)
158: throws SAXException {
159: if (getPackageAttributeName() != null) {
160: _package = attrs.getValue(getPackageAttributeName());
161: if (_package == null)
162: _package = "";
163: }
164: return true;
165: }
166:
167: /**
168: * End a package. Parses contained text by default.
169: */
170: protected void endPackage(String elem) {
171: if (getPackageAttributeName() != null)
172: _package = null;
173: else
174: _package = currentText();
175: }
176:
177: /**
178: * Start a class. Parses out class name by default. Return
179: * false to skip class element and its contents.
180: */
181: protected boolean startClass(String elem, Attributes attrs)
182: throws SAXException {
183: if (getClassAttributeName() != null) {
184: _class = attrs.getValue(getClassAttributeName());
185: if (!StringUtils.isEmpty(_package)
186: && _class.indexOf('.') == -1)
187: _class = _package + "." + _class;
188: }
189: return true;
190: }
191:
192: /**
193: * End a class. Parses contained text by default.
194: */
195: protected void endClass(String elem) throws SAXException {
196: if (getClassAttributeName() != null)
197: _class = null;
198: else {
199: _class = currentText();
200: if (!StringUtils.isEmpty(_package)
201: && _class.indexOf('.') == -1)
202: _class = _package + "." + _class;
203: }
204: }
205:
206: /**
207: * Override this method marking the start of an element outside of any
208: * package or class.
209: */
210: protected boolean startSystemElement(String name, Attributes attrs)
211: throws SAXException {
212: return false;
213: }
214:
215: /**
216: * Override this method marking the end of an element outside of any
217: * package or class.
218: */
219: protected void endSystemElement(String name) throws SAXException {
220: }
221:
222: /**
223: * Override this method marking the start of an element within a declared
224: * package.
225: */
226: protected boolean startPackageElement(String name, Attributes attrs)
227: throws SAXException {
228: return false;
229: }
230:
231: /**
232: * Override this method marking the end of an element within a declared
233: * package.
234: */
235: protected void endPackageElement(String name) throws SAXException {
236: }
237:
238: /**
239: * Override this method marking the start of an element within a declared
240: * class.
241: */
242: protected boolean startClassElement(String name, Attributes attrs)
243: throws SAXException {
244: return false;
245: }
246:
247: /**
248: * Override this method marking the end of an element within a declared
249: * class.
250: */
251: protected void endClassElement(String name) throws SAXException {
252: }
253:
254: /**
255: * Override this method to clear any state and ready the parser for
256: * a new document. Subclasses should call
257: * <code>super.reset()</code> to clear superclass state.
258: */
259: protected void reset() {
260: super .reset();
261: _package = null;
262: _class = null;
263: }
264:
265: /**
266: * Return the current class being parsed; the returned name will
267: * be fully qualified.
268: */
269: protected String currentClassName() {
270: return _class;
271: }
272:
273: /**
274: * Return the current package being parsed.
275: */
276: protected String currentPackage() {
277: return _package;
278: }
279:
280: /**
281: * Helper method to create the {@link Class} for the given name,
282: * taking into account the package currently being parsed for relative
283: * class names.
284: */
285: protected Class classForName(String name, boolean resolve)
286: throws SAXException {
287: if (name == null)
288: return null;
289: Class cls = classForName(name, _package, resolve,
290: currentClassLoader());
291: if (cls == null)
292: throw getException(_loc.get("invalid-class", name)
293: .getMessage());
294: return cls;
295: }
296:
297: /**
298: * Load the given class name against the given package and the set
299: * of accepted standard packages. Return null if the class cannot be loaded.
300: */
301: public static Class classForName(String name, String pkg,
302: boolean resolve, ClassLoader loader) {
303: if (StringUtils.isEmpty(name))
304: return null;
305:
306: if (loader == null)
307: loader = (ClassLoader) AccessController
308: .doPrivileged(J2DoPrivHelper
309: .getContextClassLoaderAction());
310: boolean fullName = name.indexOf('.') != -1;
311: boolean noPackage = StringUtils.isEmpty(pkg);
312: try {
313: if (fullName || noPackage)
314: return Strings.toClass(name, resolve, loader);
315: return Strings.toClass(pkg + "." + name, resolve, loader);
316: } catch (RuntimeException re) {
317: }
318:
319: // if not a full name, now try the name without a package
320: if (!fullName && !noPackage) {
321: try {
322: return Strings.toClass(name, resolve, loader);
323: } catch (RuntimeException re) {
324: }
325: }
326:
327: // try with standard packages
328: if (!fullName) {
329: for (int i = 0; i < PACKAGES.length; i++) {
330: try {
331: return Strings.toClass(PACKAGES[i] + name, resolve,
332: loader);
333: } catch (RuntimeException re) {
334: }
335: }
336: }
337: return null;
338: }
339: }
|