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    }