FileDocCategorySizeDatePackage
MetadataProcessor.javaAPI DocGlassfish v2 API25380Tue May 22 16:54:24 BST 2007oracle.toplink.essentials.internal.ejb.cmp3.metadata

MetadataProcessor

public class MetadataProcessor extends Object
The object/relational metadata processor for the EJB3.0 specification.
author
Guy Pelletier, Sanjeeb.Sahoo@Sun.COM
since
TopLink EJB 3.0 Reference Implementation

Fields Summary
protected ClassLoader
m_loader
protected MetadataLogger
m_logger
protected MetadataProject
m_project
protected MetadataValidator
m_validator
protected AbstractSession
m_session
Constructors Summary
public MetadataProcessor(PersistenceUnitInfo puInfo, AbstractSession session, ClassLoader loader, boolean enableLazyForOneToOne)
INTERNAL: Called from EntityManagerSetupImpl. The 'real' EJB 3.0 processing that includes XML and annotations.

        m_loader = loader;
        m_session = session;
        m_logger = new MetadataLogger(session);
        m_project = new MetadataProject(puInfo, session, enableLazyForOneToOne);
    
public MetadataProcessor(AbstractSession session, ClassLoader loader, Collection entities, boolean enableLazyForOneToOne)
INTERNAL: Called from RelationshipWeaverTestSuite. Use this constructor to avoid XML processing.

deprecated

        m_loader = loader;
        m_project = new MetadataProject(null, session, enableLazyForOneToOne);
        m_session = session;
        Collection<String> entityNames = new HashSet<String>(entities.size());
        for (Class entity : entities) {
            m_project.addDescriptor(new MetadataDescriptor(entity));
            entityNames.add(entity.getName());
        }
        m_project.setEntityNames(entityNames);
        m_logger = new MetadataLogger(session);
    
Methods Summary
public voidaddEntityListeners()
INTERNAL: Method to place EntityListener's on the descriptors from the given session. This call is made from the EntityManagerSetup deploy call.

        for (MetadataDescriptor descriptor: m_project.getDescriptors()) {
            // Process all descriptors that are in our project.
            ClassAccessor accessor = descriptor.getClassAccessor();
            
            descriptor.setJavaClass(descriptor.getClassDescriptor().getJavaClass());
            // The class loader has changed, update the class stored for
            // our class accessor and its list of mapped superclasses.
            accessor.setAnnotatedElement(descriptor.getJavaClass());
            accessor.clearMappedSuperclasses();            
            
            accessor.processListeners(m_loader);
        }
    
public voidaddNamedQueries()
INTERNAL: Method to place NamedQueries and NamedNativeQueries on the given session. This call is made from the EntityManagerSetup deploy call.

        m_project.processNamedQueries(m_validator);
        m_project.processNamedNativeQueries(m_loader);
    
private static java.util.SetbuildEntityClassSetForNodeList(oracle.toplink.essentials.internal.ejb.cmp3.xml.XMLHelper helper, java.lang.String xPath, java.lang.String defaultPkg)
INTERNAL: The class name of each node in the node list will be added to the provided collection.

    	HashSet<String> classNames = new HashSet<String>();
        NodeList nodes = helper.getNodes(XMLConstants.ENTITY_MAPPINGS, xPath);
    	int nodeCount = nodes.getLength();
        
        for (int i = 0; i < nodeCount; i++) {
            // Process the required class attribute node.
            classNames.add(XMLHelper.getFullyQualifiedClassName(helper.getNode(nodes.item(i), XMLConstants.ATT_CLASS).getNodeValue(), defaultPkg));
        }
        
        return classNames;
    
private java.util.SetbuildEntityClassSetFromAnnotations()
Return a set of class names that are annotated as either @Entity from the base URL of this PersistenceUnit

        Set<String> set = new HashSet<String>();
        PersistenceUnitInfo puInfo = m_project.getPUInfo();

        for (String className : puInfo.getManagedClassNames()) {
            if (PersistenceUnitProcessor.isEntity(className, m_loader, true)) {
                set.add(className);
            }
        }

        for (URL url : puInfo.getJarFileUrls()) {
            set.addAll(PersistenceUnitProcessor.getEntityClassNamesFromURL(url, m_loader));
        }

        if (!puInfo.excludeUnlistedClasses()){
            set.addAll(PersistenceUnitProcessor.getEntityClassNamesFromURL(
                    puInfo.getPersistenceUnitRootUrl(), m_loader));
        }
       return set;

    
