org.exolab.castor.mapping.Mapping.java Source code

Java tutorial

Introduction

Here is the source code for org.exolab.castor.mapping.Mapping.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.exolab.castor.mapping;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.util.Messages;
import org.castor.mapping.MappingSource;
import org.exolab.castor.mapping.xml.MappingRoot;
import org.exolab.castor.net.util.URIUtils;
import org.exolab.castor.util.DTDResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Utility class for loading mapping files and providing them to the XML marshaller, JDO engine etc.
 * The mapping file can be loaded from a URL, input stream or SAX <tt>InputSource</tt>.
 * <p>
 * Multiple mapping files can be loaded with the same <tt>Mapping</tt> object. When loading master
 * mapping files that include other mapping files it might be convenient to use {@link #setBaseURL}
 * or {@link #setEntityResolver}.
 * <p>
 * If the desired class loader is different than the one used by Castor (e.g. if Castor is installed
 * as a Java extension), the <tt>Mapping</tt> object can be constructed with the proper class
 * loader.
 * <p>
 * The following example loads two mapping files:
 * 
 * <pre>
 * Mapping mapping;
 *
 * mapping = new Mapping(getClass().getClassLoader());
 * mapping.loadMapping("mapping.xml");
 * mapping.loadMapping(url);
 * </pre>
 *
 * @author <a href="mailto:arkin AT intalio DOT com">Assaf Arkin</a>
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision$ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
 */
public final class Mapping {
    // --------------------------------------------------------------------------

    /**
     * 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(Mapping.class);

    private static final String DEFAULT_SOURCE_TYPE = "CastorXmlMapping";

    /** List of mapping sources to resolve. */
    private final List<MappingSource> _mappings = new ArrayList<>();

    /** Set of processed systemID's. */
    private final Set<Object> _processed = new HashSet<>();

    /** The loaded mapping. */
    private final MappingRoot _root = new MappingRoot();

    /** The class loader to use. */
    private final ClassLoader _classLoader;

    /** The entity resolver to use. May be null. */
    private DTDResolver _resolver = new DTDResolver();

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

    /**
     * Constructs a new mapping.
     *
     * @param loader The class loader to use, null for the default
     */
    public Mapping(final ClassLoader loader) {
        if (loader == null) {
            _classLoader = getClass().getClassLoader();
        } else {
            _classLoader = loader;
        }
    }

    /**
     * Constructs a new mapping.
     */
    public Mapping() {
        this(null);
    }

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

    /**
     * Get list of mapping sources to resolve.
     * 
     * @return List of mapping sources to resolve.
     * @throws MappingException If no mapping source has been loaded previously.
     */
    public List<MappingSource> getMappingSources() throws MappingException {
        return Collections.unmodifiableList(_mappings);
    }

    /**
     * Marks the given mapping as having been processed.
     * 
     * @param id systemID or stream to identify the mapping to mark.
     */
    public void markAsProcessed(final Object id) {
        _processed.add(id);
    }

    /**
     * Returns true if the given systemID or stream has been marked as processed.
     * 
     * @param id systemID or stream to check for being marked as processed.
     * @return true if the given systemID or stream has been marked as processed.
     */
    public boolean processed(final Object id) {
        return _processed.contains(id);
    }

    /**
     * Get the loaded mapping.
     * 
     * @return The loaded mapping.
     */
    public MappingRoot getRoot() {
        return _root;
    }

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

    /**
     * Returns the class loader used by this mapping object. The returned class loaded may be the one
     * passed in the constructor, the one used to load Castor, or in some 1.1 JVMs null.
     *
     * @return The class loader used by this mapping object (may be null)
     */
    public ClassLoader getClassLoader() {
        return _classLoader;
    }

    /**
     * Sets the entity resolver. The entity resolver can be used to resolve external entities and
     * cached documents that are used from within mapping files.
     *
     * @param resolver The entity resolver to use
     */
    public void setEntityResolver(final EntityResolver resolver) {
        _resolver = new DTDResolver(resolver);
    }

    /**
     * Sets the base URL for the mapping and related files. If the base URL is known, files can be
     * included using relative names. Any URL can be passed, if the URL can serve as a base URL it
     * will be used. If url is an absolute path, it is converted to a file URL.
     *
     * @param url The base URL
     */
    public void setBaseURL(final String url) {
        String location = url;
        // -- remove filename if necessary:
        if (location != null) {
            int idx = location.lastIndexOf('/');
            if (idx < 0)
                idx = location.lastIndexOf('\\');
            if (idx >= 0) {
                int extIdx = location.indexOf('.', idx);
                if (extIdx > 0) {
                    location = location.substring(0, idx);
                }
            }
        }

        try {
            _resolver.setBaseURL(new URL(location));
        } catch (MalformedURLException except) {
            // try to parse the url as an absolute path
            try {
                LOG.info(Messages.format("mapping.wrongURL", location));
                _resolver.setBaseURL(new URL("file", null, location));
            } catch (MalformedURLException except2) {
            }
        }
    }

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

    /**
     * Loads the mapping from the specified URL with type defaults to 'CastorXmlMapping'. If an entity
     * resolver was specified, will use the entity resolver to resolve the URL. This method is also
     * used to load mappings referenced from another mapping or configuration file.
     *
     * @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.
     */
    public void loadMapping(final String url) throws IOException, MappingException {
        loadMapping(url, DEFAULT_SOURCE_TYPE);
    }

    /**
     * Loads the mapping from the specified URL. If an entity resolver was specified, will use the
     * entity resolver to resolve the URL. This method is also used to load mappings referenced from
     * another mapping or configuration file.
     *
     * @param url The URL of the mapping file.
     * @param type The source type.
     * @throws IOException An error occured when reading the mapping file.
     * @throws MappingException The mapping file is invalid.
     */
    public void loadMapping(final String url, final String type) throws IOException, MappingException {
        String location = url;
        if (_resolver.getBaseURL() == null) {
            setBaseURL(location);
            location = URIUtils.getRelativeURI(location);
        }
        try {
            InputSource source = _resolver.resolveEntity(null, location);
            if (source == null) {
                source = new InputSource(location);
            }
            if (source.getSystemId() == null) {
                source.setSystemId(location);
            }
            LOG.info(Messages.format("mapping.loadingFrom", location));
            loadMapping(source, type);
        } catch (SAXException ex) {
            throw new MappingException(ex);
        }
    }

    /**
     * Loads the mapping from the specified URL with type defaults to 'CastorXmlMapping'.
     *
     * @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.
     */
    public void loadMapping(final URL url) throws IOException, MappingException {
        loadMapping(url, DEFAULT_SOURCE_TYPE);
    }

    /**
     * Loads the mapping from the specified URL.
     *
     * @param url The URL of the mapping file.
     * @param type The source type.
     * @throws IOException An error occured when reading the mapping file.
     * @throws MappingException The mapping file is invalid.
     */
    public void loadMapping(final URL url, final String type) throws IOException, MappingException {
        try {
            if (_resolver.getBaseURL() == null) {
                _resolver.setBaseURL(url);
            }
            InputSource source = _resolver.resolveEntity(null, url.toExternalForm());
            if (source == null) {
                source = new InputSource(url.toExternalForm());
                source.setByteStream(url.openStream());
            } else
                source.setSystemId(url.toExternalForm());
            LOG.info(Messages.format("mapping.loadingFrom", url.toExternalForm()));
            loadMapping(source, type);
        } catch (SAXException ex) {
            throw new MappingException(ex);
        }
    }

    /**
     * Loads the mapping from the specified input source with type defaults to 'CastorXmlMapping'.
     *
     * @param source The input source.
     */
    public void loadMapping(final InputSource source) {
        loadMapping(source, DEFAULT_SOURCE_TYPE);
    }

    /**
     * Loads the mapping from the specified input source.
     *
     * @param source The input source.
     * @param type The source type.
     */
    public void loadMapping(final InputSource source, final String type) {
        _mappings.add(new MappingSource(source, type, _resolver));
    }

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