001 /*
002 * Copyright 1999-2001,2004 The Apache Software Foundation.
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
017 package org.apache.commons.workflow.core;
018
019
020 import java.lang.reflect.Constructor;
021 import org.apache.commons.workflow.Context;
022 import org.apache.commons.workflow.Descriptor;
023 import org.apache.commons.workflow.StepException;
024 import org.apache.commons.workflow.base.DescriptorStep;
025
026
027 /**
028 * <p>Create a new object of the specified class, using the constructor that
029 * accepts the arguments specified by the associated <code>Descriptor</code>
030 * objects. The <strong>first</strong> descriptor must identify the
031 * <code>java.lang.Class</code> object to be used to construct the new
032 * object.</p>
033 *
034 * <p><strong>FIXME</strong> - Constructors that take primitive arguments are
035 * not recognized and matched up to the wrapper classes.</p>
036 *
037 * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
038 * @author Craig R. McClanahan
039 */
040
041 public class ConstructStep extends DescriptorStep {
042
043
044 // ----------------------------------------------------------= Constructors
045
046
047 /**
048 * Construct a default instance of this Step.
049 */
050 public ConstructStep() {
051
052 super();
053
054 }
055
056
057 /**
058 * Construct an instance of this Step with the specified identifier.
059 *
060 * @param id Step identifier
061 */
062 public ConstructStep(String id) {
063
064 super();
065 setId(id);
066
067 }
068
069
070 /**
071 * Construct an instance of this Step with the specified identifier
072 * and associated Descriptor.
073 *
074 * @param id Step identifier
075 * @param descriptor Initial descriptor
076 */
077 public ConstructStep(String id, Descriptor descriptor) {
078
079 super();
080 setId(id);
081 addDescriptor(descriptor);
082
083 }
084
085
086 // --------------------------------------------------------- Public Methods
087
088
089 /**
090 * Perform the executable actions related to this Step, in the context of
091 * the specified Context.
092 *
093 * @param context The Context that is tracking our execution state
094 *
095 * @exception StepException if a processing error has occurred
096 */
097 public void execute(Context context) throws StepException {
098
099 // 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 }