private static java.util.SetbuildEntityClassSetFromXMLDocument(org.w3c.dom.Document document, java.lang.String fileName, java.lang.ClassLoader loader)
INTERNAL: Return a set of class names for each entity found in the xml descriptor instance document.

        XMLHelper helper = new XMLHelper(document, fileName, loader);
        
        // Process the package node.
        String defaultPkg = helper.getNodeValue(new String[] {XMLConstants.ENTITY_MAPPINGS, XMLConstants.PACKAGE, XMLConstants.TEXT});

        // Handle entities only. Mapped superclasses and embeddables are
        // discovered and processed separately.
        HashSet<String> classSet = new HashSet<String>();
        classSet.addAll(buildEntityClassSetForNodeList(helper, XMLConstants.ENTITY, defaultPkg));

        return classSet;
    
public java.util.SetbuildEntityClassSetFromXMLDocuments()
INTERNAL: Return a set of class names for each entity found in the list of xml descriptor instance documents to be processed by the MetadataProcessor.

return

        HashSet<String> classSet = new HashSet<String>();
        for (Map.Entry<URL, Document> urlToDoc :
                m_project.getMappingFiles().entrySet()) {
            classSet.addAll(buildEntityClassSetFromXMLDocument(
                    urlToDoc.getValue(), urlToDoc.getKey().getFile(), m_loader));
        }
        return classSet;
    
public voidbuildEntityList()
This method is responsible for discovering all the entity classes for this PU and adding corresponding MetadataDescriptor in the MetadataProject. Don't call this method more than once.

        Set<String> classNames = buildEntityClassSetFromAnnotations();

        // append the list of entity classes that are defined in the XML descriptor
        classNames.addAll(buildEntityClassSetFromXMLDocuments());

        m_project.setEntityNames(classNames);

        // Add a metadata descriptor to the project for every entity class.
        // Any persistence unit metadata/defaults will be applied
        for (String className : classNames) {
            try {
                m_project.addDescriptor(
                        new MetadataDescriptor(m_loader.loadClass(className)));
            } catch (ClassNotFoundException e) {
                AbstractSessionLog.getLog().log(SessionLog.WARNING,
                        "exception_loading_entity_class", className, e);
            }
        }
    
public voidcleanup()
This method frees up resources acquired by this object.

        m_project.cleanup();
        m_loader = null;
        m_project = null;
        m_session = null;
    
public oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataLoggergetLogger()
INTERNAL: Return the logger used by the processor.

        return m_logger;
    
public oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProjectgetProject()
INTERNAL:

         return m_project;
     
public oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataValidatorgetValidator()
INTERNAL: Return the validator used by the processor.

        return m_validator;
    
private voidhandleORMException(java.lang.RuntimeException e, java.lang.String mf, boolean throwException)
Handle an exception that occured while processing ORM xml

        if (m_session == null){
            // Metadata processor is mainly used with a session.
            // Java SE bootstraping uses some functions such as ORM processing without
            // a session.  In these cases, it is impossible to get the
            // session to properly handle the exception.  As a result we
            // log an error.  The same code will be called later in the bootstrapping
            // code and the error will be handled then.
            AbstractSessionLog.getLog().log(SessionLog.CONFIG,
                    EntityManagerSetupImpl.ERROR_LOADING_XML_FILE,
                    new Object[] {mf, e});
        } else if (!throwException) {
            // fail quietly
            m_session.log(SessionLog.CONFIG,
                    SessionLog.EJB_OR_METADATA,
                    EntityManagerSetupImpl.ERROR_LOADING_XML_FILE,
                    new Object[] {mf, e});
        } else {
            // fail loudly
            m_session.handleException(e);
        }
    
private voidlogMessage(java.lang.String msg)
Log an untranslated message to the TopLink log at FINER level.

param
msg message to be logged

        if (m_session == null){
            AbstractSessionLog.getLog().log(SessionLog.FINER, msg);
        } else {
            m_session.logMessage(msg);
        }
    
public voidprocessAnnotations()
INTERNAL: Called from RelationshipWeaverTestSuite which uses only annotations and no XML.

        // Set the correct contextual validator.
        m_validator = new MetadataValidator();

        // take a copy of the collection to avoid concurrent modification exception
        // that would result when embeddables are added lazily.
        for (MetadataDescriptor descriptor:
             m_project.getDescriptors().toArray(new MetadataDescriptor[]{})) {
            // Process all descriptors that are in our project.
            ClassAccessor accessor = descriptor.getClassAccessor();
                
            // If there is no accessor on this descriptor then it has not been
            // processed yet. Create one and process it.
            if (accessor == null) {
                accessor = new ClassAccessor(new MetadataClass(descriptor.getJavaClass()), this, descriptor);
                descriptor.setClassAccessor(accessor);
                accessor.process();
            }
        } 
        
        // Process the project and anything that was deferred like
        // sequencing and relationship mappings and we are done.
        m_project.process();
    
