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 }