org.castor.mapping.MappingUnmarshaller.java Source code

Java tutorial

Introduction

Here is the source code for org.castor.mapping.MappingUnmarshaller.java

Source

/*
 * Copyright 2005 Ralf Joachim
 *
 * Licensed 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.castor.mapping;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.CoreProperties;
import org.castor.core.util.Messages;
import org.castor.xml.AbstractInternalContext;
import org.castor.xml.InternalContext;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.mapping.MappingLoader;
import org.exolab.castor.mapping.loader.AbstractMappingLoader;
import org.exolab.castor.mapping.xml.ClassMapping;
import org.exolab.castor.mapping.xml.FieldHandlerDef;
import org.exolab.castor.mapping.xml.Include;
import org.exolab.castor.mapping.xml.KeyGeneratorDef;
import org.exolab.castor.mapping.xml.MappingRoot;
import org.exolab.castor.util.DTDResolver;
import org.exolab.castor.xml.ClassDescriptorResolverFactory;
import org.exolab.castor.xml.Introspector;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.XMLClassDescriptorResolver;
import org.exolab.castor.xml.util.ResolverStrategy;
import org.exolab.castor.xml.util.resolvers.CastorXMLStrategy;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
 */
public final class MappingUnmarshaller {
    // --------------------------------------------------------------------------

    /**
     * The <a href="http://jakarta.apache.org/commons/logging/">Jakarta Commons Logging </a> instance
     * used for all logging.
     */
    private static final Log LOG = LogFactory.getLog(MappingUnmarshaller.class);

    /** The registry of MappingLoader's. */
    private final MappingLoaderRegistry _registry;

    /**
     * The IDResolver to give to the Unmarshaller. This allows resolving "extends" and "depends" for
     * included Mappings.
     */
    private final MappingUnmarshallIDResolver _idResolver;

    /**
     * A flag that indicates of whether or not to allow redefinitions of class mappings.
     */
    private boolean _allowRedefinitions = false;

    /**
     * The {@link AbstractInternalContext}?holds all 'global' Castor states and access to
     * configuration.
     */
    private InternalContext _internalContext;

    // --------------------------------------------------------------------------

    /**
     * Construct a new MappingUnmarshaller.
     */
    public MappingUnmarshaller() {
        _registry = new MappingLoaderRegistry(new CoreProperties());
        _idResolver = new MappingUnmarshallIDResolver();
        AbstractInternalContext internalContext = new AbstractInternalContext() {
        };
        internalContext.setClassLoader(getClass().getClassLoader());

        XMLClassDescriptorResolver cdr = (XMLClassDescriptorResolver) ClassDescriptorResolverFactory
                .createClassDescriptorResolver(BindingType.XML);
        cdr.setInternalContext(internalContext);
        internalContext.setXMLClassDescriptorResolver(cdr);

        Introspector introspector = new Introspector();
        introspector.setInternalContext(internalContext);
        internalContext.setIntrospector(introspector);
        cdr.setIntrospector(introspector);

        ResolverStrategy resolverStrategy = new CastorXMLStrategy();
        internalContext.setResolverStrategy(resolverStrategy);
        cdr.setResolverStrategy(resolverStrategy);

        _internalContext = internalContext;
    }

    /**
     * Enables or disables the ability to allow the redefinition of class mappings.
     * 
     * @param allow a boolean that when true enables redefinitions.
     **/
    public void setAllowRedefinitions(final boolean allow) {
        _allowRedefinitions = allow;
    }

    // --------------------------------------------------------------------------

    /**
     * Returns a mapping resolver for the suitable engine. The engine's specific mapping loader is
     * created and used to create engine specific descriptors, returning a suitable mapping resolver.
     * The mapping resolver is cached in memory and returned in subsequent method calls.
     *
     * @param mapping The mapping to load and resolve.
     * @param bindingType The binding type to read from mapping.
     * @return A mapping resolver.
     * @throws MappingException A mapping error occured preventing descriptors from being generated
     *         from the loaded mapping.
     */
    public MappingLoader getMappingLoader(final Mapping mapping, final BindingType bindingType)
            throws MappingException {
        return getMappingLoader(mapping, bindingType, null);
    }

    /**
     * Returns a mapping resolver for the suitable engine. The engine's specific mapping loader is
     * created and used to create engine specific descriptors, returning a suitable mapping resolver.
     * The mapping resolver is cached in memory and returned in subsequent method calls.
     *
     * @param mapping The mapping to load and resolve.
     * @param bindingType The binding type to read from mapping.
     * @param param Arbitrary parameter that is to be passed to resolver.loadMapping().
     * @return A mapping resolver
     * @throws MappingException A mapping error occured preventing descriptors from being generated
     *         from the loaded mapping.
     */
    public MappingLoader getMappingLoader(final Mapping mapping, final BindingType bindingType, final Object param)
            throws MappingException {
        synchronized (this) {
            Iterator iter = mapping.getMappingSources().iterator();
            while (iter.hasNext()) {
                MappingSource source = (MappingSource) iter.next();
                loadMappingInternal(mapping, source.getResolver(), source.getSource());
            }

            AbstractMappingLoader loader;
            loader = (AbstractMappingLoader) _registry.getMappingLoader("CastorXmlMapping", bindingType);
            loader.setClassLoader(mapping.getClassLoader());
            loader.setAllowRedefinitions(_allowRedefinitions);
            loader.setInternalContext(_internalContext);
            loader.loadMapping(mapping.getRoot(), param);
            return loader;
        }
    }