private voidprocessMappingFile(org.w3c.dom.Document document, java.lang.String fileName)
Process the xml and fill in the project. Process the entity-mappings information then process the entities.

        if (m_project.hasDescriptors()) {
            XMLHelper helper = new XMLHelper(document, fileName, m_loader);

            // Process the entity mappings ... this is a crude way of doing
            // things ... but hey ... the clock is ticking ...
            MetadataDescriptor desc = m_project.getDescriptors().iterator().next();
            XMLClassAccessor dummyAccessor = new XMLClassAccessor(new MetadataClass(desc.getJavaClass()), null, helper, this, desc);
            dummyAccessor.processEntityMappings();

            // Process the entity nodes for this xml document.
            NodeList entityNodes = helper.getNodes(XMLConstants.ENTITY_MAPPINGS, XMLConstants.ENTITY);

            if (entityNodes != null) {
                for (int i = 0; i < entityNodes.getLength(); i++) {
                    Node entityNode = entityNodes.item(i);
                    Class entityClass = helper.getClassForNode(entityNode);
                    MetadataDescriptor descriptor = m_project.getDescriptor(entityClass);

                    // Process all descriptors that are in our project.
                    ClassAccessor accessor = descriptor.getClassAccessor();

                    // If there is no accessor on this descriptor then it has not
                    // been processed yet. Create one and process it.
                    if (accessor == null) {
                        accessor = new XMLClassAccessor(new MetadataClass(descriptor.getJavaClass()), entityNode, helper, this, descriptor);
                        descriptor.setClassAccessor(accessor);
                        accessor.process();
                    }
                }
            }
        } else {
            // WIP - log a warning that we have no entities to process ...
        }
    
public voidprocessMappingFiles()
INTERNAL: Process metadata found in all the mapping files for this PU.

see
#processMappingFile(org.w3c.dom.Document, String)

        for (Map.Entry<URL, Document> urlToDocPair : m_project.getMappingFiles().entrySet()) {
            processMappingFile(urlToDocPair.getValue(), urlToDocPair.getKey().getFile());
        }
    
public voidprocessPersistenceUnitMetadata()
INTERNAL: Process persistence unit metadata and defaults, and apply them to each entity in the collection. Any conflicts in elements defined in multiple documents will cause an exception to be thrown. The first instance encountered wins, i.e. any conflicts between PU metadata definitions in multiple instance documents will cause an exception to be thrown. The one exception to this rule is default listeners: all default listeners found will be added to a list in the order that they are read from the instance document(s).

        // For each orm xml instance document, process persistence unit
        // metadata/defaults and mapped superclasses.
        for (Map.Entry<URL, Document> mfDocPair : m_project.getMappingFiles().entrySet()) {
            // Initialize a helper for navigating the instance document.
            XMLHelper helper = new XMLHelper(mfDocPair.getValue(), mfDocPair.getKey().getFile(), m_loader);

            // Store all mapped-superclasses.
            NodeList nodes = helper.getNodes(XMLConstants.ENTITY_MAPPINGS, XMLConstants.MAPPED_SUPERCLASS);

            for (int i = 0; i < nodes.getLength(); i++) {
                Node node = nodes.item(i);
                Class cls = helper.getNodeValue(nodes.item(i), XMLConstants.ATT_CLASS, void.class);
                m_project.addMappedSuperclass(cls, node, helper);
            }

            // Store all embeddable classes.
            nodes = helper.getNodes(XMLConstants.ENTITY_MAPPINGS, XMLConstants.EMBEDDABLE);

            for (int i = 0; i < nodes.getLength(); i++) {
                Node node = nodes.item(i);
                Class cls = helper.getNodeValue(nodes.item(i), XMLConstants.ATT_CLASS, void.class);
                m_project.addEmbeddable(cls, node, helper);
            }

            // Look for a persistence-unit-metadata node.
            Node persistenceUnitMetadataNode = helper.getNode(new String[] {XMLConstants.ENTITY_MAPPINGS, XMLConstants.PU_METADATA});

            if (persistenceUnitMetadataNode != null) {
                MetadataPersistenceUnit persistenceUnit = new MetadataPersistenceUnit();

                // Process the xml-mapping-metadata-complete tag.
                persistenceUnit.setIsMetadataComplete(helper.getNode(persistenceUnitMetadataNode, XMLConstants.METADATA_COMPLETE) != null);

                // process persistence unit defaults
                Node persistenceUnitDefaultsNode = helper.getNode(persistenceUnitMetadataNode, XMLConstants.PU_DEFAULTS);

                if (persistenceUnitDefaultsNode != null) {
                    // Process the persistence unit access.
                    persistenceUnit.setAccess(helper.getNodeTextValue(persistenceUnitDefaultsNode, XMLConstants.ACCESS));

                    // Process the persitence unit schema.
                    persistenceUnit.setSchema(helper.getNodeTextValue(persistenceUnitDefaultsNode, XMLConstants.SCHEMA));

                    // Process the persistence unit catalog.
                    persistenceUnit.setCatalog(helper.getNodeTextValue(persistenceUnitDefaultsNode, XMLConstants.CATALOG));

                    // Process the persistence unit cascade-persist.
                    persistenceUnit.setIsCascadePersist(helper.getNode(persistenceUnitDefaultsNode, XMLConstants.CASCADE_PERSIST) != null);

                    // Process the default entity-listeners. No conflict
                    // checking will be done, that is, any and all
                    // default listeners will be added to the project.
                    NodeList listenerNodes = helper.getNodes(persistenceUnitDefaultsNode, XMLConstants.ENTITY_LISTENERS, XMLConstants.ENTITY_LISTENER);
                    if (listenerNodes != null) {
                        m_project.addDefaultListeners(listenerNodes, helper);
                    }
                }

                // Add the metadata persistence unit to the project if
                // there is no conflicting metadata (from other
                // persistence unit metadata)
                MetadataPersistenceUnit existingPersistenceUnit = m_project.getPersistenceUnit();
                if (existingPersistenceUnit != null) {
                    if (! existingPersistenceUnit.equals(persistenceUnit)) {
                        (new XMLValidator()).throwPersistenceUnitMetadataConflict(existingPersistenceUnit.getConflict());
                    }
                } else {
                    m_project.setPersistenceUnit(persistenceUnit);
                }
            }
        }
    
