001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jbpm.configuration;
023:
024: import java.io.Serializable;
025: import java.lang.reflect.Constructor;
026: import java.lang.reflect.Method;
027: import java.util.List;
028:
029: import org.jbpm.JbpmException;
030: import org.jbpm.util.ClassLoaderUtil;
031: import org.jbpm.util.XmlUtil;
032: import org.w3c.dom.Element;
033:
034: public class ConstructorInfo implements Serializable {
035:
036: private static final long serialVersionUID = 1L;
037:
038: BeanInfo beanInfo = null;
039: String className = null;
040: String factoryRefName = null;
041: String factoryClassName = null;
042: String factoryMethodName = null;
043: String[] parameterClassNames = null;
044: ObjectInfo[] parameterInfos = null;
045:
046: public ConstructorInfo(Element constructorElement,
047: ObjectFactoryParser configParser) {
048: // beanInfo is set by the beanInfo itself
049:
050: // className
051: if (constructorElement.hasAttribute("class")) {
052: className = constructorElement.getAttribute("class");
053: }
054:
055: // factoryInfo
056: if (constructorElement.hasAttribute("factory")) {
057: factoryRefName = constructorElement.getAttribute("factory");
058: if (!constructorElement.hasAttribute("method")) {
059: throw new JbpmException(
060: "factory element in constructor requires method attribute in constructor: "
061: + XmlUtil.toString(constructorElement));
062: }
063: factoryMethodName = constructorElement
064: .getAttribute("method");
065:
066: } else if (constructorElement.hasAttribute("factory-class")) {
067: factoryClassName = constructorElement
068: .getAttribute("factory-class");
069: if (!constructorElement.hasAttribute("method")) {
070: throw new JbpmException(
071: "factory-class element in constructor requires method attribute in constructor: "
072: + XmlUtil.toString(constructorElement));
073: }
074: factoryMethodName = constructorElement
075: .getAttribute("method");
076:
077: } else {
078: if (constructorElement.hasAttribute("method")) {
079: throw new JbpmException(
080: "'method' element in constructor requires 'factory' of 'factory-class' attribute in constructor: "
081: + XmlUtil.toString(constructorElement));
082: }
083: }
084:
085: // parameterTypesNames and parameterInfos
086: List parameterElements = XmlUtil.elements(constructorElement,
087: "parameter");
088: parameterClassNames = new String[parameterElements.size()];
089: parameterInfos = new ObjectInfo[parameterElements.size()];
090: for (int i = 0; i < parameterElements.size(); i++) {
091: Element parameterElement = (Element) parameterElements
092: .get(i);
093: if (!parameterElement.hasAttribute("class")) {
094: throw new JbpmException(
095: "parameter element must have a class attribute: "
096: + XmlUtil.toString(parameterElement));
097: }
098: parameterClassNames[i] = parameterElement
099: .getAttribute("class");
100: Element parameterInfoElement = XmlUtil
101: .element(parameterElement);
102: if (parameterInfoElement == null) {
103: throw new JbpmException(
104: "parameter element must have exactly 1 child element: "
105: + XmlUtil.toString(parameterElement));
106: }
107: parameterInfos[i] = configParser
108: .parse(parameterInfoElement);
109: }
110: }
111:
112: public Object createObject(ObjectFactoryImpl objectFactory) {
113: Object newObject = null;
114:
115: Object[] args = getArgs(objectFactory);
116: Class[] parameterTypes = getParameterTypes(objectFactory);
117:
118: if ((factoryRefName != null) || (factoryClassName != null)) {
119: Object factory = null;
120: Class factoryClass = null;
121:
122: if (factoryRefName != null) {
123: factory = objectFactory.getObject(factoryRefName);
124: factoryClass = factory.getClass();
125: } else {
126: factoryClass = ClassLoaderUtil
127: .loadClass(factoryClassName);
128: }
129:
130: try {
131: Method factoryMethod = findMethod(factoryClass,
132: parameterTypes);
133: newObject = factoryMethod.invoke(factory, args);
134: } catch (Exception e) {
135: throw new JbpmException(
136: "couldn't create new bean with factory method '"
137: + factoryClass.getName() + "."
138: + factoryMethodName, e);
139: }
140:
141: } else {
142: String className = (this .className != null ? this .className
143: : beanInfo.getClassName());
144: Class clazz = objectFactory.loadClass(className);
145:
146: try {
147: Constructor constructor = clazz
148: .getDeclaredConstructor(parameterTypes);
149: newObject = constructor.newInstance(args);
150: } catch (Exception e) {
151: throw new JbpmException("couldn't instantiate new '"
152: + className + "' with constructor", e);
153: }
154:
155: }
156:
157: return newObject;
158: }
159:
160: protected Class[] getParameterTypes(ObjectFactoryImpl objectFactory) {
161: int nbrOfParameters = (parameterClassNames != null ? parameterClassNames.length
162: : 0);
163: Class[] parameterTypes = new Class[nbrOfParameters];
164: for (int i = 0; i < nbrOfParameters; i++) {
165: parameterTypes[i] = objectFactory
166: .loadClass(parameterClassNames[i]);
167: }
168: return parameterTypes;
169: }
170:
171: protected Object[] getArgs(ObjectFactoryImpl objectFactory) {
172: int nbrOfParameters = (parameterClassNames != null ? parameterClassNames.length
173: : 0);
174: Object[] args = new Object[nbrOfParameters];
175: for (int i = 0; i < nbrOfParameters; i++) {
176: args[i] = objectFactory.getObject(parameterInfos[i]);
177: }
178: return args;
179: }
180:
181: public Method findMethod(Class clazz, Class[] parameterTypes) {
182: Method method = null;
183:
184: Class candidateClass = clazz;
185: while ((candidateClass != null) && (method == null)) {
186: try {
187: method = clazz.getDeclaredMethod(factoryMethodName,
188: parameterTypes);
189: } catch (NoSuchMethodException e1) {
190: candidateClass = candidateClass.getSuperclass();
191: }
192: }
193:
194: if (method == null) {
195: throw new JbpmException("couldn't find factory method '"
196: + factoryMethodName + "' in class '"
197: + clazz.getName() + "'");
198: }
199:
200: return method;
201: }
202: }
|