| /* |
| * 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.persistence; |
| |
| import static javax.persistence.CascadeType.DETACH; |
| import static javax.persistence.CascadeType.MERGE; |
| import static javax.persistence.CascadeType.PERSIST; |
| import static javax.persistence.CascadeType.REFRESH; |
| import static javax.persistence.CascadeType.REMOVE; |
| import static org.apache.openjpa.meta.MetaDataModes.MODE_MAPPING; |
| import static org.apache.openjpa.meta.MetaDataModes.MODE_META; |
| import static org.apache.openjpa.meta.MetaDataModes.MODE_NONE; |
| import static org.apache.openjpa.meta.MetaDataModes.MODE_QUERY; |
| import static org.apache.openjpa.persistence.MetaDataTag.DATASTORE_ID; |
| import static org.apache.openjpa.persistence.MetaDataTag.DATA_CACHE; |
| import static org.apache.openjpa.persistence.MetaDataTag.EMBEDDED_ID; |
| import static org.apache.openjpa.persistence.MetaDataTag.ENTITY_LISTENERS; |
| import static org.apache.openjpa.persistence.MetaDataTag.EXCLUDE_DEFAULT_LISTENERS; |
| import static org.apache.openjpa.persistence.MetaDataTag.EXCLUDE_SUPERCLASS_LISTENERS; |
| import static org.apache.openjpa.persistence.MetaDataTag.EXTERNALIZER; |
| import static org.apache.openjpa.persistence.MetaDataTag.EXTERNAL_VAL; |
| import static org.apache.openjpa.persistence.MetaDataTag.EXTERNAL_VALS; |
| import static org.apache.openjpa.persistence.MetaDataTag.FACTORY; |
| import static org.apache.openjpa.persistence.MetaDataTag.FETCH_ATTRIBUTE; |
| import static org.apache.openjpa.persistence.MetaDataTag.FETCH_GROUP; |
| import static org.apache.openjpa.persistence.MetaDataTag.FETCH_GROUPS; |
| import static org.apache.openjpa.persistence.MetaDataTag.FLUSH_MODE; |
| import static org.apache.openjpa.persistence.MetaDataTag.GENERATED_VALUE; |
| import static org.apache.openjpa.persistence.MetaDataTag.ID; |
| import static org.apache.openjpa.persistence.MetaDataTag.ID_CLASS; |
| import static org.apache.openjpa.persistence.MetaDataTag.LOB; |
| import static org.apache.openjpa.persistence.MetaDataTag.MAPPED_BY_ID; |
| import static org.apache.openjpa.persistence.MetaDataTag.MAP_KEY; |
| import static org.apache.openjpa.persistence.MetaDataTag.MAP_KEY_CLASS; |
| import static org.apache.openjpa.persistence.MetaDataTag.NATIVE_QUERY; |
| import static org.apache.openjpa.persistence.MetaDataTag.OPENJPA_VERSION; |
| import static org.apache.openjpa.persistence.MetaDataTag.ORDER_BY; |
| import static org.apache.openjpa.persistence.MetaDataTag.ORDER_COLUMN; |
| import static org.apache.openjpa.persistence.MetaDataTag.POST_LOAD; |
| import static org.apache.openjpa.persistence.MetaDataTag.POST_PERSIST; |
| import static org.apache.openjpa.persistence.MetaDataTag.POST_REMOVE; |
| import static org.apache.openjpa.persistence.MetaDataTag.POST_UPDATE; |
| import static org.apache.openjpa.persistence.MetaDataTag.PRE_PERSIST; |
| import static org.apache.openjpa.persistence.MetaDataTag.PRE_REMOVE; |
| import static org.apache.openjpa.persistence.MetaDataTag.PRE_UPDATE; |
| import static org.apache.openjpa.persistence.MetaDataTag.QUERY; |
| import static org.apache.openjpa.persistence.MetaDataTag.QUERY_HINT; |
| import static org.apache.openjpa.persistence.MetaDataTag.QUERY_STRING; |
| import static org.apache.openjpa.persistence.MetaDataTag.READ_ONLY; |
| import static org.apache.openjpa.persistence.MetaDataTag.REFERENCED_FETCH_GROUP; |
| import static org.apache.openjpa.persistence.MetaDataTag.SEQ_GENERATOR; |
| import static org.apache.openjpa.persistence.MetaDataTag.VERSION; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.BASIC; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.ELEM_COLL; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.EMBEDDED; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.MANY_MANY; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.MANY_ONE; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.ONE_MANY; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.ONE_ONE; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.PERS; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.PERS_COLL; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.PERS_MAP; |
| import static org.apache.openjpa.persistence.PersistenceStrategy.TRANSIENT; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Serializable; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Member; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.Stack; |
| |
| import javax.persistence.CascadeType; |
| import javax.persistence.GenerationType; |
| import javax.persistence.LockModeType; |
| |
| import org.apache.openjpa.conf.OpenJPAConfiguration; |
| import org.apache.openjpa.enhance.PersistenceCapable; |
| import org.apache.openjpa.event.BeanLifecycleCallbacks; |
| import org.apache.openjpa.event.LifecycleCallbacks; |
| import org.apache.openjpa.event.LifecycleEvent; |
| import org.apache.openjpa.event.MethodLifecycleCallbacks; |
| import org.apache.openjpa.kernel.QueryLanguages; |
| import org.apache.openjpa.kernel.jpql.JPQLParser; |
| import org.apache.openjpa.lib.conf.Configurations; |
| import org.apache.openjpa.lib.log.Log; |
| import org.apache.openjpa.lib.meta.CFMetaDataParser; |
| import org.apache.openjpa.lib.meta.SourceTracker; |
| import org.apache.openjpa.lib.meta.XMLVersionParser; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.StringUtil; |
| import org.apache.openjpa.meta.AccessCode; |
| import org.apache.openjpa.meta.ClassMetaData; |
| import org.apache.openjpa.meta.DelegatingMetaDataFactory; |
| import org.apache.openjpa.meta.FieldMetaData; |
| import org.apache.openjpa.meta.JavaTypes; |
| import org.apache.openjpa.meta.LifecycleMetaData; |
| import org.apache.openjpa.meta.MetaDataContext; |
| import org.apache.openjpa.meta.MetaDataDefaults; |
| import org.apache.openjpa.meta.MetaDataFactory; |
| import org.apache.openjpa.meta.MetaDataRepository; |
| import org.apache.openjpa.meta.Order; |
| import org.apache.openjpa.meta.QueryMetaData; |
| import org.apache.openjpa.meta.SequenceMetaData; |
| import org.apache.openjpa.meta.UpdateStrategies; |
| import org.apache.openjpa.meta.ValueMetaData; |
| import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.FetchAttributeImpl; |
| import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.FetchGroupImpl; |
| import org.apache.openjpa.util.ImplHelper; |
| import org.apache.openjpa.util.InternalException; |
| import org.apache.openjpa.util.MetaDataException; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| |
| |
| /** |
| * Custom SAX parser used by the system to quickly parse persistence |
| * metadata files. This parser may invoke |
| * {@linkplain AnnotationPersistenceMetaDataParser another parser} to scan |
| * source code annotation. |
| * |
| * @author Steve Kim |
| * @author Pinaki Poddar |
| */ |
| public class XMLPersistenceMetaDataParser |
| extends CFMetaDataParser |
| implements PersistenceMetaDataFactory.Parser { |
| |
| // parse constants |
| protected static final String ELEM_PKG = "package"; |
| protected static final String ELEM_ACCESS = "access"; |
| protected static final String ELEM_ATTRS = "attributes"; |
| protected static final String ELEM_LISTENER = "entity-listener"; |
| protected static final String ELEM_CASCADE = "cascade"; |
| protected static final String ELEM_CASCADE_ALL = "cascade-all"; |
| protected static final String ELEM_CASCADE_PER = "cascade-persist"; |
| protected static final String ELEM_CASCADE_MER = "cascade-merge"; |
| protected static final String ELEM_CASCADE_REM = "cascade-remove"; |
| protected static final String ELEM_CASCADE_REF = "cascade-refresh"; |
| protected static final String ELEM_CASCADE_DET = "cascade-detach"; |
| protected static final String ELEM_PU_META = "persistence-unit-metadata"; |
| protected static final String ELEM_PU_DEF = "persistence-unit-defaults"; |
| protected static final String ELEM_XML_MAP_META_COMPLETE = "xml-mapping-metadata-complete"; |
| protected static final String ELEM_DELIM_IDS = "delimited-identifiers"; |
| |
| // The following is needed for input into the delimitString() method |
| protected static enum localDBIdentifiers { |
| SEQUENCE_GEN_SEQ_NAME, |
| SEQUENCE_GEN_SCHEMA |
| } |
| |
| private static final Map<String, Object> _elems = |
| new HashMap<>(); |
| |
| // Map for storing deferred metadata which needs to be populated |
| // after embeddables are loaded. |
| private static final Map<Class<?>, ArrayList<MetaDataContext>> |
| _embeddables = new HashMap<>(); |
| private static final Map<Class<?>, Integer> |
| _embeddableAccess = new HashMap<>(); |
| |
| // Hold fetch group info |
| private FetchGroupImpl[] _fgs = null; |
| private List<FetchGroupImpl> _fgList = null; |
| private List<String> _referencedFgList = null; |
| private FetchGroupImpl _currentFg = null; |
| private List<FetchAttributeImpl> _fetchAttrList = null; |
| |
| static { |
| _elems.put(ELEM_PKG, ELEM_PKG); |
| _elems.put(ELEM_ACCESS, ELEM_ACCESS); |
| _elems.put(ELEM_ATTRS, ELEM_ATTRS); |
| _elems.put(ELEM_LISTENER, ELEM_LISTENER); |
| _elems.put(ELEM_CASCADE, ELEM_CASCADE); |
| _elems.put(ELEM_CASCADE_ALL, ELEM_CASCADE_ALL); |
| _elems.put(ELEM_CASCADE_PER, ELEM_CASCADE_PER); |
| _elems.put(ELEM_CASCADE_REM, ELEM_CASCADE_REM); |
| _elems.put(ELEM_CASCADE_MER, ELEM_CASCADE_MER); |
| _elems.put(ELEM_CASCADE_REF, ELEM_CASCADE_REF); |
| _elems.put(ELEM_CASCADE_DET, ELEM_CASCADE_DET); |
| _elems.put(ELEM_PU_META, ELEM_PU_META); |
| _elems.put(ELEM_PU_DEF, ELEM_PU_DEF); |
| _elems.put(ELEM_XML_MAP_META_COMPLETE, ELEM_XML_MAP_META_COMPLETE); |
| _elems.put(ELEM_DELIM_IDS, ELEM_DELIM_IDS); |
| |
| _elems.put("entity-listeners", ENTITY_LISTENERS); |
| _elems.put("pre-persist", PRE_PERSIST); |
| _elems.put("post-persist", POST_PERSIST); |
| _elems.put("pre-remove", PRE_REMOVE); |
| _elems.put("post-remove", POST_REMOVE); |
| _elems.put("pre-update", PRE_UPDATE); |
| _elems.put("post-update", POST_UPDATE); |
| _elems.put("post-load", POST_LOAD); |
| _elems.put("exclude-default-listeners", EXCLUDE_DEFAULT_LISTENERS); |
| _elems.put("exclude-superclass-listeners", |
| EXCLUDE_SUPERCLASS_LISTENERS); |
| |
| _elems.put("named-query", QUERY); |
| _elems.put("named-native-query", NATIVE_QUERY); |
| _elems.put("hint", QUERY_HINT); |
| _elems.put("query", QUERY_STRING); |
| |
| _elems.put("flush-mode", FLUSH_MODE); |
| _elems.put("sequence-generator", SEQ_GENERATOR); |
| |
| _elems.put("id", ID); |
| _elems.put("id-class", ID_CLASS); |
| _elems.put("embedded-id", EMBEDDED_ID); |
| _elems.put("maps-id", MAPPED_BY_ID); |
| _elems.put("version", VERSION); |
| _elems.put("generated-value", GENERATED_VALUE); |
| _elems.put("map-key", MAP_KEY); |
| _elems.put("order-by", ORDER_BY); |
| _elems.put("order-column", ORDER_COLUMN); |
| _elems.put("lob", LOB); |
| _elems.put("data-store-id", DATASTORE_ID); |
| _elems.put("data-cache", DATA_CACHE); |
| |
| _elems.put("basic", BASIC); |
| _elems.put("many-to-one", MANY_ONE); |
| _elems.put("one-to-one", ONE_ONE); |
| _elems.put("embedded", EMBEDDED); |
| _elems.put("one-to-many", ONE_MANY); |
| _elems.put("many-to-many", MANY_MANY); |
| _elems.put("transient", TRANSIENT); |
| _elems.put("element-collection", ELEM_COLL); |
| _elems.put("persistent", PERS); |
| _elems.put("persistent-collection", PERS_COLL); |
| _elems.put("persistent-map", PERS_MAP); |
| _elems.put("map-key-class", MAP_KEY_CLASS); |
| |
| _elems.put("read-only", READ_ONLY); |
| _elems.put("external-values", EXTERNAL_VALS); |
| _elems.put("external-value", EXTERNAL_VAL); |
| _elems.put("externalizer", EXTERNALIZER); |
| _elems.put("factory", FACTORY); |
| |
| _elems.put("fetch-groups", FETCH_GROUPS); |
| _elems.put("fetch-group", FETCH_GROUP); |
| _elems.put("fetch-attribute", FETCH_ATTRIBUTE); |
| _elems.put("referenced-fetch-group", REFERENCED_FETCH_GROUP); |
| |
| _elems.put("openjpa-version", OPENJPA_VERSION); |
| } |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (XMLPersistenceMetaDataParser.class); |
| |
| private final OpenJPAConfiguration _conf; |
| private MetaDataRepository _repos = null; |
| private AnnotationPersistenceMetaDataParser _parser = null; |
| private ClassLoader _envLoader = null; |
| private int _mode = MODE_NONE; |
| private boolean _override = false; |
| |
| private final Stack<Object> _elements = new Stack<>(); |
| private final Stack<Object> _parents = new Stack<>(); |
| |
| private StringBuffer _externalValues = null; |
| |
| protected Class<?> _cls = null; |
| // List of classes currently being parsed |
| private ArrayList<Class<?>> _parseList = new ArrayList<>(); |
| private int _fieldPos = 0; |
| private int _clsPos = 0; |
| private int _access = AccessCode.UNKNOWN; |
| private PersistenceStrategy _strategy = null; |
| private Set<CascadeType> _cascades = null; |
| private Set<CascadeType> _pkgCascades = null; |
| |
| private Class<?> _listener = null; |
| private Collection<LifecycleCallbacks>[] _callbacks = null; |
| private Collection<Class<?>> _listeners = null; |
| private int[] _highs = null; |
| private boolean _isXMLMappingMetaDataComplete = false; |
| |
| private String _ormVersion; |
| private String _schemaLocation; |
| |
| private static final String ORM_XSD_1_0 = "orm_1_0.xsd"; |
| private static final String ORM_XSD_2_0 = "orm_2_0.xsd"; |
| private static final String ORM_XSD_2_1 = "orm_2_1.xsd"; |
| private static final String ORM_XSD_2_2 = "orm_2_2.xsd"; |
| |
| /** |
| * Constructor; supply configuration. |
| */ |
| public XMLPersistenceMetaDataParser(OpenJPAConfiguration conf) { |
| _conf = conf; |
| setValidating(true); |
| setLog(conf.getLog(OpenJPAConfiguration.LOG_METADATA)); |
| setParseComments(true); |
| setMode(MODE_META | MODE_MAPPING | MODE_QUERY); |
| setParseText(true); |
| } |
| |
| /** |
| * Configuration supplied on construction. |
| */ |
| public OpenJPAConfiguration getConfiguration() { |
| return _conf; |
| } |
| |
| /** |
| * The annotation parser. When class is discovered in an XML file, |
| * we first parse any annotations present, then override with the XML. |
| */ |
| public AnnotationPersistenceMetaDataParser getAnnotationParser() { |
| return _parser; |
| } |
| |
| /** |
| * The annotation parser. When class is discovered in an XML file, |
| * we first parse any annotations present, then override with the XML. |
| */ |
| public void setAnnotationParser(AnnotationPersistenceMetaDataParser parser){ |
| _parser = parser; |
| } |
| |
| /** |
| * Returns the repository for this parser. If none has been set, creates |
| * a new repository and sets it. |
| */ |
| @Override |
| public MetaDataRepository getRepository() { |
| if (_repos == null) { |
| MetaDataRepository repos = _conf.newMetaDataRepositoryInstance(); |
| MetaDataFactory mdf = repos.getMetaDataFactory(); |
| if (mdf instanceof DelegatingMetaDataFactory) |
| mdf = ((DelegatingMetaDataFactory) mdf).getInnermostDelegate(); |
| if (mdf instanceof PersistenceMetaDataFactory) |
| ((PersistenceMetaDataFactory) mdf).setXMLParser(this); |
| _repos = repos; |
| } |
| return _repos; |
| } |
| |
| /** |
| * Set the metadata repository for this parser. |
| */ |
| public void setRepository(MetaDataRepository repos) { |
| _repos = repos; |
| if (repos != null |
| && (repos.getValidate() & MetaDataRepository.VALIDATE_RUNTIME) != 0) |
| setParseComments(false); |
| |
| if (repos != null) { |
| // Determine if the Thread Context Classloader needs to be temporally overridden to the Classloader |
| // that loaded the OpenJPA classes, to avoid a potential deadlock issue with the way Xerces |
| // handles parsers and classloaders. |
| this.setOverrideContextClassloader(repos.getConfiguration().getCompatibilityInstance(). |
| getOverrideContextClassloader()); |
| } |
| } |
| |
| /** |
| * Return the environmental class loader to pass on to parsed |
| * metadata instances. |
| */ |
| public ClassLoader getEnvClassLoader() { |
| return _envLoader; |
| } |
| |
| /** |
| * Set the environmental class loader to pass on to parsed |
| * metadata instances. |
| */ |
| public void setEnvClassLoader(ClassLoader loader) { |
| _envLoader = loader; |
| } |
| |
| /** |
| * Whether to allow later parses of mapping information to override |
| * earlier information for the same class. Defaults to false. Useful |
| * when a tool is mapping a class, so that .jdo file partial mapping |
| * information can be used even when mappings are stored in .orm files |
| * or other locations. |
| */ |
| public boolean getMappingOverride() { |
| return _override; |
| } |
| |
| /** |
| * Whether to allow later parses of mapping information to override |
| * earlier information for the same class. Defaults to false. Useful |
| * when a tool is mapping a class, so that .jdo file partial mapping |
| * information can be used even when mappings are stored in .orm files |
| * or other locations. |
| */ |
| public void setMappingOverride(boolean override) { |
| _override = override; |
| } |
| |
| /** |
| * The parse mode according to the expected document type. The |
| * mode constants act as bit flags, and therefore can be combined. |
| */ |
| public int getMode() { |
| return _mode; |
| } |
| |
| /** |
| * The parse mode according to the expected document type. |
| */ |
| public void setMode(int mode, boolean on) { |
| if (mode == MODE_NONE) |
| setMode(MODE_NONE); |
| else if (on) |
| setMode(_mode | mode); |
| else |
| setMode(_mode & ~mode); |
| } |
| |
| /** |
| * The parse mode according to the expected document type. |
| */ |
| @Override |
| public void setMode(int mode) { |
| _mode = mode; |
| if (_parser != null) |
| _parser.setMode(mode); |
| } |
| |
| @Override |
| public void parse(URL url) throws IOException { |
| // peek at the doc to determine the version |
| XMLVersionParser vp = new XMLVersionParser("entity-mappings"); |
| try { |
| vp.parse(url); |
| _ormVersion = vp.getVersion(); |
| _schemaLocation = vp.getSchemaLocation(); |
| } catch (Throwable t) { |
| Log log = getLog(); |
| if (log.isInfoEnabled()) |
| log.trace(_loc.get("version-check-error", |
| url.toString())); |
| } |
| super.parse(url); |
| } |
| |
| @Override |
| public void parse(File file) throws IOException { |
| // peek at the doc to determine the version |
| XMLVersionParser vp = new XMLVersionParser("entity-mappings"); |
| try { |
| vp.parse(file); |
| _ormVersion = vp.getVersion(); |
| _schemaLocation = vp.getSchemaLocation(); |
| } catch (Throwable t) { |
| Log log = getLog(); |
| if (log.isInfoEnabled()) |
| log.trace(_loc.get("version-check-error", |
| file.toString())); |
| } |
| super.parse(file); |
| } |
| /** |
| * Convenience method for interpreting {@link #getMode}. |
| */ |
| protected boolean isMetaDataMode() { |
| return (_mode & MODE_META) != 0; |
| } |
| |
| /** |
| * Convenience method for interpreting {@link #getMode}. |
| */ |
| protected boolean isQueryMode() { |
| return (_mode & MODE_QUERY) != 0; |
| } |
| |
| /** |
| * Convenience method for interpreting {@link #getMode}. |
| */ |
| protected boolean isMappingMode() { |
| return (_mode & MODE_MAPPING) != 0; |
| } |
| |
| /** |
| * Returns true if we're in mapping mode or in metadata mode with |
| * mapping override enabled. |
| */ |
| protected boolean isMappingOverrideMode() { |
| return isMappingMode() || (_override && isMetaDataMode()); |
| } |
| |
| /////////////// |
| // XML parsing |
| /////////////// |
| |
| /** |
| * Push a parse element onto the stack. |
| */ |
| protected void pushElement(Object elem) { |
| _elements.push(elem); |
| } |
| |
| /** |
| * Pop a parse element from the stack. |
| */ |
| protected Object popElement() { |
| return _elements.pop(); |
| } |
| |
| /** |
| * Peek a parse element from the stack. |
| */ |
| protected Object peekElement() { |
| return _elements.peek(); |
| } |
| |
| /** |
| * Return the current element being parsed. May be a class metadata, |
| * field metadata, query metadata, etc. |
| */ |
| protected Object currentElement() { |
| if (_elements.isEmpty()) |
| return null; |
| return _elements.peek(); |
| } |
| |
| /** |
| * Return the current {@link PersistenceStrategy} if any. |
| */ |
| protected PersistenceStrategy currentStrategy() { |
| return _strategy; |
| } |
| |
| /** |
| * Return the tag of the current parent element. |
| */ |
| protected Object currentParent() { |
| if (_parents.isEmpty()) |
| return null; |
| return _parents.peek(); |
| } |
| |
| /** |
| * Return whether we're running the parser at runtime. |
| */ |
| protected boolean isRuntime() { |
| return (getRepository().getValidate() |
| & MetaDataRepository.VALIDATE_RUNTIME) != 0; |
| } |
| |
| @Override |
| protected Object getSchemaSource() { |
| // use the latest schema by default. 'unknown' docs should parse |
| // with the latest schema. |
| String ormxsd = "orm_2_0-xsd.rsrc"; |
| boolean useExtendedSchema = true; |
| // if the version and/or schema location is for 1.0, use the 1.0 |
| // schema |
| if (XMLVersionParser.VERSION_1_0.equals(_ormVersion) |
| || (_schemaLocation != null && _schemaLocation.indexOf(ORM_XSD_1_0) > -1)) { |
| ormxsd = "orm-xsd.rsrc"; |
| useExtendedSchema = false; |
| } else if (XMLVersionParser.VERSION_2_0.equals(_ormVersion) |
| || (_schemaLocation != null && _schemaLocation.indexOf(ORM_XSD_2_0) > -1)) { |
| ormxsd = "orm_2_0-xsd.rsrc"; |
| } else if (XMLVersionParser.VERSION_2_1.equals(_ormVersion) |
| || (_schemaLocation != null && _schemaLocation.indexOf(ORM_XSD_2_1) > -1)) { |
| ormxsd = "orm_2_1.xsd.rsrc"; |
| } else if (XMLVersionParser.VERSION_2_2.equals(_ormVersion) |
| || (_schemaLocation != null && _schemaLocation.indexOf(ORM_XSD_2_2) > -1)) { |
| ormxsd = "orm_2_2.xsd.rsrc"; |
| } |
| |
| List<InputStream> schema = new ArrayList<>(); |
| schema.add(XMLPersistenceMetaDataParser.class.getResourceAsStream(ormxsd)); |
| |
| if (useExtendedSchema) { |
| // Get the extendable schema |
| InputStream extendableXSDIS = |
| XMLPersistenceMetaDataParser.class.getResourceAsStream("extendable-orm.xsd"); |
| if (extendableXSDIS != null) { |
| schema.add(extendableXSDIS); |
| } |
| else { |
| // TODO: log/trace |
| } |
| |
| // Get the openjpa extended schema |
| InputStream openjpaXSDIS = |
| XMLPersistenceMetaDataParser.class.getResourceAsStream("openjpa-orm.xsd"); |
| if (openjpaXSDIS != null) { |
| schema.add(openjpaXSDIS); |
| } |
| else { |
| // TODO: log/trace |
| } |
| } |
| |
| return schema.toArray(); |
| } |
| |
| @Override |
| protected String getPackageAttributeName() { |
| return null; |
| } |
| |
| @Override |
| protected String getClassAttributeName() { |
| return "class"; |
| } |
| |
| @Override |
| protected int getClassElementDepth() { |
| return 1; |
| } |
| |
| @Override |
| protected boolean isClassElementName(String name) { |
| return "entity".equals(name) |
| || "embeddable".equals(name) |
| || "mapped-superclass".equals(name); |
| } |
| |
| @Override |
| protected void reset() { |
| // Add all remaining deferred embeddable metadata |
| addDeferredEmbeddableMetaData(); |
| |
| super.reset(); |
| _elements.clear(); |
| _parents.clear(); |
| _cls = null; |
| _parseList.clear(); |
| _fieldPos = 0; |
| _clsPos = 0; |
| |
| _access = AccessCode.UNKNOWN; |
| _strategy = null; |
| _listener = null; |
| _callbacks = null; |
| _highs = null; |
| _cascades = null; |
| _pkgCascades = null; |
| } |
| |
| @Override |
| protected boolean startSystemElement(String name, Attributes attrs) |
| throws SAXException { |
| Object tag = _elems.get(name); |
| boolean ret = false; |
| if (tag == null) { |
| if (isMappingOverrideMode()) |
| tag = startSystemMappingElement(name, attrs); |
| ret = tag != null; |
| } else if (tag instanceof MetaDataTag) { |
| switch ((MetaDataTag) tag) { |
| case QUERY: |
| ret = startNamedQuery(attrs); |
| break; |
| case QUERY_HINT: |
| ret = startQueryHint(attrs); |
| break; |
| case NATIVE_QUERY: |
| ret = startNamedNativeQuery(attrs); |
| break; |
| case QUERY_STRING: |
| ret = startQueryString(attrs); |
| break; |
| case SEQ_GENERATOR: |
| ret = startSequenceGenerator(attrs); |
| break; |
| case FLUSH_MODE: |
| ret = startFlushMode(attrs); |
| break; |
| case ENTITY_LISTENERS: |
| ret = startEntityListeners(attrs); |
| break; |
| case PRE_PERSIST: |
| case POST_PERSIST: |
| case PRE_REMOVE: |
| case POST_REMOVE: |
| case PRE_UPDATE: |
| case POST_UPDATE: |
| case POST_LOAD: |
| ret = startCallback((MetaDataTag) tag, attrs); |
| break; |
| default: |
| warnUnsupportedTag(name); |
| } |
| } else if (tag == ELEM_PU_META || tag == ELEM_PU_DEF) |
| ret = isMetaDataMode(); |
| else if (tag == ELEM_XML_MAP_META_COMPLETE) { |
| setAnnotationParser(null); |
| _isXMLMappingMetaDataComplete = true; |
| } |
| else if (tag == ELEM_ACCESS) |
| ret = _mode != MODE_QUERY; |
| else if (tag == ELEM_LISTENER) |
| ret = startEntityListener(attrs); |
| else if (tag == ELEM_DELIM_IDS) |
| ret = startDelimitedIdentifiers(); |
| else if (tag == ELEM_CASCADE) |
| ret = isMetaDataMode(); |
| else if (tag == ELEM_CASCADE_ALL || tag == ELEM_CASCADE_PER |
| || tag == ELEM_CASCADE_MER || tag == ELEM_CASCADE_REM |
| || tag == ELEM_CASCADE_REF || tag == ELEM_CASCADE_DET) |
| ret = startCascade(tag, attrs); |
| |
| if (ret) |
| _parents.push(tag); |
| return ret; |
| } |
| |
| @Override |
| protected void endSystemElement(String name) |
| throws SAXException { |
| Object tag = _elems.get(name); |
| if (tag == null && isMappingOverrideMode()) |
| endSystemMappingElement(name); |
| else if (tag instanceof MetaDataTag) { |
| switch ((MetaDataTag) tag) { |
| case QUERY: |
| endNamedQuery(); |
| break; |
| case QUERY_HINT: |
| endQueryHint(); |
| break; |
| case NATIVE_QUERY: |
| endNamedNativeQuery(); |
| break; |
| case QUERY_STRING: |
| endQueryString(); |
| break; |
| case SEQ_GENERATOR: |
| endSequenceGenerator(); |
| break; |
| } |
| } else if (tag == ELEM_ACCESS) |
| endAccess(); |
| else if (tag == ELEM_LISTENER) |
| endEntityListener(); |
| |
| _parents.pop(); |
| } |
| |
| /** |
| * Implement to parse a mapping element outside of any class. |
| * |
| * @return the tag for the given element, or null to skip the element |
| */ |
| protected Object startSystemMappingElement(String name, Attributes attrs) |
| throws SAXException { |
| return null; |
| } |
| |
| /** |
| * Implement to parse a mapping element outside of any class. |
| */ |
| protected void endSystemMappingElement(String name) |
| throws SAXException { |
| } |
| |
| @Override |
| protected boolean startClassElement(String name, Attributes attrs) |
| throws SAXException { |
| Object tag = (Object) _elems.get(name); |
| boolean ret = false; |
| if (tag == null) { |
| if (isMappingOverrideMode()) |
| tag = startClassMappingElement(name, attrs); |
| ret = tag != null; |
| } else if (tag instanceof MetaDataTag) { |
| switch ((MetaDataTag) tag) { |
| case GENERATED_VALUE: |
| ret = startGeneratedValue(attrs); |
| break; |
| case ID: |
| ret = startId(attrs); |
| break; |
| case EMBEDDED_ID: |
| ret = startEmbeddedId(attrs); |
| break; |
| case ID_CLASS: |
| ret = startIdClass(attrs); |
| break; |
| case LOB: |
| ret = startLob(attrs); |
| break; |
| case QUERY: |
| ret = startNamedQuery(attrs); |
| break; |
| case QUERY_HINT: |
| ret = startQueryHint(attrs); |
| break; |
| case NATIVE_QUERY: |
| ret = startNamedNativeQuery(attrs); |
| break; |
| case QUERY_STRING: |
| ret = startQueryString(attrs); |
| break; |
| case SEQ_GENERATOR: |
| ret = startSequenceGenerator(attrs); |
| break; |
| case VERSION: |
| ret = startVersion(attrs); |
| break; |
| case MAP_KEY: |
| ret = startMapKey(attrs); |
| break; |
| case MAP_KEY_CLASS: |
| ret = startMapKeyClass(attrs); |
| break; |
| case FLUSH_MODE: |
| ret = startFlushMode(attrs); |
| break; |
| case ORDER_COLUMN: |
| ret = startOrderColumn(attrs); |
| break; |
| case ORDER_BY: |
| case ENTITY_LISTENERS: |
| ret = isMetaDataMode(); |
| break; |
| case EXCLUDE_DEFAULT_LISTENERS: |
| ret = startExcludeDefaultListeners(attrs); |
| break; |
| case EXCLUDE_SUPERCLASS_LISTENERS: |
| ret = startExcludeSuperclassListeners(attrs); |
| break; |
| case PRE_PERSIST: |
| case POST_PERSIST: |
| case PRE_REMOVE: |
| case POST_REMOVE: |
| case PRE_UPDATE: |
| case POST_UPDATE: |
| case POST_LOAD: |
| ret = startCallback((MetaDataTag) tag, attrs); |
| break; |
| case DATASTORE_ID: |
| ret = startDatastoreId(attrs); |
| break; |
| case DATA_CACHE: |
| ret = startDataCache(attrs); |
| break; |
| case READ_ONLY: |
| ret = startReadOnly(attrs); |
| break; |
| case EXTERNAL_VALS: |
| ret = startExternalValues(attrs); |
| break; |
| case EXTERNAL_VAL: |
| ret = startExternalValue(attrs); |
| break; |
| case EXTERNALIZER: |
| ret = startExternalizer(attrs); |
| break; |
| case FACTORY: |
| ret = startFactory(attrs); |
| break; |
| case FETCH_GROUPS: |
| ret = startFetchGroups(attrs); |
| break; |
| case FETCH_GROUP: |
| ret = startFetchGroup(attrs); |
| break; |
| case FETCH_ATTRIBUTE: |
| ret = startFetchAttribute(attrs); |
| break; |
| case REFERENCED_FETCH_GROUP: |
| ret = startReferencedFetchGroup(attrs); |
| break; |
| case OPENJPA_VERSION: |
| ret = true; |
| // TODO: right now the schema enforces this value, but may need to change in the future |
| break; |
| default: |
| warnUnsupportedTag(name); |
| } |
| } else if (tag instanceof PersistenceStrategy) { |
| PersistenceStrategy ps = (PersistenceStrategy) tag; |
| if (_openjpaNamespace > 0) { |
| if (ps == PERS |
| || ps == PERS_COLL |
| || ps == PERS_MAP) |
| ret = startStrategy(ps, attrs); |
| else |
| ret = startExtendedStrategy(ps, attrs); |
| } |
| else { |
| ret = startStrategy(ps, attrs); |
| } |
| if (ret) |
| _strategy = ps; |
| } else if (tag == ELEM_LISTENER) |
| ret = startEntityListener(attrs); |
| else if (tag == ELEM_ATTRS) |
| ret = _mode != MODE_QUERY; |
| else if (tag == ELEM_CASCADE) |
| ret = isMetaDataMode(); |
| else if (tag == ELEM_CASCADE_ALL || tag == ELEM_CASCADE_PER |
| || tag == ELEM_CASCADE_MER || tag == ELEM_CASCADE_REM |
| || tag == ELEM_CASCADE_REF || tag == ELEM_CASCADE_DET) |
| ret = startCascade(tag, attrs); |
| |
| if (ret) |
| _parents.push(tag); |
| return ret; |
| } |
| |
| @Override |
| protected void endClassElement(String name) |
| throws SAXException { |
| Object tag = _elems.get(name); |
| if (tag == null && isMappingOverrideMode()) |
| endClassMappingElement(name); |
| else if (tag instanceof MetaDataTag) { |
| switch ((MetaDataTag) tag) { |
| case GENERATED_VALUE: |
| endGeneratedValue(); |
| break; |
| case ID: |
| endId(); |
| break; |
| case EMBEDDED_ID: |
| endEmbeddedId(); |
| break; |
| case ID_CLASS: |
| endIdClass(); |
| break; |
| case LOB: |
| endLob(); |
| break; |
| case QUERY: |
| endNamedQuery(); |
| break; |
| case QUERY_HINT: |
| endQueryHint(); |
| break; |
| case NATIVE_QUERY: |
| endNamedNativeQuery(); |
| break; |
| case QUERY_STRING: |
| endQueryString(); |
| break; |
| case SEQ_GENERATOR: |
| endSequenceGenerator(); |
| break; |
| case VERSION: |
| endVersion(); |
| break; |
| case ORDER_BY: |
| endOrderBy(); |
| break; |
| case EXTERNAL_VALS: |
| endExternalValues(); |
| break; |
| case EXTERNALIZER: |
| endExternalizer(); |
| break; |
| case FACTORY: |
| endFactory(); |
| break; |
| case FETCH_GROUP: |
| endFetchGroup(); |
| break; |
| case REFERENCED_FETCH_GROUP: |
| endReferencedFetchGroup(); |
| break; |
| } |
| } else if (tag instanceof PersistenceStrategy) { |
| PersistenceStrategy ps = (PersistenceStrategy) tag; |
| if (_openjpaNamespace > 0) { |
| endExtendedStrategy(ps); |
| } |
| else { |
| endStrategy(ps); |
| } |
| } |
| else if (tag == ELEM_ACCESS) |
| endAccess(); |
| else if (tag == ELEM_LISTENER) |
| endEntityListener(); |
| |
| _parents.pop(); |
| } |
| |
| /** |
| * Log warning about an unsupported tag. |
| */ |
| private void warnUnsupportedTag(String name) { |
| Log log = getLog(); |
| if (log.isInfoEnabled()) |
| log.trace(_loc.get("unsupported-tag", name)); |
| } |
| |
| /** |
| * Implement to parse a mapping element within a class. |
| * |
| * @return the tag for the given element, or null to skip element |
| */ |
| protected Object startClassMappingElement(String name, Attributes attrs) |
| throws SAXException { |
| return null; |
| } |
| |
| /** |
| * Implement to parse a mapping element within a class. |
| */ |
| protected void endClassMappingElement(String name) |
| throws SAXException { |
| } |
| |
| boolean isMetaDataComplete(Attributes attrs) { |
| return attrs != null |
| && "true".equals(attrs.getValue("metadata-complete")); |
| } |
| |
| void resetAnnotationParser() { |
| setAnnotationParser(((PersistenceMetaDataFactory)getRepository() |
| .getMetaDataFactory()).getAnnotationParser()); |
| } |
| |
| @Override |
| protected boolean startClass(String elem, Attributes attrs) |
| throws SAXException { |
| boolean metaDataComplete = false; |
| super.startClass(elem, attrs); |
| if (isMetaDataComplete(attrs)) { |
| metaDataComplete = true; |
| setAnnotationParser(null); |
| } else if (!_isXMLMappingMetaDataComplete){ |
| resetAnnotationParser(); |
| } |
| |
| // query mode only? |
| _cls = classForName(currentClassName()); |
| |
| // Prevent a reentrant parse for the same class |
| if (parseListContains(_cls)) { |
| return false; |
| } |
| |
| if (_mode == MODE_QUERY) { |
| if(_conf.getCompatibilityInstance().getParseAnnotationsForQueryMode()){ |
| if (_parser != null) { |
| _parser.parse(_cls); |
| } |
| } |
| return true; |
| } |
| |
| Log log = getLog(); |
| if (log.isTraceEnabled()) |
| log.trace(_loc.get("parse-class", _cls.getName())); |
| |
| MetaDataRepository repos = getRepository(); |
| ClassMetaData meta = repos.getCachedMetaData(_cls); |
| if (meta != null |
| && ((isMetaDataMode() && (meta.getSourceMode() & MODE_META) != 0) |
| || (isMappingMode() && (meta.getSourceMode() & MODE_MAPPING) != 0))) |
| { |
| if(isDuplicateClass(meta)) { |
| if (log.isWarnEnabled()) { |
| log.warn(_loc.get("dup-metadata", _cls, getSourceName())); |
| } |
| if(log.isTraceEnabled()) { |
| log.trace(String.format( |
| "MetaData originally obtained from source: %s under mode: %d with scope: %s, and type: %d", |
| meta.getSourceName(), meta.getSourceMode(), meta.getSourceScope(), meta.getSourceType())); |
| } |
| } |
| _cls = null; |
| return false; |
| } |
| |
| int access = AccessCode.UNKNOWN; |
| if (meta == null) { |
| int accessCode = toAccessType(attrs.getValue("access")); |
| // if access not specified and access was specified at |
| // the system level, use the system default (which may |
| // be UNKNOWN) |
| if (accessCode == AccessCode.UNKNOWN) |
| accessCode = _access; |
| meta = repos.addMetaData(_cls, accessCode, metaDataComplete); |
| FieldMetaData[] fmds = meta.getFields(); |
| if (metaDataComplete) { |
| for (FieldMetaData fmd : fmds) { |
| fmd.setExplicit(true); |
| } |
| } |
| meta.setEnvClassLoader(_envLoader); |
| meta.setSourceMode(MODE_NONE); |
| |
| // parse annotations first so XML overrides them |
| if (_parser != null) { |
| _parser.parse(_cls); |
| } |
| } |
| access = meta.getAccessType(); |
| |
| boolean mappedSuper = "mapped-superclass".equals(elem); |
| boolean embeddable = "embeddable".equals(elem); |
| |
| if (isMetaDataMode()) { |
| Locator locator = getLocation().getLocator(); |
| meta.setSource(getSourceFile(), SourceTracker.SRC_XML, locator != null ? locator.getSystemId() : "" ); |
| meta.setSourceMode(MODE_META, true); |
| |
| if (locator != null) { |
| meta.setLineNumber(locator.getLineNumber()); |
| meta.setColNumber(locator.getColumnNumber()); |
| } |
| meta.setListingIndex(_clsPos); |
| String name = attrs.getValue("name"); |
| if (!StringUtil.isEmpty(name)) |
| meta.setTypeAlias(name); |
| meta.setAbstract(mappedSuper); |
| meta.setEmbeddedOnly(mappedSuper || embeddable); |
| |
| if (embeddable) { |
| meta.setEmbeddable(); |
| setDeferredEmbeddableAccessType(_cls, access); |
| } |
| } |
| |
| if (attrs.getValue("cacheable") != null) { |
| meta.setCacheEnabled(Boolean.valueOf(attrs.getValue("cacheable"))); |
| } |
| |
| if (isMappingMode()) |
| meta.setSourceMode(MODE_MAPPING, true); |
| if (isMappingOverrideMode()) |
| startClassMapping(meta, mappedSuper, attrs); |
| if (isQueryMode()) |
| meta.setSourceMode(MODE_QUERY, true); |
| |
| _clsPos++; |
| _fieldPos = 0; |
| addComments(meta); |
| pushElement(meta); |
| return true; |
| } |
| |
| @Override |
| protected void endClass(String elem) |
| throws SAXException { |
| if (_mode != MODE_QUERY) { |
| ClassMetaData meta = (ClassMetaData) popElement(); |
| storeCallbacks(meta); |
| |
| if (isMappingOverrideMode()) |
| endClassMapping(meta); |
| } |
| _cls = null; |
| super.endClass(elem); |
| } |
| |
| /** |
| * Implement to add mapping attributes to class. |
| */ |
| protected void startClassMapping(ClassMetaData mapping, |
| boolean mappedSuper, Attributes attrs) |
| throws SAXException { |
| } |
| |
| /** |
| * Implement to finalize class mapping. |
| */ |
| protected void endClassMapping(ClassMetaData mapping) |
| throws SAXException { |
| } |
| |
| /** |
| * Default access element. |
| */ |
| private void endAccess() { |
| _access = toAccessType(currentText()); |
| } |
| |
| /** |
| * Parse the given string as an entity access type, defaulting to given |
| * default if string is empty. |
| */ |
| private int toAccessType(String str) { |
| if (StringUtil.isEmpty(str)) |
| return AccessCode.UNKNOWN; |
| if ("PROPERTY".equals(str)) |
| return AccessCode.EXPLICIT | AccessCode.PROPERTY; |
| return AccessCode.EXPLICIT | AccessCode.FIELD; |
| } |
| /** |
| * Parse flush-mode element. |
| */ |
| private boolean startFlushMode(Attributes attrs) |
| throws SAXException { |
| Log log = getLog(); |
| if (log.isWarnEnabled()) |
| log.warn(_loc.get("unsupported", "flush-mode", getSourceName())); |
| return false; |
| } |
| |
| /** |
| * Parse sequence-generator. |
| */ |
| protected boolean startSequenceGenerator(Attributes attrs) { |
| if (!isMappingOverrideMode()) |
| return false; |
| |
| String name = attrs.getValue("name"); |
| Log log = getLog(); |
| if (log.isTraceEnabled()) |
| log.trace(_loc.get("parse-sequence", name)); |
| |
| SequenceMetaData meta = getRepository().getCachedSequenceMetaData(name); |
| if (meta != null && log.isWarnEnabled()) |
| log.warn(_loc.get("override-sequence", name)); |
| |
| meta = getRepository().addSequenceMetaData(name); |
| String seq = attrs.getValue("sequence-name"); |
| // Do not normalize the sequence name if it appears to be a plugin |
| if (seq.indexOf('(') == -1){ |
| seq = normalizeSequenceName(seq); |
| } |
| String val = attrs.getValue("initial-value"); |
| int initial = val == null ? 1 : Integer.parseInt(val); |
| val = attrs.getValue("allocation-size"); |
| int allocate = val == null ? 50 : Integer.parseInt(val); |
| String schema = normalizeSchemaName(attrs.getValue("schema")); |
| String catalog = normalizeCatalogName(attrs.getValue("catalog")); |
| |
| String clsName, props; |
| if (seq == null || seq.indexOf('(') == -1) { |
| clsName = SequenceMetaData.IMPL_NATIVE; |
| props = null; |
| } else { // plugin |
| clsName = Configurations.getClassName(seq); |
| props = Configurations.getProperties(seq); |
| seq = null; |
| } |
| |
| meta.setSequencePlugin(Configurations.getPlugin(clsName, props)); |
| meta.setSequence(seq); |
| meta.setInitialValue(initial); |
| meta.setAllocate(allocate); |
| meta.setSchema(schema); |
| meta.setCatalog(catalog); |
| |
| Object cur = currentElement(); |
| Object scope = (cur instanceof ClassMetaData) |
| ? ((ClassMetaData) cur).getDescribedType() : null; |
| meta.setSource(getSourceFile(), scope, SourceTracker.SRC_XML); |
| Locator locator = getLocation().getLocator(); |
| if (locator != null) { |
| meta.setLineNumber(locator.getLineNumber()); |
| meta.setColNumber(locator.getColumnNumber()); |
| } |
| return true; |
| } |
| |
| protected void endSequenceGenerator() { |
| } |
| |
| /** |
| * Parse id. |
| */ |
| protected boolean startId(Attributes attrs) |
| throws SAXException { |
| FieldMetaData fmd = parseField(attrs); |
| fmd.setExplicit(true); |
| fmd.setPrimaryKey(true); |
| return true; |
| } |
| |
| protected void endId() |
| throws SAXException { |
| finishField(); |
| } |
| |
| /** |
| * Parse embedded-id. |
| */ |
| protected boolean startEmbeddedId(Attributes attrs) |
| throws SAXException { |
| FieldMetaData fmd = parseField(attrs); |
| fmd.setExplicit(true); |
| fmd.setPrimaryKey(true); |
| fmd.setEmbedded(true); |
| fmd.setSerialized(false); |
| if (fmd.getEmbeddedMetaData() == null) |
| // fmd.addEmbeddedMetaData(); |
| deferEmbeddable(fmd.getDeclaredType(), fmd); |
| return true; |
| } |
| |
| protected void endEmbeddedId() |
| throws SAXException { |
| finishField(); |
| } |
| |
| /** |
| * Parse id-class. |
| */ |
| protected boolean startIdClass(Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| |
| ClassMetaData meta = (ClassMetaData) currentElement(); |
| String cls = attrs.getValue("class"); |
| Class<?> idCls = null; |
| try { |
| idCls = classForName(cls); |
| } catch (Throwable t) { |
| throw getException(_loc.get("invalid-id-class", meta, cls), t); |
| } |
| if (!Serializable.class.isAssignableFrom(idCls)) { |
| _conf.getConfigurationLog().warn(_loc.get("id-class-not-serializable", idCls, _cls)); |
| } |
| meta.setObjectIdType(idCls, true); |
| return true; |
| } |
| |
| protected void endIdClass() |
| throws SAXException { |
| } |
| |
| /** |
| * Parse lob. |
| */ |
| protected boolean startLob(Attributes attrs) |
| throws SAXException { |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| int typeCode = fmd.isElementCollection() ? fmd.getElement().getDeclaredTypeCode() : fmd.getDeclaredTypeCode(); |
| Class<?> type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : fmd.getDeclaredType(); |
| if (typeCode != JavaTypes.STRING |
| && type != char[].class |
| && type != Character[].class |
| && type != byte[].class |
| && type != Byte[].class) |
| fmd.setSerialized(true); |
| return true; |
| } |
| |
| protected void endLob() |
| throws SAXException { |
| } |
| |
| /** |
| * Parse generated-value. |
| */ |
| protected boolean startGeneratedValue(Attributes attrs) |
| throws SAXException { |
| if (!isMappingOverrideMode()) |
| return false; |
| |
| String strategy = attrs.getValue("strategy"); |
| String generator = attrs.getValue("generator"); |
| GenerationType type = StringUtil.isEmpty(strategy) |
| ? GenerationType.AUTO : GenerationType.valueOf(strategy); |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| AnnotationPersistenceMetaDataParser.parseGeneratedValue(fmd, type, |
| generator); |
| return true; |
| } |
| |
| protected void endGeneratedValue() |
| throws SAXException { |
| } |
| |
| /** |
| * Lazily parse cascades. |
| */ |
| protected boolean startCascade(Object tag, Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| |
| boolean puDefault = false; |
| |
| Set<CascadeType> cascades = null; |
| if (currentElement() instanceof FieldMetaData) { |
| if (_cascades == null) |
| _cascades = EnumSet.noneOf(CascadeType.class); |
| cascades = _cascades; |
| } else { |
| if (_pkgCascades == null) |
| _pkgCascades = EnumSet.noneOf(CascadeType.class); |
| cascades = _pkgCascades; |
| puDefault = true; |
| } |
| boolean all = ELEM_CASCADE_ALL == tag; |
| if (all || ELEM_CASCADE_PER == tag) { |
| cascades.add(PERSIST); |
| if (puDefault) { |
| MetaDataDefaults mdd = _repos.getMetaDataFactory().getDefaults(); |
| mdd.setDefaultCascadePersistEnabled(true); |
| } |
| } |
| |
| if (all || ELEM_CASCADE_REM == tag) |
| cascades.add(REMOVE); |
| if (all || ELEM_CASCADE_MER == tag) |
| cascades.add(MERGE); |
| if (all || ELEM_CASCADE_REF == tag) |
| cascades.add(REFRESH); |
| if (all || ELEM_CASCADE_DET == tag) |
| cascades.add(DETACH); |
| return true; |
| } |
| |
| /** |
| * Set the cached cascades into the field. |
| */ |
| protected void setCascades(FieldMetaData fmd) { |
| Set<CascadeType> cascades = _cascades; |
| if (_cascades == null) |
| cascades = _pkgCascades; |
| if (cascades == null) |
| return; |
| |
| ValueMetaData vmd = fmd; |
| if (_strategy == ONE_MANY || _strategy == MANY_MANY) { |
| vmd = fmd.getElement(); |
| } |
| for (CascadeType cascade : cascades) { |
| switch (cascade) { |
| case PERSIST: |
| vmd.setCascadePersist(ValueMetaData.CASCADE_IMMEDIATE, false); |
| break; |
| case MERGE: |
| vmd.setCascadeAttach(ValueMetaData.CASCADE_IMMEDIATE); |
| break; |
| case DETACH: |
| vmd.setCascadeDetach(ValueMetaData.CASCADE_IMMEDIATE); |
| break; |
| case REMOVE: |
| vmd.setCascadeDelete(ValueMetaData.CASCADE_IMMEDIATE); |
| break; |
| case REFRESH: |
| vmd.setCascadeRefresh(ValueMetaData.CASCADE_IMMEDIATE); |
| break; |
| } |
| } |
| _cascades = null; |
| } |
| |
| /** |
| * Parse common field attributes. |
| */ |
| private FieldMetaData parseField(Attributes attrs) |
| throws SAXException { |
| ClassMetaData meta = (ClassMetaData) currentElement(); |
| String name = attrs.getValue("name"); |
| FieldMetaData field = meta.getDeclaredField(name); |
| int fldAccess = getFieldAccess(field, attrs); |
| // If the access defined in XML is not the same as what was defined |
| // by default or annotation, find the appropriate backing member and |
| // replace what is currently defined in metadata. |
| if ((field == null || field.getDeclaredType() == Object.class || |
| field.getAccessType() != fldAccess) |
| && meta.getDescribedType() != Object.class) { |
| Member member = _repos.getMetaDataFactory().getDefaults() |
| .getMemberByProperty(meta, name, fldAccess, false); |
| Class<?> type = Field.class.isInstance(member) ? |
| ((Field)member).getType() : ((Method)member).getReturnType(); |
| |
| if (field == null) { |
| field = meta.addDeclaredField(name, type); |
| PersistenceMetaDataDefaults.setCascadeNone(field); |
| PersistenceMetaDataDefaults.setCascadeNone(field.getKey()); |
| PersistenceMetaDataDefaults.setCascadeNone(field.getElement()); |
| } |
| field.backingMember(member); |
| } else if (field == null) { |
| field = meta.addDeclaredField(name, Object.class); |
| PersistenceMetaDataDefaults.setCascadeNone(field); |
| PersistenceMetaDataDefaults.setCascadeNone(field.getKey()); |
| PersistenceMetaDataDefaults.setCascadeNone(field.getElement()); |
| } |
| |
| if (isMetaDataMode()) |
| field.setListingIndex(_fieldPos); |
| |
| _fieldPos++; |
| pushElement(field); |
| addComments(field); |
| |
| if (isMappingOverrideMode()) |
| startFieldMapping(field, attrs); |
| return field; |
| } |
| |
| /** |
| * Pops field element. |
| */ |
| private void finishField() |
| throws SAXException { |
| FieldMetaData field = (FieldMetaData) popElement(); |
| setCascades(field); |
| if (isMappingOverrideMode()) |
| endFieldMapping(field); |
| _strategy = null; |
| } |
| |
| /** |
| * Determines access for field based upon existing metadata and XML |
| * attributes. |
| * |
| * @param field FieldMetaData current metadata for field |
| * @param attrs XML Attributes defined on this field |
| */ |
| private int getFieldAccess(FieldMetaData field, Attributes attrs) { |
| if (attrs != null) { |
| String access = attrs.getValue("access"); |
| if ("PROPERTY".equals(access)) |
| return AccessCode.EXPLICIT | AccessCode.PROPERTY; |
| if ("FIELD".equals(access)) |
| return AccessCode.EXPLICIT | AccessCode.FIELD; |
| } |
| // Check access defined on field, if provided |
| if (field != null) { |
| return field.getAccessType(); |
| } |
| // Otherwise, get the default access type of the declaring class |
| ClassMetaData meta = (ClassMetaData) currentElement(); |
| if (meta != null) { |
| return AccessCode.toFieldCode(meta.getAccessType()); |
| } |
| return AccessCode.UNKNOWN; |
| } |
| |
| /** |
| * Implement to add field mapping data. Does nothing by default. |
| */ |
| protected void startFieldMapping(FieldMetaData field, Attributes attrs) |
| throws SAXException { |
| } |
| |
| /** |
| * Implement to finalize field mapping. Does nothing by default. |
| */ |
| protected void endFieldMapping(FieldMetaData field) |
| throws SAXException { |
| } |
| |
| /** |
| * Parse version. |
| */ |
| protected boolean startVersion(Attributes attrs) |
| throws SAXException { |
| FieldMetaData fmd = parseField(attrs); |
| fmd.setExplicit(true); |
| fmd.setVersion(true); |
| return true; |
| } |
| |
| protected void endVersion() |
| throws SAXException { |
| finishField(); |
| } |
| |
| /** |
| * Parse strategy element. |
| */ |
| private boolean startStrategy(PersistenceStrategy strategy, |
| Attributes attrs) |
| throws SAXException { |
| FieldMetaData fmd = parseField(attrs); |
| fmd.setExplicit(true); |
| fmd.setManagement(FieldMetaData.MANAGE_PERSISTENT); |
| |
| String val = attrs.getValue("optional"); |
| if ("false".equals(val)) |
| fmd.setNullValue(FieldMetaData.NULL_EXCEPTION); |
| else if ("true".equals(val) |
| && fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION) { |
| // Reset value if the field was annotated with optional=false. |
| // Otherwise leave it alone. |
| fmd.setNullValue(FieldMetaData.NULL_UNSET); |
| } |
| if (isMappingOverrideMode()) { |
| val = attrs.getValue("mapped-by"); |
| if (val != null) |
| fmd.setMappedBy(val); |
| } |
| parseStrategy(fmd, strategy, attrs); |
| return true; |
| } |
| |
| private void endStrategy(PersistenceStrategy strategy) |
| throws SAXException { |
| finishField(); |
| } |
| |
| /** |
| * Parse strategy specific attributes. |
| */ |
| private void parseStrategy(FieldMetaData fmd, |
| PersistenceStrategy strategy, Attributes attrs) |
| throws SAXException { |
| switch (strategy) { |
| case BASIC: |
| parseBasic(fmd, attrs); |
| break; |
| case EMBEDDED: |
| parseEmbedded(fmd, attrs); |
| break; |
| case ONE_ONE: |
| parseOneToOne(fmd, attrs); |
| break; |
| case MANY_ONE: |
| parseManyToOne(fmd, attrs); |
| break; |
| case MANY_MANY: |
| parseManyToMany(fmd, attrs); |
| break; |
| case ONE_MANY: |
| parseOneToMany(fmd, attrs); |
| break; |
| case TRANSIENT: |
| String val = attrs.getValue("fetch"); |
| if (val != null) { |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| } |
| fmd.setManagement(FieldMetaData.MANAGE_NONE); |
| break; |
| case ELEM_COLL: |
| parseElementCollection(fmd, attrs); |
| break; |
| case PERS: |
| parsePersistent(fmd, attrs); |
| break; |
| case PERS_COLL: |
| parsePersistentCollection(fmd, attrs); |
| break; |
| case PERS_MAP: |
| parsePersistentMap(fmd, attrs); |
| break; |
| } |
| } |
| |
| /** |
| * Parse basic. |
| */ |
| protected void parseBasic(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("fetch"); |
| if (val != null) { |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| } |
| } |
| |
| /** |
| * Parse embedded. |
| */ |
| protected void parseEmbedded(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| assertPC(fmd, "Embedded"); |
| fmd.setInDefaultFetchGroup(true); |
| fmd.setEmbedded(true); |
| fmd.setSerialized(false); // override any Lob annotation |
| |
| if (fmd.getEmbeddedMetaData() == null) |
| // fmd.addEmbeddedMetaData(); |
| deferEmbeddable(fmd.getDeclaredType(), fmd); |
| } |
| |
| /** |
| * Throw proper exception if given value is not possibly persistence |
| * capable. |
| */ |
| private void assertPC(FieldMetaData fmd, String attr) |
| throws SAXException { |
| if (!JavaTypes.maybePC(fmd)) |
| throw getException(_loc.get("bad-meta-anno", fmd, attr)); |
| } |
| |
| /** |
| * Parse one-to-one. |
| */ |
| protected void parseOneToOne(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("fetch"); |
| boolean dfg = (val != null && val.equals("LAZY")) ? false : true; |
| |
| // We need to toggle the DFG explicit flag here because this is used for an optimization when selecting an |
| // Entity with lazy fields. |
| fmd.setDefaultFetchGroupExplicit(true); |
| fmd.setInDefaultFetchGroup(dfg); |
| fmd.setDefaultFetchGroupExplicit(false); |
| |
| val = attrs.getValue("target-entity"); |
| if (val != null) |
| fmd.setTypeOverride(AnnotationPersistenceMetaDataParser.toOverrideType(classForName(val))); |
| assertPC(fmd, "OneToOne"); |
| fmd.setSerialized(false); // override any Lob annotation |
| boolean orphanRemoval = Boolean.valueOf(attrs.getValue( |
| "orphan-removal")); |
| setOrphanRemoval(fmd, orphanRemoval); |
| String mapsId = attrs.getValue("maps-id"); |
| if (mapsId != null) |
| fmd.setMappedByIdValue(mapsId); |
| } |
| |
| /** |
| * Parse many-to-one. |
| */ |
| protected void parseManyToOne(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("fetch"); |
| boolean dfg = (val != null && val.equals("LAZY")) ? false : true; |
| |
| // We need to toggle the DFG explicit flag here because this is used for an optimization when selecting an |
| // Entity with lazy fields. |
| fmd.setDefaultFetchGroupExplicit(true); |
| fmd.setInDefaultFetchGroup(dfg); |
| fmd.setDefaultFetchGroupExplicit(false); |
| |
| val = attrs.getValue("target-entity"); |
| if (val != null) |
| fmd.setTypeOverride(AnnotationPersistenceMetaDataParser.toOverrideType(classForName(val))); |
| assertPC(fmd, "ManyToOne"); |
| fmd.setSerialized(false); // override any Lob annotation |
| String mapsId = attrs.getValue("maps-id"); |
| if (mapsId != null) |
| fmd.setMappedByIdValue(mapsId); |
| } |
| |
| /** |
| * Parse many-to-many. |
| */ |
| protected void parseManyToMany(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("fetch"); |
| if (val != null) { |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| } |
| val = attrs.getValue("target-entity"); |
| if (val != null) |
| fmd.getElement().setDeclaredType(classForName(val)); |
| assertPCCollection(fmd, "ManyToMany"); |
| fmd.setSerialized(false); // override Lob in annotation |
| } |
| |
| /** |
| * Throw exception if given field not a collection of possible persistence |
| * capables. |
| */ |
| private void assertPCCollection(FieldMetaData fmd, String attr) |
| throws SAXException { |
| switch (fmd.getDeclaredTypeCode()) { |
| case JavaTypes.ARRAY: |
| case JavaTypes.COLLECTION: |
| case JavaTypes.MAP: |
| if (JavaTypes.maybePC(fmd.getElement())) |
| break; |
| // no break |
| default: |
| throw getException(_loc.get("bad-meta-anno", fmd, attr)); |
| } |
| } |
| |
| /** |
| * Parse one-to-many. |
| */ |
| protected void parseOneToMany(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("fetch"); |
| if (val != null) { |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| } |
| val = attrs.getValue("target-entity"); |
| if (val != null) |
| fmd.getElement().setDeclaredType(classForName(val)); |
| assertPCCollection(fmd, "OneToMany"); |
| fmd.setSerialized(false); // override any Lob annotation |
| boolean orphanRemoval = Boolean.valueOf(attrs.getValue( |
| "orphan-removal")); |
| setOrphanRemoval(fmd.getElement(), orphanRemoval); |
| } |
| |
| protected void setOrphanRemoval(ValueMetaData vmd, boolean orphanRemoval) { |
| if (orphanRemoval) |
| vmd.setCascadeDelete(ValueMetaData.CASCADE_AUTO); |
| } |
| |
| protected void parseElementCollection(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String val = attrs.getValue("target-class"); |
| if (val != null) |
| fmd.getElement().setDeclaredType(classForName(val)); |
| |
| if (fmd.getDeclaredTypeCode() != JavaTypes.COLLECTION && |
| fmd.getDeclaredTypeCode() != JavaTypes.MAP) |
| throw getException(_loc.get("bad-meta-anno", fmd, |
| "ElementCollection")); |
| |
| val = attrs.getValue("fetch"); |
| if (val != null) |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| fmd.setElementCollection(true); |
| fmd.setSerialized(false); |
| if (JavaTypes.maybePC(fmd.getElement()) && !fmd.getElement().getDeclaredType().isEnum()) { |
| fmd.getElement().setEmbedded(true); |
| if (fmd.getElement().getEmbeddedMetaData() == null) |
| // fmd.getElement().addEmbeddedMetaData(); |
| deferEmbeddable(fmd.getElement().getDeclaredType(), |
| fmd.getElement()); |
| } |
| } |
| |
| /** |
| * Parse map-key. |
| */ |
| private boolean startMapKey(Attributes attrs) |
| throws SAXException { |
| if (!isMappingOverrideMode()) |
| return false; |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String mapKey = attrs.getValue("name"); |
| if (mapKey == null) |
| fmd.getKey().setValueMappedBy(ValueMetaData.MAPPED_BY_PK); |
| else |
| fmd.getKey().setValueMappedBy(mapKey); |
| return true; |
| } |
| |
| |
| /** |
| * Parse map-key-class. |
| */ |
| private boolean startMapKeyClass(Attributes attrs) |
| throws SAXException { |
| if (!isMappingOverrideMode()) |
| return false; |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String mapKeyClass = attrs.getValue("class"); |
| |
| if (mapKeyClass != null) { |
| try { |
| fmd.getKey().setDeclaredType(Class.forName(mapKeyClass)); |
| } catch (ClassNotFoundException e) { |
| throw new IllegalArgumentException("Class not found"); |
| } |
| } else |
| throw new IllegalArgumentException( |
| "The value of the MapKeyClass cannot be null"); |
| return true; |
| } |
| |
| /** |
| * Parse order-by. |
| */ |
| private void endOrderBy() |
| throws SAXException { |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String dec = currentText(); |
| if (fmd.isElementCollection() && |
| fmd.getElement().getEmbeddedMetaData() != null || |
| isDeferredEmbeddable(fmd.getElement().getDeclaredType(), |
| fmd.getElement())) { |
| if (dec.length() == 0 || dec.equals("ASC") || |
| dec.equals("DESC")) |
| throw new MetaDataException(_loc.get( |
| "invalid-orderBy", fmd)); |
| } |
| if (StringUtil.isEmpty(dec) || dec.equals("ASC")) |
| dec = Order.ELEMENT + " asc"; |
| else if (dec.equals("DESC")) |
| dec = Order.ELEMENT + " desc"; |
| |
| fmd.setOrderDeclaration(dec); |
| } |
| |
| /** |
| * Parse named-query. |
| */ |
| protected boolean startNamedQuery(Attributes attrs) |
| throws SAXException { |
| if (!isQueryMode()) |
| return false; |
| |
| String name = attrs.getValue("name"); |
| Log log = getLog(); |
| if (log.isTraceEnabled()) |
| log.trace(_loc.get("parse-query", name)); |
| |
| QueryMetaData meta = getRepository().searchQueryMetaDataByName(name); |
| if (meta != null) { |
| Class<?> defType = meta.getDefiningType(); |
| if ((defType != _cls) && log.isWarnEnabled()) { |
| log.warn(_loc.get("dup-query", name, currentLocation(), |
| defType)); |
| } |
| pushElement(meta); |
| return true; |
| } |
| |
| meta = getRepository().addQueryMetaData(null, name); |
| meta.setDefiningType(_cls); |
| meta.setLanguage(JPQLParser.LANG_JPQL); |
| meta.setQueryString(attrs.getValue("query")); |
| String lockModeStr = attrs.getValue("lock-mode"); |
| LockModeType lmt = processNamedQueryLockModeType(log, lockModeStr, name); |
| if (lmt != null && lmt != LockModeType.NONE) { |
| meta.addHint("openjpa.FetchPlan.ReadLockMode", lmt); |
| } |
| Locator locator = getLocation().getLocator(); |
| if (locator != null) { |
| meta.setLineNumber(locator.getLineNumber()); |
| meta.setColNumber(locator.getColumnNumber()); |
| } |
| Object cur = currentElement(); |
| Object scope = (cur instanceof ClassMetaData) |
| ? ((ClassMetaData) cur).getDescribedType() : null; |
| meta.setSource(getSourceFile(), scope, SourceTracker.SRC_XML, locator == null ? "" : locator.getSystemId()); |
| if (isMetaDataMode()) |
| meta.setSourceMode(MODE_META); |
| else if (isMappingMode()) |
| meta.setSourceMode(MODE_MAPPING); |
| else |
| meta.setSourceMode(MODE_QUERY); |
| pushElement(meta); |
| return true; |
| } |
| |
| /** |
| * A private worker method that calculates the lock mode for an individual NamedQuery. If the NamedQuery is |
| * configured to use the NONE lock mode(explicit or implicit), this method will promote the lock to a READ |
| * level lock. This was done to allow for JPA1 apps to function properly under a 2.0 runtime. |
| */ |
| private LockModeType processNamedQueryLockModeType(Log log, String lockModeString, String queryName) { |
| if (lockModeString == null) { |
| return null; |
| } |
| LockModeType lmt = LockModeType.valueOf(lockModeString); |
| String lm = _conf.getLockManager(); |
| boolean optimistic = _conf.getOptimistic(); |
| if (lm != null) { |
| lm = lm.toLowerCase(); |
| if (lm.contains("pessimistic")) { |
| if (lmt == LockModeType.NONE && !optimistic) { |
| if (log != null && log.isWarnEnabled()) { |
| log.warn(_loc.get("override-named-query-lock-mode", new String[] { "xml", queryName, |
| _cls.getName() })); |
| } |
| lmt = LockModeType.READ; |
| } |
| } |
| } |
| |
| return lmt; |
| } |
| |
| protected void endNamedQuery() |
| throws SAXException { |
| popElement(); |
| } |
| |
| protected boolean startQueryString(Attributes attrs) |
| throws SAXException { |
| return true; |
| } |
| |
| protected void endQueryString() |
| throws SAXException { |
| QueryMetaData meta = (QueryMetaData) currentElement(); |
| meta.setQueryString(currentText()); |
| } |
| |
| /** |
| * Parse query-hint. |
| */ |
| protected boolean startQueryHint(Attributes attrs) |
| throws SAXException { |
| QueryMetaData meta = (QueryMetaData) currentElement(); |
| meta.addHint(attrs.getValue("name"), attrs.getValue("value")); |
| return true; |
| } |
| |
| protected void endQueryHint() |
| throws SAXException { |
| } |
| |
| /** |
| * Parse native-named-query. |
| */ |
| protected boolean startNamedNativeQuery(Attributes attrs) |
| throws SAXException { |
| if (!isQueryMode()) |
| return false; |
| |
| String name = attrs.getValue("name"); |
| Log log = getLog(); |
| if (log.isTraceEnabled()) |
| log.trace(_loc.get("parse-native-query", name)); |
| |
| QueryMetaData meta = getRepository().getCachedQueryMetaData(name); |
| if (meta != null && isDuplicateQuery(meta) ) { |
| log.warn(_loc.get("override-query", name, currentLocation())); |
| } |
| |
| meta = getRepository().addQueryMetaData(null, name); |
| meta.setDefiningType(_cls); |
| meta.setLanguage(QueryLanguages.LANG_SQL); |
| meta.setQueryString(attrs.getValue("query")); |
| String val = attrs.getValue("result-class"); |
| if (val != null) { |
| Class<?> type = classForName(val); |
| if (ImplHelper.isManagedType(getConfiguration(), type)) |
| meta.setCandidateType(type); |
| else |
| meta.setResultType(type); |
| } |
| |
| val = attrs.getValue("result-set-mapping"); |
| if (val != null) |
| meta.setResultSetMappingName(val); |
| |
| Object cur = currentElement(); |
| Object scope = (cur instanceof ClassMetaData) ? ((ClassMetaData) cur).getDescribedType() : null; |
| Locator locator = getLocation().getLocator(); |
| meta.setSource(getSourceFile(), scope, SourceTracker.SRC_XML, locator == null ? "" : locator.getSystemId()); |
| if (locator != null) { |
| meta.setLineNumber(locator.getLineNumber()); |
| meta.setColNumber(locator.getColumnNumber()); |
| } |
| if (isMetaDataMode()) |
| meta.setSourceMode(MODE_META); |
| else if (isMappingMode()) |
| meta.setSourceMode(MODE_MAPPING); |
| else |
| meta.setSourceMode(MODE_QUERY); |
| pushElement(meta); |
| return true; |
| } |
| |
| protected void endNamedNativeQuery() |
| throws SAXException { |
| popElement(); |
| } |
| |
| /** |
| * Start entity-listeners |
| */ |
| private boolean startEntityListeners(Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| if (currentElement() == null) |
| return true; |
| |
| // reset listeners declared in annotations. |
| LifecycleMetaData meta = ((ClassMetaData) currentElement()). |
| getLifecycleMetaData(); |
| for (int i = 0; i < LifecycleEvent.ALL_EVENTS.length; i++) |
| meta.setDeclaredCallbacks(i, null, 0); |
| return true; |
| } |
| |
| /** |
| * Parse exclude-default-listeners. |
| */ |
| private boolean startExcludeDefaultListeners(Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| ClassMetaData meta = (ClassMetaData) currentElement(); |
| meta.getLifecycleMetaData().setIgnoreSystemListeners(true); |
| return true; |
| } |
| |
| /** |
| * Parse exclude-superclass-listeners. |
| */ |
| private boolean startExcludeSuperclassListeners(Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| ClassMetaData meta = (ClassMetaData) currentElement(); |
| meta.getLifecycleMetaData().setIgnoreSuperclassCallbacks |
| (LifecycleMetaData.IGNORE_HIGH); |
| return true; |
| } |
| |
| /** |
| * Parse entity-listener. |
| */ |
| private boolean startEntityListener(Attributes attrs) |
| throws SAXException { |
| _listener = classForName(attrs.getValue("class")); |
| if (!_conf.getCallbackOptionsInstance().getAllowsDuplicateListener()) { |
| if (_listeners == null) |
| _listeners = new ArrayList<>(); |
| if (_listeners.contains(_listener)) |
| return true; |
| _listeners.add(_listener); |
| } |
| |
| boolean system = currentElement() == null; |
| Collection<LifecycleCallbacks>[] parsed = |
| AnnotationPersistenceMetaDataParser.parseCallbackMethods(_listener, |
| null, true, true, _repos); |
| if (parsed == null) |
| return true; |
| |
| if (_callbacks == null) { |
| _callbacks = (Collection<LifecycleCallbacks>[]) |
| new Collection[LifecycleEvent.ALL_EVENTS.length]; |
| if (!system) |
| _highs = new int[LifecycleEvent.ALL_EVENTS.length]; |
| } |
| for (int i = 0; i < parsed.length; i++) { |
| if (parsed[i] == null) |
| continue; |
| if (_callbacks[i] == null) |
| _callbacks[i] = parsed[i]; |
| else |
| _callbacks[i].addAll(parsed[i]); |
| if (!system) |
| _highs[i] += parsed[i].size(); |
| } |
| return true; |
| } |
| |
| private void endEntityListener() |
| throws SAXException { |
| // should be in endEntityListeners I think to merge callbacks |
| // into a single listener. But then the user cannot remove. |
| if (currentElement() == null && _callbacks != null) { |
| _repos.addSystemListener(new PersistenceListenerAdapter |
| (_callbacks)); |
| _callbacks = null; |
| } |
| _listener = null; |
| } |
| |
| private boolean startCallback(MetaDataTag callback, Attributes attrs) |
| throws SAXException { |
| if (!isMetaDataMode()) |
| return false; |
| int[] events = MetaDataParsers.getEventTypes(callback, _conf); |
| if (events == null) |
| return false; |
| |
| boolean system = currentElement() == null; |
| |
| // If in a multi-level parse, do not add system level listeners. |
| // Otherwise, they will get added multiple times. |
| if (system && _parseList != null && _parseList.size() > 0) { |
| return false; |
| } |
| |
| Class<?> type = currentElement() == null ? null : |
| ((ClassMetaData) currentElement()).getDescribedType(); |
| if (type == null) |
| type = Object.class; |
| |
| if (_callbacks == null) { |
| _callbacks = (Collection<LifecycleCallbacks>[]) |
| new Collection[LifecycleEvent.ALL_EVENTS.length]; |
| if (!system) |
| _highs = new int[LifecycleEvent.ALL_EVENTS.length]; |
| } |
| |
| LifecycleCallbacks adapter; |
| if (_listener != null) |
| adapter = new BeanLifecycleCallbacks(_listener, |
| attrs.getValue("method-name"), false, type); |
| else |
| adapter = new MethodLifecycleCallbacks(_cls, |
| attrs.getValue("method-name"), false); |
| |
| for (int event : events) { |
| if (_listener != null) { |
| MetaDataParsers.validateMethodsForSameCallback(_listener, |
| _callbacks[event], ((BeanLifecycleCallbacks) adapter). |
| getCallbackMethod(), callback, _conf, getLog()); |
| } |
| else { |
| MetaDataParsers.validateMethodsForSameCallback(_cls, |
| _callbacks[event], ((MethodLifecycleCallbacks) adapter). |
| getCallbackMethod(), callback, _conf, getLog()); |
| |
| } |
| if (_callbacks[event] == null) |
| _callbacks[event] = new ArrayList<>(3); |
| _callbacks[event].add(adapter); |
| if (!system && _listener != null) |
| _highs[event]++; |
| } |
| return true; |
| } |
| |
| /** |
| * Store lifecycle metadata. |
| */ |
| private void storeCallbacks(ClassMetaData cls) { |
| LifecycleMetaData meta = cls.getLifecycleMetaData(); |
| Class<?> supCls = cls.getDescribedType().getSuperclass(); |
| Collection<LifecycleCallbacks>[] supCalls = null; |
| if (!Object.class.equals(supCls)) { |
| supCalls = AnnotationPersistenceMetaDataParser.parseCallbackMethods |
| (supCls, null, true, false, _repos); |
| } |
| if (supCalls != null) { |
| for (int event : LifecycleEvent.ALL_EVENTS) { |
| if (supCalls[event] == null) |
| continue; |
| meta.setNonPCSuperclassCallbacks(event, supCalls[event].toArray |
| (new LifecycleCallbacks[supCalls[event].size()]), 0); |
| } |
| } |
| if (_callbacks == null) |
| return; |
| |
| for (int event : LifecycleEvent.ALL_EVENTS) { |
| if (_callbacks[event] == null) |
| continue; |
| meta.setDeclaredCallbacks(event, (LifecycleCallbacks[]) |
| _callbacks[event].toArray |
| (new LifecycleCallbacks[_callbacks[event].size()]), |
| _highs[event]); |
| } |
| _callbacks = null; |
| _highs = null; |
| } |
| |
| protected boolean startOrderColumn(Attributes attrs) |
| throws SAXException { |
| return true; |
| } |
| |
| /** |
| * Instantiate the given class, taking into account the default package. |
| */ |
| protected Class<?> classForName(String name) |
| throws SAXException { |
| if ("Entity".equals(name)) |
| return PersistenceCapable.class; |
| return super.classForName(name, isRuntime()); |
| } |
| |
| /** |
| * Process all deferred embeddables using an unknown access type. |
| */ |
| protected void addDeferredEmbeddableMetaData() { |
| if (_embeddables != null && _embeddables.size() > 0) { |
| // Reverse iterate the array of remaining deferred embeddables |
| // since elements will be removed as they are processed. |
| Class<?>[] classes = _embeddables.keySet().toArray( |
| new Class<?>[_embeddables.size()]); |
| for (int i = classes.length - 1 ; i >= 0; i--) { |
| try { |
| Integer access = _embeddableAccess.get(classes[i]); |
| if (access == null) { |
| access = AccessCode.UNKNOWN; |
| } |
| addDeferredEmbeddableMetaData(classes[i], |
| access); |
| } |
| catch (Exception e) { |
| throw new MetaDataException( |
| _loc.get("no-embeddable-metadata", |
| classes[i].getName()), e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Process all deferred embeddables and embeddable mapping overrides |
| * for a given class. This should only happen after the access type |
| * of the embeddable is known. |
| * |
| * @param embedType embeddable class |
| * @param access class level access for embeddable |
| * @throws SAXException |
| */ |
| protected void addDeferredEmbeddableMetaData(Class<?> embedType, |
| int access) throws SAXException { |
| ArrayList<MetaDataContext> fmds = _embeddables.get(embedType); |
| if (fmds != null && fmds.size() > 0) { |
| for (MetaDataContext md : fmds) { |
| if (md instanceof FieldMetaData) { |
| FieldMetaData fmd = (FieldMetaData)md; |
| fmd.addEmbeddedMetaData(access); |
| } |
| else if (md instanceof ValueMetaData) { |
| ValueMetaData vmd = (ValueMetaData)md; |
| vmd.addEmbeddedMetaData(access); |
| } |
| } |
| applyDeferredEmbeddableOverrides(embedType); |
| // Clean up deferrals after they have been processed |
| fmds.clear(); |
| _embeddables.remove(embedType); |
| } |
| } |
| protected void setDeferredEmbeddableAccessType(Class<?> embedType, |
| int access) { |
| _embeddableAccess.put(embedType, access); |
| } |
| |
| /* |
| * Clear any deferred metadata |
| */ |
| @Override |
| protected void clearDeferredMetaData() { |
| _embeddables.clear(); |
| _embeddableAccess.clear(); |
| } |
| |
| /* |
| * Determines whether the embeddable type is deferred. |
| */ |
| protected boolean isDeferredEmbeddable(Class<?> embedType, |
| MetaDataContext fmd) { |
| ArrayList<MetaDataContext> fmds = _embeddables.get(embedType); |
| if (fmds != null) { |
| return fmds.contains(fmd); |
| } |
| return false; |
| } |
| |
| /* |
| * Add the fmd to the defer list for for the given embeddable type |
| */ |
| protected void deferEmbeddable(Class<?> embedType, MetaDataContext fmd) { |
| ArrayList<MetaDataContext> fmds = _embeddables.computeIfAbsent(embedType, k -> new ArrayList<>()); |
| fmds.add(fmd); |
| } |
| |
| /* |
| * Apply any deferred overrides. |
| */ |
| protected void applyDeferredEmbeddableOverrides(Class<?> cls) |
| throws SAXException { |
| } |
| |
| /* |
| * Add the array of classes to the active parse list. |
| */ |
| public void addToParseList(ArrayList<Class<?>> parseList) { |
| if (parseList == null) |
| return; |
| _parseList.addAll(parseList); |
| } |
| |
| /* |
| * Add the class to the active parse list. |
| */ |
| public void addToParseList(Class<?> parentCls) { |
| if (parentCls == null) |
| return; |
| _parseList.add(parentCls); |
| } |
| |
| /* |
| * Whether the active parse list contains the specified class. |
| */ |
| public boolean parseListContains(Class<?> cls) { |
| if (_parseList.size() == 0) |
| return false; |
| return _parseList.contains(cls); |
| } |
| |
| /* |
| * Returns the list of classes actively being parsed. |
| */ |
| public ArrayList<Class<?>> getParseList() { |
| return _parseList; |
| } |
| |
| /* |
| * Returns class currently being parsed. |
| */ |
| public Class<?> getParseClass() { |
| return _cls; |
| } |
| |
| protected boolean startDelimitedIdentifiers() { |
| return false; |
| } |
| |
| protected String normalizeSequenceName(String seqName) { |
| return seqName; |
| } |
| |
| protected String normalizeSchemaName(String schName) { |
| return schName; |
| } |
| |
| protected String normalizeCatalogName(String catName) { |
| return catName; |
| } |
| |
| /** |
| * Determines whether the ClassMetaData has been resolved more than once. Compares the current sourceName and |
| * linenumber to the ones used to originally resolve the metadata. |
| * |
| * @param meta The ClassMetaData to inspect. |
| * @return true if the source was has already been resolved from a different location. Otherwise return false |
| */ |
| protected boolean isDuplicateClass(ClassMetaData meta) { |
| if (!Objects.equals(getSourceName(), meta.getSourceName())) { |
| return true; |
| } |
| |
| if (getLineNum() != meta.getLineNumber()) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Determines whether the QueryMetaData has been resolved more than once. |
| * @param meta QueryMetaData that has already been resolved. |
| * @return true if the QueryMetaData was defined in a different place - e.g. another line in orm.xml. |
| */ |
| protected boolean isDuplicateQuery(QueryMetaData meta) { |
| if(! Objects.equals(getSourceName(), meta.getSourceName())) { |
| return true; |
| } |
| if(getLineNum() != meta.getLineNumber()) { |
| return true; |
| } |
| return false; |
| |
| } |
| |
| private int getLineNum() { |
| int lineNum = 0; |
| Locator loc = getLocation().getLocator(); |
| if(loc != null ) { |
| lineNum = loc.getLineNumber(); |
| } |
| return lineNum; |
| } |
| |
| private boolean startDatastoreId(Attributes attrs) |
| throws SAXException { |
| MetaDataRepository repos = getRepository(); |
| ClassMetaData meta = repos.getCachedMetaData(_cls); |
| |
| //Set default value if not specified |
| String strategy = attrs.getValue("strategy"); |
| if (StringUtil.isEmpty(strategy)) { |
| strategy ="AUTO" ; |
| } |
| GenerationType stratType = GenerationType.valueOf(strategy); |
| |
| AnnotationPersistenceMetaDataParser.parseDataStoreId(meta, stratType, |
| attrs.getValue("generator")); |
| |
| return true; |
| } |
| |
| private boolean startDataCache(Attributes attrs) |
| throws SAXException { |
| String enabledStr = attrs.getValue("enabled"); |
| boolean enabled = (Boolean) (StringUtil.isEmpty(enabledStr) ? true : |
| Boolean.parseBoolean(enabledStr)); |
| |
| String timeoutStr = attrs.getValue("timeout"); |
| int timeout = (Integer) (StringUtil.isEmpty(timeoutStr) ? Integer.MIN_VALUE : |
| Integer.parseInt(timeoutStr)); |
| |
| String name = attrs.getValue("name"); |
| name = StringUtil.isEmpty(name) ? "" : name; |
| |
| AnnotationPersistenceMetaDataParser.parseDataCache(getRepository().getCachedMetaData(_cls), |
| enabled, name, timeout); |
| |
| return true; |
| } |
| |
| private boolean startExtendedStrategy(PersistenceStrategy ps, Attributes attrs) |
| throws SAXException { |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| parseExtendedStrategy(fmd, ps, attrs); |
| |
| return true; |
| } |
| |
| private void endExtendedStrategy(PersistenceStrategy ps) |
| throws SAXException { |
| if (ps == PERS |
| || ps == PERS_COLL |
| || ps == PERS_MAP) { |
| finishField(); |
| } |
| |
| } |
| |
| /** |
| * Parse strategy specific attributes. |
| */ |
| private void parseExtendedStrategy(FieldMetaData fmd, |
| PersistenceStrategy strategy, Attributes attrs) |
| throws SAXException { |
| |
| // The following attributes will be temporarily parsed for all strategy types. This |
| // is because it is not clear which attributes should be supported for which strategies. |
| // And more testing needs to be done to determine what actually works. |
| // Right now they are limited by the schema. But, putting these here allows a temporary schema |
| // update by a developer without requiring a corresponding code update. |
| parseTypeAttr(fmd, attrs); |
| parseElementTypeAttr(fmd, attrs); |
| parseKeyTypeAttr(fmd, attrs); |
| parseDependentAttr(fmd, attrs); |
| parseElementDependentAttr(fmd, attrs); |
| parseKeyDependentAttr(fmd, attrs); |
| parseElementClassCriteriaAttr(fmd, attrs); |
| parseLRSAttr(fmd, attrs); |
| parseInverseLogicalAttr(fmd, attrs); |
| parseEagerFetchModeAttr(fmd, attrs); |
| |
| switch (strategy) { |
| case BASIC: |
| parseExtendedBasic(fmd, attrs); |
| break; |
| case EMBEDDED: |
| parseExtendedEmbedded(fmd, attrs); |
| break; |
| case ONE_ONE: |
| parseExtendedOneToOne(fmd, attrs); |
| break; |
| case MANY_ONE: |
| parseExtendedManyToOne(fmd, attrs); |
| break; |
| case MANY_MANY: |
| parseExtendedManyToMany(fmd, attrs); |
| break; |
| case ONE_MANY: |
| parseExtendedOneToMany(fmd, attrs); |
| break; |
| case ELEM_COLL: |
| parseExtendedElementCollection(fmd, attrs); |
| } |
| } |
| |
| private void parseExtendedBasic(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| |
| } |
| |
| private void parseExtendedEmbedded(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| } |
| |
| private void parseExtendedOneToOne(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| } |
| |
| private void parseExtendedManyToOne(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| } |
| |
| private void parseExtendedManyToMany(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| } |
| |
| private void parseExtendedOneToMany(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| |
| } |
| |
| private void parseExtendedElementCollection(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| // TODO: Handle specific attributes |
| |
| } |
| |
| private void parsePersistent(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| parseTypeAttr(fmd, attrs); |
| // TODO - handle attributes |
| String val = attrs.getValue("fetch"); |
| if (val != null) { |
| fmd.setInDefaultFetchGroup("EAGER".equals(val)); |
| } |
| |
| switch (fmd.getDeclaredTypeCode()) { |
| case JavaTypes.ARRAY: |
| if (fmd.getDeclaredType() == byte[].class |
| || fmd.getDeclaredType() == Byte[].class |
| || fmd.getDeclaredType() == char[].class |
| || fmd.getDeclaredType() == Character[].class) |
| break; |
| // no break |
| case JavaTypes.COLLECTION: |
| case JavaTypes.MAP: |
| throw new MetaDataException(_loc.get("bad-meta-anno", fmd, |
| "Persistent")); |
| } |
| } |
| |
| private void parsePersistentCollection(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| parseElementTypeAttr(fmd, attrs); |
| // TODO - handle attributes and field type |
| } |
| |
| private void parsePersistentMap(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| parseCommonExtendedAttributes(fmd, attrs); |
| parseElementTypeAttr(fmd, attrs); |
| parseKeyTypeAttr(fmd, attrs); |
| // TODO - handle attributes and field type |
| } |
| |
| private void parseCommonExtendedAttributes(FieldMetaData fmd, Attributes attrs) { |
| String loadFetchGroup = attrs.getValue("load-fetch-group"); |
| if (!StringUtil.isEmpty(loadFetchGroup)) { |
| fmd.setLoadFetchGroup(loadFetchGroup); |
| } |
| |
| String externalizer = attrs.getValue("externalizer"); |
| if (!StringUtil.isEmpty(externalizer)) { |
| fmd.setExternalizer(externalizer); |
| } |
| |
| String factory = attrs.getValue("factory"); |
| if (!StringUtil.isEmpty(factory)) { |
| fmd.setFactory(factory); |
| } |
| |
| parseStrategy(fmd, attrs); |
| } |
| |
| protected void parseStrategy(FieldMetaData fmd, Attributes attrs) { |
| |
| } |
| |
| private boolean startReadOnly(Attributes attrs) |
| throws SAXException { |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String updateAction = attrs.getValue("update-action"); |
| |
| if (updateAction.equalsIgnoreCase("RESTRICT")) { |
| fmd.setUpdateStrategy(UpdateStrategies.RESTRICT); |
| } |
| else if (updateAction.equalsIgnoreCase("IGNORE")) { |
| fmd.setUpdateStrategy(UpdateStrategies.IGNORE); |
| } |
| else |
| throw new InternalException(); |
| |
| return true; |
| } |
| |
| private void parseDependentAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String dependentStr = attrs.getValue("dependent"); |
| if (!StringUtil.isEmpty(dependentStr)) { |
| boolean dependent = Boolean.parseBoolean(dependentStr); |
| if (dependent) { |
| fmd.setCascadeDelete(ValueMetaData.CASCADE_AUTO); |
| } |
| else { |
| fmd.setCascadeDelete(ValueMetaData.CASCADE_NONE); |
| } |
| } |
| } |
| |
| private void parseElementDependentAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String elementDependentStr = attrs.getValue("element-dependent"); |
| if (!StringUtil.isEmpty(elementDependentStr)) { |
| boolean elementDependent = Boolean.parseBoolean(elementDependentStr); |
| if (elementDependent) { |
| fmd.getElement().setCascadeDelete(ValueMetaData.CASCADE_AUTO); |
| } |
| else { |
| fmd.getElement().setCascadeDelete(ValueMetaData.CASCADE_NONE); |
| } |
| } |
| } |
| |
| private void parseKeyDependentAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String keyDependentStr = attrs.getValue("key-dependent"); |
| if (!StringUtil.isEmpty(keyDependentStr)) { |
| boolean keyDependent = Boolean.parseBoolean(keyDependentStr); |
| if (keyDependent) { |
| fmd.getKey().setCascadeDelete(ValueMetaData.CASCADE_AUTO); |
| } |
| else { |
| fmd.getKey().setCascadeDelete(ValueMetaData.CASCADE_NONE); |
| } |
| } |
| } |
| |
| protected void parseElementClassCriteriaAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| // String elementClassCriteriaString = attrs.getValue("element-class-criteria"); |
| // if (!StringUtil.isEmpty(elementClassCriteriaString)) { |
| // FieldMapping fm = (FieldMapping) fmd; |
| // boolean elementClassCriteria = Boolean.parseBoolean(elementClassCriteriaString); |
| // fm.getElementMapping().getValueInfo().setUseClassCriteria(elementClassCriteria); |
| // } |
| } |
| |
| private void parseTypeAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String typeStr = attrs.getValue("type"); |
| if (!StringUtil.isEmpty(typeStr)) { |
| if (StringUtil.endsWithIgnoreCase(typeStr, ".class")) { |
| typeStr = typeStr.substring(0, typeStr.lastIndexOf('.')); |
| } |
| Class<?> typeCls = parseTypeStr(typeStr); |
| |
| fmd.setTypeOverride(typeCls); |
| } |
| } |
| |
| private void parseLRSAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| String lrsStr = attrs.getValue("lrs"); |
| if (!StringUtil.isEmpty(lrsStr)) { |
| boolean lrs = Boolean.parseBoolean(lrsStr); |
| fmd.setLRS(lrs); |
| } |
| } |
| |
| private void parseElementTypeAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String typeStr = attrs.getValue("element-type"); |
| if (!StringUtil.isEmpty(typeStr)) { |
| if (StringUtil.endsWithIgnoreCase(typeStr, ".class")) { |
| typeStr = typeStr.substring(0, typeStr.lastIndexOf('.')); |
| } |
| Class<?> typeCls = parseTypeStr(typeStr); |
| |
| fmd.setTypeOverride(typeCls); |
| } |
| } |
| |
| private void parseKeyTypeAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String typeStr = attrs.getValue("key-type"); |
| if (!StringUtil.isEmpty(typeStr)) { |
| if (StringUtil.endsWithIgnoreCase(typeStr, ".class")) { |
| typeStr = typeStr.substring(0, typeStr.lastIndexOf('.')); |
| } |
| Class<?> typeCls = parseTypeStr(typeStr); |
| |
| fmd.setTypeOverride(typeCls); |
| } |
| } |
| |
| private Class<?> parseTypeStr(String typeStr) |
| throws SAXException { |
| Class<?> typeCls = null; |
| try { |
| if (typeStr.equalsIgnoreCase("int")) { |
| typeCls = int.class; |
| } |
| else if (typeStr.equalsIgnoreCase("byte")) { |
| typeCls = byte.class; |
| } |
| else if (typeStr.equalsIgnoreCase("short")) { |
| typeCls = short.class; |
| } |
| else if (typeStr.equalsIgnoreCase("long")) { |
| typeCls = long.class; |
| } |
| else if (typeStr.equalsIgnoreCase("float")) { |
| typeCls = float.class; |
| } |
| else if (typeStr.equalsIgnoreCase("double")) { |
| typeCls = double.class; |
| } |
| else if (typeStr.equalsIgnoreCase("boolean")) { |
| typeCls = boolean.class; |
| } |
| else if (typeStr.equalsIgnoreCase("char")) { |
| typeCls = char.class; |
| } |
| else { |
| typeCls = Class.forName(typeStr); |
| } |
| } catch (ClassNotFoundException e) { |
| throw new SAXException(e); |
| } |
| |
| return typeCls; |
| } |
| |
| private void parseInverseLogicalAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| |
| String inverseLogical = attrs.getValue("inverse-logical"); |
| if (!StringUtil.isEmpty(inverseLogical)) { |
| fmd.setInverse(inverseLogical); |
| } |
| } |
| |
| protected void parseEagerFetchModeAttr(FieldMetaData fmd, Attributes attrs) |
| throws SAXException { |
| } |
| |
| private boolean startExternalValues(Attributes attrs) |
| throws SAXException { |
| |
| _externalValues = new StringBuffer(10); |
| |
| return true; |
| } |
| |
| private void endExternalValues() |
| throws SAXException { |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| fmd.setExternalValues(_externalValues.toString()); |
| _externalValues = null; |
| } |
| |
| private boolean startExternalValue(Attributes attrs) |
| throws SAXException { |
| |
| if (_externalValues.length() > 0) { |
| _externalValues.append(','); |
| } |
| _externalValues.append(attrs.getValue("java-value")); |
| _externalValues.append('='); |
| _externalValues.append(attrs.getValue("datastore-value")); |
| |
| return true; |
| } |
| |
| private boolean startExternalizer(Attributes attrs) |
| throws SAXException { |
| |
| return true; |
| } |
| |
| private void endExternalizer() |
| throws SAXException { |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String externalizer = currentText(); |
| fmd.setExternalizer(externalizer); |
| } |
| |
| private boolean startFactory(Attributes attrs) |
| throws SAXException { |
| |
| return true; |
| } |
| |
| private void endFactory() |
| throws SAXException { |
| |
| FieldMetaData fmd = (FieldMetaData) currentElement(); |
| String factory = currentText(); |
| fmd.setFactory(factory); |
| } |
| |
| private boolean startFetchGroups(Attributes attrs) |
| throws SAXException { |
| if (_fgList == null) { |
| _fgList = new ArrayList<>(); |
| } |
| return true; |
| } |
| |
| private boolean startFetchGroup(Attributes attrs) |
| throws SAXException { |
| |
| if (_fgList == null) { |
| _fgList = new ArrayList<>(); |
| } |
| _currentFg = new AnnotationPersistenceMetaDataParser.FetchGroupImpl(attrs.getValue("name"), |
| Boolean.parseBoolean(attrs.getValue("post-load"))); |
| |
| return true; |
| } |
| |
| private void endFetchGroup() |
| throws SAXException { |
| |
| String[] referencedFetchGroups = {}; |
| if (_referencedFgList != null &&_referencedFgList.size() > 0) { |
| referencedFetchGroups = _referencedFgList.toArray(referencedFetchGroups); |
| } |
| _currentFg.setFetchGroups(referencedFetchGroups); |
| |
| FetchAttributeImpl[] fetchAttrs = {}; |
| if (_fetchAttrList != null && _fetchAttrList.size() > 0) { |
| fetchAttrs = _fetchAttrList.toArray(fetchAttrs); |
| } |
| _currentFg.setAttributes(fetchAttrs); |
| |
| _fgList.add(_currentFg); |
| _currentFg = null; |
| _referencedFgList = null; |
| _fetchAttrList = null; |
| } |
| |
| private boolean startFetchAttribute(Attributes attrs) |
| throws SAXException { |
| if (_fetchAttrList == null) { |
| _fetchAttrList = new ArrayList<>(); |
| } |
| |
| FetchAttributeImpl fetchAttribute = new FetchAttributeImpl(attrs.getValue("name"), |
| Integer.parseInt(attrs.getValue("recursion-depth"))); |
| |
| _fetchAttrList.add(fetchAttribute); |
| |
| return true; |
| } |
| |
| private boolean startReferencedFetchGroup(Attributes attrs) |
| throws SAXException { |
| |
| if (_referencedFgList == null) { |
| _referencedFgList = new ArrayList<>(); |
| } |
| |
| return true; |
| } |
| |
| private void endReferencedFetchGroup() |
| throws SAXException { |
| |
| _referencedFgList.add(currentText()); |
| } |
| |
| @Override |
| protected void endExtendedClass(String elem) throws SAXException { |
| ClassMetaData meta = (ClassMetaData) peekElement(); |
| |
| if (_fgList != null) { |
| // Handle fetch groups |
| _fgs = new FetchGroupImpl[]{}; |
| _fgs = _fgList.toArray(_fgs); |
| AnnotationPersistenceMetaDataParser.parseFetchGroups(meta, _fgs); |
| _fgList = null; |
| _fgs = null; |
| } |
| } |
| } |