/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.action.hql; import org.apache.commons.logging.Log; import org.pentaho.actionsequence.dom.ActionInputConstant; import org.pentaho.actionsequence.dom.IActionOutput; import org.pentaho.actionsequence.dom.IActionResource; import org.pentaho.actionsequence.dom.actions.HQLConnectionAction; import org.pentaho.actionsequence.dom.actions.HQLQueryAction; import org.pentaho.commons.connection.IPentahoConnection; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.platform.api.data.IPreparedComponent; import org.pentaho.platform.api.engine.IActionSequenceResource; import org.pentaho.platform.engine.services.connection.PentahoConnectionFactory; import org.pentaho.platform.engine.services.runtime.MapParameterResolver; import org.pentaho.platform.engine.services.runtime.TemplateUtil; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.plugin.action.messages.Messages; import org.pentaho.platform.plugin.services.connections.hql.HQLConnection; import java.io.File; import java.util.ArrayList; import java.util.Map; import java.util.StringTokenizer; public abstract class HQLBaseComponent extends ComponentBase implements IPreparedComponent { private static final long serialVersionUID = 5949258346877934670L; private IPentahoResultSet rSet; /** reference to connection object */ private IPentahoConnection connection; /** specifies whether component owns connection or not */ private boolean connectionOwner = true; /** holds the query string for ipreparedcomponent functionality */ private String preparedQuery = null; @Override public abstract boolean validateSystemSettings(); public abstract String getResultOutputName(); @Override public abstract Log getLogger(); public IPentahoResultSet getResultSet() { return rSet; } @Override protected boolean validateAction() { HQLConnectionAction connAction = null; HQLQueryAction queryAction = null; boolean actionValidated = true; try { if ( getActionDefinition() instanceof HQLQueryAction ) { queryAction = (HQLQueryAction) getActionDefinition(); actionValidated = isConnectionInfoSpecified( queryAction ); // Check if the query is defined. if ( actionValidated && ( queryAction.getQuery() == ActionInputConstant.NULL_INPUT ) ) { actionValidated = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0004_QUERY_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } // Check if output for the query is correctly defined. if ( actionValidated && ( queryAction.getOutputResultSetName() == null ) && ( queryAction.getOutputPreparedStatementName() == null ) ) { actionValidated = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0005_OUTPUT_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } } else if ( getActionDefinition() instanceof HQLConnectionAction ) { connAction = (HQLConnectionAction) getActionDefinition(); actionValidated = isConnectionInfoSpecified( connAction ); } else { actionValidated = false; error( Messages.getInstance().getErrorString( "ComponentBase.ERROR_0001_UNKNOWN_ACTION_TYPE", getActionDefinition().getElement().asXML() ) ); //$NON-NLS-1$ } } catch ( Exception e ) { actionValidated = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0006_VALIDATION_FAILED", getActionName() ), e ); //$NON-NLS-1$ } return actionValidated; } private boolean isConnectionInfoSpecified( final HQLConnectionAction connAction ) { boolean value = true; if ( connAction instanceof HQLQueryAction ) { if ( ( ( (HQLQueryAction) connAction ).getInputSharedConnection() == ActionInputConstant.NULL_INPUT ) && !isBasicConnectionInfoSpecified( connAction ) ) { value = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0003_CONNECTION_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } } else { if ( !isBasicConnectionInfoSpecified( connAction ) ) { value = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0003_CONNECTION_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } } return value; } private boolean isBasicConnectionInfoSpecified( final HQLConnectionAction connAction ) { boolean value = true; if ( connAction.getClassNames() == ActionInputConstant.NULL_INPUT ) { value = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0001_CLASS_NAMES_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } if ( connAction.getHibernateConfigResource() == null ) { value = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0002_HIBERNATE_CONFIG_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } return value; } @Override public void done() { // TODO Auto-generated method stub } @Override protected boolean executeAction() { boolean returnValue = true; try { if ( getActionDefinition() instanceof HQLQueryAction ) { HQLQueryAction queryAction = (HQLQueryAction) getActionDefinition(); String[] classNames = null; String query = queryAction.getQuery().getStringValue(); if ( queryAction.getInputSharedConnection() != ActionInputConstant.NULL_INPUT ) { connectionOwner = false; IPreparedComponent component = (IPreparedComponent) queryAction.getInputSharedConnection().getValue(); IPentahoConnection conn = component.shareConnection(); if ( IPentahoConnection.HQL_DATASOURCE.equals( conn.getDatasourceType() ) ) { connection = conn; } else { connection = null; returnValue = false; error( Messages.getInstance().getErrorString( "IPreparedComponent.ERROR_0001_INVALID_CONNECTION_TYPE", getActionName() ) ); //$NON-NLS-1$ } } else { createBasicConnection( queryAction, classNames ); } if ( connection != null ) { IActionOutput actionOutput = queryAction.getOutputPreparedStatementParam(); if ( actionOutput != null ) { // prepare the query for execution, but don't execute quite yet. prepareQuery( query ); // set the output as self, which will be used later by another component. actionOutput.setValue( this ); } else { return runQuery( connection, classNames, query ); } } } else if ( getActionDefinition() instanceof HQLConnectionAction ) { HQLConnectionAction connAction = (HQLConnectionAction) getActionDefinition(); String[] classNames = null; createBasicConnection( connAction, classNames ); if ( connection != null ) { IActionOutput outputConnection = connAction.getOutputConnectionParam(); if ( outputConnection != null ) { outputConnection.setValue( this ); } } } else { returnValue = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00011_INVALID_HQL_COMPONENT", getActionName() ) ); //$NON-NLS-1$ } } catch ( Exception e ) { returnValue = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00012_EXECUTE_FAILED", getActionName() ), e ); //$NON-NLS-1$ } return returnValue; } /* * Create the basic connection. This requires retrieving class names and catalog info. */ private void createBasicConnection( final HQLConnectionAction connAction, String[] classNames ) { boolean proceed = true; String catalog = null; if ( connAction.getClassNames() != ActionInputConstant.NULL_INPUT ) { classNames = getClassNames( connAction ); } else { proceed = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0001_CLASS_NAMES_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } if ( proceed ) { catalog = getCatalog(); if ( ( null == catalog ) || ( catalog.trim().length() <= 0 ) ) { proceed = false; error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00010_CATALOG_INFO_NOT_SPECIFIED", getActionName() ) ); //$NON-NLS-1$ } } if ( proceed ) { connection = getConnection( new File( catalog ), classNames ); if ( connection == null ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION", getActionName() ) ); //$NON-NLS-1$ } } } /* * Utitlity function to get the class names from the XML. */ private String[] getClassNames( final HQLConnectionAction connAction ) { ArrayList classNamesList = new ArrayList(); String[] classNames = null; try { String classes = connAction.getClassNames().getStringValue(); StringTokenizer st = new StringTokenizer( classes, "," ); //getInputStringValue(CLASSNAMES), ","); //$NON-NLS-1$ while ( st.hasMoreTokens() ) { String token = st.nextToken(); classNamesList.add( token.trim() ); } classNames = (String[]) classNamesList.toArray( new String[0] ); } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0008_COULD_NOT_RETRIEVE_CLASS_NAMES", getActionName() ), e ); //$NON-NLS-1$ } return classNames; } /* * Utility function to get the catalog info from hibernate config. */ private String getCatalog() { IActionResource hibernateConfigRes = ( (HQLConnectionAction) getActionDefinition() ).getHibernateConfigResource(); String catalog = null; String resAddress = null; if ( hibernateConfigRes != null ) { String resName = this.applyInputsToFormat( hibernateConfigRes.getName() ); IActionSequenceResource resource = getResource( resName ); resAddress = resource.getAddress(); if ( resAddress != null ) { catalog = this.applyInputsToFormat( resAddress ); } } return catalog; } /** * called when in prepared-component mode, this method populates the preparedQuery string and preparedParameters * object. * * @param rawQuery * @return */ protected boolean prepareQuery( final String rawQuery ) { try { if ( connection == null ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00013_NO_CONNECTION" ) ); //$NON-NLS-1$ return false; } if ( !connection.initialized() ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00013_NO_CONNECTION" ) ); //$NON-NLS-1$ return false; } if ( rawQuery != null ) { preparedQuery = applyInputsToFormat( rawQuery ); } return true; } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00014_COULD_NOT_PREPARE_QUERY", getActionName() ), e ); //$NON-NLS-1$ } return false; } /** * executes a prepared method that returns a result set executePrepared looks up any "PREPARELATER" params in the * preparedParams map. * * @param preparedParams * a map of possible parameters. * @return result set */ public IPentahoResultSet executePrepared( final Map preparedParams ) { try { if ( connection == null ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION" ) ); //$NON-NLS-1$ return null; } if ( !connection.initialized() ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION" ) ); //$NON-NLS-1$ return null; } if ( preparedQuery == null ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00016_QUERY_NOT_SPECIFIED" ) ); //$NON-NLS-1$ return null; } // parse preparedQuery, replacing any {PREPARELATER:NAME} with appropriate values String query = TemplateUtil.applyTemplate( preparedQuery, getRuntimeContext(), new MapParameterResolver( preparedParams, IPreparedComponent.PREPARE_LATER_PREFIX, getRuntimeContext() ) ); if ( ComponentBase.debug ) { debug( Messages.getInstance().getString( "HQLBaseComponent.DEBUG_RUNNING_QUERY", query ) ); //$NON-NLS-1$ } // evaluate IPentahoResultSet resultSet = connection.executeQuery( query ); rSet = resultSet; return resultSet; } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_00012_EXECUTE_FAILED", getActionName() ), e ); //$NON-NLS-1$ } return null; } protected boolean runQuery( final IPentahoConnection conn, final String[] classNames, final String query ) { try { if ( conn == null ) { return false; } rSet = ( (HQLConnection) conn ).executeQuery( query ); IActionOutput actionOutput = ( (HQLQueryAction) getActionDefinition() ).getOutputResultSetParam(); if ( actionOutput != null ) { actionOutput.setValue( rSet ); } return true; } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0007_QUERY_EXECUTION_FAILED", getActionName() ), e ); //$NON-NLS-1$ return false; } } /** * if the owner, dispose of the connection */ public void dispose() { if ( connectionOwner ) { if ( connection != null ) { connection.close(); } } connection = null; } protected IPentahoConnection getConnection( final File hbmCfgFile, final String[] classNames ) { IPentahoConnection conn = null; try { conn = (HQLConnection) PentahoConnectionFactory.getConnection( "HQL", getSession(), this ); //$NON-NLS-1$ HQLConnection hconn = (HQLConnection) conn; hconn.setConfigFile( hbmCfgFile ); hconn.setClassNames( classNames ); return conn; } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "HQLBaseComponent.ERROR_0009_COULD_NOT_ESTABLISH_CONNECTION", getActionName() ), e ); //$NON-NLS-1$ } return null; } /** * return this class's connection. This implements the IPreparedComponent interface, which may share its connection * with others. * * @return connection object */ public IPentahoConnection shareConnection() { return connection; } @Override public boolean init() { return true; } }