1 /*
2 * Copyright 1999-2001,2004 The Apache Software Foundation.
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
17 package org.apache.commons.workflow.core;
18
19
20 import java.lang.reflect.Constructor;
21 import org.apache.commons.workflow.Context;
22 import org.apache.commons.workflow.Descriptor;
23 import org.apache.commons.workflow.StepException;
24 import org.apache.commons.workflow.base.DescriptorStep;
25
26
27 /**
28 * <p>Create a new object of the specified class, using the constructor that
29 * accepts the arguments specified by the associated <code>Descriptor</code>
30 * objects. The <strong>first</strong> descriptor must identify the
31 * <code>java.lang.Class</code> object to be used to construct the new
32 * object.</p>
33 *
34 * <p><strong>FIXME</strong> - Constructors that take primitive arguments are
35 * not recognized and matched up to the wrapper classes.</p>
36 *
37 * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
38 * @author Craig R. McClanahan
39 */
40
41 public class ConstructStep extends DescriptorStep {
42
43
44 // ----------------------------------------------------------= Constructors
45
46
47 /**
48 * Construct a default instance of this Step.
49 */
50 public ConstructStep() {
51
52 super();
53
54 }
55
56
57 /**
58 * Construct an instance of this Step with the specified identifier.
59 *
60 * @param id Step identifier
61 */
62 public ConstructStep(String id) {
63
64 super();
65 setId(id);
66
67 }
68
69
70 /**
71 * Construct an instance of this Step with the specified identifier
72 * and associated Descriptor.
73 *
74 * @param id Step identifier
75 * @param descriptor Initial descriptor
76 */
77 public ConstructStep(String id, Descriptor descriptor) {
78
79 super();
80 setId(id);
81 addDescriptor(descriptor);
82
83 }
84
85
86 // --------------------------------------------------------- Public Methods
87
88
89 /**
90 * Perform the executable actions related to this Step, in the context of
91 * the specified Context.
92 *
93 * @param context The Context that is tracking our execution state
94 *
95 * @exception StepException if a processing error has occurred
96 */
97 public void execute(Context context) throws StepException {
98
99 // Identify the Class object to be used for object construction
100 Descriptor descriptors[] = findDescriptors();
101 if (descriptors.length < 1)
102 throw new StepException
103 ("No descriptor for Class to construct", this);
104 Class clazz = null;
105 try {
106 clazz = (Class) descriptors[0].get(context);
107 if (clazz == null)
108 throw new StepException
109 ("No Class selected by first descriptor", this);
110 } catch (ClassCastException e) {
111 throw new StepException
112 ("First descriptor does not select a Class", this);
113 }
114
115 // Assemble arrays of the argument types and values
116 Class[] types = new Class[descriptors.length - 1];
117 Object[] values = new Object[descriptors.length - 1];
118 for (int i = 1; i < descriptors.length; i++) {
119 values[i-1] = descriptors[i].get(context);
120 types[i-1] = descriptors[i].getType();
121 if (types[i-1] == null) {
122 if (values[i-1] == null)
123 types[i-1] = Object.class;
124 else
125 types[i-1] = values[i-1].getClass();
126 }
127 }
128
129 // Find a constructor that accepts this set of types
130 Constructor constructor = null;
131 try {
132 constructor = clazz.getConstructor(types);
133 } catch (NoSuchMethodException e) {
134 throw new StepException
135 ("Cannot find constructor for " +
136 signature(clazz.getName(), types), this);
137 }
138
139 // Invoke the constructor to create a new object
140 Object object = null;
141 try {
142 object = constructor.newInstance(values);
143 } catch (Throwable t) {
144 throw new StepException
145 ("Exception from constructor " +
146 signature(clazz.getName(), types), t, this);
147 }
148
149 // Push the new object onto the evaluation stack and return
150 context.push(object);
151
152 }
153
154
155 /**
156 * Render a string representation of this Step.
157 */
158 public String toString() {
159
160 StringBuffer sb = new StringBuffer("<core:construct");
161 if (getId() != null) {
162 sb.append(" id=\"");
163 sb.append(getId());
164 sb.append("\"");
165 }
166 sb.append(">");
167 Descriptor descriptors[] = findDescriptors();
168 for (int i = 0; i < descriptors.length; i++)
169 sb.append(descriptors[i].toString());
170 sb.append("</core:construct>");
171 return (sb.toString());
172
173 }
174
175
176 // ------------------------------------------------------ Protected Methods
177
178
179 /**
180 * Return a method signature useful in debugging and exception messages.
181 *
182 * @param name Method name
183 * @param types Parameter types
184 */
185 protected String signature(String name, Class types[]) {
186
187 StringBuffer sb = new StringBuffer(name);
188 sb.append('(');
189 for (int i = 0; i < types.length; i++) {
190 if (i > 0)
191 sb.append(',');
192 sb.append(types[i].getName());
193 }
194 sb.append(')');
195 return (sb.toString());
196
197 }
198
199
200 }