001: /*
002: * (C) Copyright 2000 - 2005 Nabh Information Systems, Inc.
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU General Public License
006: * as published by the Free Software Foundation; either version 2
007: * of the License, or (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: */
019: package com.nabhinc.ws.core;
020:
021: import java.io.IOException;
022: import java.io.StringReader;
023: import java.io.Writer;
024: import java.lang.reflect.Field;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.util.Vector;
028:
029: import javax.servlet.http.HttpServletRequest;
030:
031: import org.w3c.dom.Element;
032:
033: import com.nabhinc.coil.parser.COILParser;
034: import com.nabhinc.coil.parser.EvaluationException;
035: import com.nabhinc.coil.parser.JavaContext;
036: import com.nabhinc.coil.parser.ParseException;
037: import com.nabhinc.util.XMLUtil;
038:
039: /**
040: * Class providing static utility methods for Web services framework.
041: *
042: * @author Padmanabh Dabke
043: * (c) 2005 Nabh Information Systems, Inc. All Rights Reserved.
044: */
045: public class WebServiceUtil {
046: public static final String PROPERTY_NAME_PARAM_PREFIX = "property_name_";
047: public static final String PROPERTY_DESCR_PARAM_PREFIX = "property_descr_";
048: public static final String PROPERTY_PROMPT_PARAM_PREFIX = "property_prompt_";
049: public static final String PROPERTY_VALUE_PARAM_PREFIX = "property_value_";
050: public static final String PROPERTY_SPEC_TYPE_PARAM_PREFIX = "property_spec_type_";
051: public static final String PROPERTY_IS_MEMO_PARAM_PREFIX = "property_is_memo_";
052:
053: /**
054: * Looks for <init-param> child elements and creates a PropertyInfo
055: * object for each such element.
056: * @param config XML property info configuration
057: * @return Array of PropertyInfo objects created based on the configuration.
058: */
059: public static PropertyInfo[] deserializePropertiesInfo(
060: Element config) {
061: Element[] params = XMLUtil.getSubElements(config, "init-param");
062: PropertyInfo[] propInfo = null;
063: if (params == null) {
064: propInfo = new PropertyInfo[0];
065: } else {
066:
067: propInfo = new PropertyInfo[params.length];
068: for (int i = 0; i < params.length; i++) {
069: propInfo[i] = new PropertyInfo();
070: propInfo[i].init(params[i]);
071:
072: }
073: }
074: return propInfo;
075: }
076:
077: public static PropertyInfo[] constructPropertiesInfo(
078: HttpServletRequest req) throws WebServiceException {
079: int i = 0;
080: String propertyName = req
081: .getParameter(PROPERTY_NAME_PARAM_PREFIX + i);
082: Vector propList = new Vector();
083: while (propertyName != null) {
084: PropertyInfo prop = new PropertyInfo();
085: prop.name = propertyName;
086: prop.description = req
087: .getParameter(PROPERTY_DESCR_PARAM_PREFIX + i);
088: prop.isMemo = req
089: .getParameter(PROPERTY_IS_MEMO_PARAM_PREFIX + i) != null;
090: prop.prompt = req.getParameter(PROPERTY_PROMPT_PARAM_PREFIX
091: + i);
092: prop.value = req.getParameter(PROPERTY_VALUE_PARAM_PREFIX
093: + i);
094: String specTypeStr = req
095: .getParameter(PROPERTY_SPEC_TYPE_PARAM_PREFIX + i);
096: if (specTypeStr != null)
097: prop.specType = PropertyInfo.SPEC_TYPE_COIL;
098: if (prop.prompt == null)
099: throw new WebServiceException(
100: "You must specify property display name.");
101: i++;
102: propertyName = req.getParameter(PROPERTY_NAME_PARAM_PREFIX
103: + i);
104: propList.addElement(prop);
105: }
106: PropertyInfo[] propArray = new PropertyInfo[propList.size()];
107: propList.copyInto(propArray);
108: return propArray;
109: }
110:
111: /**
112: * Serializes <code>PropertyInfo</code> objects as XML. Each object is written
113: * as a <init-param> element.
114: * @param propertiesInfo PropertyInfo objects to be serialized
115: * @param indent Starting indent for XML formatting
116: * @param delta Delta added to the indent when going to the next level in XML formatting
117: * @param w Writer used for writing out the serialized information.
118: * @throws IOException
119: */
120: public static void serializePropertiesInfo(
121: PropertyInfo[] propertiesInfo, String indent, String delta,
122: Writer w) throws IOException {
123: if (propertiesInfo == null)
124: return;
125: for (int i = 0; i < propertiesInfo.length; i++) {
126: propertiesInfo[i].serialize(indent, delta, w, "init-param");
127: }
128: }
129:
130: public static void serializeBaseObject(BaseObject obj, String name,
131: String tag, PropertyInfo[] props, String indent,
132: String delta, Writer w) throws IOException {
133: String indent1 = indent + delta;
134: XMLUtil.writeElementStart(indent, tag, w);
135: XMLUtil.writeElement(indent1, "name", name, w);
136: XMLUtil.writeElement(indent1, "class",
137: obj.getClass().getName(), w);
138: serializePropertiesInfo(props, indent1, delta, w);
139: XMLUtil.writeElementEnd(indent, tag, w);
140: }
141:
142: public static void setProperty(Object target,
143: PropertyInfo propInfo, boolean strict)
144: throws WebServiceException {
145: if (propInfo.specType == PropertyInfo.SPEC_TYPE_COIL) {
146:
147: try {
148: WebServiceUtil
149: .setObjectProperty(
150: target,
151: propInfo.name,
152: WebServiceUtil
153: .evaluateCOILExpression(propInfo.value),
154: true);
155: } catch (WebServiceException e) {
156: throw e;
157: } catch (ParseException e) {
158: throw new WebServiceException(
159: "Failed to parse COIL expression.", e);
160: } catch (EvaluationException e) {
161: throw new WebServiceException(
162: "Failed to evaluate COIL expression.", e);
163: }
164: } else {
165: WebServiceUtil.setProperty(target, propInfo.name,
166: propInfo.value, true);
167: }
168: }
169:
170: /**
171: * Attempts to look up a field or a "setXXX" method on the target object and
172: * use it to set specified property. If the "strict" flag is true and
173: * this method fails to match property name with a field/method, it throws
174: * <code>IllegalArgumentException</code>. The value
175: * is converted to an object of the appropriate class based on the field type.
176: * Currently this method does not handle array or non-primitive properties.
177: *
178: * @param target Target object
179: * @param Property name
180: * @param String specifying property value
181: * @param strict If true and a matching field/method is not found, this method
182: * throws IllegalAccessException.
183: */
184: public static void setProperty(Object target, String name,
185: String value, boolean strict) throws WebServiceException {
186:
187: try {
188: Field f = target.getClass().getField(name);
189: setFieldValue(target, f, value);
190: return;
191: } catch (NoSuchFieldException ex) {
192: // Ignore this since we want to see if there is a set method
193: } catch (IllegalAccessException e) {
194: // Ignore this since there may be a set method for this field
195: }
196: Method m = findMethod(target.getClass(), name);
197: if (m == null) {
198: if (strict)
199: throw new IllegalArgumentException(
200: "No field or set method matching property "
201: + name + ".");
202: else
203: return;
204: } else {
205: try {
206: setProperty(target, m, m.getParameterTypes()[0], value);
207: } catch (IllegalArgumentException e) {
208: throw new WebServiceException(
209: "Invalid value for property " + name + ".", e);
210: } catch (IllegalAccessException e) {
211: throw new WebServiceException(
212: "Could not find a field or a method for setting property "
213: + name + ".", e);
214: } catch (InvocationTargetException e) {
215: throw new WebServiceException(
216: "Error in the set method for property " + name
217: + ".", e);
218: }
219: }
220: }
221:
222: private static void setProperty(Object target, Method m,
223: Class fieldType, String value)
224: throws IllegalAccessException, InvocationTargetException {
225:
226: if (fieldType.equals(String.class)) {
227: m.invoke(target, new Object[] { value });
228: } else if (fieldType.equals(Integer.class)
229: || fieldType.equals(Integer.TYPE)) {
230: m.invoke(target, new Object[] { new Integer(value) });
231: } else if (fieldType.equals(Long.class)
232: || fieldType.equals(Long.TYPE)) {
233: m.invoke(target, new Object[] { new Long(value) });
234: } else if (fieldType.equals(Short.class)
235: || fieldType.equals(Short.TYPE)) {
236: m.invoke(target, new Object[] { new Short(value) });
237: } else if (fieldType.equals(Boolean.class)
238: || fieldType.equals(Boolean.TYPE)) {
239: m.invoke(target, new Object[] { new Boolean(value) });
240: } else if (fieldType.equals(Double.class)
241: || fieldType.equals(Double.TYPE)) {
242: m.invoke(target, new Object[] { new Double(value) });
243: } else if (fieldType.equals(Float.class)
244: || fieldType.equals(Float.TYPE)) {
245: m.invoke(target, new Object[] { new Float(value) });
246: }
247: }
248:
249: /**
250: * Attempts to look up a field or a "setXXX" method on the target object and
251: * use it to set specified property. The value is specified as a String. This
252: * is converted to an object of the appropriate class based on the field type.
253: * Currently this method does not handle array or non-primitive properties.
254: */
255: public static void setObjectProperty(Object target, String name,
256: Object value, boolean strict) throws WebServiceException {
257:
258: try {
259: Field f = target.getClass().getField(name);
260: f.set(target, value);
261: return;
262: } catch (IllegalAccessException ex) {
263: // Ignore since there may be a set method for this field
264: } catch (NoSuchFieldException ex) {
265: // Ignore this since we want to see if there is a set method
266: }
267: Method m = findMethod(target.getClass(), name);
268: if (m == null) {
269: if (strict)
270: throw new IllegalArgumentException(
271: "No field or set method matching property "
272: + name + ".");
273: else
274: return;
275: } else {
276: try {
277: m.invoke(target, new Object[] { value });
278: } catch (IllegalArgumentException e) {
279: throw new WebServiceException(
280: "Invalid value for property " + name + ".", e);
281: } catch (IllegalAccessException e) {
282: throw new WebServiceException(
283: "Could not find a field or a method for setting property "
284: + name + ".", e);
285: } catch (InvocationTargetException e) {
286: throw new WebServiceException(
287: "Error in the set method for property " + name
288: + ".", e);
289: }
290: }
291: }
292:
293: private static void setFieldValue(Object target, Field f,
294: String value) throws IllegalAccessException {
295: Class fieldType = f.getClass();
296: if (fieldType.equals(String.class)) {
297: f.set(target, value);
298: } else if (fieldType.equals(Integer.class)
299: || fieldType.equals(Integer.TYPE)) {
300: f.set(target, new Integer(value));
301: } else if (fieldType.equals(Long.class)
302: || fieldType.equals(Long.TYPE)) {
303: f.set(target, new Long(value));
304: } else if (fieldType.equals(Short.class)
305: || fieldType.equals(Short.TYPE)) {
306: f.set(target, new Short(value));
307: } else if (fieldType.equals(Boolean.class)
308: || fieldType.equals(Boolean.TYPE)) {
309: f.set(target, new Boolean(value));
310: } else if (fieldType.equals(Double.class)
311: || fieldType.equals(Double.TYPE)) {
312: f.set(target, new Double(value));
313: } else if (fieldType.equals(Float.class)
314: || fieldType.equals(Float.TYPE)) {
315: f.set(target, new Float(value));
316: }
317: }
318:
319: private static Method findMethod(Class cl, String name) {
320: Method[] methods = cl.getMethods();
321:
322: String firstChar = name.substring(0, 1);
323: name = name.replaceFirst(firstChar, firstChar.toUpperCase());
324: String methodName = "set" + name;
325: for (int i = 0; i < methods.length; i++) {
326: if (methods[i].getName().equals(methodName)
327: && methods[i].getParameterTypes().length == 1) {
328: return methods[i];
329: }
330: }
331: return null;
332:
333: }
334:
335: public static Object evaluateCOILExpression(String propValueStr)
336: throws ParseException, EvaluationException {
337:
338: if (propValueStr == null)
339: return null;
340: COILParser parser = new COILParser(new StringReader(""));
341: parser.ReInit(new StringReader(propValueStr));
342: return parser.COILExpression().evaluate(new JavaContext());
343:
344: }
345:
346: }
|