001: /*
002: Copyright (c) 2002-2005, Sosnoski Software Solutions, Inc.
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.runtime;
030:
031: import java.lang.reflect.Field;
032: import java.lang.reflect.InvocationTargetException;
033: import java.lang.reflect.Method;
034:
035: /**
036: * Abstract class with static method to find the binding factory corresponding
037: * to a binding name.
038: *
039: * @author Dennis M. Sosnoski
040: * @version 1.0
041: */
042:
043: public abstract class BindingDirectory {
044: /** Name of <code>String[]</code> field giving binding factory name list. */
045: public static final String BINDINGLIST_NAME = "JiBX_bindingList";
046:
047: /** Prefix of binding factory name. */
048: public static final String BINDINGFACTORY_PREFIX = "JiBX_";
049:
050: /** Suffix of binding factory name. */
051: public static final String BINDINGFACTORY_SUFFIX = "Factory";
052:
053: /** Binding factory method to get instance of factory. */
054: public static final String FACTORY_INSTMETHOD = "getInstance";
055:
056: /** Empty argument list. */
057: public static final Class[] EMPTY_ARGS = new Class[0];
058:
059: /**
060: * Get list of bindings for class. This just accesses the static variable
061: * added to each class with a top-level mapping.
062: *
063: * @param clas class with top-level mapping in binding
064: * @return list of bindings defined for that class (as a text string)
065: * @throws JiBXException on error accessing binding information
066: */
067: private static String getBindingList(Class clas)
068: throws JiBXException {
069: try {
070: Field field = clas.getDeclaredField(BINDINGLIST_NAME);
071: try {
072: // should be able to access field anyway, but just in case
073: field.setAccessible(true);
074: } catch (Exception e) { /* deliberately left empty */
075: }
076: return (String) field.get(null);
077: } catch (NoSuchFieldException e) {
078: throw new JiBXException(
079: "Unable to access binding information for class "
080: + clas.getName()
081: + "\nMake sure the binding has been compiled",
082: e);
083: } catch (IllegalAccessException e) {
084: throw new JiBXException("Error in added code for class "
085: + clas.getName()
086: + "Please report this to the JiBX developers", e);
087: }
088: }
089:
090: /**
091: * Get instance of factory. Loads the factory class using the classloader
092: * for the supplied class, then calls the get instance method of the
093: * factory class.
094: *
095: * @param name fully qualified name of factory class
096: * @param clas class providing factory
097: * @param loader class loader to be used for loading factory
098: * @return binding factory instance
099: * @throws JiBXException on error loading or accessing factory
100: */
101: private static IBindingFactory getFactoryFromName(String name,
102: Class clas, ClassLoader loader) throws JiBXException {
103: Throwable ex = null;
104: Object result = null;
105: IBindingFactory ifact = null;
106: try {
107: Class factory = loader.loadClass(name);
108: Method method = factory.getMethod(FACTORY_INSTMETHOD,
109: EMPTY_ARGS);
110: result = method.invoke(null, (Object[]) null);
111: } catch (SecurityException e) {
112: ex = e;
113: } catch (ClassNotFoundException e) {
114: ex = e;
115: } catch (NoSuchMethodException e) {
116: ex = e;
117: } catch (IllegalAccessException e) {
118: ex = e;
119: } catch (InvocationTargetException e) {
120: ex = e;
121: } finally {
122: if (ex == null) {
123: if (result instanceof IBindingFactory) {
124: ifact = (IBindingFactory) result;
125: int diff = ifact.getCompilerVersion()
126: ^ IBindingFactory.CURRENT_VERSION_NUMBER;
127: if ((diff & IBindingFactory.COMPATIBLE_VERSION_MASK) != 0) {
128: throw new JiBXException(
129: "Binding information for class "
130: + clas.getName()
131: + " must be recompiled with current binding "
132: + "compiler (compiled with "
133: + ifact
134: .getCompilerDistribution()
135: + ", runtime is "
136: + IBindingFactory.CURRENT_VERSION_NAME
137: + ")");
138: }
139: } else {
140: throw new JiBXException(
141: "Binding information for class "
142: + clas.getName()
143: + " must be regenerated with current binding "
144: + "compiler");
145: }
146: } else {
147: throw new JiBXException(
148: "Unable to access binding information for class "
149: + clas.getName()
150: + "\nMake sure classes generated by the "
151: + "binding compiler are available at runtime",
152: ex);
153: }
154: }
155: return ifact;
156: }
157:
158: /**
159: * Get instance of binding factory. Finds the binding factory for the
160: * named binding on the target class, then loads that factory and returns
161: * an instance.
162: *
163: * @param name binding name
164: * @param clas target class for binding
165: * @param loader class loader to be used for loading factory
166: * @return binding factory instance
167: * @throws JiBXException on any error in finding or accessing factory
168: */
169: public static IBindingFactory getFactory(String name, Class clas,
170: ClassLoader loader) throws JiBXException {
171: String list = getBindingList(clas);
172: String match = BINDINGFACTORY_PREFIX + name
173: + BINDINGFACTORY_SUFFIX + '|';
174: int index = list.indexOf(match);
175: if (index >= 0) {
176: int mark = list.lastIndexOf('|', index);
177: String fname = list.substring(mark + 1, index
178: + match.length() - 1);
179: mark = fname.indexOf('=');
180: if (mark >= 0) {
181: fname = fname.substring(0, mark);
182: }
183: return getFactoryFromName(fname, clas, loader);
184: } else {
185: throw new JiBXException("Binding '" + name
186: + "' not found for class " + clas.getName());
187: }
188: }
189:
190: /**
191: * Get instance of binding factory. Finds the binding factory for the
192: * named binding on the target class, then loads that factory and returns
193: * an instance.
194: *
195: * @param name binding name
196: * @param clas target class for binding
197: * @return binding factory instance
198: * @throws JiBXException on any error in finding or accessing factory
199: */
200: public static IBindingFactory getFactory(String name, Class clas)
201: throws JiBXException {
202: return getFactory(name, clas, clas.getClassLoader());
203: }
204:
205: /**
206: * Get instance of binding factory. Finds the binding factory for the
207: * target class, then loads that factory and returns an instance. This
208: * method can only be used with target classes that are mapped in only
209: * one binding.
210: *
211: * @param clas target class for binding
212: * @return binding factory instance
213: * @throws JiBXException on any error in finding or accessing factory
214: */
215: public static IBindingFactory getFactory(Class clas)
216: throws JiBXException {
217: String list = getBindingList(clas);
218: if (list != null && list.length() > 2) {
219: String fact = list.substring(1, list.length() - 1);
220: if (fact.indexOf('|') < 0) {
221: return getFactoryFromName(fact, clas, clas
222: .getClassLoader());
223: }
224: }
225: throw new JiBXException("Multiple bindings defined for class "
226: + clas.getName());
227: }
228:
229: /**
230: * Get instance of binding factory. Finds the binding factory for the
231: * named binding on the target class, then loads that factory and returns
232: * an instance.
233: *
234: * @param bname binding name
235: * @param pack target package for binding
236: * @param loader class loader to be used for loading factory
237: * @return binding factory instance
238: * @throws JiBXException on any error in finding or accessing factory
239: */
240: public static IBindingFactory getFactory(String bname, String pack,
241: ClassLoader loader) throws JiBXException {
242: String cname = (pack == null ? "" : pack + '.')
243: + BINDINGFACTORY_PREFIX + bname + BINDINGFACTORY_SUFFIX;
244: Throwable ex = null;
245: Object result = null;
246: IBindingFactory ifact = null;
247: try {
248: Class factory = loader.loadClass(cname);
249: Method method = factory.getMethod(FACTORY_INSTMETHOD,
250: EMPTY_ARGS);
251: result = method.invoke(null, (Object[]) null);
252: } catch (SecurityException e) {
253: ex = e;
254: } catch (ClassNotFoundException e) {
255: ex = e;
256: } catch (NoSuchMethodException e) {
257: ex = e;
258: } catch (IllegalAccessException e) {
259: ex = e;
260: } catch (InvocationTargetException e) {
261: ex = e;
262: } finally {
263: if (ex == null) {
264: if (result instanceof IBindingFactory) {
265: ifact = (IBindingFactory) result;
266: int diff = ifact.getCompilerVersion()
267: ^ IBindingFactory.CURRENT_VERSION_NUMBER;
268: if ((diff & IBindingFactory.COMPATIBLE_VERSION_MASK) != 0) {
269: throw new JiBXException(
270: "Binding '"
271: + bname
272: + "' must be recompiled with current binding "
273: + "compiler (compiled with "
274: + ifact
275: .getCompilerDistribution()
276: + ", runtime is "
277: + IBindingFactory.CURRENT_VERSION_NAME
278: + ")");
279: }
280: } else {
281: throw new JiBXException(
282: "Binding '"
283: + bname
284: + "' must be regenerated with current binding "
285: + "compiler");
286: }
287: } else {
288: throw new JiBXException("Unable to access binding '"
289: + bname
290: + "'\nMake sure classes generated by the "
291: + "binding compiler are available at runtime",
292: ex);
293: }
294: }
295: return ifact;
296: }
297:
298: /**
299: * Get instance of binding factory. Finds the binding factory for the named
300: * binding compiled to the specified package, then loads that factory and
301: * returns an instance.
302: *
303: * @param bname binding name
304: * @param pack target package for binding
305: * @return binding factory instance
306: * @throws JiBXException on any error in finding or accessing factory
307: */
308: public static IBindingFactory getFactory(String bname, String pack)
309: throws JiBXException {
310: return getFactory(bname, pack, BindingDirectory.class
311: .getClassLoader());
312: }
313: }
|