001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * Created Dec 27, 2006
014: * @author mdamour
015: */
016: package org.pentaho.plugin.hql;
017:
018: import java.io.File;
019: import java.util.ArrayList;
020: import java.util.Map;
021: import java.util.StringTokenizer;
022:
023: import org.apache.commons.logging.Log;
024: import org.pentaho.actionsequence.dom.ActionOutput;
025: import org.pentaho.actionsequence.dom.ActionResource;
026: import org.pentaho.actionsequence.dom.IActionInputValueProvider;
027: import org.pentaho.actionsequence.dom.actions.HQLConnectionAction;
028: import org.pentaho.actionsequence.dom.actions.HQLQueryAction;
029: import org.pentaho.core.component.IPreparedComponent;
030: import org.pentaho.commons.connection.IPentahoConnection;
031: import org.pentaho.commons.connection.IPentahoResultSet;
032: import org.pentaho.core.solution.IActionResource;
033: import org.pentaho.core.system.PentahoSystem;
034: import org.pentaho.core.util.MapParameterResolver;
035: import org.pentaho.core.util.TemplateUtil;
036: import org.pentaho.data.connection.hql.HQLConnection;
037: import org.pentaho.messages.Messages;
038: import org.pentaho.plugin.ComponentBase;
039:
040: public abstract class HQLBaseComponent extends ComponentBase implements
041: IPreparedComponent {
042:
043: private IPentahoResultSet rSet;
044:
045: /** reference to connection object */
046: private IPentahoConnection connection;
047:
048: /** specifies whether component owns connection or not */
049: private boolean connectionOwner = true;
050:
051: /** holds the query string for ipreparedcomponent functionality */
052: private String preparedQuery = null;
053:
054: public abstract boolean validateSystemSettings();
055:
056: public abstract String getResultOutputName();
057:
058: public abstract Log getLogger();
059:
060: public IPentahoResultSet getResultSet() {
061: return rSet;
062: }
063:
064: protected boolean validateAction() {
065: HQLConnectionAction connAction = null;
066: HQLQueryAction queryAction = null;
067: boolean actionValidated = true;
068:
069: try {
070: if (getActionDefinition() instanceof HQLQueryAction) {
071: queryAction = (HQLQueryAction) getActionDefinition();
072:
073: actionValidated = isConnectionInfoSpecified(queryAction);
074:
075: // Check if the query is defined.
076: if (actionValidated
077: && queryAction.getQuery() == IActionInputValueProvider.NULL_INPUT) {
078: actionValidated = false;
079: error(Messages
080: .getErrorString(
081: "HQLBaseComponent.ERROR_0004_QUERY_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
082: }
083:
084: // Check if output for the query is correctly defined.
085: if (actionValidated
086: && queryAction.getOutputResultSetName() == null
087: && queryAction.getOutputPreparedStatementName() == null) {
088: actionValidated = false;
089: error(Messages
090: .getErrorString(
091: "HQLBaseComponent.ERROR_0005_OUTPUT_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
092: }
093: } else if (getActionDefinition() instanceof HQLConnectionAction) {
094: connAction = (HQLConnectionAction) getActionDefinition();
095: actionValidated = isConnectionInfoSpecified(connAction);
096: } else {
097: actionValidated = false;
098: error(Messages
099: .getErrorString(
100: "ComponentBase.ERROR_0001_UNKNOWN_ACTION_TYPE", getActionDefinition().getElement().asXML())); //$NON-NLS-1$
101: }
102: } catch (Exception e) {
103: actionValidated = false;
104: error(
105: Messages
106: .getErrorString(
107: "HQLBaseComponent.ERROR_0006_VALIDATION_FAILED", getActionName()), e); //$NON-NLS-1$
108: }
109:
110: return actionValidated;
111: }
112:
113: private boolean isConnectionInfoSpecified(
114: HQLConnectionAction connAction) {
115: boolean value = true;
116:
117: if (connAction instanceof HQLQueryAction) {
118: if (((HQLQueryAction) connAction)
119: .getInputSharedConnection() == IActionInputValueProvider.NULL_INPUT
120: && !isBasicConnectionInfoSpecified(connAction)) {
121: value = false;
122: error(Messages
123: .getErrorString(
124: "HQLBaseComponent.ERROR_0003_CONNECTION_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
125: }
126: } else if (connAction instanceof HQLConnectionAction) {
127: if (!isBasicConnectionInfoSpecified(connAction)) {
128: value = false;
129: error(Messages
130: .getErrorString(
131: "HQLBaseComponent.ERROR_0003_CONNECTION_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
132: }
133: }
134: return value;
135: }
136:
137: private boolean isBasicConnectionInfoSpecified(
138: HQLConnectionAction connAction) {
139: boolean value = true;
140:
141: if (connAction.getClassNames() == IActionInputValueProvider.NULL_INPUT) {
142: value = false;
143: error(Messages
144: .getErrorString(
145: "HQLBaseComponent.ERROR_0001_CLASS_NAMES_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
146: }
147: if (connAction.getHibernateConfigResource() == null) {
148: value = false;
149: error(Messages
150: .getErrorString(
151: "HQLBaseComponent.ERROR_0002_HIBERNATE_CONFIG_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
152: }
153:
154: return value;
155: }
156:
157: public void done() {
158: // TODO Auto-generated method stub
159: }
160:
161: protected boolean executeAction() {
162: boolean returnValue = true;
163:
164: try {
165: if (getActionDefinition() instanceof HQLQueryAction) {
166: HQLQueryAction queryAction = (HQLQueryAction) getActionDefinition();
167: String classNames[] = null;
168: String query = queryAction.getQuery().getStringValue();
169:
170: if (queryAction.getInputSharedConnection() != IActionInputValueProvider.NULL_INPUT) {
171: connectionOwner = false;
172: IPreparedComponent component = (IPreparedComponent) queryAction
173: .getInputSharedConnection().getValue();
174: IPentahoConnection conn = component
175: .shareConnection();
176: if (conn.getDatasourceType() == IPentahoConnection.HQL_DATASOURCE) {
177: connection = conn;
178: } else {
179: connection = null;
180: returnValue = false;
181: error(Messages
182: .getErrorString(
183: "IPreparedComponent.ERROR_0001_INVALID_CONNECTION_TYPE", getActionName())); //$NON-NLS-1$
184: }
185: } else {
186: createBasicConnection(queryAction, classNames);
187: }
188:
189: if (connection != null) {
190: ActionOutput actionOutput = queryAction
191: .getOutputPreparedStatementParam();
192: if (actionOutput != null) {
193: // prepare the query for execution, but don't execute quite yet.
194: prepareQuery(query);
195:
196: // set the output as self, which will be used later by another component.
197: actionOutput.setValue(this );
198: } else {
199: return runQuery(connection, classNames, query);
200: }
201: }
202: } else if (getActionDefinition() instanceof HQLConnectionAction) {
203: HQLConnectionAction connAction = (HQLConnectionAction) getActionDefinition();
204: String classNames[] = null;
205: createBasicConnection(connAction, classNames);
206: if (connection != null) {
207: ActionOutput outputConnection = connAction
208: .getOutputConnectionParam();
209: if (outputConnection != null) {
210: outputConnection.setValue(this );
211: }
212: }
213: } else {
214: returnValue = false;
215: error(Messages
216: .getErrorString(
217: "HQLBaseComponent.ERROR_00011_INVALID_HQL_COMPONENT", getActionName())); //$NON-NLS-1$
218: }
219: } catch (Exception e) {
220: returnValue = false;
221: error(
222: Messages
223: .getErrorString(
224: "HQLBaseComponent.ERROR_00012_EXECUTE_FAILED", getActionName()), e); //$NON-NLS-1$
225: }
226: return returnValue;
227: }
228:
229: /*
230: * Create the basic connection. This requires retrieving class names and catalog info.
231: */
232: private void createBasicConnection(HQLConnectionAction connAction,
233: String[] classNames) {
234: boolean proceed = true;
235: String catalog = null;
236:
237: if (connAction.getClassNames() != IActionInputValueProvider.NULL_INPUT) {
238: classNames = getClassNames(connAction);
239: } else {
240: proceed = false;
241: error(Messages
242: .getErrorString(
243: "HQLBaseComponent.ERROR_0001_CLASS_NAMES_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
244: }
245:
246: if (proceed) {
247: catalog = getCatalog();
248:
249: if (null == catalog || catalog.trim().length() <= 0) {
250: proceed = false;
251: error(Messages
252: .getErrorString(
253: "HQLBaseComponent.ERROR_00010_CATALOG_INFO_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
254: }
255: }
256:
257: if (proceed) {
258: connection = getConnection(new File(catalog), classNames);
259:
260: if (connection == null) {
261: proceed = false;
262: error(Messages
263: .getErrorString(
264: "HQLBaseComponent.HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION", getActionName())); //$NON-NLS-1$
265: }
266: }
267: }
268:
269: /*
270: * Utitlity function to get the class names from the XML.
271: */
272: private String[] getClassNames(HQLConnectionAction connAction) {
273: ArrayList classNamesList = new ArrayList();
274: String classNames[] = null;
275: try {
276: String classes = connAction.getClassNames()
277: .getStringValue();
278: StringTokenizer st = new StringTokenizer(classes, ",");//getInputStringValue(CLASSNAMES), ","); //$NON-NLS-1$
279: while (st.hasMoreTokens()) {
280: String token = st.nextToken();
281: classNamesList.add(token.trim());
282: }
283:
284: classNames = (String[]) classNamesList
285: .toArray(new String[0]);
286:
287: } catch (Exception e) {
288: error(
289: Messages
290: .getErrorString(
291: "HQLBaseComponent.ERROR_0008_COULD_NOT_RETRIEVE_CLASS_NAMES", getActionName()), e); //$NON-NLS-1$
292: }
293:
294: return classNames;
295: }
296:
297: /*
298: * Utility function to get the catalog info from hibernate config.
299: */
300: private String getCatalog() {
301: ActionResource hibernateConfigRes = ((HQLConnectionAction) getActionDefinition())
302: .getHibernateConfigResource();
303: String catalog = null;
304:
305: if (hibernateConfigRes != null) {
306: IActionResource resource = getResource(hibernateConfigRes
307: .getName());
308: catalog = resource.getAddress();
309: if (resource.getSourceType() == IActionResource.SOLUTION_FILE_RESOURCE) {
310: catalog = PentahoSystem.getApplicationContext()
311: .getSolutionPath(catalog);
312: }
313: }
314: return catalog;
315: }
316:
317: /**
318: * called when in prepared-component mode, this method populates the preparedQuery string and
319: * preparedParameters object.
320: *
321: * @param rawQuery
322: * @return
323: */
324: protected boolean prepareQuery(String rawQuery) {
325:
326: try {
327: if (connection == null) {
328: error(Messages
329: .getErrorString("HQLBaseComponent.ERROR_00013_NO_CONNECTION")); //$NON-NLS-1$
330: return false;
331: }
332: if (!connection.initialized()) {
333: error(Messages
334: .getErrorString("HQLBaseComponent.ERROR_00013_NO_CONNECTION")); //$NON-NLS-1$
335: return false;
336: }
337: if (rawQuery != null) {
338: preparedQuery = applyInputsToFormat(rawQuery);
339: }
340:
341: return true;
342: } catch (Exception e) {
343: error(
344: Messages
345: .getErrorString(
346: "HQLBaseComponent.ERROR_00014_COULD_NOT_PREPARE_QUERY", getActionName()), e); //$NON-NLS-1$
347: }
348:
349: return false;
350: }
351:
352: /**
353: * executes a prepared method that returns a result set
354: * executePrepared looks up any "PREPARELATER" params
355: * in the preparedParams map.
356: *
357: * @param preparedParams a map of possible parameters.
358: * @return result set
359: */
360: public IPentahoResultSet executePrepared(Map preparedParams) {
361: try {
362: if (connection == null) {
363: error(Messages
364: .getErrorString("HQLBaseComponent.ERROR_0007_NO_CONNECTION")); //$NON-NLS-1$
365: return null;
366: }
367: if (!connection.initialized()) {
368: error(Messages
369: .getErrorString("HQLBaseComponent.ERROR_0007_NO_CONNECTION")); //$NON-NLS-1$
370: return null;
371: }
372:
373: if (preparedQuery == null) {
374: error(Messages
375: .getErrorString("HQLBaseComponent.ERROR_0001_QUERY_NOT_SPECIFIED")); //$NON-NLS-1$
376: return null;
377: }
378:
379: // parse preparedQuery, replacing any {PREPARELATER:NAME} with appropriate values
380: String query = TemplateUtil.applyTemplate(preparedQuery,
381: getRuntimeContext(), new MapParameterResolver(
382: preparedParams, PREPARE_LATER_PREFIX,
383: getRuntimeContext()));
384:
385: if (debug)
386: debug(Messages.getString(
387: "HQLBaseComponent.DEBUG_RUNNING_QUERY", query)); //$NON-NLS-1$
388:
389: // evaluate
390: IPentahoResultSet resultSet = connection
391: .executeQuery(query);
392: rSet = resultSet;
393: return resultSet;
394: } catch (Exception e) {
395: error(
396: Messages
397: .getErrorString(
398: "HQLBaseComponent.ERROR_0006_EXECUTE_FAILED", getActionName()), e); //$NON-NLS-1$
399: }
400: return null;
401: }
402:
403: protected boolean runQuery(IPentahoConnection conn,
404: String[] classNames, String query) {
405: try {
406:
407: if (conn == null) {
408: return false;
409: }
410:
411: rSet = ((HQLConnection) conn).executeQuery(query);
412:
413: ActionOutput actionOutput = ((HQLQueryAction) getActionDefinition())
414: .getOutputResultSetParam();
415: if (actionOutput != null) {
416: actionOutput.setValue(rSet);
417: }
418: return true;
419: } catch (Exception e) {
420: error(
421: Messages
422: .getErrorString(
423: "HQLBaseComponent.ERROR_0007_QUERY_EXECUTION_FAILED", getActionName()), e); //$NON-NLS-1$
424: return false;
425: }
426: }
427:
428: /**
429: * if the owner, dispose of the connection
430: */
431: public void dispose() {
432: if (connectionOwner) {
433: if (connection != null) {
434: connection.close();
435: }
436: }
437: connection = null;
438: }
439:
440: protected IPentahoConnection getConnection(File hbmCfgFile,
441: String classNames[]) {
442: IPentahoConnection conn = null;
443: try {
444: conn = new HQLConnection(null, hbmCfgFile, classNames);
445: return conn;
446: } catch (Exception e) {
447: error(
448: Messages
449: .getErrorString(
450: "HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION", getActionName()), e); //$NON-NLS-1$
451: }
452: return null;
453: }
454:
455: /**
456: * return this class's connection. This implements the IPreparedComponent
457: * interface, which may share its connection with others.
458: *
459: * @return connection object
460: */
461: public IPentahoConnection shareConnection() {
462: return connection;
463: }
464:
465: public boolean init() {
466: return true;
467: }
468: }
|