All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.exolab.castor.mapping.Mapping Maven / Gradle / Ivy

/*
 * 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 InputSource.
 * 

* Multiple mapping files can be loaded with the same Mapping object. When loading master * mapping files that include other mapping files it might be convenient to use {@link #setBaseURL} * or {@link #setEntityResolver}. *

* If the desired class loader is different than the one used by Castor (e.g. if Castor is installed * as a Java extension), the Mapping object can be constructed with the proper class * loader. *

* The following example loads two mapping files: * *

 * Mapping mapping;
 *
 * mapping = new Mapping(getClass().getClassLoader());
 * mapping.loadMapping("mapping.xml");
 * mapping.loadMapping(url);
 * 
* * @author Assaf Arkin * @author Ralf Joachim * @version $Revision$ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $ */ public final class Mapping { // -------------------------------------------------------------------------- /** * The Jakarta Commons Logging 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 _mappings = new ArrayList<>(); /** Set of processed systemID's. */ private final Set _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 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)); } // -------------------------------------------------------------------------- }