001: /*
002: * (C) Copyright 2004 Nabh Information Systems, Inc.
003: *
004: * All copyright notices regarding Nabh's products MUST remain
005: * intact in the scripts and in the outputted HTML.
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021: package com.nabhinc.portlet.mvcportlet.actionprocessor;
022:
023: import java.io.IOException;
024: import java.sql.Connection;
025: import java.sql.PreparedStatement;
026: import java.sql.ResultSet;
027: import java.sql.ResultSetMetaData;
028: import java.sql.SQLException;
029: import java.text.ParseException;
030:
031: import javax.portlet.ActionRequest;
032: import javax.portlet.ActionResponse;
033: import javax.portlet.PortletException;
034:
035: import org.w3c.dom.Element;
036:
037: import com.nabhinc.portlet.mvcportlet.core.ActionConfig;
038: import com.nabhinc.portlet.mvcportlet.core.ActionProcessor;
039: import com.nabhinc.portlet.mvcportlet.core.BaseRequestProcessor;
040: import com.nabhinc.portlet.mvcportlet.core.ControllerPortletConfig;
041: import com.nabhinc.util.StringUtil;
042: import com.nabhinc.util.XMLUtil;
043: import com.nabhinc.util.db.DBConfigUtil;
044: import com.nabhinc.util.db.DBParamUtil;
045: import com.nabhinc.util.db.DBUtil;
046:
047: /**
048: * Retrieves a database record and sets request attribute
049: * "mvcportlet.record" to an array of objects corresponding to
050: * the record fields. Optionally, it also sets render request
051: * parameters from record fields.
052: * <ul>
053: * <li>sql - SQL used to update or insert a record.</li>
054: * </ul>
055: * Optional configuration parameters
056: * <ul>
057: * <li>params - Comma separated list of names of SQL parameters to be
058: * inserted. In general, these are the request parameter names. The
059: * following specialtokens are used to insert other values:
060: * <ul>
061: * <li>$userName - Current user name returned by request.getRemoteUser()</li>
062: * <li>$currentDate - Today's date</li>
063: * <li>$currentTimestamp - Current time</li>
064: * </ul>
065: * </li>
066: * <li>param-types - Comma separated list of SQL parameter types. This
067: * parameter must be specified if "params" are specified. Possible parameter
068: * types are: VARCHAR, INTEGER, DECIMAL, BOOLEAN, SMALLINT, DATE,
069: * TIME, TIMESTAMP, FLOAT, DOUBLE, ARRAY, BIGINT, BINARY, BIT,
070: * BLOB, CHAR, CLOB, LONGVARBINARY, LONGVARCHAR, JAVA_OBJECT
071: * </li>
072: * <li>render-params - Comma separated list of render parameter names. If
073: * this parameter is set, specified render parameters will be set from
074: * the record fields.</li>
075: * </ul>
076: *
077: * @author Padmanabh Dabke
078: * (c) 2004 Nabh Information Systems, Inc. All Rights Reserved.
079: */
080:
081: public class SelectRecord extends BaseRequestProcessor implements
082: ActionProcessor {
083: private boolean srMarkOldValues = false;
084:
085: private class OperationInfo {
086: public boolean isMultiple = true;
087: public String sql = null;
088: public String[] params = null;
089: public int[] paramTypes = null;
090: public String[] renderParams = null;
091: public int[] renderParamTypes = null;
092:
093: public OperationInfo(boolean mult, String sq, String[] pa,
094: int[] paTypes, String[] rParams, int[] rParamTypes) {
095: isMultiple = mult;
096: sql = sq;
097: params = pa;
098: paramTypes = paTypes;
099: renderParams = rParams;
100: renderParamTypes = rParamTypes;
101: }
102: }
103:
104: private OperationInfo[] srOpInfo = null;
105:
106: /**
107: * Initialization.
108: * @param config XML configuration element
109: * @throws PortletException Thrown if sql parameter is not specified,
110: * "params" parameter is specified but corresponding "param-types"
111: * are not specified.
112: */
113: public void init(Element config, ControllerPortletConfig cpConfig)
114: throws PortletException {
115: super .init(config, cpConfig);
116: String markOldValues = config.getAttribute("markOldValues");
117: if ("true".equals(markOldValues))
118: srMarkOldValues = true;
119: Element[] opElems = XMLUtil.getSubElements(config,
120: "transaction");
121: if (opElems == null || opElems.length == 0) {
122: throw new PortletException(
123: "SelectRecord configuration requires at least one transaction.");
124: }
125: srOpInfo = new OperationInfo[opElems.length];
126: for (int i = 0; i < opElems.length; i++) {
127: srOpInfo[i] = constructOperationInfo(opElems[i]);
128: }
129: }
130:
131: private OperationInfo constructOperationInfo(Element config)
132: throws PortletException {
133: String sql = XMLUtil.getSubElementText(config, "sql");
134: boolean isMultiple = "true".equals(config
135: .getAttribute("multiple"));
136: String[] paramArray = null;
137: int[] paramTypeArray = null;
138: String[] renderParamArray = null;
139: int[] renderParamTypeArray = null;
140:
141: if (sql == null) {
142: throw new PortletException(
143: "Missing required parameter: sql");
144: }
145:
146: String params = XMLUtil.getSubElementText(config, "params");
147: if (params != null) {
148: paramArray = StringUtil.split(params, ",");
149: String paramTypes = XMLUtil.getSubElementText(config,
150: "param-types");
151: if (paramTypes == null) {
152: throw new PortletException(
153: "You must specify param-types if you specify params.");
154: }
155: String[] typeArray = StringUtil.split(paramTypes, ",");
156: if (typeArray.length != paramArray.length) {
157: throw new PortletException(
158: "Number of param-types must be equal to number of params.");
159: }
160: paramTypeArray = new int[typeArray.length];
161: for (int i = 0; i < typeArray.length; i++) {
162: try {
163: paramTypeArray[i] = DBConfigUtil
164: .getSQLType(typeArray[i]);
165: } catch (Exception ex) {
166: throw new PortletException(
167: "Failed to parse parameter type.", ex);
168: }
169: }
170: }
171:
172: String temp = XMLUtil
173: .getSubElementText(config, "render-params");
174: if (temp != null) {
175: renderParamArray = StringUtil.split(temp, ",");
176: String paramTypes = XMLUtil.getSubElementText(config,
177: "render-param-types");
178: String[] typeArray = null;
179: if (paramTypes == null) {
180: renderParamTypeArray = new int[renderParamArray.length];
181: for (int i = 0; i < renderParamArray.length; i++) {
182: renderParamTypeArray[i] = java.sql.Types.VARCHAR;
183: }
184: } else {
185: typeArray = StringUtil.split(paramTypes, ",");
186: if (typeArray.length != renderParamArray.length) {
187: throw new PortletException(
188: "Number of render-param-types must be equal to number of render-params.");
189: }
190: renderParamTypeArray = new int[typeArray.length];
191: for (int i = 0; i < typeArray.length; i++) {
192: try {
193: renderParamTypeArray[i] = DBConfigUtil
194: .getSQLType(typeArray[i]);
195: } catch (Exception ex) {
196: throw new PortletException(
197: "Failed to parse parameter type.", ex);
198: }
199: }
200: }
201: }
202:
203: return new OperationInfo(isMultiple, sql, paramArray,
204: paramTypeArray, renderParamArray, renderParamTypeArray);
205: }
206:
207: /**
208: * Retrieves a database record and sets request attribute
209: * "mvcportlet.record" to an array of objects corresponding to
210: * the record fields. Optionally, it also sets render request
211: * parameters from record fields.
212: * @param request Action request
213: * @param response Action response
214: * @param config Action config
215: * @return "success".
216: * @throws PortletException
217: * @throws IOException
218: */
219: public String process(ActionRequest request,
220: ActionResponse response, ActionConfig config)
221: throws PortletException, IOException {
222:
223: Connection conn = null;
224: ResultSet results = null;
225: PreparedStatement st = null;
226:
227: try {
228: conn = brpConfig.getDataSource().getConnection();
229:
230: for (int count = 0; count < srOpInfo.length; count++) {
231: String sql = srOpInfo[count].sql;
232: boolean isMultiple = srOpInfo[count].isMultiple;
233: String[] params = srOpInfo[count].params;
234: int[] paramTypes = srOpInfo[count].paramTypes;
235: String[] renderParams = srOpInfo[count].renderParams;
236: int[] renderParamTypes = srOpInfo[count].renderParamTypes;
237:
238: st = conn.prepareStatement(sql);
239: if (params != null) {
240: for (int i = 0; i < params.length; i++) {
241: DBParamUtil.setSQLParam(st, i, params[i],
242: paramTypes[i], request, -1);
243: }
244: }
245: results = st.executeQuery();
246:
247: if (isMultiple) {
248: if (results.next()) {
249: DBParamUtil.setRenderParam(results, 0,
250: renderParams[0], renderParamTypes[0],
251: request, response, true);
252: }
253:
254: } else {
255: ResultSetMetaData metaData = results.getMetaData();
256: int numColumns = metaData.getColumnCount();
257: if (renderParams != null) {
258: if (renderParams.length != numColumns) {
259: throw new PortletException(
260: "Number of columns returned by database query do not match number of configured parameters.");
261: }
262: if (results.next()) {
263: for (int i = 0; i < numColumns; i++) {
264: if (srMarkOldValues) {
265: DBParamUtil.setAndMarkRenderParam(
266: results, i,
267: renderParams[i],
268: renderParamTypes[i],
269: request, response, false);
270: } else {
271: DBParamUtil.setRenderParam(results,
272: i, renderParams[i],
273: renderParamTypes[i],
274: request, response, false);
275: }
276: }
277: }
278: } else {
279: Object[] record = new Object[numColumns];
280: for (int i = 0; i < numColumns; i++) {
281: record[i] = results.getObject(i + 1);
282: }
283: request.setAttribute("mvcportlet.record",
284: record);
285: }
286: }
287: }
288: return "success";
289: } catch (SQLException sqe) {
290: throw new PortletException("Database exception.", sqe);
291: } catch (ParseException pex) {
292: throw new PortletException("Malformed request parameter.",
293: pex);
294: } finally {
295: DBUtil.close(results);
296: DBUtil.close(st);
297: DBUtil.close(conn);
298: }
299: }
300:
301: }
|