001: package com.xoetrope.service.data;
002:
003: import java.io.StringReader;
004: import java.lang.reflect.Method;
005: import net.xoetrope.xui.data.XModelHelper;
006: import net.xoetrope.optional.data.XOptionalDataSource;
007: import net.xoetrope.optional.service.ServiceContext;
008: import net.xoetrope.optional.service.ServiceProxyArgs;
009: import net.xoetrope.optional.service.ServiceProxyException;
010: import net.xoetrope.xml.XmlElement;
011: import net.xoetrope.xml.XmlSource;
012: import net.xoetrope.xui.XProjectManager;
013: import net.xoetrope.xui.data.XBaseModel;
014:
015: import javax.servlet.http.HttpServletRequest;
016: import javax.servlet.http.HttpSession;
017:
018: /**
019: * ServiceProxy class which processes a list of fields from a dataset in order to
020: * create the stubs of Insert and Update statements.
021: *
022: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
023: * the GNU Public License (GPL), please see license.txt for more details. If
024: * you make commercial use of this software you must purchase a commercial
025: * license from Xoetrope.</p>
026: * <p> $Revision: 1.11 $</p>
027: */
028: public abstract class TableProcessor extends QueryService {
029: /**
030: * The name of the pass parameter which contains the dataset which needs to be
031: * processed
032: */
033: public static final String ARG_NAME_DATA_PARAMNAME = "tableprocessor:dataparamname";
034:
035: /**
036: * Needs to be set in the subclass to indicate that the operation has suceeded
037: * or failed. Use either ARG_VALUE_UPDATES_FAILED or ARG_VALUE_UPDATES_COMPLETED
038: */
039: public static final String ARG_NAME_RETURNSTATE = "tableprocessor:returnstate";
040:
041: /**
042: * Assigned to the ARG_NAME_RETURNSTATE parameter if the operation fails
043: */
044: public static final String ARG_VALUE_UPDATES_FAILED = "tableprocessor:updatesfailed";
045:
046: /**
047: * Assigned to the ARG_NAME_RETURNSTATE parameter if the operation completes
048: */
049: public static final String ARG_VALUE_UPDATES_COMPLETED = "tableprocessor:updatescompleted";
050:
051: /**
052: * Used by the processFields method to indicate that an insert statement is
053: * being generated
054: */
055: public static final int MODE_INSERT = 1;
056:
057: /**
058: * Used by the processFields method to indicate that an update statement is
059: * being generated
060: */
061: public static final int MODE_UPDATE = 2;
062:
063: public static final int MODE_DELETE = 3;
064:
065: protected XBaseModel rootModel;
066: protected ServiceProxyArgs args;
067: protected XBaseModel dataMdl;
068:
069: /**
070: * Call this proxy with the specified arguments
071: * @return the result of the call
072: * @param context The ServiceContext contain pass and return parameters
073: * @param method the name of the service being called
074: * @throws net.xoetrope.optional.service.ServiceProxyException Throw an exception if there is a problem with the call
075: */
076: public Object call(String method, ServiceContext context)
077: throws ServiceProxyException {
078: Object ret = null;
079: rootModel = (XBaseModel) XProjectManager.getModel();
080: args = context.getArgs();
081: String dataParam = (String) args
082: .getPassParam(ARG_NAME_DATA_PARAMNAME);
083: String dataModelText = (String) args.getPassParam(dataParam);
084: loadDataModel(dataModelText);
085: processQueries(args);
086: ret = callNextProxy(method, context, ret);
087: return ret;
088: }
089:
090: /*
091: * Overload this method to process whatever queries are required by the
092: * subclassed ServiceProxy
093: * @param args the arguments passed to the ServiceProxy
094: */
095: protected abstract void processQueries(ServiceProxyArgs args);
096:
097: /**
098: * Create an XModel object from the passed dataset
099: * @param dataModelText the dataset String which has been passed from the client
100: */
101: protected void loadDataModel(String dataModelText) {
102: dataMdl = new XBaseModel();
103: StringReader sr = new StringReader(dataModelText);
104: XmlElement src = XmlSource.read(sr);
105: XOptionalDataSource dataSource = new XOptionalDataSource(
106: currentProject);
107: dataSource.loadTable(src, dataMdl);
108: }
109:
110: /**
111: * Build the SQL statement from the list of fields found in the model node
112: * specified by the fieldPath parameter.
113: * @param fieldPath the path into the model where the field list is stored
114: * @param mode specifies either Insert or Update mode
115: * @param dataModelSection the XModel from which data is to be retrieved
116: * @return the formatted SQL statment
117: */
118: protected String processFields(String fieldPath, int mode,
119: XBaseModel dataModelSection) {
120: XBaseModel fieldModel = (XBaseModel) rootModel.get(fieldPath);
121: String tableName = XModelHelper.getAttrib(fieldModel, "table");
122: StringBuffer fieldSQL = new StringBuffer();
123: for (int i = 0; i < fieldModel.getNumChildren(); i++) {
124: XBaseModel childMdl = (XBaseModel) fieldModel.get(i);
125: String modeAtt = XModelHelper.getAttrib(childMdl, "mode");
126: boolean process = false;
127: if (modeAtt == null)
128: process = true;
129: else if ((modeAtt.compareToIgnoreCase("insert") == 0)
130: && (mode == MODE_INSERT))
131: process = true;
132: else if ((modeAtt.compareToIgnoreCase("update") == 0)
133: && (mode == MODE_UPDATE))
134: process = true;
135:
136: if (process) {
137: String id = childMdl.getId();
138: String value = "";
139: String serviceParam = XModelHelper.getAttrib(childMdl,
140: "serviceparam");
141: String attrib = XModelHelper.getAttrib(childMdl,
142: "attrib");
143: String sessionField = XModelHelper.getAttrib(childMdl,
144: "sessionfield");
145: String call = XModelHelper.getAttrib(childMdl, "call");
146: if (serviceParam != null)
147: value = "'"
148: + fixFieldData((String) args
149: .getPassParam(serviceParam)) + "'";
150: else if (sessionField != null) {
151: HttpServletRequest request = (HttpServletRequest) args
152: .getPassParam("session");
153: HttpSession session = request.getSession(false);
154: value = "'"
155: + fixFieldData((String) session
156: .getAttribute(sessionField)) + "'";
157: } else if (call != null) {
158: value = "'" + fixFieldData(getCallValue(call))
159: + "'";
160: } else if (childMdl.get() != null)
161: value = (String) childMdl.get();
162: else if (attrib != null) {
163: String fieldValue = XModelHelper.getAttrib(
164: dataModelSection, attrib);
165: if (fieldValue == null)
166: value = null;
167: else
168: value = "'" + fixFieldData(fieldValue) + "'";
169: }
170:
171: if ((mode == MODE_UPDATE) || (value != null)) {
172: if (fieldSQL.length() != 0)
173: fieldSQL.append(", ");
174: fieldSQL.append(childMdl.getId());
175: fieldSQL.append("=");
176: fieldSQL.append(value);
177: }
178: }
179: }
180:
181: if (tableName != null) {
182: if (mode == MODE_UPDATE)
183: return "UPDATE " + tableName + " SET "
184: + fieldSQL.toString();
185: else if (mode == MODE_INSERT)
186: return "INSERT INTO " + tableName + " SET "
187: + fieldSQL.toString();
188: }
189:
190: return fieldSQL.toString();
191: }
192:
193: /**
194: * Calls methods in subclasses with the name of the passed function and
195: * returns the result of that call.
196: * @param function The name of the function to call
197: * @return The result of the function call
198: */
199: protected String getCallValue(String function) {
200: try {
201: Class classParams[] = {};
202: Method method = getClass().getMethod(function, classParams);
203: Object params[] = {};
204: Object ret = method.invoke(this , params);
205: return (String) ret;
206: } catch (Exception ex) {
207: ex.printStackTrace();
208: }
209: return null;
210: }
211:
212: /**
213: * Fix the field data for ' single quotes that appear in the query data.
214: * @param data The data being used in the query
215: * @return The fixed data
216: */
217: protected String fixFieldData(String data) {
218: int pos = data.indexOf("'");
219: while (pos > -1) {
220: String fixed = data.substring(0, pos);
221: fixed += "''";
222: fixed += data.substring(pos + 1, data.length());
223: data = fixed;
224: pos = data.indexOf("'", pos + 2);
225: }
226: return data;
227: }
228: }
|