Home » apache-openjpa-1.1.0-source » org.apache.openjpa » persistence » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied.  See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.    
   18    */
   19   package org.apache.openjpa.persistence;
   20   
   21   import java.io.File;
   22   import java.io.IOException;
   23   import java.net.URL;
   24   import java.security.AccessController;
   25   import java.util.Arrays;
   26   import java.util.Collection;
   27   import java.util.Collections;
   28   import java.util.HashMap;
   29   import java.util.HashSet;
   30   import java.util.Map;
   31   import java.util.Set;
   32   import javax.persistence.Embeddable;
   33   import javax.persistence.Entity;
   34   import javax.persistence.MappedSuperclass;
   35   import javax.persistence.NamedNativeQueries;
   36   import javax.persistence.NamedNativeQuery;
   37   import javax.persistence.NamedQueries;
   38   import javax.persistence.NamedQuery;
   39   import javax.persistence.SqlResultSetMapping;
   40   import javax.persistence.SqlResultSetMappings;
   41   
   42   import org.apache.openjpa.lib.conf.Configurable;
   43   import org.apache.openjpa.lib.conf.Configuration;
   44   import org.apache.openjpa.lib.conf.GenericConfigurable;
   45   import org.apache.openjpa.lib.meta.ClassAnnotationMetaDataFilter;
   46   import org.apache.openjpa.lib.meta.ClassArgParser;
   47   import org.apache.openjpa.lib.meta.MetaDataFilter;
   48   import org.apache.openjpa.lib.meta.MetaDataParser;
   49   import org.apache.openjpa.lib.util.J2DoPriv5Helper;
   50   import org.apache.openjpa.lib.util.Localizer;
   51   import org.apache.openjpa.lib.util.Options;
   52   import org.apache.openjpa.meta.AbstractCFMetaDataFactory;
   53   import org.apache.openjpa.meta.ClassMetaData;
   54   import org.apache.openjpa.meta.FieldMetaData;
   55   import org.apache.openjpa.meta.MetaDataDefaults;
   56   import org.apache.openjpa.meta.MetaDataFactory;
   57   import org.apache.openjpa.meta.QueryMetaData;
   58   import org.apache.openjpa.meta.SequenceMetaData;
   59   import org.apache.openjpa.util.GeneralException;
   60   import org.apache.openjpa.util.MetaDataException;
   61   
   62   /**
   63    * {@link MetaDataFactory} for JPA metadata.
   64    *
   65    * @author Steve Kim
   66    * @since 0.4.0
   67    * @nojavadoc
   68    */
   69   public class PersistenceMetaDataFactory
   70       extends AbstractCFMetaDataFactory
   71       implements Configurable, GenericConfigurable {
   72   
   73       private static final Localizer _loc = Localizer.forPackage
   74           (PersistenceMetaDataFactory.class);
   75   
   76       private final PersistenceMetaDataDefaults _def = 
   77           new PersistenceMetaDataDefaults();
   78       private AnnotationPersistenceMetaDataParser _annoParser = null;
   79       private AnnotationPersistenceXMLMetaDataParser _annoXMLParser = null;
   80       private XMLPersistenceMetaDataParser _xmlParser = null;
   81       private Map<URL, Set> _xml = null; // xml rsrc -> class names
   82       private Set<URL> _unparsed = null; // xml rsrc
   83       private boolean _fieldOverride = true;
   84   
   85       /**
   86        * Whether to use field-level override or class-level override.
   87        * Defaults to true.
   88        */
   89       public void setFieldOverride(boolean field) {
   90           _fieldOverride = field;
   91       }
   92   
   93       /**
   94        * Whether to use field-level override or class-level override.
   95        * Defaults to true.
   96        */
   97       public boolean getFieldOverride() {
   98           return _fieldOverride;
   99       }
  100   
  101       /**
  102        * Return metadata parser, creating it if it does not already exist.
  103        */
  104       public AnnotationPersistenceMetaDataParser getAnnotationParser() {
  105           if (_annoParser == null) {
  106               _annoParser = newAnnotationParser();
  107               _annoParser.setRepository(repos);
  108           }
  109           return _annoParser;
  110       }
  111   
  112       /**
  113        * Set the metadata parser.
  114        */
  115       public void setAnnotationParser(
  116           AnnotationPersistenceMetaDataParser parser) {
  117           if (_annoParser != null)
  118               _annoParser.setRepository(null);
  119           if (parser != null)
  120               parser.setRepository(repos);
  121           _annoParser = parser;
  122       }
  123   
  124       /**
  125        * Create a new metadata parser.
  126        */
  127       protected AnnotationPersistenceMetaDataParser newAnnotationParser() {
  128           return new AnnotationPersistenceMetaDataParser
  129               (repos.getConfiguration());
  130       }
  131   
  132       /**
  133        * Create a new annotation serializer.
  134        */
  135       protected AnnotationPersistenceMetaDataSerializer
  136           newAnnotationSerializer() {
  137           return new AnnotationPersistenceMetaDataSerializer
  138               (repos.getConfiguration());
  139       }
  140   
  141       /**
  142        * Return XML metadata parser, creating it if it does not already exist.
  143        */
  144       public XMLPersistenceMetaDataParser getXMLParser() {
  145           if (_xmlParser == null) {
  146               _xmlParser = newXMLParser(true);
  147               _xmlParser.setRepository(repos);
  148               if (_fieldOverride)
  149                   _xmlParser.setAnnotationParser(getAnnotationParser());
  150           }
  151           return _xmlParser;
  152       }
  153   
  154       /**
  155        * Set the metadata parser.
  156        */
  157       public void setXMLParser(XMLPersistenceMetaDataParser parser) {
  158           if (_xmlParser != null)
  159               _xmlParser.setRepository(null);
  160           if (parser != null)
  161               parser.setRepository(repos);
  162           _xmlParser = parser;
  163       }
  164   
  165       /**
  166        * Create a new metadata parser.
  167        */
  168       protected XMLPersistenceMetaDataParser newXMLParser(boolean loading) {
  169           return new XMLPersistenceMetaDataParser(repos.getConfiguration());
  170       }
  171   
  172       /**
  173        * Create a new serializer
  174        */
  175       protected XMLPersistenceMetaDataSerializer newXMLSerializer() {
  176           return new XMLPersistenceMetaDataSerializer(repos.getConfiguration());
  177       }
  178   
  179       public void load(Class cls, int mode, ClassLoader envLoader) {
  180           if (mode == MODE_NONE)
  181               return;
  182           if (!strict && (mode & MODE_META) != 0)
  183               mode |= MODE_MAPPING;
  184   
  185           // getting the list of persistent types runs callbacks to
  186           // mapPersistentTypeNames if it hasn't been called already, which
  187           // caches XML resources
  188           getPersistentTypeNames(false, envLoader);
  189           URL xml = findXML(cls);
  190   
  191           // we have to parse metadata up-front to register persistence unit
  192           // defaults and system callbacks
  193           ClassMetaData meta;
  194           boolean parsedXML = false;
  195           if (_unparsed != null && !_unparsed.isEmpty()
  196               && (mode & MODE_META) != 0) {
  197               for (URL url : _unparsed)
  198                   parseXML(url, cls, mode, envLoader);
  199               parsedXML = _unparsed.contains(xml);
  200               _unparsed.clear();
  201   
  202               // XML process check
  203               meta = repos.getCachedMetaData(cls);
  204               if (meta != null && (meta.getSourceMode() & mode) == mode) {
  205                   validateStrategies(meta);
  206                   return;
  207               }
  208           }
  209   
  210           // might have been looking for system-level query
  211           if (cls == null)
  212               return;
  213   
  214           // we may still need to parse XML if this is a redeploy of a class, or
  215           // if we're in strict query-only mode
  216           if (!parsedXML && xml != null) {
  217               parseXML(xml, cls, mode, envLoader);
  218               // XML process check
  219               meta = repos.getCachedMetaData(cls);
  220               if (meta != null && (meta.getSourceMode() & mode) == mode) {
  221                   validateStrategies(meta);
  222                   return;
  223               }
  224           }
  225   
  226           AnnotationPersistenceMetaDataParser parser = getAnnotationParser();
  227           parser.setEnvClassLoader(envLoader);
  228           parser.setMode(mode);
  229           parser.parse(cls);
  230   
  231           meta = repos.getCachedMetaData(cls);
  232           if (meta != null && (meta.getSourceMode() & mode) == mode)
  233               validateStrategies(meta);
  234       }
  235   
  236       /**
  237        * Parse the given XML resource.
  238        */
  239       private void parseXML(URL xml, Class cls, int mode, ClassLoader envLoader) {
  240           ClassLoader loader = repos.getConfiguration().
  241               getClassResolverInstance().getClassLoader(cls, envLoader);
  242           XMLPersistenceMetaDataParser xmlParser = getXMLParser();
  243           xmlParser.setClassLoader(envLoader != null ? envLoader : loader);
  244           xmlParser.setEnvClassLoader(envLoader);
  245           xmlParser.setMode(mode);
  246           try {
  247               xmlParser.parse(xml);
  248           } catch (IOException ioe) {
  249               throw new GeneralException(ioe);
  250           }
  251       }
  252   
  253       /**
  254        * Locate the XML resource for the given class.
  255        */
  256       private URL findXML(Class cls) {
  257           if (_xml != null && cls != null)
  258               for (Map.Entry<URL, Set> entry : _xml.entrySet())
  259                   if (entry.getValue().contains(cls.getName()))
  260                       return entry.getKey();
  261           return null;
  262       }
  263   
  264       @Override
  265       protected void mapPersistentTypeNames(Object rsrc, String[] names) {
  266           if (rsrc.toString().endsWith(".class")) {
  267               if (log.isTraceEnabled())
  268                   log.trace(
  269                       _loc.get("map-persistent-types-skipping-class", rsrc));
  270               return;
  271           } else if (!(rsrc instanceof URL)) {
  272               if (log.isTraceEnabled())
  273                   log.trace(
  274                       _loc.get("map-persistent-types-skipping-non-url", rsrc));
  275               return;
  276           }
  277   
  278           if (log.isTraceEnabled())
  279               log.trace(_loc.get(
  280                   "map-persistent-type-names", rsrc, Arrays.asList(names)));
  281           
  282           if (_xml == null)
  283               _xml = new HashMap<URL, Set>();
  284           _xml.put((URL) rsrc, new HashSet(Arrays.asList(names)));
  285           if (_unparsed == null)
  286               _unparsed = new HashSet<URL>();
  287           _unparsed.add((URL) rsrc);
  288       }
  289   
  290       @Override
  291       public Class getQueryScope(String queryName, ClassLoader loader) {
  292           if (queryName == null)
  293               return null;
  294           Collection classes = repos.loadPersistentTypes(false, loader);
  295           for (Class cls : (Collection<Class>) classes) {
  296               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  297                   .isAnnotationPresentAction(cls, NamedQuery.class)))
  298                   .booleanValue() && hasNamedQuery
  299                   (queryName, (NamedQuery) cls.getAnnotation(NamedQuery.class)))
  300                   return cls;
  301               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  302                   .isAnnotationPresentAction(cls, NamedQueries.class)))
  303                   .booleanValue() &&
  304                   hasNamedQuery(queryName, ((NamedQueries) cls.
  305                       getAnnotation(NamedQueries.class)).value()))
  306                   return cls;
  307               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  308                   .isAnnotationPresentAction(cls, NamedNativeQuery.class)))
  309                   .booleanValue() &&
  310                   hasNamedNativeQuery(queryName, (NamedNativeQuery) cls.
  311                       getAnnotation(NamedNativeQuery.class)))
  312                   return cls;
  313               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  314                   .isAnnotationPresentAction(cls, NamedNativeQueries.class)))
  315                   .booleanValue() &&
  316                   hasNamedNativeQuery(queryName, ((NamedNativeQueries) cls.
  317                       getAnnotation(NamedNativeQueries.class)).value()))
  318                   return cls;
  319           }
  320           return null;
  321       }
  322   
  323       @Override
  324       public Class getResultSetMappingScope(String rsMappingName,
  325           ClassLoader loader) {
  326           if (rsMappingName == null)
  327               return null;
  328           
  329           Collection classes = repos.loadPersistentTypes(false, loader);
  330           for (Class cls : (Collection<Class>) classes) {
  331   
  332               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  333                   .isAnnotationPresentAction(cls, SqlResultSetMapping.class)))
  334                   .booleanValue() &&
  335                   hasRSMapping(rsMappingName, (SqlResultSetMapping) cls.
  336                   getAnnotation(SqlResultSetMapping.class)))
  337                   return cls;
  338   
  339               if (((Boolean) AccessController.doPrivileged(J2DoPriv5Helper
  340                   .isAnnotationPresentAction(cls, SqlResultSetMappings.class)))
  341                   .booleanValue() &&
  342                   hasRSMapping(rsMappingName, ((SqlResultSetMappings) cls.
  343                   getAnnotation(SqlResultSetMappings.class)).value()))
  344                   return cls;
  345           }
  346           return null;
  347       }
  348   
  349       private boolean hasNamedQuery(String query, NamedQuery... queries) {
  350           for (NamedQuery q : queries) {
  351               if (query.equals(q.name()))
  352                   return true;
  353           }
  354           return false;
  355       }
  356   
  357       private boolean hasRSMapping(String rsMapping,
  358           SqlResultSetMapping... mappings) {
  359           for (SqlResultSetMapping m : mappings) {
  360               if (rsMapping.equals(m.name()))
  361                   return true;
  362           }
  363           return false;
  364       }
  365   
  366       private boolean hasNamedNativeQuery(String query,
  367           NamedNativeQuery... queries) {
  368           for (NamedNativeQuery q : queries) {
  369               if (query.equals(q.name()))
  370                   return true;
  371           }
  372           return false;
  373       }
  374   
  375       @Override
  376       protected MetaDataFilter newMetaDataFilter() {
  377           ClassAnnotationMetaDataFilter camdf = new ClassAnnotationMetaDataFilter(
  378                   new Class[] { Entity.class, Embeddable.class,
  379                           MappedSuperclass.class });
  380           camdf.setLog(log);
  381           return camdf;
  382       }
  383   
  384       /**
  385        * Ensure all fields have declared a strategy.
  386        */
  387       private void validateStrategies(ClassMetaData meta) {
  388           StringBuffer buf = null;
  389           for (FieldMetaData fmd : meta.getDeclaredFields()) {
  390               if (!fmd.isExplicit()) {
  391                   if (buf == null)
  392                       buf = new StringBuffer();
  393                   else
  394                       buf.append(", ");
  395                   buf.append(fmd);
  396               }
  397           }
  398           if (buf != null)
  399               throw new MetaDataException(_loc.get("no-pers-strat", buf));
  400       }
  401   
  402       public MetaDataDefaults getDefaults() {
  403           return _def;
  404       }
  405   
  406       @Override
  407       public ClassArgParser newClassArgParser() {
  408           ClassArgParser parser = new ClassArgParser();
  409           parser.setMetaDataStructure("package", null, new String[]{
  410               "entity", "embeddable", "mapped-superclass" }, "class");
  411           return parser;
  412       }
  413   
  414       @Override
  415       public void clear() {
  416           super.clear();
  417           if (_annoParser != null)
  418               _annoParser.clear();
  419           if (_xmlParser != null)
  420               _xmlParser.clear();
  421           if (_xml != null)
  422               _xml.clear();
  423       }
  424   
  425       protected Parser newParser(boolean loading) {
  426           return newXMLParser(loading);
  427       }
  428   
  429       protected Serializer newSerializer() {
  430           return newXMLSerializer();
  431       }
  432   
  433       @Override
  434       protected void parse(MetaDataParser parser, Class[] cls) {
  435           parse(parser, Collections.singleton(defaultXMLFile()));
  436       }
  437   
  438       protected File defaultSourceFile(ClassMetaData meta) {
  439           return defaultXMLFile();
  440       }
  441   
  442       protected File defaultSourceFile(QueryMetaData query, Map clsNames) {
  443           ClassMetaData meta = getDefiningMetaData(query, clsNames);
  444           File file = (meta == null) ? null : meta.getSourceFile();
  445           if (file != null)
  446               return file;
  447           return defaultXMLFile();
  448       }
  449   
  450       protected File defaultSourceFile(SequenceMetaData seq, Map clsNames) {
  451           return defaultXMLFile();
  452       }
  453   
  454       /**
  455        * Look for META-INF/orm.xml, and if it doesn't exist, choose a default.
  456        */
  457       private File defaultXMLFile() {
  458           ClassLoader loader = repos.getConfiguration().
  459               getClassResolverInstance().getClassLoader(getClass(), null);
  460           URL rsrc = (URL) AccessController.doPrivileged(
  461               J2DoPriv5Helper.getResourceAction(loader, "META-INF/orm.xml"));
  462           if (rsrc != null) {
  463               File file = new File(rsrc.getFile());
  464               if (((Boolean) AccessController.doPrivileged(
  465                   J2DoPriv5Helper.existsAction(file))).booleanValue())
  466                   return file;
  467           }
  468           return new File("orm.xml");
  469       }
  470   
  471       public void setConfiguration(Configuration conf) {
  472       }
  473   
  474       public void startConfiguration() {
  475       }
  476   
  477       public void endConfiguration() {
  478           if (rsrcs == null)
  479               rsrcs = Collections.singleton("META-INF/orm.xml");
  480           else
  481   			rsrcs.add("META-INF/orm.xml");
  482   	}
  483   
  484       public void setInto(Options opts) {
  485           opts.keySet().retainAll(opts.setInto(_def).keySet());
  486       }
  487   
  488       /**
  489        * Return JAXB XML annotation parser, 
  490        * creating it if it does not already exist.
  491        */
  492       public AnnotationPersistenceXMLMetaDataParser getXMLAnnotationParser() {
  493           if (_annoXMLParser == null) {
  494               _annoXMLParser = newXMLAnnotationParser();
  495               _annoXMLParser.setRepository(repos);
  496           }
  497           return _annoXMLParser;
  498       }
  499   
  500       /**
  501        * Set the JAXB XML annotation parser.
  502        */
  503       public void setXMLAnnotationParser(
  504           AnnotationPersistenceXMLMetaDataParser parser) {
  505           if (_annoXMLParser != null)
  506               _annoXMLParser.setRepository(null);
  507           if (parser != null)
  508               parser.setRepository(repos);
  509           _annoXMLParser = parser;
  510       }
  511   
  512       /**
  513        * Create a new JAXB XML annotation parser.
  514        */
  515       protected AnnotationPersistenceXMLMetaDataParser newXMLAnnotationParser() {
  516           return new AnnotationPersistenceXMLMetaDataParser
  517               (repos.getConfiguration());
  518       }
  519   
  520       public void loadXMLMetaData(FieldMetaData fmd) {
  521           AnnotationPersistenceXMLMetaDataParser parser
  522               = getXMLAnnotationParser();
  523           parser.parse(fmd);
  524       }
  525   }

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa » persistence » [javadoc | source]