| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.lib.meta; |
| |
| import java.security.AccessController; |
| |
| import org.apache.openjpa.lib.util.ClassUtil; |
| import org.apache.openjpa.lib.util.J2DoPrivHelper; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.StringUtil; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * Custom SAX parser used by the system to quickly parse metadata files |
| * for classes. |
| * |
| * @author Abe White |
| */ |
| public class CFMetaDataParser extends XMLMetaDataParser { |
| |
| static final String[] PACKAGES = new String[]{ |
| "java.lang.", "java.util.", "java.math." }; |
| private static final Localizer _loc = Localizer.forPackage |
| (CFMetaDataParser.class); |
| |
| // the current package and class being parsed |
| private String _package = null; |
| private String _class = null; |
| |
| public CFMetaDataParser() { |
| setParseText(false); |
| } |
| |
| /** |
| * The name of the package element. Defaults to "package". |
| */ |
| protected boolean isPackageElementName(String name) { |
| return "package".equals(name); |
| } |
| |
| /** |
| * The attribute of the package element that holds the name, or null to |
| * use the element text. Defaults to "name". |
| */ |
| protected String getPackageAttributeName() { |
| return "name"; |
| } |
| |
| /** |
| * The depth of the package element. Defaults to 1. |
| */ |
| protected int getPackageElementDepth() { |
| return 1; |
| } |
| |
| /** |
| * The name of the class element. Defaults to "class". |
| */ |
| protected boolean isClassElementName(String name) { |
| return "class".equals(name); |
| } |
| |
| /** |
| * The attribute of the class element that holds the name, or null to |
| * use the element text. Defaults to "name". |
| */ |
| protected String getClassAttributeName() { |
| return "name"; |
| } |
| |
| /** |
| * The depth of the class element. Defaults to 2. |
| */ |
| protected int getClassElementDepth() { |
| return 2; |
| } |
| |
| @Override |
| protected boolean startElement(String name, Attributes attrs) |
| throws SAXException { |
| // skip root element |
| int depth = currentDepth(); |
| if (depth == 0) |
| return true; |
| |
| if (StringUtil.contains(name, ':')) { |
| int index = name.indexOf(':'); |
| name = name.substring(index + 1); |
| } |
| |
| try { |
| if (_openjpaNamespace > 0) { |
| if (name.equals("entity")) |
| return startExtendedClass(name,attrs); |
| if (name.equals("attributes")) { |
| return true; |
| } |
| return startClassElement(name, attrs); |
| |
| } |
| if (depth == getPackageElementDepth() |
| && isPackageElementName(name)) |
| return startPackage(name, attrs); |
| if (depth == getClassElementDepth() && isClassElementName(name)) |
| return startClass(name, attrs); |
| if (depth > getClassElementDepth() && _class != null |
| && getClassAttributeName() != null) |
| return startClassElement(name, attrs); |
| if (depth > getPackageElementDepth() && _package != null |
| && getPackageAttributeName() != null) |
| return startPackageElement(name, attrs); |
| return startSystemElement(name, attrs); |
| } catch (SAXException se) { |
| throw se; |
| } catch (NullPointerException npe) { |
| throw getException(_loc.get("parse-error", name), npe); |
| } |
| } |
| |
| @Override |
| protected void endElement(String name) throws SAXException { |
| // skip root element |
| int depth = currentDepth(); |
| if (depth == 0) |
| return; |
| |
| if (StringUtil.contains(name, ':')) { |
| int index = name.indexOf(':'); |
| name = name.substring(index + 1); |
| } |
| |
| try { |
| if (_openjpaNamespace > 0) { |
| if (name.equals("entity")) |
| endExtendedClass(name); |
| else if (name.equals("attributes")) { |
| // do nothing |
| } |
| else { |
| endClassElement(name); |
| } |
| } |
| else if (depth == getPackageElementDepth() |
| && isPackageElementName(name)) |
| endPackage(name); |
| else if (depth == getClassElementDepth() |
| && isClassElementName(name)) |
| endClass(name); |
| else if (depth > getClassElementDepth() && _class != null |
| && getClassAttributeName() != null) |
| endClassElement(name); |
| else if (depth > getPackageElementDepth() && _package != null |
| && getPackageAttributeName() != null) |
| endPackageElement(name); |
| else |
| endSystemElement(name); |
| } catch (SAXException se) { |
| throw se; |
| } catch (NullPointerException npe) { |
| throw getException(_loc.get("parse-error", name), npe); |
| } |
| } |
| |
| /** |
| * Start a package. Parses out package attribute by default. |
| * Return false to skip package element and its contents. |
| */ |
| protected boolean startPackage(String elem, Attributes attrs) |
| throws SAXException { |
| if (getPackageAttributeName() != null) { |
| _package = attrs.getValue(getPackageAttributeName()); |
| if (_package == null) |
| _package = ""; |
| } |
| return true; |
| } |
| |
| /** |
| * End a package. Parses contained text by default. |
| */ |
| protected void endPackage(String elem) { |
| if (getPackageAttributeName() != null) |
| _package = null; |
| else |
| _package = currentText(); |
| } |
| |
| /** |
| * Start a class. Parses out class name by default. Return |
| * false to skip class element and its contents. |
| */ |
| protected boolean startClass(String elem, Attributes attrs) |
| throws SAXException { |
| if (getClassAttributeName() != null) { |
| _class = attrs.getValue(getClassAttributeName()); |
| if (!StringUtil.isEmpty(_package) && _class.indexOf('.') == -1) |
| _class = _package + "." + _class; |
| } |
| return true; |
| } |
| |
| /** |
| * End a class. Parses contained text by default. |
| */ |
| protected void endClass(String elem) throws SAXException { |
| if (getClassAttributeName() != null) |
| _class = null; |
| else { |
| _class = currentText(); |
| if (!StringUtil.isEmpty(_package) && _class.indexOf('.') == -1) |
| _class = _package + "." + _class; |
| } |
| } |
| |
| protected boolean startExtendedClass(String elem, Attributes attrs) |
| throws SAXException { |
| return false; |
| } |
| |
| protected void endExtendedClass(String elem) throws SAXException { |
| } |
| |
| /** |
| * Override this method marking the start of an element outside of any |
| * package or class. |
| */ |
| protected boolean startSystemElement(String name, Attributes attrs) |
| throws SAXException { |
| return false; |
| } |
| |
| /** |
| * Override this method marking the end of an element outside of any |
| * package or class. |
| */ |
| protected void endSystemElement(String name) throws SAXException { |
| } |
| |
| /** |
| * Override this method marking the start of an element within a declared |
| * package. |
| */ |
| protected boolean startPackageElement(String name, Attributes attrs) |
| throws SAXException { |
| return false; |
| } |
| |
| /** |
| * Override this method marking the end of an element within a declared |
| * package. |
| */ |
| protected void endPackageElement(String name) throws SAXException { |
| } |
| |
| /** |
| * Override this method marking the start of an element within a declared |
| * class. |
| */ |
| protected boolean startClassElement(String name, Attributes attrs) |
| throws SAXException { |
| return false; |
| } |
| |
| /** |
| * Override this method marking the end of an element within a declared |
| * class. |
| */ |
| protected void endClassElement(String name) throws SAXException { |
| } |
| |
| /** |
| * Override this method to clear any state and ready the parser for |
| * a new document. Subclasses should call |
| * <code>super.reset()</code> to clear superclass state. |
| */ |
| @Override |
| protected void reset() { |
| super.reset(); |
| _package = null; |
| _class = null; |
| } |
| |
| /** |
| * Return the current class being parsed; the returned name will |
| * be fully qualified. |
| */ |
| protected String currentClassName() { |
| return _class; |
| } |
| |
| /** |
| * Return the current package being parsed. |
| */ |
| protected String currentPackage() { |
| return _package; |
| } |
| |
| /** |
| * Helper method to create the {@link Class} for the given name, |
| * taking into account the package currently being parsed for relative |
| * class names. |
| */ |
| protected Class<?> classForName(String name, boolean resolve) |
| throws SAXException { |
| if (name == null) |
| return null; |
| Class<?> cls = |
| classForName(name, _package, resolve, currentClassLoader()); |
| if (cls == null) |
| throw getException(_loc.get("invalid-class", name).getMessage()); |
| return cls; |
| } |
| |
| /** |
| * Load the given class name against the given package and the set |
| * of accepted standard packages. Return null if the class cannot be loaded. |
| */ |
| public static Class<?> classForName(String name, String pkg, |
| boolean resolve, ClassLoader loader) { |
| if (StringUtil.isEmpty(name)) |
| return null; |
| |
| if (loader == null) |
| loader = AccessController.doPrivileged( |
| J2DoPrivHelper.getContextClassLoaderAction()); |
| boolean fullName = name.indexOf('.') != -1; |
| boolean noPackage = StringUtil.isEmpty(pkg); |
| try { |
| if (fullName || noPackage) |
| return ClassUtil.toClass(name, resolve, loader); |
| return ClassUtil.toClass(pkg + "." + name, resolve, loader); |
| } catch (RuntimeException re) { |
| } |
| |
| // if not a full name, now try the name without a package |
| if (!fullName && !noPackage) { |
| try { |
| return ClassUtil.toClass(name, resolve, loader); |
| } catch (RuntimeException re) { |
| } |
| } |
| |
| // try with standard packages |
| if (!fullName) { |
| for (String aPackage : PACKAGES) { |
| try { |
| return ClassUtil.toClass(aPackage + name, resolve, loader); |
| } |
| catch (RuntimeException re) { |
| } |
| } |
| } |
| return null; |
| } |
| } |