001: /*
002: * Copyright 2005 Ralf Joachim
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.castor.mapping;
017:
018: import java.io.IOException;
019: import java.util.Enumeration;
020: import java.util.Iterator;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.castor.util.Configuration;
025: import org.castor.util.Messages;
026: import org.exolab.castor.mapping.Mapping;
027: import org.exolab.castor.mapping.MappingException;
028: import org.exolab.castor.mapping.MappingLoader;
029: import org.exolab.castor.mapping.loader.AbstractMappingLoader;
030: import org.exolab.castor.mapping.xml.ClassMapping;
031: import org.exolab.castor.mapping.xml.Include;
032: import org.exolab.castor.mapping.xml.KeyGeneratorDef;
033: import org.exolab.castor.mapping.xml.MappingRoot;
034: import org.exolab.castor.util.DTDResolver;
035: import org.exolab.castor.xml.Unmarshaller;
036: import org.xml.sax.InputSource;
037: import org.xml.sax.SAXException;
038:
039: /**
040: * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
041: * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
042: */
043: public final class MappingUnmarshaller {
044: //--------------------------------------------------------------------------
045:
046: /** The <a href="http://jakarta.apache.org/commons/logging/">Jakarta Commons
047: * Logging </a> instance used for all logging. */
048: private static final Log LOG = LogFactory
049: .getLog(MappingUnmarshaller.class);
050:
051: /** The registry of MappingLoader's. */
052: private final MappingLoaderRegistry _registry;
053:
054: /** The IDResolver to give to the Unmarshaller. This allows resolving "extends" and
055: * "depends" for included Mappings. */
056: private final MappingUnmarshallIDResolver _idResolver;
057:
058: /** A flag that indicates of whether or not to allow redefinitions of class
059: * mappings. */
060: private boolean _allowRedefinitions = false;
061:
062: //--------------------------------------------------------------------------
063:
064: /**
065: * Construct a new MappingUnmarshaller.
066: */
067: public MappingUnmarshaller() {
068: _registry = new MappingLoaderRegistry(Configuration
069: .getInstance());
070: _idResolver = new MappingUnmarshallIDResolver();
071: }
072:
073: /**
074: * Enables or disables the ability to allow the redefinition
075: * of class mappings.
076: *
077: * @param allow a boolean that when true enables redefinitions.
078: **/
079: public void setAllowRedefinitions(final boolean allow) {
080: _allowRedefinitions = allow;
081: }
082:
083: //--------------------------------------------------------------------------
084:
085: /**
086: * Returns a mapping resolver for the suitable engine. The engine's
087: * specific mapping loader is created and used to create engine
088: * specific descriptors, returning a suitable mapping resolver.
089: * The mapping resolver is cached in memory and returned in
090: * subsequent method calls.
091: *
092: * @param mapping The mapping to load and resolve.
093: * @param bindingType The binding type to read from mapping.
094: * @return A mapping resolver.
095: * @throws MappingException A mapping error occured preventing
096: * descriptors from being generated from the loaded mapping.
097: */
098: public MappingLoader getMappingLoader(final Mapping mapping,
099: final BindingType bindingType) throws MappingException {
100: return getMappingLoader(mapping, bindingType, null);
101: }
102:
103: /**
104: * Returns a mapping resolver for the suitable engine. The engine's
105: * specific mapping loader is created and used to create engine
106: * specific descriptors, returning a suitable mapping resolver.
107: * The mapping resolver is cached in memory and returned in
108: * subsequent method calls.
109: *
110: * @param mapping The mapping to load and resolve.
111: * @param bindingType The binding type to read from mapping.
112: * @param param Arbitrary parameter that is to be passed to resolver.loadMapping().
113: * @return A mapping resolver
114: * @throws MappingException A mapping error occured preventing
115: * descriptors from being generated from the loaded mapping.
116: */
117: public MappingLoader getMappingLoader(final Mapping mapping,
118: final BindingType bindingType, final Object param)
119: throws MappingException {
120: synchronized (this ) {
121: Iterator iter = mapping.getMappingSources().iterator();
122: while (iter.hasNext()) {
123: MappingSource source = (MappingSource) iter.next();
124: loadMappingInternal(mapping, source.getResolver(),
125: source.getSource());
126: }
127:
128: AbstractMappingLoader loader;
129: loader = (AbstractMappingLoader) _registry
130: .getMappingLoader("CastorXmlMapping", bindingType);
131: loader.setClassLoader(mapping.getClassLoader());
132: loader.setAllowRedefinitions(_allowRedefinitions);
133: loader.loadMapping(mapping.getRoot(), param);
134: return loader;
135: }
136: }
137:
138: public void loadMappingOnly(final Mapping mapping)
139: throws MappingException {
140: synchronized (this ) {
141: Iterator iter = mapping.getMappingSources().iterator();
142: while (iter.hasNext()) {
143: MappingSource source = (MappingSource) iter.next();
144: loadMappingInternal(mapping, source.getResolver(),
145: source.getSource());
146: }
147: }
148: }
149:
150: //--------------------------------------------------------------------------
151:
152: /**
153: * Internal recursive loading method. This method will load the
154: * mapping document into a mapping object and load all the included
155: * mapping along the way into a single collection.
156: *
157: * @param mapping The mapping instance.
158: * @param resolver The entity resolver to use.
159: * @param url The URL of the mapping file.
160: * @throws IOException An error occured when reading the mapping file.
161: * @throws MappingException The mapping file is invalid.
162: */
163: protected void loadMappingInternal(final Mapping mapping,
164: final DTDResolver resolver, final String url)
165: throws IOException, MappingException {
166: try {
167: InputSource source = resolver.resolveEntity(null, url);
168: if (source == null) {
169: source = new InputSource(url);
170: }
171: if (source.getSystemId() == null) {
172: source.setSystemId(url);
173: }
174: LOG.info(Messages.format("mapping.loadingFrom", url));
175: loadMappingInternal(mapping, resolver, source);
176: } catch (SAXException ex) {
177: throw new MappingException(ex);
178: }
179: }
180:
181: /**
182: * Internal recursive loading method. This method will load the
183: * mapping document into a mapping object and load all the included
184: * mapping along the way into a single collection.
185: *
186: * @param mapping The mapping instance.
187: * @param resolver The entity resolver to use. May be null.
188: * @param source The input source.
189: * @throws MappingException The mapping file is invalid.
190: */
191: private void loadMappingInternal(final Mapping mapping,
192: final DTDResolver resolver, final InputSource source)
193: throws MappingException {
194: // Clear all the cached resolvers, so they can be reconstructed a
195: // second time based on the new mappings loaded
196: _registry.clear();
197:
198: Object id = source.getSystemId();
199: if (id == null) {
200: id = source.getByteStream();
201: }
202: if (id != null) {
203: //check that the mapping has already been processed
204: if (mapping.processed(id)) {
205: return;
206: }
207:
208: //mark the mapping as being processed
209: mapping.markAsProcessed(id);
210: }
211:
212: MappingRoot root = mapping.getRoot();
213: _idResolver.setMapping(root);
214:
215: try {
216: // Load the specificed mapping source
217: Unmarshaller unm = new Unmarshaller(MappingRoot.class);
218: unm.setValidation(false);
219: unm.setEntityResolver(resolver);
220: unm.setClassLoader(Mapping.class.getClassLoader());
221: unm.setIDResolver(_idResolver);
222: unm.setUnmarshalListener(new MappingUnmarshallListener(
223: this , mapping, resolver));
224:
225: MappingRoot loaded = (MappingRoot) unm.unmarshal(source);
226:
227: // Load all the included mapping by reference
228: //-- note: this is just for processing any
229: //-- includes which may have previously failed
230: //-- using the IncludeListener...and to
231: //-- report any potential errors.
232: Enumeration includes = loaded.enumerateInclude();
233: while (includes.hasMoreElements()) {
234: Include include = (Include) includes.nextElement();
235: if (!mapping.processed(include.getHref())) {
236: try {
237: loadMappingInternal(mapping, resolver, include
238: .getHref());
239: } catch (Exception ex) {
240: throw new MappingException(ex);
241: }
242: }
243: }
244:
245: // gather "class" tags
246: Enumeration enumeration = loaded.enumerateClassMapping();
247: while (enumeration.hasMoreElements()) {
248: root.addClassMapping((ClassMapping) enumeration
249: .nextElement());
250: }
251:
252: // gather "key-generator" tags
253: enumeration = loaded.enumerateKeyGeneratorDef();
254: while (enumeration.hasMoreElements()) {
255: root.addKeyGeneratorDef((KeyGeneratorDef) enumeration
256: .nextElement());
257: }
258: } catch (Exception ex) {
259: throw new MappingException(ex);
260: }
261: }
262:
263: //--------------------------------------------------------------------------
264: }
|