View Javadoc
1   /*
2    * Copyright 2007 Werner Guttmann
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.exolab.castor.xml;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.castor.mapping.BindingType;
21  import org.castor.mapping.MappingUnmarshaller;
22  import org.castor.xml.AbstractInternalContext;
23  import org.castor.xml.InternalContext;
24  import org.exolab.castor.mapping.Mapping;
25  import org.exolab.castor.mapping.MappingException;
26  import org.exolab.castor.mapping.MappingLoader;
27  import org.exolab.castor.tools.MappingTool;
28  import org.exolab.castor.util.ChangeLog2XML;
29  import org.exolab.castor.xml.util.ResolverStrategy;
30  import org.exolab.castor.xml.util.resolvers.CastorXMLStrategy;
31  
32  /**
33   * Bootstrap class for Castor XML that allows you to load information about the
34   * domain objects used with Castor XML (marshallers and unmarshallers) by various means.
35   * 
36   * @author <a href="mailto:werner DOT guttmann At gmx DOT net">Werner Guttmann</a>
37   * @since 1.1.2
38   */
39  public class XMLContext {
40      /** Logger to be used. */
41      private static final Log LOG = LogFactory.getFactory().getInstance(XMLContext.class);
42      
43      /**
44       * The internal XML context is the class which holds a couple of Castor states as it
45       * provides some central methods needed in various places of Castor.
46       */
47      private InternalContext _internalContext;
48  
49      /**
50       * Creates an instance of {@link XMLContext} with an internal XML context.
51       */
52      public XMLContext() {
53          AbstractInternalContext internalContext = new AbstractInternalContext() { };
54          
55          internalContext.setClassLoader(getClass().getClassLoader());
56          
57          XMLClassDescriptorResolver cdr = (XMLClassDescriptorResolver) ClassDescriptorResolverFactory
58              .createClassDescriptorResolver(BindingType.XML);
59          internalContext.setXMLClassDescriptorResolver(cdr);
60          cdr.setInternalContext(internalContext);
61  
62          Introspector introspector = new Introspector();
63          introspector.setInternalContext(internalContext);
64          internalContext.setIntrospector(introspector);
65          cdr.setIntrospector(introspector);
66          
67          ResolverStrategy resolverStrategy = new CastorXMLStrategy();
68          internalContext.setResolverStrategy(resolverStrategy);
69          cdr.setResolverStrategy(resolverStrategy);
70  
71          _internalContext = internalContext;
72      }
73      
74      /**
75       * Instructs Castor to load class descriptors from the mapping given.
76       * @param mapping Castor XML mapping (file), from which the required class
77       * descriptors will be derived. 
78       * @throws MappingException If the {@link Mapping} cannot be loaded and analyzed successfully.
79       */
80      public void addMapping(final Mapping mapping) throws MappingException {
81           MappingUnmarshaller mappingUnmarshaller = new MappingUnmarshaller();
82           MappingLoader mappingLoader = 
83               mappingUnmarshaller.getMappingLoader(mapping, BindingType.XML);
84           _internalContext.getXMLClassDescriptorResolver()
85               .setMappingLoader(mappingLoader);        
86      }
87  
88      /**
89       * Loads the class descriptor for the class instance specified. The use of this method is useful
90       * when no mapping is used, as happens when the domain classes has been generated
91       * using the XML code generator (in which case instead of a mapping file class
92       * descriptor files will be generated).
93       * 
94       * @param clazz the class for which the associated descriptor should be loaded.
95       * @throws ResolverException in case that resolving the Class fails fatally
96       */ 
97      public void addClass(final Class clazz) throws ResolverException { 
98          _internalContext.getXMLClassDescriptorResolver().addClass(clazz);
99      }
100 
101     /**
102      * Loads the class descriptor for the class instance specified. The use of this method is useful
103      * when no mapping is used, as happens when the domain classes hase been generated
104      * using the XML code generator (in which case instead of a mapping file class
105      * descriptor files will be generated).
106      * 
107      * @param clazzes the classes for which the associated descriptor should be loaded.
108      * @throws ResolverException in case that resolving the Class fails fatally
109      */ 
110     public void addClasses(final Class[] clazzes) throws ResolverException {
111         _internalContext.getXMLClassDescriptorResolver().addClasses(clazzes);
112     }
113 
114     /**
115      * Loads class descriptors from the package specified. The use of this method is useful
116      * when no mapping is used, as happens when the domain classes hase been generated
117      * using the XML code generator (in which case instead of a mapping file class
118      * descriptor files will be generated).
119      * <p>
120      * Please note that this functionality will work only if you provide the <tt>.castor.cdr</tt>
121      * file with your generated classes (as generated by the XML code generator).
122      * <p>
123      * @param packageName The package name for the (descriptor) classes
124      * @throws ResolverException 
125      *          If there's a problem loading class descriptors for the given package. 
126      */
127     public void addPackage(final String packageName) throws ResolverException { 
128         _internalContext.getXMLClassDescriptorResolver().addPackage(packageName); 
129     }
130 
131     /**
132      * Loads class descriptors from the packages specified. The use of this method is useful
133      * when no mapping is used, as happens when the domain classes hase been generated
134      * using the XML code generator (in which case instead of a mapping file class
135      * descriptor files will be generated).
136      * <p>
137      * Please note that this functionality will work only if you provide the <tt>.castor.cdr</tt>
138      * files with your generated classes (as generated by the XML code generator).
139      * <p>
140      * @param packageNames The package names for the (descriptor) classes
141      * @throws ResolverException 
142      *          If there's a problem loading class descriptors for the given package. 
143      */
144     public void addPackages(final String[] packageNames) throws ResolverException {
145         _internalContext.getXMLClassDescriptorResolver().addPackages(packageNames);
146     }
147 
148     /**
149      * Creates an instance of a Castor XML specific {@link Mapping} instance.
150      * @return a Castor XML specific {@link Mapping} instance.
151      */
152     public Mapping createMapping() {
153         Mapping mapping = new Mapping();
154 //        mapping.setBindingType(BindingType.XML);
155         return mapping;
156     }
157     
158     /**
159      * Creates a new {@link Marshaller} instance to be used for marshalling.
160      * @return A new {@link Marshaller} instance.
161      */
162     public Marshaller createMarshaller() {
163         if (LOG.isDebugEnabled()) {
164             LOG.debug("Creating new Marshaller instance.");
165         }
166         Marshaller marshaller = new Marshaller(_internalContext);
167         return marshaller;
168     }
169     
170     /**
171      * Creates a new {@link Unmarshaller} instance to be used for unmarshalling. 
172      * @return A new {@link Unmarshaller} instance, preconfigured with 
173      *  a {@link XMLClassDescriptorResolver} instance with the class
174      *  descriptors cached as loaded above.
175      */
176     public Unmarshaller createUnmarshaller() {
177         if (LOG.isDebugEnabled()) {
178             LOG.debug("Creating new Unmarshaller instance.");
179         }
180         Unmarshaller unmarshaller = new Unmarshaller(_internalContext);
181         return unmarshaller;
182     }
183     
184 //    /**
185 //     * To create a schema reader instance for reading XSD files.
186 //     * @param inputSource the InputSource to read from
187 //     * @return the SchemaReader instance created and initialized
188 //     */
189 //    public SchemaReader createSchemaReader(final InputSource inputSource) {
190 //        if (LOG.isDebugEnabled()) {
191 //            LOG.debug("Creating new SchemaReader instance.");
192 //        }
193 //        SchemaReader sr = new SchemaReader();
194 //        sr.setInternalContext(_internalContext);
195 //        sr.setInputSource(inputSource);
196 //        return sr;
197 //    }
198 //    
199 //    /**
200 //     * To create a schema writer instance for writing XSD files.
201 //     * @param writer the Writer to write the text representation of the schema to
202 //     * @return the SchemaWriter instance created and initialized
203 //     * @throws IOException in case that initialization of SchemaWriter fails
204 //     */
205 //    public SchemaWriter createSchemaWriter(final Writer writer) throws IOException {
206 //        if (LOG.isDebugEnabled()) {
207 //            LOG.debug("Creating new SchemaWriter instance.");
208 //        }
209 //        SchemaWriter sw = new SchemaWriter();
210 //        sw.setInternalContext(_internalContext);
211 //        sw.setDocumentHandler(writer);
212 //        return sw;
213 //    }
214 
215     /**
216      * To create a MappingTool instance.
217      * @return the MappingTool instance ready to use
218      */
219     public MappingTool createMappingTool() {
220         if (LOG.isDebugEnabled()) {
221             LOG.debug("Creating new MappingTool instance.");
222         }
223         MappingTool mt = new MappingTool();
224         mt.setInternalContext(_internalContext);
225         return mt;
226     }
227 
228     /**
229      * To create a new {@link ChangeLog2XML} instance.
230      * @return the {@link ChangeLog2XML} instance ready to use
231      */
232     public ChangeLog2XML createChangeLog2XML() {
233         if (LOG.isDebugEnabled()) {
234             LOG.debug("Creating new ChangeLog2XML instance.");
235         }
236         ChangeLog2XML changeLog2XML = new ChangeLog2XML();
237         changeLog2XML.setInternalContext(_internalContext);
238         return changeLog2XML;
239     }
240 
241     /**
242      * To set properties for marshalling and unmarshalling behavior. 
243      * @param propertyName name of the property to set
244      * @param value the value to set to
245      */
246     public void setProperty(final String propertyName, final Object value) {
247         _internalContext.setProperty(propertyName, value);
248     }
249 
250     /**
251      * To set properties for marshalling and unmarshalling behavior. 
252      * @param propertyName name of the property to set
253      * @param value the value to set to
254      */
255     public void setProperty(final String propertyName, final boolean value) {
256         _internalContext.setProperty(propertyName, value);
257     }
258 
259     /**
260      * To get the value of a specific property.
261      * @param propertyName name of the Property
262      * @return the value (Object) of the property
263      */
264     public Object getProperty(final String propertyName) {
265         return _internalContext.getProperty(propertyName);
266     }
267 
268     /**
269      * To get the {@link InternalContext} as used when instantiating other
270      * classes. Mind that this method is only used in tests and should
271      * NOT be used in production code!
272      * 
273      * @return the {@link InternalContext} used
274      * @deprecated
275      */
276     public InternalContext getInternalContext() {
277         return _internalContext;
278     }
279     
280     /**
281      * Sets a custom {@link ClassLoader} to be used for loading classes.
282      * @param classLoader A custom {@link ClassLoader}.
283      */
284     public void setClassLoader(ClassLoader classLoader) {
285         this._internalContext.setClassLoader(classLoader);
286     }
287 }