| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.transformation; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.StringReader; |
| import java.lang.reflect.Field; |
| import java.sql.CallableStatement; |
| import java.sql.Clob; |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.TreeMap; |
| import java.util.Vector; |
| |
| import javax.xml.transform.OutputKeys; |
| |
| import org.apache.avalon.excalibur.datasource.DataSourceComponent; |
| import org.apache.avalon.framework.activity.Disposable; |
| import org.apache.avalon.framework.configuration.Configurable; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.logger.Logger; |
| import org.apache.avalon.framework.parameters.Parameters; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.service.ServiceSelector; |
| import org.apache.cocoon.ProcessingException; |
| import org.apache.cocoon.components.sax.XMLDeserializer; |
| import org.apache.cocoon.components.sax.XMLSerializer; |
| import org.apache.cocoon.environment.SourceResolver; |
| import org.apache.cocoon.util.Tokenizer; |
| import org.apache.cocoon.xml.IncludeXMLConsumer; |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.excalibur.xml.sax.SAXParser; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| /** |
| * |
| * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a> |
| * @author <a href="mailto:balld@webslingerZ.com">Donald Ball</a> |
| * @author <a href="mailto:giacomo.pati@pwr.ch">Giacomo Pati</a> |
| * (PWR Organisation & Entwicklung) |
| * @author <a href="mailto:sven.beauprez@the-ecorp.com">Sven Beauprez</a> |
| * @author <a href="mailto:a.saglimbeni@pro-netics.com">Alfio Saglimbeni</a> |
| * @version CVS $Id: SQLTransformer.java,v 1.15 2004/03/05 13:01:55 bdelacretaz Exp $ |
| */ |
| public class SQLTransformer |
| extends AbstractSAXTransformer |
| implements Disposable, Configurable { |
| |
| /** The SQL namespace **/ |
| public static final String NAMESPACE = "http://apache.org/cocoon/SQL/2.0"; |
| |
| /** The SQL namespace element names **/ |
| public static final String MAGIC_EXECUTE_QUERY = "execute-query"; |
| public static final String MAGIC_CONNECTION = "use-connection"; |
| public static final String MAGIC_DBURL = "dburl"; |
| public static final String MAGIC_USERNAME = "username"; |
| public static final String MAGIC_PASSWORD = "password"; |
| public static final String MAGIC_NR_OF_ROWS = "show-nr-of-rows"; |
| public static final String MAGIC_QUERY = "query"; |
| public static final String MAGIC_VALUE = "value"; |
| public static final String MAGIC_DOC_ELEMENT = "doc-element"; |
| public static final String MAGIC_ROW_ELEMENT = "row-element"; |
| public static final String MAGIC_IN_PARAMETER = "in-parameter"; |
| public static final String MAGIC_IN_PARAMETER_NR_ATTRIBUTE = "nr"; |
| public static final String MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE = "value"; |
| public static final String MAGIC_OUT_PARAMETER = "out-parameter"; |
| public static final String MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE = "name"; |
| public static final String MAGIC_OUT_PARAMETER_NR_ATTRIBUTE = "nr"; |
| public static final String MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE = "type"; |
| public static final String MAGIC_ESCAPE_STRING = "escape-string"; |
| public static final String MAGIC_ERROR = "error"; |
| |
| public static final String MAGIC_NS_URI_ELEMENT = "namespace-uri"; |
| public static final String MAGIC_NS_PREFIX_ELEMENT = "namespace-prefix"; |
| |
| public static final String MAGIC_ANCESTOR_VALUE = "ancestor-value"; |
| public static final String MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE = "level"; |
| public static final String MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE = "name"; |
| public static final String MAGIC_SUBSTITUTE_VALUE = "substitute-value"; |
| public static final String MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE = "name"; |
| public static final String MAGIC_NAME_ATTRIBUTE = "name"; |
| public static final String MAGIC_STORED_PROCEDURE_ATTRIBUTE = "isstoredprocedure"; |
| public static final String MAGIC_UPDATE_ATTRIBUTE = "isupdate"; |
| public static final String CLOB_ENCODING = "clob-encoding"; |
| |
| /** The states we are allowed to be in **/ |
| protected static final int STATE_OUTSIDE = 0; |
| protected static final int STATE_INSIDE_EXECUTE_QUERY_ELEMENT = 1; |
| protected static final int STATE_INSIDE_VALUE_ELEMENT = 2; |
| protected static final int STATE_INSIDE_QUERY_ELEMENT = 3; |
| protected static final int STATE_INSIDE_ANCESTOR_VALUE_ELEMENT = 4; |
| protected static final int STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT = 5; |
| protected static final int STATE_INSIDE_IN_PARAMETER_ELEMENT = 6; |
| protected static final int STATE_INSIDE_OUT_PARAMETER_ELEMENT = 7; |
| protected static final int STATE_INSIDE_ESCAPE_STRING = 8; |
| |
| // |
| // Configuration |
| // |
| |
| /** Is the old-driver turned on? (default is off) */ |
| protected boolean oldDriver = false; |
| |
| /** How many connection attempts to do? (default is 5 times) */ |
| protected int connectAttempts = 5; |
| |
| /** How long wait between connection attempts? (default is 5000 ms) */ |
| protected int connectWaittime = 5; |
| |
| // |
| // State |
| // |
| |
| /** The list of queries that we're currently working on **/ |
| protected Vector queries; |
| |
| /** The offset of the current query in the queries list **/ |
| protected int current_query_index; |
| |
| /** The current state of the event receiving FSM **/ |
| protected int current_state; |
| |
| /** Check if nr of rows need to be written out. **/ |
| protected boolean showNrOfRows; |
| |
| /** Namespace prefix to output */ |
| protected String outPrefix; |
| |
| /** Namespace uri to output */ |
| protected String outUri; |
| |
| /** The database selector */ |
| protected ServiceSelector dbSelector; |
| |
| /** The format for serializing xml */ |
| protected Properties format; |
| |
| protected XMLSerializer compiler; |
| protected XMLDeserializer interpreter; |
| protected SAXParser parser; |
| |
| /** Encoding we use for CLOB field */ |
| protected String clobEncoding; |
| |
| /** |
| * Constructor |
| */ |
| public SQLTransformer() { |
| // FIXME (CZ) We have to get the correct encoding from |
| // somewhere else (XML Serializer?) |
| this.format = new Properties(); |
| this.format.put(OutputKeys.METHOD, "text"); |
| this.format.put(OutputKeys.ENCODING, "ISO-8859-1"); |
| this.format.put(OutputKeys.OMIT_XML_DECLARATION, "yes"); |
| this.namespaceURI = NAMESPACE; |
| } |
| |
| /** The connection used by all top level queries */ |
| protected Connection conn; |
| |
| /** |
| * Serviceable |
| */ |
| public void service( ServiceManager manager ) throws ServiceException { |
| super.service(manager); |
| this.queries = new Vector(); |
| try { |
| this.dbSelector = (ServiceSelector) manager.lookup( DataSourceComponent.ROLE + "Selector" ); |
| } catch ( ServiceException cme ) { |
| getLogger().warn( "Could not get the DataSource Selector", cme ); |
| } |
| } |
| |
| /** |
| * Recycle this component |
| */ |
| public void recycle() { |
| super.recycle(); |
| try { |
| // Close the connection used by all top level queries |
| if (this.conn != null) { |
| this.conn.close(); |
| this.conn = null; |
| } |
| } catch ( SQLException e ) { |
| getLogger().warn( "Could not close the connection", e ); |
| } |
| this.queries.clear(); |
| this.outUri = null; |
| this.outPrefix = null; |
| this.manager.release(this.parser); |
| this.parser = null; |
| this.manager.release(this.compiler); |
| this.compiler = null; |
| this.manager.release(this.interpreter); |
| this.interpreter = null; |
| } |
| |
| /** |
| * dispose |
| */ |
| public void dispose() { |
| if ( this.dbSelector != null ) { |
| this.manager.release( this.dbSelector ); |
| this.dbSelector = null; |
| } |
| } |
| |
| /** |
| * configure |
| */ |
| public void configure(Configuration conf) throws ConfigurationException { |
| super.configure(conf); |
| |
| this.oldDriver = conf.getChild("old-driver").getValueAsBoolean(false); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("old-driver is " + this.oldDriver + " for " + this); |
| } |
| |
| this.connectAttempts = conf.getChild("connect-attempts").getValueAsInteger(5); |
| this.connectWaittime = conf.getChild("connect-waittime").getValueAsInteger(5000); |
| } |
| |
| /** |
| * Setup for the current request |
| */ |
| public void setup( SourceResolver resolver, Map objectModel, |
| String source, Parameters parameters ) |
| throws ProcessingException, SAXException, IOException { |
| super.setup(resolver, objectModel, source, parameters); |
| // setup instance variables |
| this.current_query_index = -1; |
| this.current_state = SQLTransformer.STATE_OUTSIDE; |
| |
| this.showNrOfRows = parameters.getParameterAsBoolean( SQLTransformer.MAGIC_NR_OF_ROWS, false ); |
| this.clobEncoding = parameters.getParameter(SQLTransformer.CLOB_ENCODING, ""); |
| if ( getLogger().isDebugEnabled() ) { |
| if ( this.parameters.getParameter( SQLTransformer.MAGIC_CONNECTION , null ) != null ) { |
| getLogger().debug( "CONNECTION: " + this.parameters.getParameter( SQLTransformer.MAGIC_CONNECTION , null ) ); |
| } else { |
| getLogger().debug( "DBURL: " + parameters.getParameter( SQLTransformer.MAGIC_DBURL, null ) ); |
| getLogger().debug( "USERNAME: " + parameters.getParameter( SQLTransformer.MAGIC_USERNAME, null ) ); |
| } |
| getLogger().debug( "DOC-ELEMENT: " + parameters.getParameter( SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" ) ); |
| getLogger().debug( "ROW-ELEMENT: " + parameters.getParameter( SQLTransformer.MAGIC_ROW_ELEMENT, "row" ) ); |
| getLogger().debug( "NS-URI: " + parameters.getParameter( SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE ) ); |
| getLogger().debug( "NS-PREFIX: " + parameters.getParameter( SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" ) ); |
| getLogger().debug( "CLOB_ENCODING: " + clobEncoding ); |
| } |
| } |
| |
| /** |
| * This will be the meat of SQLTransformer, where the query is run. |
| */ |
| protected void executeQuery( int index ) |
| throws SAXException { |
| if ( getLogger().isDebugEnabled() ) { |
| getLogger().debug( "SQLTransformer executing query nr " + index ); |
| } |
| |
| this.outUri = getCurrentQuery().properties.getParameter( SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE ); |
| this.outPrefix = getCurrentQuery().properties.getParameter( SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" ); |
| |
| if ( !"".equals( this.outUri ) ) { |
| super.startPrefixMapping( this.outPrefix, this.outUri ); |
| } |
| |
| AttributesImpl attr = new AttributesImpl(); |
| Query query = (Query) queries.elementAt( index ); |
| boolean query_failure = false; |
| Connection conn = null; |
| try { |
| try { |
| if (index == 0) { |
| if (this.conn == null) // The first top level execute-query |
| this.conn = query.getConnection(); |
| // reuse the global connection for all top level queries |
| conn = this.conn; |
| } |
| else // index > 0, sub queries are always executed in an own connection |
| conn = query.getConnection(); |
| |
| query.setConnection(conn); |
| query.execute(); |
| } catch ( SQLException e ) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "SQLTransformer:.executeQuery() query.execute failed ", e ); |
| } |
| AttributesImpl my_attr = new AttributesImpl(); |
| this.start( query.rowset_name, my_attr ); |
| this.start( MAGIC_ERROR, my_attr); |
| this.data( e.getMessage()); |
| this.end( MAGIC_ERROR ); |
| this.end( query.rowset_name ); |
| query_failure = true; |
| } |
| if ( !query_failure ) { |
| |
| if ( this.showNrOfRows ) { |
| attr.addAttribute( NAMESPACE, query.nr_of_rows, query.nr_of_rows, "CDATA", |
| String.valueOf( query.getNrOfRows() ) ); |
| } |
| String name = query.getName(); |
| if ( name != null ) { |
| attr.addAttribute( NAMESPACE, query.name_attribute, query.name_attribute, "CDATA", |
| name ); |
| } |
| this.start( query.rowset_name, attr ); |
| attr = new AttributesImpl(); |
| |
| if ( !query.isStoredProcedure() ) { |
| while ( query.next() ) { |
| this.start( query.row_name, attr ); |
| query.serializeRow(this.manager); |
| if ( index + 1 < queries.size() ) { |
| executeQuery( index + 1 ); |
| } |
| this.end( query.row_name ); |
| } |
| } else { |
| query.serializeStoredProcedure(this.manager); |
| } |
| |
| this.end( query.rowset_name ); |
| } |
| } catch ( SQLException e ) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "SQLTransformer.executeQuery()", e ); |
| } |
| throw new SAXException( e ); |
| } finally { |
| try { |
| query.close(); |
| if (index > 0) // close the connection used by a sub query |
| conn.close(); |
| } catch ( SQLException e ) { |
| getLogger().warn( "SQLTransformer: Could not close JDBC connection", e ); |
| } |
| } |
| if ( !"".equals( this.outUri ) ) { |
| super.endPrefixMapping( this.outPrefix ); |
| } |
| } |
| |
| protected static void throwIllegalStateException( String message ) { |
| throw new IllegalStateException( "SQLTransformer: " + message ); |
| } |
| |
| protected void startExecuteQueryElement() { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_OUTSIDE: |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| current_query_index = queries.size(); |
| Query query = new Query( this, current_query_index ); |
| queries.addElement( query ); |
| current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start execute query element" ); |
| } |
| } |
| |
| protected void startValueElement( String name ) |
| throws SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| this.stack.push(name); |
| this.startTextRecording(); |
| current_state = SQLTransformer.STATE_INSIDE_VALUE_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start value element: " + |
| name ); |
| } |
| } |
| |
| protected void startQueryElement( Attributes attributes ) |
| throws SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| this.startSerializedXMLRecording(format); |
| Query q = getCurrentQuery(); |
| current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; |
| String isupdate = |
| attributes.getValue( "", SQLTransformer.MAGIC_UPDATE_ATTRIBUTE ); |
| if ( isupdate != null && !isupdate.equalsIgnoreCase( "false" ) ) |
| q.setUpdate( true ); |
| String isstoredprocedure = |
| attributes.getValue( "", SQLTransformer.MAGIC_STORED_PROCEDURE_ATTRIBUTE ); |
| if ( isstoredprocedure != null && !isstoredprocedure.equalsIgnoreCase( "false" ) ) |
| q.setStoredProcedure( true ); |
| String name = |
| attributes.getValue( "", SQLTransformer.MAGIC_NAME_ATTRIBUTE ); |
| if ( name != null ) { |
| q.setName( name ); |
| } |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start query element" ); |
| } |
| } |
| |
| protected void endQueryElement() |
| throws ProcessingException, SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: |
| final String value = this.endSerializedXMLRecording(); |
| if ( value.length() > 0 ) { |
| this.getCurrentQuery().addQueryPart( value ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "QUERY IS \"" + value + "\"" ); |
| } |
| } |
| current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a stop query element" ); |
| } |
| } |
| |
| protected void endValueElement() |
| throws SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_VALUE_ELEMENT: |
| final String name = (String)this.stack.pop(); |
| final String value = this.endTextRecording(); |
| this.getCurrentQuery().setParameter(name, value); |
| this.current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "SETTING VALUE ELEMENT name {" + |
| name + "} value {" + value + "}" ); |
| } |
| break; |
| default: |
| throwIllegalStateException( "Not expecting an end value element" ); |
| } |
| } |
| |
| protected void endExecuteQueryElement() throws SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| if ( current_query_index == 0 ) { |
| executeQuery( 0 ); |
| queries.removeAllElements(); |
| current_state = SQLTransformer.STATE_OUTSIDE; |
| } else { |
| current_query_index--; |
| current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| } |
| break; |
| default: |
| throwIllegalStateException( "Not expecting an end execute query element" ); |
| } |
| } |
| |
| protected void startAncestorValueElement( Attributes attributes ) |
| throws ProcessingException, SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: |
| int level = 0; |
| try { |
| level = Integer.parseInt( attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE ) ); |
| } catch ( Exception e ) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "SQLTransformer", e ); |
| } |
| throwIllegalStateException( "Ancestor value elements must have a " + |
| SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE + " attribute" ); |
| } |
| String name = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE ); |
| if ( name == null ) { |
| throwIllegalStateException( "Ancestor value elements must have a " + |
| SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE + " attribute" ); |
| } |
| AncestorValue av = new AncestorValue( level, name ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "ANCESTOR VALUE " + level + " " + name ); |
| } |
| |
| final String value = this.endSerializedXMLRecording(); |
| if ( value.length() > 0 ) { |
| this.getCurrentQuery().addQueryPart( value ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "QUERY IS \"" + value + "\"" ); |
| } |
| } |
| getCurrentQuery().addQueryPart( av ); |
| this.startSerializedXMLRecording(format); |
| |
| current_state = SQLTransformer.STATE_INSIDE_ANCESTOR_VALUE_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start ancestor value element" ); |
| } |
| } |
| |
| protected void endAncestorValueElement() { |
| current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; |
| } |
| |
| protected void startSubstituteValueElement( Attributes attributes ) |
| throws ProcessingException, SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: |
| String name = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE ); |
| if ( name == null ) { |
| throwIllegalStateException( "Substitute value elements must have a " + |
| SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE + " attribute" ); |
| } |
| String substitute = parameters.getParameter( name, null ); |
| //escape single quote |
| substitute = replaceCharWithString( substitute, '\'', "''" ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "SUBSTITUTE VALUE " + substitute ); |
| } |
| final String value = this.endSerializedXMLRecording(); |
| if ( value.length() > 0 ) { |
| this.getCurrentQuery().addQueryPart( value ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "QUERY IS \"" + value + "\"" ); |
| } |
| } |
| this.getCurrentQuery().addQueryPart( substitute ); |
| this.startSerializedXMLRecording(format); |
| |
| current_state = SQLTransformer.STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start substitute value element" ); |
| } |
| } |
| |
| protected void endSubstituteValueElement() { |
| current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; |
| } |
| |
| protected void startEscapeStringElement( Attributes attributes ) |
| throws ProcessingException, SAXException { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: |
| final String value = this.endSerializedXMLRecording(); |
| if ( value.length() > 0 ) { |
| this.getCurrentQuery().addQueryPart( value ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "QUERY IS \"" + value + "\"" ); |
| } |
| } |
| this.startTextRecording(); |
| |
| current_state = SQLTransformer.STATE_INSIDE_ESCAPE_STRING; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a start escape-string element" ); |
| } |
| } |
| |
| protected void endEscapeStringElement() |
| throws SAXException { |
| switch ( current_state) { |
| case SQLTransformer.STATE_INSIDE_ESCAPE_STRING: |
| String value = this.endTextRecording(); |
| if ( value.length() > 0 ) { |
| value = replaceCharWithString( value, '\'', "''" ); |
| value = replaceCharWithString( value, '\\', "\\\\" ); |
| this.getCurrentQuery().addQueryPart( value ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "QUERY IS \"" + value + "\"" ); |
| } |
| } |
| this.startSerializedXMLRecording(format); |
| current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting a end escape-string element" ); |
| } |
| } |
| |
| protected void startInParameterElement( Attributes attributes ) { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| String nr = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_IN_PARAMETER_NR_ATTRIBUTE ); |
| String value = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "IN PARAMETER NR " + nr + "; VALUE " + value ); |
| } |
| int position = Integer.parseInt( nr ); |
| getCurrentQuery().setInParameter( position, value ); |
| current_state = SQLTransformer.STATE_INSIDE_IN_PARAMETER_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting an in-parameter element" ); |
| } |
| } |
| |
| protected void endInParameterElement() { |
| current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| } |
| |
| protected void startOutParameterElement( Attributes attributes ) { |
| switch ( current_state ) { |
| case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: |
| String name = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE ); |
| String nr = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_OUT_PARAMETER_NR_ATTRIBUTE ); |
| String type = attributes.getValue( NAMESPACE, |
| SQLTransformer.MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE ); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "OUT PARAMETER NAME" + name + ";NR " + nr + "; TYPE " + type ); |
| } |
| int position = Integer.parseInt( nr ); |
| getCurrentQuery().setOutParameter( position, type, name ); |
| current_state = SQLTransformer.STATE_INSIDE_OUT_PARAMETER_ELEMENT; |
| break; |
| default: |
| throwIllegalStateException( "Not expecting an out-parameter element" ); |
| } |
| } |
| |
| protected void endOutParameterElement() { |
| current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; |
| } |
| |
| protected Query getCurrentQuery() { |
| return (Query) queries.elementAt( current_query_index ); |
| } |
| |
| protected Query getQuery( int i ) { |
| return (Query) queries.elementAt( i ); |
| } |
| |
| private String replaceCharWithString( String in, char c, String with ) { |
| Tokenizer tok; |
| StringBuffer replaced = null; |
| if ( in.indexOf( c ) > -1 ) { |
| tok = new Tokenizer( in, c ); |
| replaced = new StringBuffer(); |
| while ( tok.hasMoreTokens() ) { |
| replaced.append( tok.nextToken() ); |
| if ( tok.hasMoreTokens() ) |
| replaced.append( with ); |
| } |
| } |
| if ( replaced != null ) { |
| return replaced.toString(); |
| } else { |
| return in; |
| } |
| } |
| |
| /** |
| * Qualifies an element name by giving it a prefix. |
| * @param name the element name |
| * @param prefix the prefix to qualify with |
| * @return a namespace qualified name that is correct |
| */ |
| protected String nsQualify( String name, String prefix ) { |
| if ( name == null || "".equals( name ) ) { |
| return name; |
| } |
| if ( prefix != null && !"".equals( prefix ) ) { |
| return new StringBuffer( prefix ).append( ":" ).append( name ).toString(); |
| } else { |
| return name; |
| } |
| } |
| |
| /** |
| * ContentHandler method |
| */ |
| public void setDocumentLocator( Locator locator ) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "PUBLIC ID: " + locator.getPublicId() ); |
| getLogger().debug( "SYSTEM ID: " + locator.getSystemId() ); |
| } |
| super.setDocumentLocator( locator ); |
| } |
| |
| /** |
| * ContentHandler method |
| */ |
| public void startTransformingElement( String uri, String name, String raw, |
| Attributes attributes ) |
| throws ProcessingException, SAXException { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "RECEIVED START ELEMENT " + name ); |
| } |
| |
| if ( name.equals( SQLTransformer.MAGIC_EXECUTE_QUERY ) ) { |
| this.startExecuteQueryElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_QUERY ) ) { |
| this.startQueryElement( attributes ); |
| } else if ( name.equals( SQLTransformer.MAGIC_ANCESTOR_VALUE ) ) { |
| this.startAncestorValueElement( attributes ); |
| } else if ( name.equals( SQLTransformer.MAGIC_SUBSTITUTE_VALUE ) ) { |
| this.startSubstituteValueElement( attributes ); |
| } else if ( name.equals( SQLTransformer.MAGIC_IN_PARAMETER ) ) { |
| this.startInParameterElement( attributes ); |
| } else if ( name.equals( SQLTransformer.MAGIC_OUT_PARAMETER ) ) { |
| this.startOutParameterElement( attributes ); |
| } else if ( name.equals( SQLTransformer.MAGIC_ESCAPE_STRING ) ) { |
| this.startEscapeStringElement( attributes ); |
| } else { |
| this.startValueElement( name ); |
| } |
| } |
| |
| /** |
| * ContentHandler method |
| */ |
| public void endTransformingElement( String uri, String name, |
| String raw ) |
| throws ProcessingException, IOException, SAXException { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug( "RECEIVED END ELEMENT " + name + "(" + uri + ")" ); |
| } |
| |
| if ( name.equals( SQLTransformer.MAGIC_EXECUTE_QUERY ) ) { |
| this.endExecuteQueryElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_QUERY ) ) { |
| this.endQueryElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_ANCESTOR_VALUE ) ) { |
| this.endAncestorValueElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_SUBSTITUTE_VALUE ) ) { |
| this.endSubstituteValueElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_IN_PARAMETER ) ) { |
| this.endInParameterElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_OUT_PARAMETER ) ) { |
| this.endOutParameterElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_VALUE ) |
| || current_state == SQLTransformer.STATE_INSIDE_VALUE_ELEMENT ) { |
| this.endValueElement(); |
| } else if ( name.equals( SQLTransformer.MAGIC_ESCAPE_STRING ) ) { |
| this.endEscapeStringElement(); |
| } else { |
| super.endTransformingElement( uri, name, raw ); |
| } |
| } |
| |
| /** |
| * Helper method for generating SAX events |
| */ |
| protected void start( String name, AttributesImpl attr ) |
| throws SAXException { |
| try { |
| super.startTransformingElement( outUri, name, nsQualify( name, outPrefix ), attr ); |
| } catch (IOException ioe) { |
| throw new SAXException(ioe); |
| } catch (ProcessingException pe) { |
| throw new SAXException(pe); |
| } |
| attr.clear(); |
| } |
| |
| /** |
| * Helper method for generating SAX events |
| */ |
| protected void end( String name ) throws SAXException { |
| try { |
| super.endTransformingElement( outUri, name, nsQualify( name, outPrefix ) ); |
| } catch (IOException ioe) { |
| throw new SAXException(ioe); |
| } catch (ProcessingException pe) { |
| throw new SAXException(pe); |
| } |
| } |
| |
| /** |
| * Helper method for generating SAX events |
| */ |
| protected void data( String data ) throws SAXException { |
| if ( data != null ) { |
| super.characters( data.toCharArray(), 0, data.length() ); |
| } |
| } |
| |
| protected static String getStringValue( Object object ) { |
| if ( object instanceof byte[] ) { |
| return new String( (byte[]) object ); |
| } else if ( object instanceof char[] ) { |
| return new String( (char[]) object ); |
| } else if ( object != null ) { |
| return object.toString(); |
| } else { |
| return ""; |
| } |
| } |
| |
| public final Logger getTheLogger() { |
| return getLogger(); |
| } |
| |
| |
| class Query { |
| |
| /** Who's your daddy? **/ |
| protected SQLTransformer transformer; |
| |
| /** What index are you in daddy's queries list **/ |
| protected int query_index; |
| |
| /** SQL configuration information **/ |
| protected Parameters properties; |
| |
| /** Dummy static variables for the moment **/ |
| protected String rowset_name; |
| protected String row_name; |
| protected String nr_of_rows = "nrofrows"; |
| protected String name_attribute = "name"; |
| |
| /** The connection, once opened **/ |
| protected Connection conn; |
| |
| /** And the statements **/ |
| protected PreparedStatement pst; |
| protected CallableStatement cst; |
| |
| /** The results, of course **/ |
| protected ResultSet rs = null; |
| |
| /** And the results' metadata **/ |
| protected ResultSetMetaData md = null; |
| |
| /** If this query is actually an update (insert, update, delete) **/ |
| protected boolean isupdate = false; |
| |
| /** If this query is actually a stored procedure **/ |
| protected boolean isstoredprocedure = false; |
| |
| protected String name = null; |
| |
| /** If it is an update/etc, the return value (num rows modified) **/ |
| protected int rv = -1; |
| |
| /** The parts of the query **/ |
| protected Vector query_parts = new Vector(); |
| |
| /** In parameters **/ |
| protected HashMap inParameters = null; |
| |
| /** Out parameters **/ |
| protected HashMap outParameters = null; |
| |
| /** Mapping out parameters - objectModel **/ |
| protected HashMap outParametersNames = null; |
| |
| protected Query( SQLTransformer transformer, int query_index ) { |
| this.transformer = transformer; |
| this.query_index = query_index; |
| this.properties = new Parameters(); |
| this.properties.merge( transformer.parameters ); |
| } |
| |
| protected void setParameter( String name, String value ) { |
| properties.setParameter( name, value ); |
| } |
| |
| protected void setUpdate( boolean flag ) { |
| isupdate = flag; |
| } |
| |
| protected void setStoredProcedure( boolean flag ) { |
| isstoredprocedure = flag; |
| } |
| |
| protected boolean isStoredProcedure() { |
| return isstoredprocedure; |
| } |
| |
| protected void setName( String name ) { |
| this.name = name; |
| } |
| |
| protected String getName() { |
| return name; |
| } |
| |
| protected void setInParameter( int pos, String val ) { |
| if ( inParameters == null ) { |
| inParameters = new HashMap(); |
| } |
| inParameters.put( new Integer( pos ), val ); |
| } |
| |
| protected void setOutParameter( int pos, String type, String name ) { |
| if ( outParameters == null ) { |
| outParameters = new HashMap(); |
| outParametersNames = new HashMap(); |
| } |
| outParameters.put( new Integer( pos ), type ); |
| outParametersNames.put( new Integer( pos ), name ); |
| } |
| |
| private void registerInParameters( PreparedStatement pst ) throws SQLException { |
| if ( inParameters == null ) |
| return; |
| Iterator itInKeys = inParameters.keySet().iterator(); |
| Integer counter; |
| String value; |
| while ( itInKeys.hasNext() ) { |
| counter = (Integer) itInKeys.next(); |
| value = (String) inParameters.get( counter ); |
| try { |
| pst.setObject( counter.intValue(), value ); |
| } catch ( SQLException e ) { |
| transformer.getTheLogger().error( "Caught a SQLException", e ); |
| throw e; |
| } |
| } |
| } |
| |
| private void registerOutParameters( CallableStatement cst ) throws SQLException { |
| if ( outParameters == null ) |
| return; |
| Iterator itOutKeys = outParameters.keySet().iterator(); |
| Integer counter; |
| int index; |
| String type, className, fieldName; |
| Class clss; |
| Field fld; |
| while ( itOutKeys.hasNext() ) { |
| counter = (Integer) itOutKeys.next(); |
| type = (String) outParameters.get( counter ); |
| index = type.lastIndexOf( "." ); |
| if ( index > -1 ) { |
| className = type.substring( 0, index ); |
| fieldName = type.substring( index + 1, type.length() ); |
| } else { |
| transformer.getTheLogger().error( "Invalid SQLType: " + type, null ); |
| throw new SQLException( "Invalid SQLType: " + type); |
| } |
| try { |
| clss = Class.forName( className ); |
| fld = clss.getField( fieldName ); |
| cst.registerOutParameter( counter.intValue(), fld.getInt( fieldName ) ); |
| } catch ( Exception e ) { |
| //lots of different exceptions to catch |
| transformer.getTheLogger().error( "Invalid SQLType: " + |
| className + "." + fieldName, e ); |
| } |
| } |
| } |
| |
| protected void setConnection(Connection conn) { |
| this.conn = conn; |
| } |
| |
| /** Get a Connection. Made this a separate method to separate the logic from the actual execution. */ |
| protected Connection getConnection() throws SQLException { |
| Connection result = null; |
| |
| try { |
| final String connection = properties.getParameter( SQLTransformer.MAGIC_CONNECTION, null ); |
| if ( connection != null ) { |
| if (this.transformer.dbSelector == null) { |
| transformer.getTheLogger().error( "No DBSelector found, could not use connection: " + connection); |
| } else { |
| DataSourceComponent datasource = null; |
| |
| try { |
| datasource = (DataSourceComponent) this.transformer.dbSelector.select( connection ); |
| for ( int i = 0; i < transformer.connectAttempts && result == null; i++) { |
| try { |
| result = datasource.getConnection(); |
| } catch ( Exception e ) { |
| final long waittime = transformer.connectWaittime; |
| transformer.getTheLogger().debug( |
| "SQLTransformer$Query: could not acquire a Connection -- waiting " |
| + waittime + " ms to try again." ); |
| try { |
| Thread.sleep( waittime ); |
| } catch ( InterruptedException ie ) { |
| } |
| } |
| } |
| } catch ( ServiceException cme ) { |
| transformer.getTheLogger().error( "Could not use connection: " + connection, cme ); |
| } finally { |
| if ( datasource != null ) this.transformer.dbSelector.release( datasource ); |
| } |
| |
| if (result == null) { |
| throw new SQLException("Failed to obtain connection. Made " |
| + transformer.connectAttempts + " attempts with " |
| + transformer.connectWaittime + "ms interval"); |
| } |
| } |
| } else { |
| final String dburl = properties.getParameter( SQLTransformer.MAGIC_DBURL, null ); |
| final String username = properties.getParameter( SQLTransformer.MAGIC_USERNAME, null ); |
| final String password = properties.getParameter( SQLTransformer.MAGIC_PASSWORD, null ); |
| |
| if ( username == null || password == null ) { |
| result = DriverManager.getConnection( dburl ); |
| } else { |
| result = DriverManager.getConnection( dburl, username, |
| password ); |
| } |
| } |
| } catch ( SQLException e ) { |
| transformer.getTheLogger().error( "Caught a SQLException", e ); |
| throw e; |
| } |
| |
| return result; |
| } |
| |
| protected void execute() throws SQLException { |
| if (this.conn == null) { |
| throw new SQLException("A connection must be set before executing a query"); |
| } |
| |
| this.rowset_name = properties.getParameter( SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" ); |
| this.row_name = properties.getParameter( SQLTransformer.MAGIC_ROW_ELEMENT, "row" ); |
| |
| Enumeration enum = query_parts.elements(); |
| StringBuffer sb = new StringBuffer(); |
| while ( enum.hasMoreElements() ) { |
| Object object = enum.nextElement(); |
| if ( object instanceof String ) { |
| sb.append( (String) object ); |
| } else if ( object instanceof AncestorValue ) { |
| /** Do a lookup into the ancestors' result's values **/ |
| AncestorValue av = (AncestorValue) object; |
| Query query = transformer.getQuery( query_index - av.level ); |
| sb.append( query.getColumnValue( av.name ) ); |
| } |
| } |
| |
| String query = StringUtils.replace(sb.toString().trim(), "\r", " ", -1); |
| // Test, if this is an update (by comparing with select) |
| if ( !isstoredprocedure && !isupdate) { |
| if (query.length() > 6 && !query.substring(0,6).equalsIgnoreCase("SELECT")) { |
| isupdate = true; |
| } |
| } |
| if (transformer.getTheLogger().isDebugEnabled()) { |
| transformer.getTheLogger().debug( "EXECUTING " + query ); |
| } |
| |
| try { |
| if ( !isstoredprocedure ) { |
| if ( oldDriver ) { |
| pst = conn.prepareStatement( query ); |
| } else { |
| pst = conn.prepareStatement( query, |
| ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| } else { |
| if ( oldDriver ) { |
| cst = conn.prepareCall( query ); |
| } else { |
| cst = conn.prepareCall( query, |
| ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| registerOutParameters( cst ); |
| pst = cst; |
| } |
| |
| registerInParameters( pst ); |
| boolean result = pst.execute(); |
| if ( result ) { |
| rs = pst.getResultSet(); |
| md = rs.getMetaData(); |
| } else { |
| rv = pst.getUpdateCount(); |
| } |
| } catch ( SQLException e ) { |
| transformer.getTheLogger().error( "Caught a SQLException", e ); |
| throw e; |
| } finally { |
| // Not closing the connection here fixes bug 12173! |
| // conn.close(); |
| // conn = null; // To make sure we don't use this connection again. |
| } |
| } |
| |
| protected int getNrOfRows() throws SQLException { |
| int nr = 0; |
| if ( rs != null ) { |
| if ( oldDriver ) { |
| nr = -1; |
| } else { |
| try { |
| rs.last(); |
| nr = rs.getRow(); |
| rs.beforeFirst(); |
| } catch ( NullPointerException e ) { |
| // A NullPointerException here crashes a whole lot of C2 -- catching it so it won't do any harm for now, but seems like it should be solved seriously |
| getTheLogger().error( "NPE while getting the nr of rows", e ); |
| } |
| } |
| } else { |
| if ( outParameters != null ) { |
| nr = outParameters.size(); |
| } |
| } |
| return nr; |
| } |
| |
| protected String getColumnValue( int i ) throws SQLException { |
| int numberOfChar = 1024; |
| String retval = SQLTransformer.getStringValue( rs.getObject( i ) ); |
| |
| if (rs.getMetaData().getColumnType(i) == 8) { |
| retval = SQLTransformer.getStringValue( rs.getBigDecimal( i ) ); |
| } else if (rs.getMetaData().getColumnType(i) == java.sql.Types.CLOB) { |
| Clob clob = rs.getClob(i); |
| InputStream inputStream = clob.getAsciiStream(); |
| byte[] readByte = new byte[numberOfChar]; |
| StringBuffer buffer = new StringBuffer(); |
| try { |
| while(inputStream.read(readByte) > -1) { |
| String string = new String(readByte, clobEncoding); |
| buffer.append(string); |
| } |
| } catch(java.io.IOException ioException) { |
| throw new SQLException("Error reading stream from CLOB"); |
| } |
| retval = buffer.toString(); |
| } |
| return retval; |
| } |
| |
| //fix not applied here because there is no metadata from Name -> number and coltype |
| //for a given "name" versus number. That being said this shouldn't be an issue |
| //as this function is only called for ancestor lookups. |
| protected String getColumnValue( String name ) throws SQLException { |
| String retval = SQLTransformer.getStringValue( rs.getObject( name ) ); |
| // if (rs.getMetaData().getColumnType( name ) == 8) |
| // retval = transformer.getStringValue( rs.getBigDecimal( name ) ); |
| return retval; |
| } |
| |
| protected boolean next() throws SQLException { |
| // if rv is not -1, then an SQL insert, update, etc, has |
| // happened (see JDBC docs - return codes for executeUpdate) |
| if ( rv != -1 ) |
| return false; |
| try { |
| if ( rs == null || !rs.next() ) { |
| //close(); |
| return false; |
| } |
| } catch ( NullPointerException e ) { |
| getTheLogger().debug( "NullPointerException, returning false.", e ); |
| return false; |
| } |
| return true; |
| } |
| |
| protected void close() throws SQLException { |
| try { |
| if ( rs != null ) |
| try { |
| //getTheLogger().debug("Trying to close resultset "+rs.toString()); |
| rs.close(); |
| rs = null; // This prevents us from using the resultset again. |
| //250getTheLogger().debug("Really closed the resultset now."); |
| } catch ( NullPointerException e ) { |
| getTheLogger().debug( "NullPointer while closing the resultset.", e ); |
| } |
| if ( pst != null ) |
| pst.close(); |
| pst = null; // Prevent using pst again. |
| if ( cst != null ) |
| cst.close(); |
| cst = null; // Prevent using cst again. |
| } finally { |
| conn = null; |
| } |
| } |
| |
| protected void addQueryPart( Object object ) { |
| query_parts.addElement( object ); |
| } |
| |
| protected void serializeData(ServiceManager manager, String value) |
| throws SQLException, SAXException { |
| if (value != null) { |
| value = value.trim(); |
| // Could this be XML ? |
| if ( value.length() > 0 && value.charAt(0) == '<') { |
| try { |
| String stripped = value; |
| |
| // Strip off the XML Declaration if there is one! |
| if( stripped.startsWith( "<?xml " ) ) { |
| stripped = stripped.substring( stripped.indexOf( "?>" ) + 2 ); |
| } |
| |
| if (transformer.parser == null) { |
| transformer.parser = (SAXParser)manager.lookup(SAXParser.ROLE); |
| } |
| if (transformer.compiler == null) { |
| transformer.compiler = (XMLSerializer)manager.lookup(XMLSerializer.ROLE); |
| } |
| if (transformer.interpreter == null) { |
| transformer.interpreter = (XMLDeserializer)manager.lookup(XMLDeserializer.ROLE); |
| } |
| transformer.parser.parse(new InputSource(new StringReader("<root>" + stripped + "</root>")), |
| transformer.compiler); |
| |
| IncludeXMLConsumer filter = new IncludeXMLConsumer(transformer, transformer); |
| filter.setIgnoreRootElement(true); |
| |
| transformer.interpreter.setConsumer(filter); |
| |
| transformer.interpreter.deserialize(transformer.compiler.getSAXFragment()); |
| } catch (Exception local) { |
| // FIXME: bad coding "catch(Exception)" |
| // if an exception occured the data was not xml |
| transformer.data(value); |
| } finally { |
| // otherwise serializer won't be reset |
| if (transformer.compiler!=null){ |
| manager.release(transformer.compiler); |
| transformer.compiler = null; |
| } |
| } |
| } else { |
| transformer.data(value); |
| } |
| } |
| } |
| |
| protected void serializeRow(ServiceManager manager) |
| throws SQLException, SAXException { |
| AttributesImpl attr = new AttributesImpl(); |
| if ( !isupdate && !isstoredprocedure ) { |
| for ( int i = 1; i <= md.getColumnCount(); i++ ) { |
| transformer.start( md.getColumnName( i ).toLowerCase(), attr ); |
| this.serializeData(manager, getColumnValue( i ) ); |
| transformer.end( md.getColumnName( i ).toLowerCase() ); |
| } |
| } else if ( isupdate && !isstoredprocedure ) { |
| transformer.start( "returncode", attr ); |
| this.serializeData(manager, String.valueOf( rv ) ); |
| transformer.end( "returncode" ); |
| rv = -1; // we only want the return code shown once. |
| } |
| } |
| |
| protected void serializeStoredProcedure(ServiceManager manager) |
| throws SQLException, SAXException { |
| if ( outParametersNames == null || cst == null ) |
| return; |
| //make sure output follows order as parameter order in stored procedure |
| Iterator itOutKeys = ( new TreeMap( outParameters ) ).keySet().iterator(); |
| Integer counter; |
| AttributesImpl attr = new AttributesImpl(); |
| try { |
| while ( itOutKeys.hasNext() ) { |
| counter = (Integer) itOutKeys.next(); |
| try { |
| if ( cst == null ) getTheLogger().debug( "SQLTransformer: cst is null" ); |
| if ( counter == null ) getTheLogger().debug( " SQLTransformer: counter is null" ); |
| Object obj = cst.getObject( counter.intValue() ); |
| if ( !( obj instanceof ResultSet ) ) { |
| transformer.start( (String) outParametersNames.get( counter ), attr ); |
| this.serializeData(manager, SQLTransformer.getStringValue( obj ) ); |
| transformer.end( (String) outParametersNames.get( counter ) ); |
| } else { |
| ResultSet rs = (ResultSet) obj; |
| try { |
| transformer.start( (String) outParametersNames.get( counter ), attr ); |
| ResultSetMetaData md = rs.getMetaData(); |
| while ( rs.next() ) { |
| transformer.start( this.row_name, attr ); |
| for ( int i = 1; i <= md.getColumnCount(); i++ ) { |
| transformer.start( md.getColumnName( i ).toLowerCase(), attr ); |
| if ( md.getColumnType( i ) == 8 ) { //prevent nasty exponent notation |
| this.serializeData(manager, SQLTransformer.getStringValue( rs.getBigDecimal( i ) )); |
| } else { |
| this.serializeData(manager, SQLTransformer.getStringValue( rs.getObject( i ) )); |
| } |
| transformer.end( md.getColumnName( i ).toLowerCase() ); |
| } |
| transformer.end( this.row_name ); |
| } |
| } finally { |
| rs.close(); |
| rs = null; |
| } |
| transformer.end( (String) outParametersNames.get( counter ) ); |
| } |
| } catch ( SQLException e ) { |
| transformer.getTheLogger().error( "Caught a SQLException", e ); |
| throw e; |
| } |
| } |
| } finally { |
| //close(); |
| } |
| } |
| } |
| |
| private class AncestorValue { |
| protected int level; |
| protected String name; |
| |
| protected AncestorValue( int level, String name ) { |
| this.level = level; |
| this.name = name; |
| } |
| } |
| |
| } |