001: package com.xoetrope.service.data;
002:
003: import com.xoetrope.service.ModelHelper;
004: import com.xoetrope.service.xml.DocumentHelper;
005: import java.io.StringReader;
006: import java.io.UnsupportedEncodingException;
007: import net.xoetrope.xml.XmlElement;
008: import net.xoetrope.xml.XmlSource;
009: import net.xoetrope.optional.service.ServiceProxy;
010: import net.xoetrope.optional.service.ServiceProxyArgs;
011: import net.xoetrope.optional.service.ServiceProxyException;
012: import net.xoetrope.optional.service.XRouteManager;
013: import net.xoetrope.optional.data.XOptionalDataSource;
014: import net.xoetrope.xui.XProjectManager;
015: import net.xoetrope.optional.data.sql.DatabaseTableModel;
016: import net.xoetrope.optional.service.ServiceContext;
017: import net.xoetrope.xui.XProject;
018: import net.xoetrope.xui.data.XModel;
019: import org.w3c.dom.DOMException;
020: import org.w3c.dom.Document;
021: import org.w3c.dom.Element;
022:
023: /**
024: * ServiceProxy class which retrieves data from a database on the server and
025: * returns an XML representation of it.
026: *
027: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
028: * the GNU Public License (GPL), please see license.txt for more details. If
029: * you make commercial use of this software you must purchase a commercial
030: * license from Xoetrope.</p>
031: * <p> $Revision: 1.12 $</p>
032: */
033: public class QueryService extends ServiceProxy {
034: /**
035: * Return parameter which contains the XML representation of the query
036: */
037: public static final String ARG_NAME_RESULTSET = "queryservice:ResultSet";
038:
039: /**
040: * The name of the query to be executed as defined in the database datasource
041: * file
042: */
043: public static final String ARG_NAME_QUERY = "queryservice:QueryName";
044:
045: /**
046: * The number of parameters to be set in the PreparedStatement
047: */
048: public static final String ARG_NAME_NUMPARAMS = "queryservice:numParams";
049:
050: /**
051: * This parameter should be concatenated with the zero based index of the
052: * parameter being set
053: */
054: public static final String ARG_NAME_PARAMVALUE = "queryservice:paramvalue";
055:
056: /**
057: * This parameter should be concatenated with the zero based index of the
058: * parameter being set
059: */
060: public static final String ARG_NAME_MODEL_RESTORE_PATH = "queryservice:paramMdlRestorePath";
061:
062: protected String databaseencoding;
063:
064: /**
065: * The owner project and the context in which this object operates.
066: */
067: protected XProject currentProject = XProjectManager
068: .getCurrentProject();
069:
070: /**
071: * Create a new instance of the service
072: */
073: public QueryService() {
074: currentProject = XProjectManager.getCurrentProject();
075: databaseencoding = currentProject
076: .getStartupParam("databaseencoding");
077: }
078:
079: /**
080: * Call this proxy with the specified arguments
081: * @return the result of the call
082: * @param context The ServiceContext contain pass and return parameters
083: * @param method the name of the service being called
084: * @throws net.xoetrope.optional.service.ServiceProxyException Throw an exception if there is a problem with the call
085: */
086: public Object call(String method, ServiceContext context)
087: throws ServiceProxyException {
088: ServiceProxyArgs args = context.getArgs();
089: try {
090: status = STARTED;
091: if (side == XRouteManager.CLIENT_SIDE) {
092: /**
093: * The query happens on the server so just pass through. Load the results
094: * into the part of the model.
095: */
096: callNextProxy(method, context, null);
097: String mdlPath = (String) args
098: .getPassParam(ARG_NAME_MODEL_RESTORE_PATH);
099: XModel restoreMdl = XProjectManager.getModel();
100: if (mdlPath != null)
101: restoreMdl = (XModel) restoreMdl.get(mdlPath);
102:
103: loadResults((String) args
104: .getReturnParam(ARG_NAME_RESULTSET), restoreMdl);
105: } else {
106: /*
107: * The 'QueryType' argument determines which ResultSet from the datasets
108: * databse xml file is to be executed. Parameters need to be sent up from
109: * the client which are used to populate the PreparedStatement. Retrieve
110: * the ResultSet and output it to an XML string.
111: */
112: String queryType = (String) args
113: .getPassParam(ARG_NAME_QUERY);
114:
115: // Setup the PreparedStatement params
116: int paramCount = args
117: .getPassParamAsInt(ARG_NAME_NUMPARAMS);
118: String[] params = null;
119: if (paramCount > 0) {
120: params = new String[paramCount];
121: for (int i = 0; i < paramCount; i++) {
122: String param = (String) args
123: .getPassParam(ARG_NAME_PARAMVALUE + i);
124: params[i] = param;
125: }
126: }
127:
128: String retStr = retrieveData(context, queryType, params);
129: args.setReturnParam(ARG_NAME_RESULTSET, retStr);
130: callNextProxy(method, context, null);
131: }
132: } catch (Exception e) {
133: e.printStackTrace();
134: }
135: return null;
136: }
137:
138: /**
139: * Called when a named query is to be processed with the specified parameters.
140: * The dataset is built up from the data and returned.
141: * @param context The ServiceContext object sent from the client
142: * @param queryType The query to be processed
143: * @param params The parameters for the PreparedStatement
144: */
145: public String retrieveData(ServiceContext context,
146: String queryType, String[] params) {
147: DatabaseTableModel dtm = (DatabaseTableModel) XProjectManager
148: .getModel().get(queryType);
149: DatabaseTableModel dtmRes = null;
150: dtm.setParams(params);
151: dtmRes = (DatabaseTableModel) dtm.get();
152: dtmRes.setDistinct(true);
153: dtmRes.setDirty(true);
154: dtmRes.retrieve();
155: dtmRes.first();
156:
157: // Construct the data XML
158: Document doc = DocumentHelper.createDocument();
159: Element topEle = doc.createElement("data");
160: topEle.setAttribute("id", "resultset");
161: doc.appendChild(topEle);
162: String retStr = null;
163: try {
164: Element headerEle = doc.createElement("header");
165: headerEle.setAttribute("id", "header");
166: topEle.appendChild(headerEle);
167: for (int i = 0; i < dtmRes.getNumAttributes(); i++) {
168: if (dtmRes.getAttribName(i).compareTo("id") != 0) {
169: String value = dtmRes.getAttribName(i);
170: String dataValue = value;
171: if (databaseencoding != null)
172: dataValue = new String(value
173: .getBytes(databaseencoding));
174: headerEle.setAttribute(dtmRes.getAttribName(i),
175: dataValue);
176: }
177: }
178: if (dtmRes.getNumChildren() > 0) {
179: do {
180: Element dataEle = doc.createElement("data");
181: for (int i = 0; i < dtmRes.getNumAttributes(); i++) {
182: try {
183: String value = dtmRes
184: .getAttribValueAsString(i);
185: if (value != null) {
186: String dataValue = value;
187: if (databaseencoding != null)
188: dataValue = new String(value
189: .getBytes(databaseencoding));
190: dataEle.setAttribute(dtmRes
191: .getAttribName(i), dataValue);
192: }
193: } catch (Exception e) {
194: e.printStackTrace();
195: }
196: }
197: recordProcessed(context, dataEle);
198: topEle.appendChild(dataEle);
199: } while (dtmRes.next());
200: }
201: retStr = DocumentHelper.outputXML(topEle);
202: } catch (UnsupportedEncodingException ex) {
203: ex.printStackTrace();
204: } catch (DOMException ex) {
205: ex.printStackTrace();
206: }
207: return retStr;
208: }
209:
210: /**
211: * Provided for overloading. This method is called when a record has been
212: * processed and should be overloaded where additonal work needs to be carried
213: * out on the data.
214: * @param context The ServiceContext object sent from the client
215: * @param dataEle The XML Element containing data for the current record
216: */
217: protected void recordProcessed(ServiceContext context,
218: Element dataEle) {
219:
220: }
221:
222: /**
223: * Load the returned data into the model.
224: * @param resultSet the returned XML data
225: * @param model The model which will be populated with the data
226: */
227: public void loadResults(String resultSet, XModel model) {
228: StringReader sr = new StringReader(resultSet);
229: XmlElement src = XmlSource.read(sr);
230: XOptionalDataSource dataSource = ModelHelper
231: .getDataSource(currentProject);
232: dataSource.loadTable(src, model);
233: }
234:
235: }
|