    public void loadMappingOnly(final Mapping mapping) throws MappingException {
        synchronized (this) {
            Iterator iter = mapping.getMappingSources().iterator();
            while (iter.hasNext()) {
                MappingSource source = (MappingSource) iter.next();
                loadMappingInternal(mapping, source.getResolver(), source.getSource());
            }
        }
    }

    // --------------------------------------------------------------------------

    /**
     * Internal recursive loading method. This method will load the mapping document into a mapping
     * object and load all the included mapping along the way into a single collection.
     *
     * @param mapping The mapping instance.
     * @param resolver The entity resolver to use.
     * @param url The URL of the mapping file.
     * @throws IOException An error occured when reading the mapping file.
     * @throws MappingException The mapping file is invalid.
     */
    protected void loadMappingInternal(final Mapping mapping, final DTDResolver resolver, final String url)
            throws IOException, MappingException {
        try {
            InputSource source = resolver.resolveEntity(null, url);
            if (source == null) {
                source = new InputSource(url);
            }
            if (source.getSystemId() == null) {
                source.setSystemId(url);
            }
            LOG.info(Messages.format("mapping.loadingFrom", url));
            loadMappingInternal(mapping, resolver, source);
        } catch (SAXException ex) {
            throw new MappingException(ex);
        }
    }

    /**
     * Internal recursive loading method. This method will load the mapping document into a mapping
     * object and load all the included mapping along the way into a single collection.
     *
     * @param mapping The mapping instance.
     * @param resolver The entity resolver to use. May be null.
     * @param source The input source.
     * @throws MappingException The mapping file is invalid.
     */
    private void loadMappingInternal(final Mapping mapping, final DTDResolver resolver, final InputSource source)
            throws MappingException {
        // Clear all the cached resolvers, so they can be reconstructed a
        // second time based on the new mappings loaded
        _registry.clear();

        Object id = source.getSystemId();
        if (id == null) {
            id = source.getByteStream();
        }
        if (id != null) {
            // check that the mapping has already been processed
            if (mapping.processed(id)) {
                return;
            }

            // mark the mapping as being processed
            mapping.markAsProcessed(id);
        }

        MappingRoot root = mapping.getRoot();
        _idResolver.setMapping(root);

        try {
            // Load the specificed mapping source
            Unmarshaller unm = new Unmarshaller(MappingRoot.class);
            unm.setValidation(false);
            unm.setEntityResolver(resolver);
            unm.setClassLoader(Mapping.class.getClassLoader());
            unm.setIDResolver(_idResolver);
            unm.setUnmarshalListener(new MappingUnmarshallListener(this, mapping, resolver));

            MappingRoot loaded = (MappingRoot) unm.unmarshal(source);

            // Load all the included mapping by reference
            // -- note: this is just for processing any
            // -- includes which may have previously failed
            // -- using the IncludeListener...and to
            // -- report any potential errors.
            Enumeration includes = loaded.enumerateInclude();
            while (includes.hasMoreElements()) {
                Include include = (Include) includes.nextElement();
                if (!mapping.processed(include.getHref())) {
                    try {
                        loadMappingInternal(mapping, resolver, include.getHref());
                    } catch (Exception ex) {
                        throw new MappingException(ex);
                    }
                }
            }

            // gather "class" tags
            Enumeration<? extends ClassMapping> classMappings = loaded.enumerateClassMapping();
            while (classMappings.hasMoreElements()) {
                root.addClassMapping(classMappings.nextElement());
            }

            // gather "key-generator" tags
            Enumeration<? extends KeyGeneratorDef> keyGeneratorDefinitions = loaded.enumerateKeyGeneratorDef();
            while (keyGeneratorDefinitions.hasMoreElements()) {
                root.addKeyGeneratorDef(keyGeneratorDefinitions.nextElement());
            }

            // gather "field-handler" tags
            Enumeration<? extends FieldHandlerDef> fieldHandlerDefinitions = loaded.enumerateFieldHandlerDef();
            while (fieldHandlerDefinitions.hasMoreElements()) {
                root.addFieldHandlerDef(fieldHandlerDefinitions.nextElement());
            }
        } catch (Exception ex) {
            throw new MappingException(ex);
        }
    }

    /**
     * To set the internal context.
     * 
     * @param internalContext the {@link AbstractInternalContext}?to use
     */
    // public void setInternalContext(final InternalContext internalContext) {
    // _internalContext = internalContext;
    // }

    // --------------------------------------------------------------------------
}