private java.util.MapreadExplicitlySpecifiedMappingFiles(boolean throwExceptionOnFail)

        Map<URL, Document> list = new HashMap<URL, Document>();
        final PersistenceUnitInfo puInfo = m_project.getPUInfo();
        for (String mf : puInfo.getMappingFileNames()) {
            try {
                Enumeration<URL> mfURLs = m_loader.getResources(mf);
                if (mfURLs.hasMoreElements()) {
                    URL nextURL = mfURLs.nextElement();
                    if(mfURLs.hasMoreElements()) {
                        handleORMException(ValidationException.nonUniqueMappingFileName(puInfo.getPersistenceUnitName(), mf), mf, throwExceptionOnFail);
                    }
                    InputStream stream = null;
                    stream = nextURL.openStream();
                    Document document = XMLHelper.parseDocument(stream, nextURL.getFile(), m_loader);
                    list.put(nextURL, document);
                    try{
                        stream.close();
                    } catch (IOException e) {}
                } else {
                    handleORMException(ValidationException.mappingFileNotFound(puInfo.getPersistenceUnitName(), mf), mf, throwExceptionOnFail);
                }
            } catch (IOException e) {
                handleORMException(
                        PersistenceUnitLoadingException.exceptionLoadingORMXML(mf, e),
                        mf, throwExceptionOnFail);
            }
        }
        return list;
    
public voidreadMappingFiles(boolean throwExceptionOnFail)
This method is responsible for figuring out list of mapping files to be read for a persistence unit and storing that list in {@link MetadataProject}.

param
throwExceptionOnFail

        // Initialize the correct contextual objects.
        m_validator = new XMLValidator();

        // step #1: discover all the standard XML mapping files.
        Map<URL, Document> list = readStandardMappingFiles();

        // step #2: add URLs corresponding to explicitly specified files
        list.putAll(readExplicitlySpecifiedMappingFiles(throwExceptionOnFail));
        m_project.setMappingFiles(list);
    
private java.util.MapreadStandardMappingFiles()

        Map<URL, Document> list = new HashMap<URL, Document>();
        final PersistenceUnitInfo puInfo = m_project.getPUInfo();
        Collection<URL> rootUrls = new HashSet<URL>(puInfo.getJarFileUrls());
        rootUrls.add(puInfo.getPersistenceUnitRootUrl());
        final String ormXMLFile = "META-INF/orm.xml";
        for(URL rootURL : rootUrls) {
            logMessage("Searching for default mapping file in " + rootURL); // NOI18N
            URL ormURL = null;
            InputStream stream = null;
            try {
                Archive m_par = null;
                m_par = new ArchiveFactoryImpl().createArchive(rootURL);
                ormURL = m_par.getEntryAsURL(ormXMLFile);
                stream = m_par.getEntry(ormXMLFile);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            if (stream != null){
                logMessage("Found a default mapping file at " + ormURL + " for root URL " + rootURL); // NOI18N
                try {
                    Document document = XMLHelper.parseDocument(stream, ormURL.getFile(), m_loader);
                    list.put(ormURL, document);
                } finally {
                    try{
                        stream.close();
                    } catch (IOException e) {}
                }
            }
        }
        return list;
    
public voidsetClassLoader(java.lang.ClassLoader loader)
INTERNAL: Use this method to set the correct class loader that should be used during processing.

        m_loader = loader;