haul 2002/10/18 07:04:28
Added: src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb
Server.java ServerImpl.java
src/blocks/hsqldb/conf hsqldb.xconf hsqldb.xroles
src/blocks/databases/java/org/apache/cocoon/util
JDBCTypeConversions.java JDBCxlobHelper.java
src/blocks/databases/java/org/apache/cocoon/transformation
SQLTransformer.java
src/blocks/databases/java/org/apache/cocoon/reading
DatabaseReader.java
src/blocks/databases/java/org/apache/cocoon/components/modules/input
CollectionMetaModule.java
src/blocks/databases/java/org/apache/cocoon/components/modules/database
AbstractAutoIncrementModule.java
AutoIncrementModule.java
HsqlIdentityAutoIncrementModule.java
IfxSerialAutoIncrementModule.java
ManualAutoIncrementModule.java
MysqlAutoIncrementModule.java
PgsqlAutoIncrementModule.java package.html
src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp
EsqlConnection.java EsqlConnectionCocoon2.java
EsqlHelper.java EsqlQuery.java
src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java
esql.xsl
src/blocks/databases/java/org/apache/cocoon/acting
AbstractDatabaseAction.java DatabaseAddAction.java
DatabaseAuthenticatorAction.java
DatabaseCookieAuthenticatorAction.java
DatabaseDeleteAction.java DatabaseSelectAction.java
DatabaseUpdateAction.java
DbXMLAuthenticatorAction.java OraAddAction.java
OraUpdateAction.java
src/blocks/databases/java/org/apache/cocoon/acting/modular
DatabaseAction.java DatabaseAddAction.java
DatabaseDeleteAction.java DatabaseQueryAction.java
DatabaseSelectAction.java DatabaseUpdateAction.java
package.html
src/blocks/databases/conf databases-trans.xmap
datasources.xconf db-modules-input.xconf
db-modules.xconf db-modules.xroles esql.xconf
Log:
New block for database related stuff
New block for hsqldb related stuff
Minor changes to module related stuff (i.e. defaults changed
to new names)
Minor additions to modules
New ChainMetaModule implementing chaining as discussed on list
Not finished:
- database samples not yet in block
- change to InputModule Interface to use Iterator instead of Enumeration
- other minor tweaks and corrections
Revision Changes Path
1.1
xml-cocoon2/src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb/Server.java
Index: Server.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.hsqldb;
import org.apache.avalon.framework.component.Component;
/**
*
* @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
* @version CVS $Id: Server.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public interface Server extends Component {
String ROLE = Server.class.getName();
}
1.1
xml-cocoon2/src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb/ServerImpl.java
Index: ServerImpl.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.hsqldb;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Enumeration;
/**
* This class runs an instance of HSQLDB Server.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a>
* @version CVS $Id: ServerImpl.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class ServerImpl extends AbstractLogEnabled
implements Server,
Parameterizable,
Contextualizable,
ThreadSafe,
Runnable,
Startable {
/** Port which HSQLDB server will listen to */
private String port;
/** Arguments for running the server */
private String arguments[] = new String[8];
/** Check if the server has already been started */
private boolean started = false;
/**
* Initialize the ServerImpl.
* A few options can be used :
* <UL>
* <LI>port = port where the server is listening</LI>
* <LI>silent = display all queries</LI>
* <LI>trace = print JDBC trace messages</LI>
* </UL>
*/
public void parameterize(Parameters params) {
this.getLogger().debug("Parameterize ServerImpl");
arguments[0] = "-port";
arguments[1] = this.port = params.getParameter("port", "9002");
arguments[2] = "-silent";
arguments[3] = params.getParameter("silent","true");
arguments[4] = "-trace";
arguments[5] = params.getParameter("trace","false");
arguments[4] = "-no_system_exit";
arguments[5] = "true";
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("Configure ServerImpl with port: " +
arguments[1]
+ ", silent: " + arguments[3]
+ ", trace: " +arguments[5]);
}
}
/** Contextualize this class */
public void contextualize(Context context) throws ContextException {
org.apache.cocoon.environment.Context ctx =
(org.apache.cocoon.environment.Context)
context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
// test if we are running inside a WAR file
final String dbPath = ctx.getRealPath("/WEB-INF/db");
if (dbPath == null) {
throw new ContextException("The hsqldb cannot be used inside a
WAR file.");
}
try {
arguments[6] = "-database";
arguments[7] = new File(dbPath).getCanonicalPath();
arguments[7] += File.separator + "cocoondb";
getLogger().debug("database is " + arguments[7]);
} catch (MalformedURLException e) {
getLogger().error("MalformedURLException - Could not get database
directory ", e);
} catch (IOException e) {
getLogger().error("IOException - Could not get database directory
", e);
}
}
/** Start the server */
public void start() {
if (!started) {
// FIXME (VG): This dirty hack here is till shutdown issue is
resolved
File file = new File(arguments[7] + ".backup");
if (file.exists() && file.delete()) {
getLogger().info("HSQLDB backup file has been deleted.");
}
Thread server = new Thread(this);
this.getLogger().debug("Intializing hsqldb server thread");
server.setPriority(Thread.currentThread().getPriority());
server.setDaemon(true);
server.setName("hsqldb server");
server.start();
}
}
/** Stop the server */
public void stop() {
if (started) {
try {
getLogger().debug("Shutting down HSQLDB");
Connection connection =
DriverManager.getConnection("jdbc:hsqldb:hsql://localhost:" + this.port, "sa",
"");
Statement statement = connection.createStatement();
statement.executeQuery("SHUTDOWN");
try {
connection.close();
} catch (SQLException e) {
getLogger().debug("Shutting down HSQLDB: Ignoring
exception: " + e);
}
} catch (Exception e){
getLogger().error("Error while shutting down HSQLDB", e);
}
getLogger().debug("Shutting down HSQLDB: Done");
}
}
public void run() {
if(!started) {
started = true;
try {
getLogger().debug("HSQLDB Server arguments are as follows:");
for(int i=0;i<8;i++) {
getLogger().debug(i + " : " + arguments[i]);
}
org.hsqldb.Server.main(arguments);
} catch(Exception e){
getLogger().error("Got exception", e);
} finally {
started = false;
}
}
}
}
1.1 xml-cocoon2/src/blocks/hsqldb/conf/hsqldb.xconf
Index: hsqldb.xconf
===================================================================
<?xml version="1.0"?>
<xconf xpath="/cocoon" unless="hsqldb-server" insert-before="xml-parser">
<!-- HSQLDB Server for samples:
Comment this section out if you don't care about the samples.
port : number port where the server is listening
silent : true/false display all queries
trace : true/false display JDBC trace messages
-->
<hsqldb-server class="org.apache.cocoon.components.hsqldb.ServerImpl"
logger="core.hsqldb-server"
pool-max="1" pool-min="1">
<parameter name="port" value="9002"/>
<parameter name="silent" value="true"/>
<parameter name="trace" value="false"/>
</hsqldb-server>
</xconf>
1.1 xml-cocoon2/src/blocks/hsqldb/conf/hsqldb.xroles
Index: hsqldb.xroles
===================================================================
<?xml version="1.0"?>
<xroles xpath="/role-list" unless="[EMAIL
PROTECTED]'org.apache.cocoon.components.hsqldb.Server']">
<role name="org.apache.cocoon.components.hsqldb.Server"
shorthand="hsqldb-server"
default-class="org.apache.cocoon.components.hsqldb.ServerImpl"/>
</xroles>
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/util/JDBCTypeConversions.java
Index: JDBCTypeConversions.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.util;
import java.io.*;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Time;
import java.sql.Date;
import java.sql.Array;
import java.sql.Types;
import java.sql.Clob;
import java.sql.Struct;
import java.math.BigDecimal;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.excalibur.source.Source;
/**
* Provide some utility methods to read from JDBC result sets or store
* them to JDBC statements. Largely copied from
* org.apache.cocoon.acting.AbstractDatabaseAction.
*
*/
public class JDBCTypeConversions {
public static final Map typeConstants;
static {
/** Initialize the map of type names to jdbc column types.
Note that INTEGER, BLOB, and VARCHAR column types map to more than
one type name. **/
Map constants = new HashMap();
constants.put("ascii", new Integer(Types.CLOB));
constants.put("big-decimal", new Integer(Types.BIGINT));
constants.put("binary", new Integer(Types.BLOB));
constants.put("boolean", new Integer(Types.BIT));
constants.put("byte", new Integer(Types.TINYINT));
constants.put("string", new Integer(Types.VARCHAR));
constants.put("date", new Integer(Types.DATE));
constants.put("double", new Integer(Types.DOUBLE));
constants.put("float", new Integer(Types.FLOAT));
constants.put("int", new Integer(Types.INTEGER));
constants.put("long", new Integer(Types.NUMERIC));
constants.put("short", new Integer(Types.SMALLINT));
constants.put("time", new Integer(Types.TIME));
constants.put("time-stamp", new Integer(Types.TIMESTAMP));
constants.put("array", new Integer(Types.ARRAY));
constants.put("row", new Integer(Types.STRUCT));
constants.put("object", new Integer(Types.OTHER));
typeConstants = Collections.unmodifiableMap(constants);
}
/**
* Converts an object to a JDBC type. This has just been started
* and does not do much at the moment.
*
*/
public static Object convert(Object value, String jType) {
Object object=null;
if (jType.equalsIgnoreCase("string")) {
if (value instanceof String) {
object = value;
} else {
object = value.toString();
}
} else if (jType.equalsIgnoreCase("int")) {
if (value instanceof String) {
object = Integer.decode((String)value);
} else if (value instanceof Integer) {
object = value;
} else {
//
}
} else if (jType.equalsIgnoreCase("long")) {
if (value instanceof String) {
object = Long.decode((String)value);
} else if (value instanceof Long) {
object = value;
} else {
//
}
} else {
// other types need parsing & creation
//
}
return object;
}
/**
* Get the Statement column so that the results are mapped correctly.
* (this has been copied from AbstractDatabaseAction and modified
slightly)
*/
public static Object getColumn(ResultSet set, Configuration column )
throws Exception {
Integer type = (Integer)
JDBCTypeConversions.typeConstants.get(column.getAttribute("type"));
String dbcol = column.getAttribute("name");
Object value = null;
switch (type.intValue()) {
case Types.CLOB:
Clob dbClob = set.getClob(dbcol);
int length = (int) dbClob.length();
InputStream asciiStream = new
BufferedInputStream(dbClob.getAsciiStream());
byte[] buffer = new byte[length];
asciiStream.read(buffer);
String str = new String(buffer);
asciiStream.close();
value = str;
break;
case Types.BIGINT:
value = set.getBigDecimal(dbcol);
break;
case Types.TINYINT:
value = new Byte(set.getByte(dbcol));
break;
case Types.VARCHAR:
value = set.getString(dbcol);
break;
case Types.DATE:
value = set.getDate(dbcol);
break;
case Types.DOUBLE:
value = new Double(set.getDouble(dbcol));
break;
case Types.FLOAT:
value = new Float(set.getFloat(dbcol));
break;
case Types.INTEGER:
value = new Integer(set.getInt(dbcol));
break;
case Types.NUMERIC:
value = new Long(set.getLong(dbcol));
break;
case Types.SMALLINT:
value = new Short(set.getShort(dbcol));
break;
case Types.TIME:
value = set.getTime(dbcol);
break;
case Types.TIMESTAMP:
value = set.getTimestamp(dbcol);
break;
case Types.ARRAY:
value = set.getArray(dbcol); // new Integer(set.getInt(dbcol));
break;
case Types.BIT:
value = new Integer(set.getInt(dbcol));
break;
case Types.CHAR:
value = new Integer(set.getInt(dbcol));
break;
case Types.STRUCT:
value = (Struct) set.getObject(dbcol);
break;
case Types.OTHER:
value = set.getObject(dbcol);
break;
default:
// The blob types have to be requested separately, via a Reader.
value = "";
break;
}
return value;
}
/**
* Set the Statement column so that the results are mapped correctly.
*
* @param statement the prepared statement
* @param position the position of the column
* @param request the request
* @param entry the configuration object
* @param param the name of the request parameter
* @param value the value of the column
* @param rowIndex the index of the current row for manyrows inserts
*/
public static void setColumn(PreparedStatement statement, int position,
Object value, Integer typeObject) throws Exception {
if (value instanceof String) {
value = ((String) value).trim();
}
if (typeObject == null) {
throw new SQLException("Can't set column because the type is
unrecognized");
}
if (value == null) {
/** If the value is null, set the column value null and return **/
statement.setNull(position, typeObject.intValue());
return;
}
if ("".equals(value)) {
switch (typeObject.intValue()) {
case Types.CHAR:
case Types.CLOB:
case Types.VARCHAR:
/** If the value is an empty string and the column is
a string type, we can continue **/
break;
default:
/** If the value is an empty string and the column
is something else, we treat it as a null value **/
statement.setNull(position, typeObject.intValue());
return;
}
}
File file = null;
switch (typeObject.intValue()) {
case Types.CLOB:
int length = -1;
InputStream asciiStream = null;
if (value instanceof File) {
File asciiFile = (File) value;
asciiStream = new BufferedInputStream(new
FileInputStream(asciiFile));
length = (int) asciiFile.length();
} else if (value instanceof JDBCxlobHelper) {
asciiStream = ((JDBCxlobHelper) value).inputStream;
length = ((JDBCxlobHelper) value).length;
} else if (value instanceof Source) {
asciiStream = ((Source) value).getInputStream();
length = (int)((Source) value).getContentLength();
} else {
String asciiText = (String) value;
asciiStream = new BufferedInputStream(new
ByteArrayInputStream(asciiText.getBytes()));
length = asciiText.length();
}
statement.setAsciiStream(position, asciiStream, length);
break;
case Types.BIGINT:
BigDecimal bd = null;
if (value instanceof BigDecimal) {
bd = (BigDecimal) value;
} else {
bd = new BigDecimal((String) value);
}
statement.setBigDecimal(position, bd);
break;
case Types.TINYINT:
Byte b = null;
if (value instanceof Byte) {
b = (Byte) value;
} else {
b = new Byte((String) value);
}
statement.setByte(position, b.byteValue());
break;
case Types.DATE:
Date d = null;
if (value instanceof Date) {
d = (Date) value;
} else if (value instanceof java.util.Date) {
d = new Date(((java.util.Date) value).getTime());
}
statement.setDate(position, d);
break;
case Types.DOUBLE:
Double db = null;
if (value instanceof Double) {
db = (Double) value;
} else {
db = new Double((String) value);
}
statement.setDouble(position, db.doubleValue());
break;
case Types.FLOAT:
Float f = null;
if (value instanceof Float) {
f = (Float) value;
} else {
f = new Float((String) value);
}
statement.setFloat(position, f.floatValue());
break;
case Types.NUMERIC:
Long l = null;
if (value instanceof Long) {
l = (Long) value;
} else {
l = new Long((String) value);
}
statement.setLong(position, l.longValue());
break;
case Types.SMALLINT:
Short s = null;
if (value instanceof Short) {
s = (Short) value;
} else {
s = new Short((String) value);
}
statement.setShort(position, s.shortValue());
break;
case Types.TIME:
Time t = null;
if (value instanceof Time) {
t = (Time) value;
}
statement.setTime(position, t);
break;
case Types.TIMESTAMP:
Timestamp ts = null;
if (value instanceof Time) {
ts = (Timestamp) value;
}
statement.setTimestamp(position, ts);
break;
case Types.ARRAY:
statement.setArray(position, (Array) value); // no way to
convert string to array
break;
case Types.STRUCT:
case Types.OTHER:
statement.setObject(position, value);
break;
case Types.LONGVARBINARY:
statement.setTimestamp(position, new Timestamp((new
java.util.Date()).getTime()));
case Types.VARCHAR:
statement.setString(position, (String) value);
break;
case Types.BLOB:
if (value instanceof JDBCxlobHelper) {
statement.setBinaryStream(position,
((JDBCxlobHelper)value).inputStream, ((JDBCxlobHelper)value).length);
} else if (value instanceof Source){
statement.setBinaryStream(position,
((Source)value).getInputStream(), (int)((Source)value).getContentLength());
} else {
if (value instanceof File) {
file = (File)value;
} else if (value instanceof String) {
file = new File((String)value);
} else {
throw new SQLException("Invalid type for blob:
"+value.getClass().getName());
}
//InputStream input = new BufferedInputStream(new
FileInputStream(file));
FileInputStream input = new FileInputStream(file);
statement.setBinaryStream(position, input,
(int)file.length());
}
break;
case Types.INTEGER:
Integer i = null;
if (value instanceof Integer) {
i = (Integer) value;
} else if (value instanceof java.lang.Number) {
i = new Integer(((java.lang.Number) value).intValue());
} else {
i = new Integer(value.toString());
}
statement.setInt(position, i.intValue());
break;
case Types.BIT:
Boolean bo = null;
if (value instanceof Boolean) {
bo = (Boolean) value;
} else if (value instanceof java.lang.Number) {
bo = new Boolean(((java.lang.Number)
value).intValue()==1);
} else {
bo = new Boolean(value.toString());
}
statement.setBoolean(position, bo.booleanValue());
break;
default:
throw new SQLException("Impossible exception - invalid type
");
}
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/util/JDBCxlobHelper.java
Index: JDBCxlobHelper.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.util;
import java.io.InputStream;
/**
* Helper to pass a length plus an InputStream to JDBCTypeConversions
* to insert BLOB (setBinaryStream) or CLOB (setAsciiStream) via data using
* org.apache.cocoon.acting.modular.DatabaseAction. Create an input module
* that returns an instance of this class and use that in your database.xml
*
*/
public class JDBCxlobHelper {
public int length = 0;
public InputStream inputStream = null;
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/transformation/SQLTransformer.java
Index: SQLTransformer.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.transformation;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.excalibur.xml.Parser;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.*;
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.parameters.Parameters;
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.avalon.framework.logger.Logger;
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;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;
import javax.xml.transform.OutputKeys;
/**
*
* @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Giacomo Pati</a>
* (PWR Organisation & Entwicklung)
* @author <a href="mailto:[EMAIL PROTECTED]">Sven Beauprez</a>
* @version CVS $Id: SQLTransformer.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class SQLTransformer
extends AbstractSAXTransformer
implements Composable, 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";
/** 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) */
private boolean oldDriver = false;
/** How many connection attempts to do? (default is 5 times) */
private int connectAttempts = 5;
/** How long wait between connection attempts? (default is 5000 ms) */
private 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 prefix of our namespace to listen to */
protected String inPrefix;
/** The database selector */
protected ComponentSelector dbSelector;
/** The format for serializing xml */
protected Properties format;
protected XMLSerializer compiler;
protected XMLDeserializer interpreter;
protected Parser parser;
/**
* 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;
}
/**
* Composable
*/
public void compose( ComponentManager manager ) {
super.compose(manager);
this.queries = new Vector();
try {
this.dbSelector = (ComponentSelector) manager.lookup(
DataSourceComponent.ROLE + "Selector" );
} catch ( ComponentException cme ) {
this.getLogger().warn( "Could not get the DataSource Selector",
cme );
}
}
/**
* Recycle this component
*/
public void recycle() {
super.recycle();
this.queries.clear();
this.outUri = null;
this.inPrefix = 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( (Component) this.dbSelector );
}
}
/**
* configure
*/
public void configure( Configuration conf ) throws ConfigurationException
{
super.configure( conf );
if ( conf != null ) {
this.oldDriver = conf.getChild( "old-driver" ).getValueAsBoolean(
false );
if (this.getLogger().isDebugEnabled()) {
this.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 );
if ( this.getLogger().isDebugEnabled() ) {
if ( this.parameters.getParameter(
SQLTransformer.MAGIC_CONNECTION , null ) != null ) {
this.getLogger().debug( "CONNECTION: " +
this.parameters.getParameter( SQLTransformer.MAGIC_CONNECTION , null ) );
} else {
this.getLogger().debug( "DBURL: " + parameters.getParameter(
SQLTransformer.MAGIC_DBURL, null ) );
this.getLogger().debug( "USERNAME: " +
parameters.getParameter( SQLTransformer.MAGIC_USERNAME, null ) );
}
this.getLogger().debug( "DOC-ELEMENT: " +
parameters.getParameter( SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" ) );
this.getLogger().debug( "ROW-ELEMENT: " +
parameters.getParameter( SQLTransformer.MAGIC_ROW_ELEMENT, "row" ) );
this.getLogger().debug( "NS-URI: " + parameters.getParameter(
SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE ) );
this.getLogger().debug( "NS-PREFIX: " + parameters.getParameter(
SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" ) );
}
}
/**
* This will be the meat of SQLTransformer, where the query is run.
*/
protected void executeQuery( int index )
throws SAXException {
if ( this.getLogger().isDebugEnabled() ) {
this.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;
try {
try {
query.execute();
} catch ( SQLException e ) {
if (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
getLogger().debug( "SQLTransformer.executeQuery()", e );
}
throw new SAXException( e );
} finally {
try {
query.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.getLogger().debug( "ANCESTOR VALUE " + level + " " +
name );
}
final String value = this.endSerializedXMLRecording();
if ( value.length() > 0 ) {
this.getCurrentQuery().addQueryPart( value );
if (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.getLogger().debug( "SUBSTITUTE VALUE " + substitute
);
}
final String value = this.endSerializedXMLRecording();
if ( value.length() > 0 ) {
this.getCurrentQuery().addQueryPart( value );
if (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.getLogger().isDebugEnabled()) {
this.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 (this.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 startPrefixMapping( String prefix, String uri )
throws SAXException {
if ( uri.equals( NAMESPACE ) ) {
if (inPrefix != null) {
super.startPrefixMapping( inPrefix, NAMESPACE);
}
inPrefix = prefix;
} else {
super.startPrefixMapping( prefix, uri );
}
}
/**
* ContentHandler method
*/
public void endPrefixMapping( String prefix )
throws SAXException {
if ( !prefix.equals( inPrefix ) ) {
super.endPrefixMapping( prefix );
}
}
/**
* 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 (this.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 (this.getLogger().isDebugEnabled()) {
this.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
*/
private void attribute( AttributesImpl attr, String name, String value ) {
attr.addAttribute( outUri, name, nsQualify( name, outPrefix ),
"CDATA", value );
}
/**
* Helper method for generating SAX events
*/
private 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
*/
private 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
*/
private 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 );
}
}
}
/** 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 ( ComponentException 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 {
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 = sb.toString().trim();
// 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 );
}
conn = getConnection();
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 {
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 {
String retval = transformer.getStringValue( rs.getObject( i ) );
if (rs.getMetaData().getColumnType(i) == 8)
retval = transformer.getStringValue( rs.getBigDecimal( i ) );
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 = transformer.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 {
if ( conn != null )
conn.close();
conn = null;
}
}
protected void addQueryPart( Object object ) {
query_parts.addElement( object );
}
protected void serializeData(ComponentManager manager,
String value)
throws SQLException, SAXException {
if (value != null) {
value = value.trim();
// Could this be XML ?
if (value.length() > 0 && value.charAt(0) == '<') {
try {
if (transformer.parser != null) {
transformer.parser =
(Parser)manager.lookup(Parser.ROLE);
}
if (transformer.compiler != null) {
compiler =
(XMLSerializer)manager.lookup(XMLSerializer.ROLE);
}
if (transformer.interpreter != null) {
interpreter =
(XMLDeserializer)manager.lookup(XMLDeserializer.ROLE);
}
parser.parse(new InputSource(new
StringReader("<root>"+value+"</root>")), compiler);
IncludeXMLConsumer filter = new
IncludeXMLConsumer(transformer, transformer);
filter.setIgnoreRootElement(true);
interpreter.setConsumer(filter);
interpreter.deserialize(compiler.getSAXFragment());
} catch (Exception local) {
// if an exception occured the data was not xml
transformer.data(value);
}
} else {
transformer.data(value);
}
}
}
protected void serializeRow(ComponentManager 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(ComponentManager 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,
transformer.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,
transformer.getStringValue( rs.getBigDecimal( i ) ));
} else {
this.serializeData(manager,
transformer.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;
}
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/reading/DatabaseReader.java
Index: DatabaseReader.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.reading;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.*;
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.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
import org.apache.excalibur.source.impl.validity.TimeStampValidity;
import org.xml.sax.SAXException;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Date;
import java.util.Map;
/**
* This Reader pulls a resource from a database. It is configured with
* the Connection to use, parameters specify the table and column
* to pull the image from, and source specifies the source key information.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Id: DatabaseReader.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class DatabaseReader
extends ComposerReader
implements Configurable, Disposable, CacheableProcessingComponent {
private ComponentSelector dbselector;
private String dsn;
private long lastModified = System.currentTimeMillis();
private Blob resource = null;
private Connection con = null;
private DataSourceComponent datasource = null;
private boolean doCommit = false;
private boolean defaultCache = true;
/**
* Compose the object so that we get the <code>Component</code>s we need
from
* the <code>ComponentManager</code>.
*/
public void compose(final ComponentManager manager) throws
ComponentException {
super.compose(manager);
this.dbselector = (ComponentSelector)
manager.lookup(DataSourceComponent.ROLE + "Selector");
}
/**
* Configure the <code>Reader</code> so that we can use the same database
* for all instances.
*/
public void configure(Configuration conf) throws ConfigurationException {
this.dsn = conf.getChild("use-connection").getValue();
this.defaultCache =
conf.getChild("invalidate").getValue("never").equals("always");
}
/**
* Set the <code>SourceResolver</code> the object model <code>Map</code>,
* the source and sitemap <code>Parameters</code> used to process the
request.
*/
public void setup(SourceResolver resolver, Map objectModel, String src,
Parameters par)
throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, par);
try {
this.datasource = (DataSourceComponent) dbselector.select(dsn);
this.con = datasource.getConnection();
if (this.con.getAutoCommit()) {
this.con.setAutoCommit(false);
}
PreparedStatement statement = con.prepareStatement(getQuery());
statement.setString(1, this.source);
ResultSet set = statement.executeQuery();
if (!set.next()) throw new ResourceNotFoundException("There is no
resource with that key");
Response response = ObjectModelHelper.getResponse(objectModel);
Request request = ObjectModelHelper.getRequest(objectModel);
if (this.modifiedSince(set, request, response)) {
this.resource = set.getBlob(1);
if (this.resource == null) {
throw new ResourceNotFoundException("There is no resource
with that key");
}
}
this.doCommit = true;
} catch (Exception e) {
this.doCommit = false;
throw new ResourceNotFoundException("DatabaseReader error:", e);
}
}
/**
* Generates the resource we need to retrieve verbatim from the
* database. Granted, this can be used for any resource from a
* database, so we may want to get rid of the bias toward images.
* This reader requires a number of parameters:
*
* <pre>
* <parameter name="table" value="database_table_name"/>
* <parameter name="image" value="database_resource_column_name"/>
* <parameter name="key" value="database_lookup_key_column_name"/>
* </pre>
*
* Please note that if any of those parameters are missing, this
* <code>Reader</code> cannot function. There are a number of other
* parameters that allow you to provide hints for the reader to
* optimize resource use:
*
* <pre>
* <parameter name="last-modified"
value="database_timestamp_column_name"/>
* <parameter name="content-type" value="content_mime_type"/>
* <parameter name="expires"
value="number_of_millis_before_refresh"/>
* <parameter name="where" value="alternate_key = 'foo'"/>
* <parameter name="order-by" value="alternate_key DESC"/>
* </pre>
*
* Lastly, the <code>key</code> value is derived from the value of
* the <code>source</code> string.
*/
public void generate() throws ProcessingException, SAXException,
IOException {
try {
Response response = ObjectModelHelper.getResponse(objectModel);
this.serialize(response);
} catch (IOException ioe) {
getLogger().warn("Assuming client reset stream");
this.doCommit = false;
} catch (Exception e) {
this.doCommit = false;
throw new ResourceNotFoundException("DatabaseReader error:", e);
}
}
/**
* This method builds the query string used for accessing the database.
* If the required parameters do not exist, then we cannot build a
* correct query.
*/
public String getQuery() throws Exception {
String table = this.parameters.getParameter("table", null);
String column = this.parameters.getParameter("image", null);
String key = this.parameters.getParameter("key", null);
String where = this.parameters.getParameter("where", null);
String orderBy = this.parameters.getParameter("order-by", null);
if (table == null || column == null || key==null) {
throw new ProcessingException("We are missing a required
parameter. Please include 'table', 'image', and 'key'");
}
String date = this.parameters.getParameter("last-modified", null);
StringBuffer query = new StringBuffer("SELECT ");
query.append(column);
if (date != null) {
query.append(", ").append(date);
}
if (null != orderBy) {
query.append(", ");
if (orderBy.endsWith(" DESC")) {
query.append(orderBy.substring(0, orderBy.length() - 5));
} else {
query.append(orderBy);
}
}
query.append(" FROM ").append(table);
query.append(" WHERE ").append(key).append(" = ?");
if (null != where) {
query.append(" AND ").append(where);
}
if (null != orderBy) {
query.append(" ORDER BY ").append(orderBy);
}
return query.toString();
}
/**
* Tests whether a resource has been modified or not. As Blobs and
* database columns usually do not have intrinsic dates on them (at
* least easily accessible), we have to have a database column that
* holds a date for the resource. Please note, that the database
* column <strong>must</strong> be a <code>Timestamp</code> column.
*
* In the absence of such a column this method <em>always</em>
* returns <code>true</code>. This is because databases are much
* more prone to change than filesystems, and don't have intrinsic
* timestamps on column updates.
*/
public boolean modifiedSince(ResultSet set, Request request, Response
response)
throws SQLException {
String lastModified = this.parameters.getParameter("last-modified",
null);
if (lastModified != null) {
Timestamp modified = set.getTimestamp(lastModified, null);
if (null != modified) {
this.lastModified = modified.getTime();
} else {
// assume it has never been modified
}
response.setDateHeader("Last-Modified", this.lastModified);
return this.lastModified >
request.getDateHeader("if-modified-since");
}
// if we have nothing to compare to, then we must assume it
// has been modified
return true;
}
/**
* This method actually performs the serialization.
*/
public void serialize(Response response)
throws IOException, SQLException {
if (this.resource == null) {
throw new SQLException("The Blob is empty!");
}
InputStream is = new
BufferedInputStream(this.resource.getBinaryStream());
long expires = parameters.getParameterAsInteger("expires", -1);
if (expires > 0) {
response.setDateHeader("Expires", System.currentTimeMillis() +
expires);
}
response.setHeader("Accept-Ranges", "bytes");
byte[] buffer = new byte[8192];
int length = -1;
while ((length = is.read(buffer)) > -1) {
out.write(buffer, 0, length);
}
is.close();
out.flush();
}
/**
* Generate the unique key.
* This key must be unique inside the space of this component.
*
* @return The generated key hashes the src
*/
public java.io.Serializable generateKey() {
return this.source;
}
/**
* Generate the validity object.
*
* @return The generated validity object or <code>null</code> if the
* component is currently not cacheable.
*/
public SourceValidity generateValidity() {
if (this.lastModified > 0) {
return new TimeStampValidity(this.lastModified);
} else {
if (this.defaultCache) {
return NOPValidity.SHARED_INSTANCE;
} else {
return null;
}
}
}
public void recycle() {
super.recycle();
this.resource = null;
this.lastModified = 0;
if (this.con != null) {
try {
if (this.doCommit) {
this.con.commit();
} else {
this.con.rollback();
}
} catch (SQLException se) {
getLogger().warn("Could not commit or rollback connection",
se);
}
try {
this.con.close();
} catch (SQLException se) {
getLogger().warn("Could not close connection", se);
}
this.con = null;
}
if (this.datasource != null) {
this.dbselector.release(this.datasource);
this.datasource = null;
}
}
/**
* dispose()
*/
public void dispose()
{
this.manager.release(this.dbselector);
}
public String getMimeType() {
return this.parameters.getParameter("content-type",
super.getMimeType());
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/input/CollectionMetaModule.java
Index: CollectionMetaModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.input;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
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.component.ComponentSelector;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.modules.input.InputModule;
import org.apache.cocoon.util.JDBCTypeConversions;
import org.apache.cocoon.matching.AbstractWildcardMatcher;
import java.util.ArrayList;
import java.util.Map;
import java.util.Enumeration;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Constructs an array of values suitable for a JDBC collection type
* from parameters obtained from another input module. Application is
* not limited to JDBC collections but can be used wherever similar
* named attributes shall be collected to an array of a given
* type. Currently, long, int, and string are known, more to come.
*
* <p><b>Global and local configuration</b></p>
* <table border="1">
* <tr><td><code>input-module</code></td><td>Name of the input module used to
obtain the value and its configuration</td></tr>
* <tr><td><code>member</code></td> <td>Collection member <table
*
<tr><td>Attribute</td><td></td></tr>
* <tr><td>name</td><td>Parameter
name, "*" may distinguish multiple collections</td></tr>
* <tr><td>type</td><td>JDBC type
name of members</td></tr>
* </table>
</td></tr>
* </table>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: CollectionMetaModule.java,v 1.1 2002/10/18 14:04:26 haul
Exp $
*/
public class CollectionMetaModule extends AbstractLogEnabled
implements InputModule, Configurable, Initializable, Composable,
Disposable {
/** The component manager instance */
protected ComponentManager manager;
protected Configuration memberConf = null;
private String defaultInput = "request-param"; // default to request
parameters
private Configuration inputConf = null; // will become an empty
configuration object
// during configure() so why
bother here...
String INPUT_MODULE_ROLE = InputModule.ROLE;
String INPUT_MODULE_SELECTOR = INPUT_MODULE_ROLE+"Selector";
private boolean initialized = false;
private InputModule input = null;
private ComponentSelector inputSelector = null;
/**
* Set the current <code>ComponentManager</code> instance used by this
* <code>Composable</code>.
*/
public void compose(ComponentManager manager) throws ComponentException {
this.manager=manager;
}
public void configure(Configuration config) throws ConfigurationException
{
this.memberConf = config.getChild("member");
this.inputConf = config.getChild("input-module");
this.defaultInput =
this.inputConf.getAttribute("name",this.defaultInput);
}
public void initialize() {
try {
// obtain input module
this.inputSelector=(ComponentSelector)
this.manager.lookup(INPUT_MODULE_SELECTOR);
if (this.defaultInput != null &&
this.inputSelector != null &&
this.inputSelector.hasComponent(this.defaultInput)
){
this.input = (InputModule)
this.inputSelector.select(this.defaultInput);
if (!(this.input instanceof ThreadSafe && this.inputSelector
instanceof ThreadSafe) ) {
this.inputSelector.release(this.input);
this.manager.release(this.inputSelector);
this.input = null;
this.inputSelector = null;
}
this.initialized = true;
} else {
if (getLogger().isErrorEnabled())
getLogger().error("A problem occurred setting up '" +
this.defaultInput
+ "': Selector is
"+(this.inputSelector!=null?"not ":"")
+"null, Component is "
+(this.inputSelector!=null&&this.inputSelector.hasComponent(this.defaultInput)?"known":"unknown"));
}
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger().warn("A problem occurred setting up '" +
this.defaultInput + "': " + e.getMessage());
}
}
public void dispose() {
if (!this.initialized)
if (getLogger().isErrorEnabled())
getLogger().error("Uninitialized Component! FAILING");
else
if (this.inputSelector != null) {
if (this.input != null)
this.inputSelector.release(this.input);
this.manager.release(this.inputSelector);
}
}
public Object getAttribute( String name, Configuration modeConf, Map
objectModel )
throws ConfigurationException {
if (!this.initialized) {
if (getLogger().isErrorEnabled())
getLogger().error("Uninitialized Component! FAILING");
return null;
}
if (this.defaultInput == null) {
if (getLogger().isWarnEnabled())
getLogger().warn("No input module given. FAILING");
return null;
}
// obtain correct configuration objects
// default vs dynamic
Configuration mConf = this.memberConf;
Configuration inputConfig = null;
String inputName=null;
if (modeConf!=null) {
mConf = modeConf.getChild("member");
inputName =
modeConf.getChild("input-module").getAttribute("name",null);
if (inputName != null) {
inputConfig = modeConf.getChild("input-module");
}
}
// read necessary parameters
// name is used only if parameter name contains '*'
// in that case it replaces '*' otherwise it is
// ignored
String jType = mConf.getAttribute("type","string");
SortedSet matchset = new TreeSet();
String pName = mConf.getAttribute("name");
int index = pName.indexOf("*");
if (index>-1) {
String prefix = (index > 0 ? pName.substring(0,index) : null);
String suffix = (index < (pName.length() -1) ?
pName.substring(index+1,pName.length()) : null);
pName = prefix+name+suffix;
}
getLogger().debug("jType "+jType);
// done reading configuration
// setup modules and read values
Object result = null;
try {
Object[] values = null;
if (this.input != null && inputName == null) {
// input module is thread safe
// thus we still have a reference to it
// and
// no other module is configured dynamically
values =
input.getAttributeValues(pName,this.inputConf,objectModel);
} else {
// input was not thread safe
// or
// another module is configured dynamically
// so acquire it again
ComponentSelector iputSelector = null;
InputModule iput = null;
try {
// obtain input module
if (inputName == null) {
inputName = this.defaultInput;
inputConfig = this.inputConf;
}
iputSelector=(ComponentSelector)
this.manager.lookup(INPUT_MODULE_SELECTOR);
if (this.defaultInput != null
&& iputSelector != null
&& iputSelector.hasComponent(inputName)) {
iput = (InputModule) iputSelector.select(inputName);
}
if (iput != null) {
values = iput.getAttributeValues(pName, inputConfig,
objectModel);
}
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger().warn("A problem occurred acquiring a
value from '"
+ inputName + "' for '"+pName+"': "
+ e.getMessage());
} finally {
// release components
if (iputSelector != null) {
if (iput != null)
iputSelector.release(iput);
this.manager.release(iputSelector);
}
}
}
// done reading values
// start converting values and assemble array
if (values != null) {
Object[] objects = new Object[values.length];
// FIXME: should put this into helper class
for (int i = 0; i<values.length; i++) {
Object value = values[i];
objects[i] = JDBCTypeConversions.convert(value, jType);
}
return objects;
}
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger().warn("A problem occurred acquiring a value from
'" + inputName
+ "' for '"+pName+"': " + e.getMessage());
}
return null;
}
public Enumeration getAttributeNames( Configuration modeConf, Map
objectModel )
throws ConfigurationException {
if (!this.initialized) {
if (getLogger().isErrorEnabled())
getLogger().error("Uninitialized Component! FAILING");
return null;
}
if (this.defaultInput == null) {
if (getLogger().isWarnEnabled())
getLogger().warn("No input module given. FAILING");
return null;
}
// obtain correct configuration objects
// default vs dynamic
Configuration mConf = this.memberConf;
Configuration inputConfig = null;
String inputName=null;
if (modeConf!=null) {
mConf = modeConf.getChild("member");
inputName =
modeConf.getChild("input-module").getAttribute("name",null);
if (inputName != null) {
inputConfig = modeConf.getChild("input-module");
}
}
// done reading configuration
// setup modules and read attribute names
Object result = null;
try {
Enumeration names = null;
if (this.input != null && inputName == null) {
// input module is thread safe
// thus we still have a reference to it
// and
// no other module is configured dynamically
names = input.getAttributeNames(this.inputConf,objectModel);
} else {
// input was not thread safe
// or
// another module is configured dynamically
// so acquire it again
ComponentSelector iputSelector = null;
InputModule iput = null;
try {
// obtain input module
if (inputName == null) {
inputName = this.defaultInput;
inputConfig = this.inputConf;
}
iputSelector=(ComponentSelector)
this.manager.lookup(INPUT_MODULE_SELECTOR);
if (this.defaultInput != null
&& iputSelector != null
&& iputSelector.hasComponent(inputName)) {
iput = (InputModule) iputSelector.select(inputName);
}
if (iput != null) {
names = iput.getAttributeNames(inputConfig,
objectModel);
}
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger().warn("A problem occurred acquiring a
names from '" + inputName + "': " + e.getMessage());
} finally {
// release components
if (iputSelector != null) {
if (iput != null)
iputSelector.release(iput);
this.manager.release(iputSelector);
}
}
}
// done reading names
// find attribute names matching configuration
// and return an enumeration
if (names != null) {
SortedSet matchset = new TreeSet();
String pName = mConf.getAttribute("name");
int index = pName.indexOf("*");
if (index>-1) {
// parameter name contains '*'
// find all strings that match this '*'
// return them in an enumeration
String prefix = (index > 0 ? pName.substring(0,index) :
null);
String suffix = (index < (pName.length() -1) ?
pName.substring(index+1,pName.length()) : null);
while (names.hasMoreElements()) {
String name = (String)names.nextElement();
if (name.startsWith(prefix) && name.endsWith(suffix))
{
String wildcard = name.substring(prefix.length());
wildcard =
wildcard.substring(0,wildcard.length()-suffix.length());
matchset.add(wildcard);
}
}
} else {
// parameter name without wildcard
// check that name is among available names
// and return it in that case
boolean done=false;
while (!done && names.hasMoreElements()) {
String name = (String)names.nextElement();
if (name.equals(pName)) {
matchset.add(pName);
done = true;
}
}
}
return new EnumerationHelper(matchset.iterator());
} else {
return null;
}
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger().warn("A problem occurred acquiring names from '"
+ inputName + "': " + e.getMessage());
}
return null;
}
public Object[] getAttributeValues( String name, Configuration modeConf,
Map objectModel )
throws ConfigurationException {
Enumeration names = this.getAttributeNames( modeConf, objectModel );
ArrayList values = new ArrayList();
while (names.hasMoreElements()) {
values.add(this.getAttribute((String)
names.nextElement(),modeConf,objectModel));
}
return values.toArray();
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/AbstractAutoIncrementModule.java
Index: AbstractAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
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.AbstractLogEnabled;
import org.apache.cocoon.util.HashMap;
/**
* AbstractDatabaseModule gives you the infrastructure for easily
* deploying more AutoIncrementModules. In order to get at the Logger, use
* getLogger().
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: AbstractAutoIncrementModule.java,v 1.1 2002/10/18
14:04:26 haul Exp $
*/
public abstract class AbstractAutoIncrementModule extends AbstractLogEnabled
implements AutoIncrementModule, Configurable, Disposable {
/**
* Stores (global) configuration parameters as <code>key</code> /
* <code>value</code> pairs.
*/
protected HashMap settings = null;
/**
* Configures the database access module.
*
* Takes all elements nested in component declaration and stores
* them as key-value pairs in <code>settings</code>. Nested
* configuration option are not catered for. This way global
* configuration options can be used.
*
* For nested configurations override this function.
* */
public void configure(Configuration conf) throws ConfigurationException {
if (conf != null) {
String key = null;
String val = null;
Configuration[] parameters = conf.getChildren();
this.settings = new HashMap(parameters.length);
for ( int i = 0; i < parameters.length; i++) {
key = parameters[i].getName();
val = parameters[i].getValue();
if ( key != null )
this.settings.put(key, val);
}
}
}
/**
* dispose
*/
public void dispose() {
// Purposely empty so that we don't need to implement it in every
// class.
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/AutoIncrementModule.java
Index: AutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.Map;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Abstraction layer to encapsulate different DBMS behaviour for key
* attribute columns.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: AutoIncrementModule.java,v 1.1 2002/10/18 14:04:26 haul
Exp $
* */
public interface AutoIncrementModule extends Component {
String ROLE = AutoIncrementModule.class.getName();
/**
* Return key attribute value of last inserted row.
*
* @param name a String that specifies what the caller thinks
* would identify a set of parameters. This is mainly a fallback
* if no modeConf is present.
* @param tableConf Table's configuration from resource description.
* @param columnConf column's configuration from resource description.
* @param mdoeConf this mode's configuration from resource description.
* @param conn Connection
* @param stmt Statement that was executed to insert the last row.
* @param request The request object
* @return value representing the last key value value.
* */
Object getPostValue( Configuration tableConf, Configuration columnConf,
Configuration modeConf,
Connection conn, Statement stmt, Map objectModel )
throws SQLException, ConfigurationException;
/**
* Boolean whether the key attribute column needs to be included
* in the insert query.
*
* @return true if the column is needed, false if the column
* should be skipped.
* */
boolean includeInQuery( );
/**
* Boolean whether the key attribute needs to be included in the
* insert query as an attribute value (no subquery).
*
* @return true if a value is needed, false if a subquery
* expression is used or the column is skipped altogether.
* */
boolean includeAsValue( );
/**
* Provide the value for the key attribute column.
*
* If a value for the key value column is needed (i.e. the column
* is not skipped), this value is computed here.
*
* @param tableConf Table's configuration from resource description.
* @param columnConf column's configuration from resource description.
* @param mdoeConf this mode's configuration from resource description.
* @param conn Connection
* @param request The request object
* @param idx In case of multiple rows to be inserted, index to the
desired row
* @return exact value for key attribute column
* */
Object getPreValue( Configuration tableConf, Configuration columnConf,
Configuration modeConf,
Connection conn, Map objectModel ) throws
SQLException, ConfigurationException;
/**
* Provide subquery string for the key attribute column.
*
* If a value for the autoincrement column is needed (i.e. the
* column is not skipped), and the value can be determined through
* a nested subquery, this function provides the subquery as a
* string.
*
* @return subquery string for autoincrement column.
*/
String getSubquery( Configuration tableConf, Configuration columnConf,
Configuration modeConf ) throws ConfigurationException;
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/HsqlIdentityAutoIncrementModule.java
Index: HsqlIdentityAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.lang.Integer;
import java.util.SortedSet;
import java.util.Map;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Types;
import java.sql.SQLException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.thread.ThreadSafe;
/**
* Abstraction layer to encapsulate different DBMS behaviour for
autoincrement columns.
*
* Here: [EMAIL PROTECTED] <a
href="http://hsqldb.sourceforge.net">HSQLDB</a>} 1.6 IDENTITY columns
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: HsqlIdentityAutoIncrementModule.java,v 1.1 2002/10/18
14:04:26 haul Exp $
*/
public class HsqlIdentityAutoIncrementModule implements AutoIncrementModule,
ThreadSafe {
public Object getPostValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Statement stmt, Map
objectModel ) throws SQLException, ConfigurationException {
Integer id = null;
/*
// if hsqldb did support callable statements ...
CallableStatement callStmt = conn.prepareCall("? = {CALL
IDENTITY()}");
callStmt.registerOutParameter(1, Types.INTEGER);
ResultSet resultSet = callStmt.executeQuery();
*/
PreparedStatement pstmt = conn.prepareStatement("CALL IDENTITY()");
ResultSet resultSet = pstmt.executeQuery();
while ( resultSet.next() ) {
id = new Integer(resultSet.getInt(1));
}
resultSet.close();
return id;
}
public boolean includeInQuery() { return false; }
public boolean includeAsValue() { return false; }
public Object getPreValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Map objectModel ) throws
SQLException, ConfigurationException {
return null;
}
public String getSubquery( Configuration tableConf, Configuration
columnConf, Configuration modeConf )
throws ConfigurationException {
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/IfxSerialAutoIncrementModule.java
Index: IfxSerialAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.lang.Integer;
import java.util.SortedSet;
import java.util.Map;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.thread.ThreadSafe;
import com.informix.jdbc.IfxStatement;
/**
* Abstraction layer to encapsulate different DBMS behaviour for
autoincrement columns.
*
* Here: Informix IUS 9.21 SERIAL columns
* (need another one for SERIAL8 ones!)
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: IfxSerialAutoIncrementModule.java,v 1.1 2002/10/18
14:04:26 haul Exp $
*/
public class IfxSerialAutoIncrementModule implements AutoIncrementModule,
ThreadSafe {
public Object getPostValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Statement stmt, Map
objectModel )
throws SQLException, ConfigurationException {
return new Integer(((com.informix.jdbc.IfxStatement)
stmt).getSerial());
};
public boolean includeInQuery() { return false; };
public boolean includeAsValue() { return false; };
public Object getPreValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Map objectModel ) throws
SQLException, ConfigurationException {
return null;
};
public String getSubquery( Configuration tableConf, Configuration
columnConf, Configuration modeConf )
throws ConfigurationException {
return null;
};
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/ManualAutoIncrementModule.java
Index: ManualAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.thread.ThreadSafe;
import java.lang.Integer;
import java.util.Map;
import java.util.HashMap;
import java.util.SortedSet;
/**
* Abstraction layer to encapsulate different DBMS behaviour for
* autoincrement columns.
*
* Here: manual mode The new value is determined by doing a "select
* max(column)+1 from table" query. With transactions and correct
* isolation levels, this should to the trick almost everywhere.
*
* Note however, that the above query does not prevent a parallel
* transaction to try to insert a row with the same ID since it
* requires only shared locks. C.f. "Phantom Problem"
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: ManualAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26
haul Exp $
*/
public class ManualAutoIncrementModule extends AbstractAutoIncrementModule
implements ThreadSafe {
private Map selectStatements = new HashMap();
public Object getPostValue( Configuration tableConf, Configuration
columnConf, Configuration modenConf,
Connection conn, Statement stmt, Map
objectModel )
throws SQLException, ConfigurationException {
return null;
}
public boolean includeInQuery( ) { return true; }
public boolean includeAsValue( ) { return true; }
public Object getPreValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Map objectModel )
throws SQLException, ConfigurationException {
/** Set the key value using SELECT MAX(keyname)+1 **/
String tableName = tableConf.getAttribute("name","");
String selectQuery = this.getSelectQuery(tableName, columnConf);
PreparedStatement select_statement =
conn.prepareStatement(selectQuery);
ResultSet set = select_statement.executeQuery();
set.next();
int maxid = set.getInt("maxid");
set.close();
select_statement.close();
if (getLogger().isDebugEnabled())
getLogger().debug("autoincrementValue " + (maxid+1));
return new Integer(maxid + 1);
}
public String getSubquery( Configuration tableConf, Configuration
columnConf, Configuration modeConf )
throws ConfigurationException {
return null;
}
/**
* Set the String representation of the MaxID lookup statement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected final synchronized void setSelectQuery( String tableName,
Configuration entry ) throws ConfigurationException {
StringBuffer queryBuffer = new StringBuffer("SELECT max(");
queryBuffer.append(entry.getAttribute("name"));
queryBuffer.append(") AS maxid FROM ");
queryBuffer.append(tableName);
this.selectStatements.put(entry, queryBuffer.toString());
}
protected final synchronized String getSelectQuery( String tableName,
Configuration entry ) throws ConfigurationException {
String result = (String) this.selectStatements.get(entry);
if (result == null) {
setSelectQuery(tableName, entry);
result = (String) this.selectStatements.get(entry);
}
return result;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/MysqlAutoIncrementModule.java
Index: MysqlAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.lang.Integer;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.Map;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.thread.ThreadSafe;
/**
* Abstraction layer to encapsulate different DBMS behaviour for
autoincrement columns.
*
* Here: [EMAIL PROTECTED] <a href="http://www.mysql.com">MYSQL</a>}
AUTO_INCREMENT columns
*
* @author <a href="mailto:[EMAIL PROTECTED]">Tim Myers</a>
* @version CVS $Id: MysqlAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26
haul Exp $
*/
public class MysqlAutoIncrementModule implements AutoIncrementModule,
ThreadSafe {
public Object getPostValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Statement stmt, Map
objectModel ) throws SQLException, ConfigurationException {
Integer id = null;
/*
// if mysql did support callable statements ... i'm not sure what
what would go here, maybe:
CallableStatement callStmt = conn.prepareCall("? = {CALL
LAST_INSERT_ID()}");
callStmt.registerOutParameter(1, Types.INTEGER);
ResultSet resultSet = callStmt.executeQuery();
*/
PreparedStatement pstmt = conn.prepareStatement("SELECT
LAST_INSERT_ID()");
ResultSet resultSet = pstmt.executeQuery();
while ( resultSet.next() ) {
id = new Integer(resultSet.getInt(1));
}
resultSet.close();
return id;
}
public boolean includeInQuery() { return false; }
public boolean includeAsValue() { return false; }
public Object getPreValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Map objectModel ) throws
SQLException, ConfigurationException {
return null;
}
public String getSubquery( Configuration tableConf, Configuration
columnConf, Configuration modeConf )
throws ConfigurationException {
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/PgsqlAutoIncrementModule.java
Index: PgsqlAutoIncrementModule.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.modules.database;
import java.lang.Integer;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.Map;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.thread.ThreadSafe;
/**
* Abstraction layer to encapsulate different DBMS behaviour for
autoincrement columns.
*
* Here: [EMAIL PROTECTED] <a href="http://www.postgres.org">PostgreSQL</a>}
SERIAL columns
*
* @author <a href="mailto:[EMAIL PROTECTED]">Philipp Hahn</a>
* @version CVS $Id: PgsqlAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26
haul Exp $
*/
public class PgsqlAutoIncrementModule implements AutoIncrementModule,
ThreadSafe {
public Object getPostValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Statement stmt, Map
objectModel ) throws SQLException, ConfigurationException {
Integer id = null;
/*
// Postgres does support callable statements ... i'm not sure what
what would go here, maybe:
CallableStatement callStmt = conn.prepareCall("? = {CALL
LAST_INSERT_ID()}");
callStmt.registerOutParameter(1, Types.INTEGER);
ResultSet resultSet = callStmt.executeQuery();
*/
StringBuffer queryBuffer = new StringBuffer("SELECT currval('");
queryBuffer.append(tableConf.getAttribute("name",""));
queryBuffer.append('_');
queryBuffer.append(columnConf.getAttribute("name"));
queryBuffer.append("_seq')");
PreparedStatement pstmt =
conn.prepareStatement(queryBuffer.toString());
ResultSet resultSet = pstmt.executeQuery();
while ( resultSet.next() ) {
id = new Integer(resultSet.getInt(1));
}
resultSet.close();
return id;
}
public boolean includeInQuery() { return false; }
public boolean includeAsValue() { return false; }
public Object getPreValue( Configuration tableConf, Configuration
columnConf, Configuration modeConf,
Connection conn, Map objectModel ) throws
SQLException, ConfigurationException {
return null;
}
public String getSubquery( Configuration tableConf, Configuration
columnConf, Configuration modeConf )
throws ConfigurationException {
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/package.html
Index: package.html
===================================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>output</title>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
</head>
<body>
<h1>database<br>
</h1>
<p>Database modules provide an abstraction layer for different interfaces
used by database management systems for autoincrement columns. The value
can be obtained from the DBMS or some other source before or after the
statement
is executed. Or some code can be inserted into the query to direct the DBMS
to use the next value of a sequence.</p>
</body>
</html>
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlConnection.java
Index: EsqlConnection.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.language.markup.xsp;
import java.sql.Connection;
import java.util.Properties;
import java.sql.SQLException;
/**
* This is wrapper to extend a java.sql.Conncetion implementation
* for easier paging / limit facilities
*
* based on the orginal esql.xsl
* @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
* @version CVS $Id: EsqlConnection.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class EsqlConnection implements Connection {
public static final int LIMIT_METHOD_NOLIMIT = 0;
public static final int LIMIT_METHOD_POSTGRESQL = 1;
public static final int LIMIT_METHOD_MYSQL = 2;
public static final int LIMIT_METHOD_JDBC = 3;
public Connection connection = null;
private String url = null;
private Properties info = new Properties();
private int limitMethod = LIMIT_METHOD_NOLIMIT;
private boolean multipleResults = false;
public boolean multipleResults() {
return this.multipleResults;
}
/** It appears that some commercial DBMSs like Oracle and Informix
* are broken in that they don't follow the JDBC standard and
* calls to getUpdateCount after getMoreResults result either in
* an exception (Informix) or return the same value (i.e. not -1) (Oracle).
* In addition, this feature is only useful with stored procedures.
* Hence we disable it per default.
**/
public void setMultipleResults(String value) {
if (value != null)
this.multipleResults = ("true".equalsIgnoreCase(value) ||
"yes".equalsIgnoreCase(value));
}
public Properties getInfo() {
return(info);
}
public String getUrl() {
if (this.url == null)
try {
this.url=this.connection.getMetaData().getURL();
} catch (SQLException e) {
};
return this.url;
}
public void setUrl( String url ) {
this.url = url;
}
public void setProperty( String name, Object value ) {
info.put(name,value);
}
public void setUser(String user) {
setProperty("user",user);
}
public void setPassword(String password) {
setProperty("password",password);
}
public int getLimitMethod() {
return(limitMethod);
}
public void setLimitMethod( String method ) {
if ("".equals(method) || "auto".equals(method) ) {
String jdbcSource;
try {
jdbcSource = connection.getMetaData().getURL();
} catch (Exception e) {
throw new RuntimeException("Error accessing connection metadata: "+e);
}
if (jdbcSource.startsWith("jdbc:postgresql:")) {
limitMethod = LIMIT_METHOD_POSTGRESQL;
} else if (jdbcSource.startsWith("jdbc:mysql:")) {
limitMethod = LIMIT_METHOD_MYSQL;
} else if (jdbcSource.startsWith("jdbc:sybase:")) {
limitMethod = LIMIT_METHOD_JDBC;
}
else {
throw new RuntimeException("Cannot guess limit method from jdbc url:
" + method);
}
}
else if ("postgresql".equals(method)) {
limitMethod = LIMIT_METHOD_POSTGRESQL;
} else if ("mysql".equals(method)) {
limitMethod = LIMIT_METHOD_MYSQL;
} else if ("jdbc".equals(method)) {
limitMethod = LIMIT_METHOD_JDBC;
} else {
throw new RuntimeException("Unknown limit method: " + method);
}
}
/* */
public java.sql.Statement createStatement() throws SQLException {
return(connection.createStatement());
}
public java.sql.Statement createStatement(int i1, int i2) throws
SQLException {
return(connection.createStatement(i1, i2));
}
public java.sql.PreparedStatement prepareStatement(String s) throws
SQLException {
return(connection.prepareStatement(s));
}
public java.sql.PreparedStatement prepareStatement(String s, int i1, int
i2) throws SQLException {
return(connection.prepareStatement(s, i1, i2));
}
public void close() throws SQLException {
connection.close();
}
public void commit() throws SQLException {
connection.commit();
}
public void rollback() throws SQLException {
connection.rollback();
}
public boolean getAutoCommit() throws SQLException {
return(connection.getAutoCommit());
}
public void setAutoCommit(boolean autocommit) throws SQLException {
connection.setAutoCommit(autocommit);
}
public void setTransactionIsolation(int i) throws SQLException {
connection.setTransactionIsolation(i);
}
public int getTransactionIsolation() throws SQLException {
return(connection.getTransactionIsolation());
}
public String getCatalog() throws SQLException {
return(connection.getCatalog());
}
public java.sql.SQLWarning getWarnings() throws SQLException {
return(connection.getWarnings());
}
public java.util.Map getTypeMap() throws SQLException {
return(connection.getTypeMap());
}
public boolean isClosed() throws SQLException {
return(connection.isClosed());
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException {
return(connection.getMetaData());
}
public void setCatalog(String s) throws SQLException {
connection.setCatalog(s);
}
public void setTypeMap(java.util.Map m) throws SQLException {
connection.setTypeMap(m);
}
public void setReadOnly(boolean b) throws SQLException {
connection.setReadOnly(b);
}
public void clearWarnings() throws SQLException {
connection.clearWarnings();
}
public boolean isReadOnly() throws SQLException {
return(connection.isReadOnly());
}
public String nativeSQL(String s) throws SQLException {
return(connection.nativeSQL(s));
}
public java.sql.CallableStatement prepareCall(String s) throws SQLException
{
return(connection.prepareCall(s));
}
public java.sql.CallableStatement prepareCall(String s, int i1, int i2)
throws SQLException {
return(connection.prepareCall(s,i1,i2));
}
/* @JDBC3_START@
public void setHoldability(int holdability)
throws SQLException
{
connection.setHoldability(holdability);
}
public int getHoldability()
throws SQLException
{
return connection.getHoldability();
}
public java.sql.Savepoint setSavepoint()
throws SQLException
{
return connection.setSavepoint();
}
public java.sql.Savepoint setSavepoint(String savepoint)
throws SQLException
{
return connection.setSavepoint(savepoint);
}
public void rollback(java.sql.Savepoint savepoint)
throws SQLException
{
connection.rollback(savepoint);
}
public void releaseSavepoint(java.sql.Savepoint savepoint)
throws SQLException
{
connection.releaseSavepoint(savepoint);
}
public java.sql.Statement createStatement(int resulSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
return connection.createStatement(resulSetType, resultSetConcurrency,
resultSetHoldability);
}
public java.sql.PreparedStatement prepareStatement(String sql,
int resulSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
return connection.prepareStatement(sql, resulSetType,
resultSetConcurrency, resultSetHoldability);
}
public java.sql.CallableStatement prepareCall(String sql,
int resulSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
return connection.prepareCall(sql, resulSetType,
resultSetConcurrency, resultSetHoldability);
}
public java.sql.PreparedStatement prepareStatement(String sql,
int autoGeneratedKeys)
throws SQLException
{
return connection.prepareStatement(sql, autoGeneratedKeys);
}
public java.sql.PreparedStatement prepareStatement(String sql,
int[] columnIndexes)
throws SQLException
{
return connection.prepareStatement(sql, columnIndexes);
}
public java.sql.PreparedStatement prepareStatement(String sql,
String[] columnNames)
throws SQLException
{
return connection.prepareStatement(sql, columnNames);
}
@JDBC3_END@ */
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlConnectionCocoon2.java
Index: EsqlConnectionCocoon2.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.language.markup.xsp;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
/**
* This is the Cocoon2 specific part of an EsqlConnection.
* This should only be in the C2 codebase
*
* based on the orginal esql.xsl
* @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
* @version CVS $Id: EsqlConnectionCocoon2.java,v 1.1 2002/10/18 14:04:26
haul Exp $
*/
public class EsqlConnectionCocoon2 extends EsqlConnection {
public DataSourceComponent datasource = null;
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlHelper.java
Index: EsqlHelper.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.language.markup.xsp;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.Reader;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Types;
/**
* This is a helper class to remove redundant code in
* esql pages
*
* based on the orginal esql.xsl
* @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
* @version CVS $Id: EsqlHelper.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class EsqlHelper {
/** returns byte array from BLOB
*/
public final static byte[] getBlob(ResultSet set, String column) throws
RuntimeException {
byte[] result = null;
try {
result = EsqlHelper.getBlob(set,set.findColumn(column));
} catch (Exception e) {
throw new RuntimeException("Error getting blob data: " +
e.getMessage());
}
return result;
}
/** returns byte array from BLOB
*/
public final static byte[] getBlob(ResultSet set, int column) throws
java.lang.Exception {
InputStream reader = null;
byte[] buffer = null;
try {
if (set.getMetaData().getColumnType(column)==java.sql.Types.BLOB)
{
Blob dbBlob = set.getBlob(column);
int length = (int) dbBlob.length();
reader = dbBlob.getBinaryStream();
buffer = new byte[length];
reader.read(buffer);
reader.close();
if (reader != null)
reader.close();
if (buffer == null)
return null;
return buffer;
} else {
return set.getString(column).getBytes();
}
} catch ( Exception e) {
throw new RuntimeException("Error getting blob data: " +
e.getMessage());
}
}
/** returns byte array from BLOB
*/
public final static byte[] getBlob(CallableStatement cs, int column)
throws java.lang.Exception {
InputStream reader = null;
byte[] buffer = null;
try {
Blob dbBlob = cs.getBlob(column);
int length = (int) dbBlob.length();
reader = dbBlob.getBinaryStream();
buffer = new byte[length];
reader.read(buffer);
reader.close();
if (reader != null)
reader.close();
if (buffer == null)
return null;
return buffer;
} catch ( Exception e) {
throw new RuntimeException("Error getting blob data: " +
e.getMessage());
}
}
/** returns Unicode encoded string from CLOB or String column
*/
public final static String getStringOrClob(ResultSet set, String column)
throws RuntimeException {
String result = null;
try {
result = EsqlHelper.getStringOrClob(set,set.findColumn(column));
} catch (Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
}
return result;
}
/** returns Unicode encoded string from CLOB or String column
*/
public final static String getStringOrClob(ResultSet set, int column)
throws java.lang.Exception {
Reader reader = null;
char[] buffer = null;
try {
if (set.getMetaData().getColumnType(column)==java.sql.Types.CLOB)
{
Clob dbClob = set.getClob(column);
int length = (int) dbClob.length();
reader = new BufferedReader(dbClob.getCharacterStream());
buffer = new char[length];
reader.read(buffer);
reader.close();
if (reader != null)
reader.close();
if (buffer == null)
return "";
return new String(buffer);
} else {
return set.getString(column);
}
} catch ( Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
}
}
/** returns Unicode encoded string from CLOB or String column
*/
public final static String getStringOrClob(CallableStatement cs, int
column) throws java.lang.Exception {
Reader reader = null;
char[] buffer = null;
try {
Clob dbClob = cs.getClob(column);
int length = (int) dbClob.length();
reader = new BufferedReader(dbClob.getCharacterStream());
buffer = new char[length];
reader.read(buffer);
reader.close();
if (reader != null)
reader.close();
if (buffer == null)
return "";
return new String(buffer);
} catch ( Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
}
}
/** returns ascii string from CLOB or String column
*/
public final static String getAscii(ResultSet set, String column)
throws RuntimeException {
String result = null;
try {
result = EsqlHelper.getAscii(set,set.findColumn(column));
} catch (Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
}
return result;
}
/** returns ascii string from CLOB or String column
*/
public final static String getAscii(ResultSet set, int column) {
InputStream asciiStream = null;
String result = null;
try {
if (set.getMetaData().getColumnType(column) == Types.CLOB) {
byte[] buffer = null;
Clob dbClob = set.getClob(column);
int length = (int) dbClob.length();
asciiStream = new
BufferedInputStream(dbClob.getAsciiStream());
buffer = new byte[length];
asciiStream.read(buffer);
asciiStream.close();
result = (buffer!=null? new String(buffer) : null);
} else {
result = set.getString(column);
}
} catch (Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
} finally {
if (asciiStream != null) try {asciiStream.close();} catch
(Exception ase) {
throw new RuntimeException("Error closing clob stream: " +
ase.getMessage());
}
}
return result;
}
/** returns ascii string from CLOB or String column
*/
public final static String getAscii(CallableStatement cs, int column) {
InputStream asciiStream = null;
String result = null;
try {
byte[] buffer = null;
Clob dbClob = cs.getClob(column);
int length = (int) dbClob.length();
asciiStream = new BufferedInputStream(dbClob.getAsciiStream());
buffer = new byte[length];
asciiStream.read(buffer);
asciiStream.close();
result = (buffer!=null? new String(buffer) : null);
} catch (Exception e) {
throw new RuntimeException("Error getting clob data: " +
e.getMessage());
} finally {
if (asciiStream != null) try {asciiStream.close();} catch
(Exception ase) {
throw new RuntimeException("Error closing clob stream: " +
ase.getMessage());
}
}
return result;
}
public final static String getStringFromByteArray(byte[] bytes, String
encoding) {
if (bytes != null) {
try {
return new String(bytes,encoding);
} catch (java.io.UnsupportedEncodingException uee) {
throw new RuntimeException("Unsupported Encoding Exception: "
+ uee.getMessage());
}
}
else {
return("");
}
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlQuery.java
Index: EsqlQuery.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.components.language.markup.xsp;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.lang.reflect.Field;
/**
* This helper class takes care of contstructing queries
* and cursor positioning (paging) for all different kinds
* of databases
*
* based on the orginal esql.xsl
* @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
* @version CVS $Id: EsqlQuery.java,v 1.1 2002/10/18 14:04:26 haul Exp $
*/
public class EsqlQuery {
private static final int UPDATE_COUNT_UNSET = -2;
private Connection connection = null;
private Statement statement = null;
private PreparedStatement preparedStatement = null;
private ResultSet resultSet = null;
private ResultSetMetaData resultSetMetaData = null;
private int updateCount = EsqlQuery.UPDATE_COUNT_UNSET;
private int updateCountCount = 0;
private int resultCount = 0;
private boolean hasResultSet = false;
private boolean resultSetValid = false;
private int position = -1;
private int maxRows = -1;
private int skipRows = 0;
private boolean keepgoing = true;
private ArrayList groups = null;
private int groupLevel = -1;
private int changeLevel = -1;
private String query;
private int limitMethod;
public EsqlQuery( EsqlConnection connection, String query ) {
this.connection = connection;
this.limitMethod = connection.getLimitMethod();
this.query = query;
}
public EsqlQuery( ResultSet aResultSet ) {
this.connection = null;
this.statement = null;
this.query = null;
this.resultSetValid = true;
this.resultSet = aResultSet;
this.hasResultSet = (this.resultSet != null);
}
class EsqlGroup {
public String var = null;
public Object value = null;
EsqlGroup ( String var, Object value ) {
this.var = var;
this.value = value;
}
}
public int getSkipRows() {
return(skipRows);
}
public void setSkipRows( int i ) {
this.skipRows = i;
}
public int getMaxRows() {
return(maxRows);
}
public void setMaxRows( int i ) {
this.maxRows = i;
}
public int getCurrentRow() {
return(position);
}
public String getQueryString() {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
if (skipRows > 0) {
if (maxRows > -1) {
return(new StringBuffer(query).append(" LIMIT
").append(maxRows).append(",").append(skipRows).toString());
}
else {
return(new StringBuffer(query).append(" OFFSET
").append(skipRows).toString());
}
}
else {
if (maxRows > -1) {
return(new StringBuffer(query).append(" LIMIT
").append(maxRows).toString());
}
else {
return(query);
}
}
case EsqlConnection.LIMIT_METHOD_MYSQL:
if (skipRows > 0) {
if (maxRows > -1) {
return(new StringBuffer(query).append(" LIMIT
").append(skipRows).append(",").append(maxRows).toString());
}
else {
throw new RuntimeException("MySQL does not support a skip of rows
only");
}
}
else {
if (maxRows > -1) {
return(new StringBuffer(query).append(" LIMIT
").append(maxRows).toString());
}
else {
return(query);
}
}
default:
return(query);
}
}
public PreparedStatement prepareStatement() throws SQLException {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
case EsqlConnection.LIMIT_METHOD_MYSQL:
preparedStatement = connection.prepareStatement(getQueryString() );
break;
case EsqlConnection.LIMIT_METHOD_JDBC:
// Produce scrollable ResultSet and skip rows with
ResultSet.absolute(skipRows).
// With SQL Server, statement.getResultSet() throws
// java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for
JDBC]Error setting up static cursor cache.
// Same error with TYPE_SCROLL_SENSITIVE.
preparedStatement = connection.prepareStatement( getQueryString(),
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
break;
case EsqlConnection.LIMIT_METHOD_NOLIMIT:
default:
// maxRows can be set without the limit method being set - it
defaults to LIMIT_METHOD_NOLIMIT
// which is not such a good name as its really another way of
limiting using JDBC.
// Produce non-scrollable ResultSet and skip rows with multiple
ResultSet.next().
preparedStatement = connection.prepareStatement(getQueryString() );
break;
}
statement = preparedStatement;
return(preparedStatement);
}
public CallableStatement prepareCall() throws SQLException {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
case EsqlConnection.LIMIT_METHOD_MYSQL:
preparedStatement = connection.prepareCall( getQueryString() );
break;
case EsqlConnection.LIMIT_METHOD_JDBC:
preparedStatement = connection.prepareCall( getQueryString(),
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
break;
case EsqlConnection.LIMIT_METHOD_NOLIMIT:
default:
preparedStatement = connection.prepareCall( getQueryString() );
};
statement = preparedStatement;
return((CallableStatement)preparedStatement);
}
public PreparedStatement getPreparedStatement() {
return(preparedStatement);
}
public CallableStatement getCallableStatement() {
return((CallableStatement) preparedStatement);
}
public ResultSet getResultSet() {
return(resultSet);
}
public boolean nextRow() throws SQLException {
position++;
return(resultSet.next());
}
public boolean keepGoing() {
return(keepgoing);
}
public void setKeepGoing( boolean still ) {
keepgoing = still;
}
public void groupLevelPlusPlus() {
this.groupLevel++;
}
public void groupLevelMinusMinus() {
this.groupLevel--;
}
public boolean groupLevelExists() {
return (this.groups != null && this.groups.size() >=
this.groupLevel+1 && this.groups.get(this.groupLevel) != null);
}
public void setGroupingVar( String key ) throws SQLException {
if (this.groups == null)
this.groups = new ArrayList(1);
this.groups.ensureCapacity(this.groupLevel);
this.groups.add(this.groupLevel, new EsqlGroup(key,
this.getResultSet().getObject(key)));
}
public boolean hasGroupingVarChanged() throws SQLException {
if (this.changeLevel != -1) {
if (this.changeLevel < this.groupLevel) {
return true;
} else {
this.changeLevel = -1;
return true;
}
} else {
boolean result = false;
// need to check the complete hierarchy of nested groups for
changes
for (int i = 0; i <= this.groupLevel; i++) {
Object tmp =
this.getResultSet().getObject(((EsqlGroup)this.groups.get(i)).var);
if (!tmp.equals(((EsqlGroup)this.groups.get(i)).value)) {
((EsqlGroup)this.groups.get(i)).value = tmp;
result = true;
if (this.changeLevel == -1 && this.groupLevel != i)
this.changeLevel = i;
}
}
return result;
}
}
public ResultSetMetaData getResultSetMetaData() {
return(resultSetMetaData);
}
public Statement createStatement() throws SQLException {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_JDBC:
statement =
connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
break;
default:
statement = connection.createStatement();
};
return(statement);
}
public Statement getStatement() {
return(statement);
}
public int getUpdateCount() throws SQLException {
return this.updateCount;
}
public int getUpdateCountCount() {
return this.updateCountCount;
}
public int getResultCount() {
return this.resultCount;
}
/**
* retrieve next result, check whether it is an result set or an
* update count. Set instance vars accordingly and update
* counters.
*/
public boolean getMoreResults() throws SQLException {
if (this.statement==null)
return false;
this.hasResultSet = this.statement.getMoreResults();
this.resultSetValid=false;
this.adjustCounts();
return (this.hasResultSet || (this.updateCount>-1));
}
/**
* update counters for result sets and update counts
*/
protected void adjustCounts() throws SQLException {
this.updateCount=this.statement.getUpdateCount();
if (this.hasResultSet) {
this.resultCount++;
} else {
this.updateCountCount++;
}
};
public boolean execute() throws SQLException {
return this.execute(false);
}
public boolean execute( int resultSetFromObject ) throws SQLException {
hasResultSet = this.execute(false);
resultSet = (ResultSet) ((CallableStatement)
preparedStatement).getObject(resultSetFromObject);
resultSetValid = true;
return hasResultSet;
}
/**
* some brain dead DBMSs (Informix) don't like their callable
* statements to be 'execute'd but require 'executeQuery' instead.
*/
public boolean execute( boolean needsQuery ) throws SQLException {
if ( needsQuery ) {
if (preparedStatement != null) {
resultSet = preparedStatement.executeQuery();
}
else {
resultSet = statement.executeQuery( getQueryString() );
}
hasResultSet = (resultSet != null);
resultSetValid = true;
} else {
if (preparedStatement != null) {
hasResultSet = preparedStatement.execute();
}
else {
hasResultSet = statement.execute( getQueryString() );
}
resultSetValid = false;
}
this.adjustCounts();
return(hasResultSet);
}
public boolean hasResultSet() {
return(this.hasResultSet);
}
public int rowCount() throws SQLException {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_JDBC:
// TC: I'm not quite sure if synchronized is really necessary since
// the XSP page will be poolable
synchronized (resultSet) {
int currentRow = resultSet.getRow();
resultSet.last();
int count = resultSet.getRow();
if (currentRow > 0) {
resultSet.absolute(currentRow);
}
else {
resultSet.first();
resultSet.relative(-1);
}
return(count);
}
default:
// select count(*)
throw new RuntimeException("not yet implemented");
}
}
public void getResultRows() throws SQLException {
if ( !resultSetValid ) {
resultSet = statement.getResultSet();
}
resultSetMetaData = resultSet.getMetaData();
position = 0;
if (skipRows > 0) {
switch(limitMethod) {
case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
// in clause
position = skipRows;
break;
case EsqlConnection.LIMIT_METHOD_MYSQL:
// in clause
position = skipRows;
break;
case EsqlConnection.LIMIT_METHOD_JDBC:
resultSet.absolute(skipRows);
position = skipRows;
break;
default:
while (resultSet.next()) {
position++;
if (position == skipRows) {
break;
}
}
};
}
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl
Index: esql.xsl
===================================================================
<?xml version="1.0"?><!-- -*- xsl -*- -->
<!-- $Id: esql.xsl,v 1.1 2002/10/18 14:04:27 haul Exp $-->
<!--
============================================================================
The Apache Software License, Version 1.2
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Cocoon" and "Apache Software Foundation" must not be used to
endorse or promote products derived from this software without prior
written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
-->
<!--
* ESQL Logicsheet
*
* @author ?
* @version CVS $Revision: 1.1 $ $Date: 2002/10/18 14:04:27 $
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsp="http://apache.org/xsp"
xmlns:esql="http://apache.org/cocoon/SQL/v2"
xmlns:xspdoc="http://apache.org/cocoon/XSPDoc/v1"
>
<xsl:param name="XSP-ENVIRONMENT"/>
<xsl:param name="XSP-VERSION"/>
<xsl:param name="filename"/>
<xsl:param name="language"/>
<xsl:variable name="environment">Cocoon 2</xsl:variable>
<xsl:variable name="xsp-namespace-uri">http://apache.org/xsp</xsl:variable>
<xsl:variable name="prefix">esql</xsl:variable>
<xsl:template name="get-nested-content">
<xsl:param name="content"/>
<xsl:choose>
<xsl:when test="$content/xsp:text">"<xsl:value-of
select="$content"/>"</xsl:when>
<xsl:when test="$content/*">
<xsl:apply-templates select="$content/*"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$content"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="get-nested-string">
<xsl:param name="content"/>
<xsl:choose>
<!-- if $content has sub-elements, concatenate them -->
<xsl:when test="$content/*">
""
<xsl:for-each select="$content/node()">
<xsl:choose>
<xsl:when test="name(.)">
<!-- element -->
<xsl:choose>
<xsl:when test="namespace-uri(.)='http://apache.org/xsp' and
local-name(.)='text'">
<!-- xsp:text element -->
+ "<xsl:value-of select="translate(.,'	 ','
')"/>"
</xsl:when>
<xsl:otherwise>
<!-- other elements -->
+ <xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<!-- text node -->
+ "<xsl:value-of select="translate(.,'	 ',' ')"/>"
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<!-- else return the text value of $content -->
<xsl:otherwise>"<xsl:value-of
select="normalize-space($content)"/>"</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="get-parameter">
<xsl:param name="name"/>
<xsl:param name="default"/>
<xsl:param name="required">false</xsl:param>
<xsl:variable name="qname">
<xsl:value-of select="concat($prefix, ':param')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="@*[name(.) = $name]">"<xsl:value-of select="@*[name(.)
= $name]"/>"</xsl:when>
<xsl:when test="(*[name(.) = $qname])[EMAIL PROTECTED] = $name]">
<xsl:call-template name="get-nested-content">
<xsl:with-param name="content"
select="(*[name(.) = $qname])[EMAIL PROTECTED] =
$name]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="string-length($default) = 0">
<xsl:choose>
<xsl:when test="$required = 'true'">
<xsl:call-template name="error">
<xsl:with-param name="message">[Logicsheet processor]
Parameter '<xsl:value-of select="$name"/>' missing in dynamic tag
<<xsl:value-of select="name(.)"/>>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>""</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise><xsl:copy-of select="$default"/></xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="xsp:page">
<xsp:page>
<xsl:apply-templates select="@*"/>
<xsp:structure>
<xsp:include>java.sql.DriverManager</xsp:include>
<xsp:include>java.sql.Connection</xsp:include>
<xsp:include>java.sql.Statement</xsp:include>
<xsp:include>java.sql.PreparedStatement</xsp:include>
<xsp:include>java.sql.CallableStatement</xsp:include>
<xsp:include>java.sql.ResultSet</xsp:include>
<xsp:include>java.sql.ResultSetMetaData</xsp:include>
<xsp:include>java.sql.Struct</xsp:include>
<xsp:include>java.sql.SQLException</xsp:include>
<xsp:include>java.sql.Clob</xsp:include>
<xsp:include>java.sql.Blob</xsp:include>
<xsp:include>java.text.SimpleDateFormat</xsp:include>
<xsp:include>java.text.DecimalFormat</xsp:include>
<xsp:include>java.io.StringWriter</xsp:include>
<xsp:include>java.io.PrintWriter</xsp:include>
<xsp:include>java.io.BufferedInputStream</xsp:include>
<xsp:include>java.io.InputStream</xsp:include>
<xsp:include>java.util.Set</xsp:include>
<xsp:include>java.util.List</xsp:include>
<xsp:include>java.util.Iterator</xsp:include>
<xsp:include>java.util.ListIterator</xsp:include>
<xsp:include>java.math.BigDecimal</xsp:include>
<xsp:include>java.sql.Struct</xsp:include>
<xsp:include>java.sql.Types</xsp:include>
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlHelper</xsp:include>
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlQuery</xsp:include>
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlConnection</xsp:include>
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlConnectionCocoon2</xsp:include>
<xsp:include>org.apache.cocoon.components.language.markup.xsp.XSPUtil</xsp:include>
<xsl:if test=".//esql:connection/esql:pool">
<xsp:include>org.apache.avalon.excalibur.datasource.DataSourceComponent</xsp:include>
</xsl:if>
</xsp:structure>
<xsp:logic>
<xsl:call-template name="variables"><xsl:with-param name="modifier"
select="'private'"/></xsl:call-template>
<xsl:if test=".//esql:connection/esql:pool">
private static ComponentSelector _esql_selector = null;
protected ComponentSelector _esql_get_selector() throws
org.apache.avalon.framework.component.ComponentException {
if (_esql_selector == null) {
try {
_esql_selector = (ComponentSelector)
manager.lookup(DataSourceComponent.ROLE + "Selector");
} catch (ComponentException cme) {
getLogger().error("Could not look up the datasource
component", cme);
}
}
return _esql_selector;
}
</xsl:if>
protected void _esql_printObject ( Object obj, AttributesImpl
xspAttr) throws SAXException
{
if ( obj instanceof List) {
ListIterator j=((List)obj).listIterator();
<xsp:element name="sql-list">
<xsp:logic>
while (j.hasNext()){
<xsp:element name="sql-list-item">
<xsp:attribute
name="pos"><xsp:expr>j.nextIndex()</xsp:expr></xsp:attribute>
<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic>
</xsp:element>
};
</xsp:logic>
</xsp:element>
} else if ( obj instanceof Set ) {
Iterator j=((Set)obj).iterator();
<xsp:element name="sql-set">
<xsp:logic>
while (j.hasNext()){
<xsp:element name="sql-set-item">
<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic>
</xsp:element>
};
</xsp:logic>
</xsp:element>
} else {
<xsp:content><xsp:expr>obj</xsp:expr></xsp:content>;
}
}
</xsp:logic>
<xsl:apply-templates/>
</xsp:page>
</xsl:template>
<xsl:template name="variables">
<xsl:param name="modifier" select="''"/>
<xsp:logic>
<xsl:value-of select="$modifier"/> Stack _esql_connections = new Stack();
<xsl:value-of select="$modifier"/> EsqlConnectionCocoon2 _esql_connection
= null;
<xsl:value-of select="$modifier"/> Stack _esql_queries = new Stack();
<xsl:value-of select="$modifier"/> EsqlQuery _esql_query = null;
<xsl:value-of select="$modifier"/> SQLException _esql_exception = null;
<xsl:value-of select="$modifier"/> StringWriter _esql_exception_writer =
null;
</xsp:logic>
</xsl:template>
<xsl:template match="xsp:page/*[not(self::xsp:*)]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="esql:connection">
<xsl:variable name="driver"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:driver"/></xsl:call-template></xsl:variable>
<xsl:variable name="dburl"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:dburl"/></xsl:call-template></xsl:variable>
<xsl:variable name="username"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:username"/></xsl:call-template></xsl:variable>
<xsl:variable name="password"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:password"/></xsl:call-template></xsl:variable>
<xsl:variable name="pool"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:pool"/></xsl:call-template></xsl:variable>
<xsl:variable name="autocommit"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:autocommit"/></xsl:call-template></xsl:variable>
<xsl:variable name="use-limit-clause"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:use-limit-clause"/></xsl:call-template></xsl:variable>
<xsl:variable name="allow-multiple-results"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:allow-multiple-results"/></xsl:call-template></xsl:variable>
<xsp:logic>
if (_esql_connection != null) {
_esql_connections.push(_esql_connection);
}
_esql_connection = new EsqlConnectionCocoon2();
try {
<xsl:choose>
<xsl:when test="esql:pool">
try {
_esql_connection.datasource = (DataSourceComponent)
_esql_get_selector().select(String.valueOf(<xsl:copy-of select="$pool"/>));
_esql_connection.connection =
_esql_connection.datasource.getConnection();
<xsl:if test="esql:allow-multiple-results">
_esql_connection.setMultipleResults(String.valueOf(<xsl:copy-of
select="$allow-multiple-results"/>));
</xsl:if>
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {
getLogger().error("Could not get the
datasource",_esql_exception_<xsl:value-of select="generate-id(.)"/>);
throw new RuntimeException("Could not get the datasource
"+_esql_exception_<xsl:value-of select="generate-id(.)"/>);
}
</xsl:when>
<xsl:otherwise>
<xsl:if test="esql:driver">
try {
Thread.currentThread().getContextClassLoader().loadClass(String.valueOf(<xsl:copy-of
select="$driver"/>)).newInstance();
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {
throw new RuntimeException("Error loading driver:
"+String.valueOf(<xsl:copy-of select="$driver"/>));
}
</xsl:if>
try {
_esql_connection.setUrl(String.valueOf(<xsl:copy-of
select="$dburl"/>));
<xsl:if test="esql:username">
_esql_connection.setUser(String.valueOf(<xsl:copy-of
select="$username"/>));
</xsl:if>
<xsl:if test="esql:password">
_esql_connection.setPassword(String.valueOf(<xsl:copy-of
select="$password"/>));
</xsl:if>
<xsl:for-each select="esql:property">
_esql_connection.setProperty("<xsl:value-of
select="@name"/>",<xsl:call-template name="get-nested-string"><xsl:with-param
name="content" select="."/></xsl:call-template>);
</xsl:for-each>
<xsl:if test="esql:allow-multiple-results">
_esql_connection.setMultipleResults(String.valueOf(<xsl:copy-of
select="$allow-multiple-results"/>));
</xsl:if>
_esql_connection.connection =
DriverManager.getConnection(_esql_connection.getUrl(),
_esql_connection.getInfo());
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {
throw new RuntimeException("Error opening connection to dburl:
"+String.valueOf(<xsl:copy-of select="$dburl"/>)+":
"+_esql_exception_<xsl:value-of select="generate-id(.)"/>.getMessage());
}
</xsl:otherwise>
</xsl:choose>
try {
if ("false".equals(String.valueOf(<xsl:copy-of
select="$autocommit"/>))) {
if (_esql_connection.getAutoCommit()) {
_esql_connection.setAutoCommit(false);
}
} else {
if (!_esql_connection.getAutoCommit()) {
_esql_connection.setAutoCommit(true);
}
}
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {
// do NOT: throw new RuntimeException("Error setting connection
autocommit");
}
<xsl:if test="esql:use-limit-clause">
_esql_connection.setLimitMethod(String.valueOf(<xsl:copy-of
select="$use-limit-clause"/>));
</xsl:if>
<xsl:apply-templates/>
} finally {
try {
if(!_esql_connection.getAutoCommit()) {
_esql_connection.commit();
}
_esql_connection.close();
if (_esql_connections.empty()) {
_esql_connection = null;
} else {
_esql_connection = (EsqlConnectionCocoon2)_esql_connections.pop();
}
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {}
}
</xsp:logic>
</xsl:template>
<xsl:template match="esql:connection/esql:driver"/>
<xsl:template match="esql:connection/esql:dburl"/>
<xsl:template match="esql:connection/esql:username"/>
<xsl:template match="esql:connection/esql:password"/>
<xsl:template match="esql:connection/esql:pool"/>
<xsl:template match="esql:connection/esql:allow-multiple-results"/>
<xsl:template match="esql:connection/esql:autocommit"/>
<xsl:template match="esql:connection/esql:use-limit-clause"/>
<xsl:template match="esql:connection/esql:property"/>
<xspdoc:desc>Returns the connection's meta data.</xspdoc:desc>
<xsl:template match="esql:get-connection-metadata">
<xsp:expr>_esql_connection.getMetaData()</xsp:expr>
</xsl:template>
<xsl:template match="esql:connection/esql:get-connection">
<xsp:expr>_esql_connection</xsp:expr>
</xsl:template>
<!-- set one parameter of a prepared or callable statement and use correct
method for type -->
<xsl:template name="set-query-parameter">
<xsl:choose>
<xsl:when test="@type">
<xsl:variable name="type"><xsl:value-of
select="concat(translate(substring(@type,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),substring(@type,2))"/></xsl:variable>
<xsl:text>set</xsl:text><xsl:value-of select="$type"/>(<xsl:value-of
select="position()"/>,<xsl:call-template
name="get-nested-content"><xsl:with-param name="content"
select="."/></xsl:call-template>);<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>setString(</xsl:text><xsl:value-of
select="position()"/>,String.valueOf(<xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="."/></xsl:call-template>));<xsl:text>
</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc> internal. set one parameter of a callable statement
</xspdoc:desc>
<xsl:template name="set-call-parameter">
<xsl:if test="@direction='out' or @direction='inout'">
<xsl:text>_esql_query.getCallableStatement().</xsl:text>
registerOutParameter(<xsl:value-of select="position()"/>,
<xsl:call-template name="get-Sql-Type"><xsl:with-param
name="type"><xsl:value-of
select="@type"/></xsl:with-param></xsl:call-template><xsl:if test="@typename">,
<xsl:value-of select="@typename"/> </xsl:if>);
</xsl:if>
<xsl:if test="not(@direction) or @direction='inout' or @direction='in'">
<xsl:text>_esql_query.getCallableStatement().</xsl:text>
<xsl:call-template name="set-query-parameter"/>
</xsl:if>
</xsl:template>
<xspdoc:desc> internal. set one parameter of a prepared statement
</xspdoc:desc>
<xsl:template name="set-parameter">
<xsl:text>_esql_query.getPreparedStatement().</xsl:text>
<xsl:call-template name="set-query-parameter"/>
</xsl:template>
<xsl:template name="do-results">
do {
if (_esql_query.hasResultSet()) {
_esql_query.getResultRows();
if (_esql_query.nextRow()) {
switch (_esql_query.getResultCount()) {
<xsl:for-each select="esql:results">
case <xsl:value-of select="position()"/>: <xsl:if
test="position()=last()"><xsl:text>
default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
break;
</xsl:for-each>
}
} else {
switch (_esql_query.getUpdateCountCount()) {
<xsl:for-each select="esql:no-results">
case <xsl:value-of select="position()"/>: <xsl:if
test="position()=last()"><xsl:text>
default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
break;
</xsl:for-each>
}
}
_esql_query.getResultSet().close();
} else {
if (_esql_query.getUpdateCount() > 0) {
switch (_esql_query.getUpdateCountCount()) {
<xsl:for-each select="esql:update-results">
case <xsl:value-of select="position()"/>: <xsl:if
test="position()=last()"><xsl:text>
default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
break;
</xsl:for-each>
}
} else {
switch (_esql_query.getUpdateCountCount()) {
<xsl:for-each select="esql:no-results">
case <xsl:value-of select="position()"/>: <xsl:if
test="position()=last()"><xsl:text>
default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
break;
</xsl:for-each>
}
}
}
} while(_esql_connection.multipleResults() &&
_esql_query.getMoreResults());
</xsl:template>
<xsl:template match="esql:connection//esql:execute-query">
<xsl:variable name="query"><xsl:choose><xsl:when
test="esql:query"><xsl:call-template name="get-nested-string"><xsl:with-param
name="content" select="esql:query"/></xsl:call-template></xsl:when><xsl:when
test="esql:call"><xsl:call-template name="get-nested-string"><xsl:with-param
name="content"
select="esql:call"/></xsl:call-template></xsl:when></xsl:choose></xsl:variable>
<xsl:variable name="maxrows"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:max-rows"/></xsl:call-template></xsl:variable>
<xsl:variable name="skiprows"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:skip-rows"/></xsl:call-template></xsl:variable>
<xsp:logic>
if (_esql_query != null) {
_esql_queries.push(_esql_query);
}
_esql_query = new EsqlQuery( _esql_connection,
String.valueOf(<xsl:copy-of select="$query"/>) );
<xsl:if test="esql:max-rows">
try {
_esql_query.setMaxRows( Integer.parseInt(String.valueOf(<xsl:copy-of
select="$maxrows"/>).trim()) );
} catch (NumberFormatException e) {}
</xsl:if>
<xsl:if test="esql:skip-rows">
try {
_esql_query.setSkipRows( Integer.parseInt(String.valueOf(<xsl:copy-of
select="$skiprows"/>).trim()) );
} catch (NumberFormatException e) {}
</xsl:if>
try {
<xsl:choose>
<xsl:when test="esql:call">
_esql_query.prepareCall();
<xsl:for-each select="esql:call//esql:parameter">
<xsl:call-template name="set-call-parameter"/>
</xsl:for-each>
<xsl:choose>
<xsl:when test="esql:[EMAIL PROTECTED]'true' or
@needs-query='yes']">_esql_query.execute(true);</xsl:when>
<xsl:when test="esql:[EMAIL
PROTECTED]">_esql_query.execute(<xsl:copy-of select="esql:[EMAIL
PROTECTED]"/>);</xsl:when>
<xsl:otherwise>_esql_query.execute();</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="esql:query//esql:parameter">
_esql_query.prepareStatement();
<xsl:for-each select="esql:query//esql:parameter">
<xsl:call-template name="set-parameter"/>
</xsl:for-each>
_esql_query.execute();
</xsl:when>
<xsl:otherwise>
_esql_query.createStatement();
_esql_query.execute();
</xsl:otherwise>
</xsl:choose>
getLogger().debug("esql query: " + _esql_query.getQueryString());
<xsl:call-template name="do-results"/>
<xsl:if test="esql:call">
// call results
<xsp:content>
<xsl:apply-templates select="esql:call-results"/>
</xsp:content>
</xsl:if>
_esql_query.getStatement().close();
} catch (SQLException _esql_exception_<xsl:value-of
select="generate-id(.)"/>) {
<xsl:choose>
<xsl:when test="esql:error-results">
try {
_esql_exception = _esql_exception_<xsl:value-of
select="generate-id(.)"/>;
_esql_exception_writer = new StringWriter();
_esql_exception.printStackTrace(new
PrintWriter(_esql_exception_writer));
<xsl:apply-templates select="esql:error-results"/>
if (!_esql_connection.getAutoCommit()) {
_esql_connection.rollback();
}
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>_2) {}
</xsl:when>
<xsl:otherwise>
try {
if (!_esql_connection.getAutoCommit()) {
_esql_connection.rollback();
}
} catch (Exception _esql_exception_<xsl:value-of
select="generate-id(.)"/>_2) {}
throw new RuntimeException("Error executing statement: " +
_esql_query.getQueryString() + ": "+_esql_exception_<xsl:value-of
select="generate-id(.)"/>);
</xsl:otherwise>
</xsl:choose>
}
if (_esql_queries.empty()) {
_esql_query = null;
} else {
_esql_query = (EsqlQuery)_esql_queries.pop();
}
</xsp:logic>
</xsl:template>
<xsl:template match="esql:query//esql:parameter">"?"</xsl:template>
<xsl:template match="esql:call//esql:parameter">"?"</xsl:template>
<xsl:template match="esql:execute-query//esql:results//esql:row-count">
<xsp:expr>_esql_query.rowCount()</xsp:expr>
</xsl:template>
<xsl:template match="esql:execute-query//esql:results">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xsl:template match="esql:execute-query//esql:call-results">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xsl:template match="esql:execute-query//esql:error-results">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xsl:template match="esql:execute-query//esql:no-results">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xsl:template match="esql:execute-query//esql:update-results">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xsl:template match="esql:update-results//esql:get-update-count">
<xsp:expr>_esql_query.getUpdateCount()</xsp:expr>
</xsl:template>
<xsl:template match="esql:results//esql:row-results">
<xsl:variable name="group" select=".//esql:group"/>
<xsp:logic>
do {
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
<xsl:call-template name="nextRow"/>
} while ( _esql_query.keepGoing() );
if (_esql_query.getSkipRows() > 0 ) {
<xsl:apply-templates
select="ancestor::esql:results//esql:previous-results" mode="more"/>
}
if (_esql_query.nextRow()) {
<xsl:apply-templates
select="ancestor::esql:results//esql:more-results" mode="more"/>
}
</xsp:logic>
</xsl:template>
<xspdoc:desc>Only advance one row if no nested groups exist in this query.
Ignore nested queries.</xspdoc:desc>
<xsl:template name="nextRow">
<xsl:if test="not(.//esql:group) or
generate-id(.//esql:group)=generate-id(.//esql:execute-query//esql:group)">
<xsp:logic>
//checking out early?
if (_esql_query.getMaxRows() != -1 && _esql_query.getCurrentRow()
- _esql_query.getSkipRows() == _esql_query.getMaxRows()) {
_esql_query.setKeepGoing( false );
} else { //if not, advance normally
_esql_query.setKeepGoing( _esql_query.nextRow() );
}
</xsp:logic>
</xsl:if>
</xsl:template>
<xsl:template match="esql:results//esql:previous-results"/>
<xsl:template match="esql:results//esql:previous-results" mode="more">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xspdoc:desc>Allows header elements around groups of consecutive records with
identical values in column named by @group-on. Facilitates a single query with
joins to be used in lieu of some nested queries.</xspdoc:desc>
<xsl:template match="esql:group//esql:member">
<xsp:logic>
do {
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
<xsl:call-template name="nextRow"/>
} while (_esql_query.keepGoing() &&
!_esql_query.hasGroupingVarChanged());
</xsp:logic>
</xsl:template>
<xspdoc:desc>Used in conjunction with and nested inside esql:group.
Formatting for individual records goes within esql:member. Header stuff goes in
between group and member.</xspdoc:desc>
<xsl:template match="esql:group">
<xsl:variable name="group">
<xsl:call-template name="get-column">
<xsl:with-param name="name">group-on</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsp:logic>
_esql_query.groupLevelPlusPlus();
if (!_esql_query.groupLevelExists()) {
_esql_query.setGroupingVar(<xsl:copy-of select="$group"/>);
}
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
_esql_query.groupLevelMinusMinus();
</xsp:logic>
</xsl:template>
<xsl:template match="esql:results//esql:more-results"/>
<xsl:template match="esql:results//esql:more-results" mode="more">
<xsp:content>
<xsl:apply-templates/>
</xsp:content>
</xsl:template>
<xspdoc:desc>results in a set of elements whose names are the names of the
columns. the elements each have one text child, whose value is the value of the
column interpreted as a string. No special formatting is allowed here. If you
want to mess around with the names of the elements or the value of the text
field, use the type-specific get methods and write out the result fragment
yourself.</xspdoc:desc>
<xsl:template match="esql:row-results//esql:get-columns">
<xsl:variable name="tagcase"><xsl:value-of
select="@tag-case"/></xsl:variable>
<xsp:logic>
for (int _esql_i = 1; _esql_i <=
_esql_query.getResultSetMetaData().getColumnCount(); _esql_i++) {
String _esql_tagname =
_esql_query.getResultSetMetaData().getColumnName(_esql_i);
<xsp:element>
<xsp:param name="name">
<xsl:choose>
<xsl:when test="$tagcase='lower'">
<xsp:expr>_esql_tagname.toLowerCase()</xsp:expr>
</xsl:when>
<xsl:when test="$tagcase='upper'">
<xsp:expr>_esql_tagname.toUpperCase()</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr>_esql_tagname</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsp:param>
<xsp:logic>
switch(_esql_query.getResultSet().getMetaData().getColumnType(_esql_i)){
case java.sql.Types.ARRAY:
case java.sql.Types.STRUCT:
<xsp:element name="sql-row">
<xsp:logic>
Object[] _esql_struct = ((Struct)
_esql_query.getResultSet().getObject(_esql_i)).getAttributes();
for ( int _esql_k=0; _esql_k<_esql_struct.length;
_esql_k++){
<xsp:element
name="sql-row-item"><xsp:logic>this._esql_printObject(_esql_struct[_esql_k],xspAttr);</xsp:logic></xsp:element>
}
</xsp:logic>
</xsp:element>
break;
case java.sql.Types.OTHER: // This is what Informix uses for
Sets, Bags, Lists
// postgres is broken as it doesn't allow getObject()
// to retrieve any type (i.e. bit and bit varying)
// so don't handle complex types different for postgres
if
(!_esql_connection.getUrl().startsWith("jdbc:postgresql:")) {
this._esql_printObject(_esql_query.getResultSet().getObject(_esql_i), xspAttr);
break;
}
default:
// standard type
<xsp:content>
<xsp:expr>
<xsl:call-template name="get-string-encoded">
<xsl:with-param name="null"><xsl:value-of
select="@null"/></xsl:with-param>
<xsl:with-param
name="column-spec">_esql_i</xsl:with-param>
<xsl:with-param
name="resultset">_esql_query.getResultSet()</xsl:with-param>
</xsl:call-template>
</xsp:expr></xsp:content>
}
</xsp:logic>
</xsp:element>
}
this.characters("\n");
</xsp:logic>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a string</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-string|esql:call-results//esql:get-string"
name="get-string">
<xsp:expr>
<xsl:call-template name="get-string-encoded">
<xsl:with-param name="null"><xsl:value-of
select="@null"/></xsl:with-param>
<xsl:with-param name="column-spec"><xsl:call-template
name="get-column"/></xsl:with-param>
<xsl:with-param name="resultset"><xsl:call-template
name="get-resultset"/></xsl:with-param>
</xsl:call-template>
</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a date. if a format
attribute exists, its value is taken to be a date format string as defined in
java.text.SimpleDateFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-date|esql:call-results//esql:get-date">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getDate(<xsl:call-template name="get-column"/>) == null
? "" : new SimpleDateFormat("<xsl:value-of
select="@format"/>").format(<xsl:call-template
name="get-resultset"/>.getDate(<xsl:call-template
name="get-column"/>))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getDate(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a time. if a format
attribute exists, its value is taken to be a date format string as defined in
java.text.SimpleDateFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-time|esql:call-results//esql:get-time">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getTime(<xsl:call-template name="get-column"/>) == null
? "" : new SimpleDateFormat("<xsl:value-of
select="@format"/>").format(<xsl:call-template
name="get-resultset"/>.getTime(<xsl:call-template
name="get-column"/>))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getTime(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a timestamp. if a
format attribute exists, its value is taken to be a date format string as
defined in java.text.SimpleDateFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-timestamp|esql:call-results//esql:get-timestamp">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getTimestamp(<xsl:call-template name="get-column"/>) ==
null ? "" : new SimpleDateFormat("<xsl:value-of
select="@format"/>").format(<xsl:call-template
name="get-resultset"/>.getTimestamp(<xsl:call-template
name="get-column"/>))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getTimestamp(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the value of the given column as true or
false</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-boolean|esql:call-results//esql:get-boolean">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getBoolean(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a double. if a format
attribute exists, its value is taken to be a decimal format string as defined
in java.text.DecimalFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-double|esql:call-results//esql:get-double">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr>new DecimalFormat("<xsl:value-of
select="@format"/>").format(new Double(<xsl:call-template
name="get-resultset"/>.getDouble(<xsl:call-template
name="get-column"/>)))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getDouble(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a float. if a format
attribute exists, its value is taken to be a decimal format string as defined
in java.text.DecimalFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-float|esql:call-results//esql:get-float">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr>new DecimalFormat("<xsl:value-of
select="@format"/>").format(new Float(<xsl:call-template
name="get-resultset"/>.getFloat(<xsl:call-template
name="get-column"/>)))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getFloat(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a BigDecimal. if a
format attribute exists, its value is taken to be a decimal format string as
defined in java.text.DecimalFormat, and the result is formatted
accordingly.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-bigdecimal|esql:call-results//esql:get-bigdecimal">
<xsl:choose>
<xsl:when test="@format">
<xsp:expr>new DecimalFormat("<xsl:value-of
select="@format"/>").format(<xsl:call-template
name="get-resultset"/>.getBigDecimal(<xsl:call-template
name="get-column"/>))</xsp:expr>
</xsl:when>
<xsl:otherwise>
<xsp:expr><xsl:call-template
name="get-resultset"/>.getBigDecimal(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>returns the current result set</xspdoc:desc>
<xsl:template match="esql:results//esql:get-resultset">
<xsp:expr><xsl:call-template name="get-resultset"/></xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as an object</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-object|esql:call-results//esql:get-object">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getObject(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as an array</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-array|esql:call-results//esql:get-array">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getArray(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a struct</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-struct|esql:call-results//esql:get-struct">
<xsp:expr>(Struct) <xsl:call-template
name="get-resultset"/>.getObject(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as an integer</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-int|esql:call-results//esql:get-int">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getInt(<xsl:call-template name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a long</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-long|esql:call-results//esql:get-long">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getLong(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a short</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-short|esql:call-results//esql:get-short">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getShort(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as byte array</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-blob|esql:call-results//esql:get-blob"
name="get-blob">
<xsp:expr>EsqlHelper.getBlob(<xsl:call-template
name="get-resultset"/>,<xsl:call-template name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as unicode string (column
can be string or clob</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-clob|esql:call-results//esql:get-clob"
name="get-clob">
<xsp:expr>EsqlHelper.getStringOrClob(<xsl:call-template
name="get-resultset"/>,<xsl:call-template name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column as a clob as ascii string
with optinal encoding</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-ascii|esql:call-results//esql:get-ascii">
<xsp:expr>EsqlHelper.getAscii(<xsl:call-template name="get-resultset"/>,
<xsl:call-template name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the value of the given column interpeted as an xml
fragment.
The fragment is parsed by the default xsp parser and the document element is
returned.
If a root attribute exists, its value is taken to be the name of an element
to wrap around the contents of
the fragment before parsing.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-xml|esql:call-results//esql:get-xml">
<xsl:variable name="content">
<xsl:choose>
<xsl:when test="@root">
<xsl:text>"<</xsl:text>
<xsl:value-of select="@root"/>
<xsl:text>>"+</xsl:text>
<xsl:call-template name="get-string"/>
<xsl:text>+"</</xsl:text>
<xsl:value-of select="@root"/>
<xsl:text>>"</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="get-string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsp:logic>
{
org.apache.cocoon.components.parser.Parser newParser = null;
try {
newParser = (org.apache.cocoon.components.parser.Parser)
this.manager.lookup(org.apache.cocoon.components.parser.Parser.ROLE);
InputSource __is = new InputSource(
new StringReader(
String.valueOf(<xsl:copy-of select="$content"/>)
)
);
XSPUtil.include(__is, this.contentHandler, newParser);
} catch (Exception e) {
getLogger().error("Could not include page", e);
} finally {
if (newParser != null) this.manager.release((Component)
newParser);
}
}
</xsp:logic>
</xsl:template>
<xspdoc:desc>returns the number of columns in the resultset.</xspdoc:desc>
<xsl:template match="esql:results//esql:get-column-count">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getMetaData().getColumnCount()</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the metadata of the resultset.</xspdoc:desc>
<xsl:template match="esql:results//esql:get-metadata">
<xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData()</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the position of the current row in the result
set</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:get-row-position|esql:results//esql:get-row-position|esql:call-results//esql:get-row-position">
<xsp:expr>_esql_query.getCurrentRow()</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the name of the given column. the column must be
specified by number, not name.</xspdoc:desc>
<xsl:template match="esql:results//esql:get-column-name">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getMetaData().getColumnName(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the label of the given column. the column must be
specified by number, not name.</xspdoc:desc>
<xsl:template match="esql:results//esql:get-column-label">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getMetaData().getColumnLabel(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the name of the type of the given column. the column
must be specified by number, not name.</xspdoc:desc>
<xsl:template match="esql:results//esql:get-column-type-name">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getMetaData().getColumnTypeName(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the type of the given column as int. the column must be
specified by number, not name.</xspdoc:desc>
<xsl:template match="esql:row-results//esql:get-column-type"
name="get-column-type">
<xsp:expr><xsl:call-template
name="get-resultset"/>.getMetaData().getColumnType(<xsl:call-template
name="get-column"/>)</xsp:expr>
</xsl:template>
<xspdoc:desc>allows null-column testing. Evaluates to a Java expression,
which is true when the referred column contains a null-value for the current
resultset row</xspdoc:desc>
<xsl:template match="esql:row-results//esql:is-null">
<xsp:expr>((<xsl:call-template
name="get-resultset"/>.getObject(<xsl:call-template name="get-column"/>) ==
null) || <xsl:call-template name="get-resultset"/>.wasNull())</xsp:expr>
</xsl:template>
<xsl:template match="esql:result"/>
<xspdoc:desc>creates a nested query like block that uses the result set
obtained from a column as current result set. This version is deprecated,
please use <esql:use-result> instead.</xspdoc:desc>
<xsl:template
match="esql:row-results//esql:results[child::esql:result]|esql:call-results//esql:results[child::esql:result]">
<xsl:call-template name="use-results"/>
</xsl:template>
<xspdoc:desc>creates a nested query like block that uses the result set
obtained from a column as current result set.</xspdoc:desc>
<xsl:template name="use-results" match="esql:use-results[child::esql:result]">
<xsl:variable name="maxrows"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:max-rows"/></xsl:call-template></xsl:variable>
<xsl:variable name="skiprows"><xsl:call-template
name="get-nested-string"><xsl:with-param name="content"
select="esql:skip-rows"/></xsl:call-template></xsl:variable>
<xsp:logic>
// nested result set
if (_esql_query != null) {
_esql_queries.push(_esql_query);
}
_esql_query = new EsqlQuery((ResultSet) <xsl:apply-templates
select="esql:result/*"/>);
<xsl:if test="esql:max-rows">
try {
_esql_query.setMaxRows( Integer.parseInt(String.valueOf(<xsl:copy-of
select="$maxrows"/>).trim()) );
} catch (NumberFormatException e) {}
</xsl:if>
<xsl:if test="esql:skip-rows">
try {
_esql_query.setSkipRows( Integer.parseInt(String.valueOf(<xsl:copy-of
select="$skiprows"/>).trim()) );
} catch (NumberFormatException e) {}
</xsl:if>
{
<xsl:call-template name="do-results"/>
}
if (_esql_queries.empty()) {
_esql_query = null;
} else {
_esql_query = (EsqlQuery)_esql_queries.pop();
}
</xsp:logic>
</xsl:template>
<xspdoc:desc>returns the message of the current exception</xspdoc:desc>
<xsl:template match="esql:error-results//esql:get-message">
<xsp:expr>_esql_exception.getMessage()</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the current exception as a string</xspdoc:desc>
<xsl:template match="esql:error-results//esql:to-string">
<xsp:expr>_esql_exception.toString()</xsp:expr>
</xsl:template>
<xspdoc:desc>returns the stacktrace of the current exception</xspdoc:desc>
<xsl:template match="esql:error-results//esql:get-stacktrace">
<xsp:expr>_esql_exception_writer.toString()</xsp:expr>
</xsl:template>
<xsl:template name="get-resultset">
<xsl:call-template name="get-query"/><xsl:choose><xsl:when
test="@from-call='yes' or
@from-call='true'"><xsl:text>.getCallableStatement()</xsl:text></xsl:when><xsl:otherwise><xsl:text>.getResultSet()</xsl:text></xsl:otherwise></xsl:choose>
</xsl:template>
<xsl:template name="get-query">
<xsl:choose>
<xsl:when test="@ancestor">
<xsl:text>((EsqlQuery)_esql_queries.elementAt(_esql_queries.size()-</xsl:text>
<xsl:value-of select="@ancestor"/>
<xsl:text>))</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>_esql_query</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xspdoc:desc>used internally to determine which column is the given column.
if a column attribute exists and its value is a number, it is taken to be the
column's position. if the value is not a number, it is taken to be the column's
name. if a column attribute does not exist, an esql:column element is assumed
to exist and to render as a string (after all of the xsp instructions have been
evaluated), which is taken to be the column's name.</xspdoc:desc>
<xsl:template name="get-column">
<xsl:param name="name">column</xsl:param>
<xsl:variable name="column">
<xsl:call-template name="get-parameter">
<xsl:with-param name="name"><xsl:value-of
select="$name"/></xsl:with-param>
<xsl:with-param name="required">true</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="starts-with($column,'"')">
<xsl:variable name="raw-column">
<xsl:value-of select="substring($column,2,string-length($column)-2)"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="not(string(number($raw-column))='NaN')">
<xsl:value-of select="$raw-column"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$column"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$column"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="get-string-encoded">
<xsl:param name="column-spec"/>
<xsl:param name="resultset"/>
<xsl:param name="null"/>
<xsl:variable name="encoding">
<xsl:choose>
<xsl:when test="@encoding">"<xsl:value-of
select="@encoding"/>"</xsl:when>
<xsl:when test="esql:encoding">
<xsl:call-template name="get-nested-string">
<xsl:with-param name="content" select="esql:encoding"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>default</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$encoding = 'default'">
EsqlHelper.getAscii(<xsl:value-of select="$resultset"/>,<xsl:value-of
select="$column-spec"/>)
</xsl:when>
<xsl:otherwise>
EsqlHelper.getStringFromByteArray(<xsl:value-of
select="$resultset"/>.getBytes
(<xsl:value-of select="$column-spec"/>), <xsl:value-of
select="$encoding"/>)
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="get-Sql-Type">
<xsl:param name="type"/>
<xsl:choose>
<!-- just do the 'unusual' mappings -->
<xsl:when test="$type='Byte'">Types.TINYINT</xsl:when>
<xsl:when test="$type='Short'">Types.SMALLINT</xsl:when>
<xsl:when test="$type='Int'">Types.INTEGER</xsl:when>
<xsl:when test="$type='Long'">Types.BIGINT</xsl:when>
<xsl:when test="$type='Float'">Types.REAL</xsl:when>
<xsl:when test="$type='BigDecimal'">Types.DECIMAL</xsl:when>
<xsl:when test="$type='Boolean'">Types.BIT</xsl:when>
<xsl:when test="$type='String'">Types.VARCHAR</xsl:when>
<xsl:when test="$type='Bytes'">Types.BINARY</xsl:when>
<xsl:when test="$type='AsciiStream'">Types.LONGVARCHAR</xsl:when>
<xsl:when test="$type='UnicodeStream'">Types.LONGVARCHAR</xsl:when>
<xsl:when test="$type='BinaryStream'">Types.VARBINARY</xsl:when>
<!-- handle DBMS specific types e.g.
oracle.jdbc.driver.OracleTypes.CURSOR -->
<xsl:when test="contains($type,'.')"><xsl:value-of
select="$type"/></xsl:when>
<!-- default to upper case type -->
<xsl:otherwise>Types.<xsl:value-of
select="translate(@type,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--
Break on error.
@param message explanation of the error
-->
<xsl:template name="error">
<xsl:param name="message"/>
<xsl:message terminate="yes"><xsl:value-of select="$message"/></xsl:message>
</xsl:template>
<!--
swallow esql:param tags
-->
<xsl:template match="esql:param"/>
<xsl:template match="@*|node()" priority="-1">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/AbstractDatabaseAction.java
Index: AbstractDatabaseAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentSelector;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.generation.ImageDirectoryGenerator;
import java.io.*;
import java.math.BigDecimal;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Set up environment for configurable form handling data. It is
* important to note that all DatabaseActions use a common configuration
* format. This group of actions are unique in that they employ a
* terciary mapping. There is the Form parameter, the database column,
* and the type.
*
* Each configuration file must use the same format in order to be
* effective. The name of the root configuration element is irrelevant.
*
* <pre>
* <root>
* <connection>personnel<connection>
* <table>
* <keys>
* <key param="id" dbcol="id" type="int"/>
* </keys>
* <values>
* <value param="name" dbcol="name" type="string"/>
* <value param="department" dbcol="department_id" type="int"/>
* </values>
* </table>
* </root>
* </pre>
*
* The types recognized by this system are:
*
* <table>
* <tr>
* <th>Type</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>ascii</td>
* <td>ASCII Input Stream, a CLOB input</td>
* </tr>
* <tr>
* <td>big-decimal</td>
* <td>a <code>java.math.BigDecimal</code> value</td>
* </tr>
* <tr>
* <td>binary</td>
* <td>Binary Input Stream, a BLOB input</td>
* </tr>
* <tr>
* <td>byte</td>
* <td>a Byte</td>
* </tr>
* <tr>
* <td>string</td>
* <td>a String</td>
* </tr>
* <tr>
* <td>date</td>
* <td>a Date</td>
* </tr>
* <tr>
* <td>double</td>
* <td>a Double</td>
* </tr>
* <tr>
* <td>float</td>
* <td>a Float</td>
* </tr>
* <tr>
* <td>int</td>
* <td>an Integer</td>
* </tr>
* <tr>
* <td>long</td>
* <td>a Long</td>
* </tr>
* <tr>
* <td>short</td>
* <td>a Short</td>
* </tr>
* <tr>
* <td>time</td>
* <td>a Time</td>
* </tr>
* <tr>
* <td>time-stamp</td>
* <td>a Timestamp</td>
* </tr>
* <tr>
* <td>now</td>
* <td>a Timestamp with the current day/time--the form value is
ignored.</td>
* </tr>
* <tr>
* <td>image</td>
* <td>a binary image file, we cache the attribute information</td>
* </tr>
* <tr>
* <td>image-width</td>
* <td>
* the width attribute of the cached file attribute. NOTE:
* param attribute must equal the param for image with a
* "-width" suffix.
* </td>
* </tr>
* <tr>
* <td>image-height</td>
* <td>
* the width attribute of the cached file attribute NOTE:
* param attribute must equal the param for image with a
* "-height" suffix.
* </td>
* </tr>
* <tr>
* <td>image-size</td>
* <td>
* the size attribute of the cached file attribute NOTE:
* param attribute must equal the param for image with a
* "-size" suffix.
* </td>
* </tr>
* </table>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
* @version CVS $Id: AbstractDatabaseAction.java,v 1.1 2002/10/18 14:04:27
haul Exp $
*/
public abstract class AbstractDatabaseAction extends
AbstractComplementaryConfigurableAction implements Configurable, Disposable {
protected Map files = new HashMap();
protected static final Map typeConstants;
protected ComponentSelector dbselector;
static {
/** Initialize the map of type names to jdbc column types.
Note that INTEGER, BLOB, and VARCHAR column types map to more than
one type name. **/
Map constants = new HashMap();
constants.put("ascii", new Integer(Types.CLOB));
constants.put("big-decimal", new Integer(Types.BIGINT));
constants.put("binary", new Integer(Types.BLOB));
constants.put("byte", new Integer(Types.TINYINT));
constants.put("string", new Integer(Types.VARCHAR));
constants.put("date", new Integer(Types.DATE));
constants.put("double", new Integer(Types.DOUBLE));
constants.put("float", new Integer(Types.FLOAT));
constants.put("int", new Integer(Types.INTEGER));
constants.put("long", new Integer(Types.NUMERIC));
constants.put("short", new Integer(Types.SMALLINT));
constants.put("time", new Integer(Types.TIME));
constants.put("time-stamp", new Integer(Types.TIMESTAMP));
constants.put("now", new Integer(Types.LONGVARBINARY));
//constants.put("image", new Integer(Types.DISTINCT));
//constants.put("image-width", new Integer(Types.ARRAY));
//constants.put("image-height", new Integer(Types.BIT));
//constants.put("image-size", new Integer(Types.CHAR));
constants.put("image",new Integer(Types.BLOB));
constants.put("image-width",new Integer(Types.INTEGER));
constants.put("image-height",new Integer(Types.INTEGER));
constants.put("image-size",new Integer(Types.INTEGER));
constants.put("row-index",new Integer(Types.INTEGER));
constants.put("image-mime-type",new Integer(Types.VARCHAR));
constants.put("array", new Integer(Types.ARRAY));
constants.put("row", new Integer(Types.STRUCT));
constants.put("object", new Integer(Types.OTHER));
typeConstants = Collections.unmodifiableMap(constants);
}
/**
* Compose the Actions so that we can select our databases.
*/
public void compose(ComponentManager manager) throws ComponentException {
this.dbselector = (ComponentSelector)
manager.lookup(DataSourceComponent.ROLE + "Selector");
super.compose(manager);
}
/**
* Get the Datasource we need.
*/
protected final DataSourceComponent getDataSource(Configuration conf)
throws ComponentException {
Configuration dsn = conf.getChild("connection");
return (DataSourceComponent) this.dbselector.select(dsn.getValue(""));
}
/**
* Return whether a type is a Large Object (BLOB/CLOB).
*/
protected final boolean isLargeObject (String type) {
if ("ascii".equals(type)) return true;
if ("binary".equals(type)) return true;
if ("image".equals(type)) return true;
return false;
}
/**
* Get the Statement column so that the results are mapped correctly.
*/
protected Object getColumn(ResultSet set, Request request, Configuration
entry)
throws Exception {
Integer type = (Integer)
AbstractDatabaseAction.typeConstants.get(entry.getAttribute("type"));
String attribute = entry.getAttribute("param", "");
String dbcol = entry.getAttribute("dbcol", "");
Object value = null;
switch (type.intValue()) {
case Types.CLOB:
Clob dbClob = set.getClob(dbcol);
int length = (int) dbClob.length();
InputStream asciiStream = new
BufferedInputStream(dbClob.getAsciiStream());
byte[] buffer = new byte[length];
asciiStream.read(buffer);
String str = new String(buffer);
asciiStream.close();
value = str;
break;
case Types.BIGINT:
value = set.getBigDecimal(dbcol);
break;
case Types.TINYINT:
value = new Byte(set.getByte(dbcol));
break;
case Types.VARCHAR:
value = set.getString(dbcol);
break;
case Types.DATE:
value = set.getDate(dbcol);
break;
case Types.DOUBLE:
value = new Double(set.getDouble(dbcol));
break;
case Types.FLOAT:
value = new Float(set.getFloat(dbcol));
break;
case Types.INTEGER:
value = new Integer(set.getInt(dbcol));
break;
case Types.NUMERIC:
value = new Long(set.getLong(dbcol));
break;
case Types.SMALLINT:
value = new Short(set.getShort(dbcol));
break;
case Types.TIME:
value = set.getTime(dbcol);
break;
case Types.TIMESTAMP:
value = set.getTimestamp(dbcol);
break;
case Types.ARRAY:
value = set.getArray(dbcol);
break;
case Types.BIT:
value = new Integer(set.getInt(dbcol));
break;
case Types.CHAR:
value = new Integer(set.getInt(dbcol));
break;
case Types.STRUCT:
value = (Struct) set.getObject(dbcol);
break;
case Types.OTHER:
value = set.getObject(dbcol);
break;
default:
// The blob types have to be requested separately, via a
Reader.
value = "";
break;
}
setRequestAttribute(request,attribute,value);
return value;
}
/**
* Set the Statement column so that the results are mapped correctly.
* The name of the parameter is retrieved from the configuration object.
*
* @param statement the prepared statement
* @param position the position of the column
* @param request the request
* @param entry the configuration object
*/
protected void setColumn(PreparedStatement statement, int position,
Request request, Configuration entry)
throws Exception {
setColumn(statement,position,request,entry,entry.getAttribute("param",""));
}
/**
* Set the Statement column so that the results are mapped correctly. The
* value of the column is retrieved from the request object. If the
* named parameter exists in the request object's parameters, that value
* is used. Otherwise if the named parameter exists in the request
object's
* attributes, that value is used. Otherwise the request object is
* retrieved using Request.get(attribute), which is documented to be the
* same as Request.getAttribute(attribute), so something weird must be
* going on.
*
* @param statement the prepared statement
* @param position the position of the column
* @param request the request
* @param entry the configuration object
* @param param the name of the request parameter
*/
protected void setColumn(PreparedStatement statement, int position,
Request request, Configuration entry, String param)
throws Exception {
Object value = request.getParameter(param);
if (value == null) value = request.getAttribute(param);
if (value == null) value = request.get(param);
setColumn(statement,position,request,entry,param,value);
}
/**
* Set the Statement column so that the results are mapped correctly.
*
* @param statement the prepared statement
* @param position the position of the column
* @param request the request
* @param entry the configuration object
* @param param the name of the request parameter
* @param value the value of the column
*/
protected void setColumn(PreparedStatement statement, int position,
Request request, Configuration entry, String param, Object value) throws
Exception {
setColumn(statement,position,request,entry,param,value,0);
}
/**
* Set the Statement column so that the results are mapped correctly.
*
* @param statement the prepared statement
* @param position the position of the column
* @param request the request
* @param entry the configuration object
* @param param the name of the request parameter
* @param value the value of the column
* @param rowIndex the index of the current row for manyrows inserts
*/
protected void setColumn(PreparedStatement statement, int position,
Request request, Configuration entry, String param, Object value, int rowIndex)
throws Exception {
getLogger().debug("Setting column "+position+" named "+param+" with
value "+value);
if (value instanceof String) {
value = ((String) value).trim();
}
String typeName = entry.getAttribute("type");
Integer typeObject = (Integer)
AbstractDatabaseAction.typeConstants.get(typeName);
if (typeObject == null) {
throw new SQLException("Can't set column because the type
"+typeName+" is unrecognized");
}
if (value == null) {
/** If the value is null, set the column value null and return **/
if (typeName.equals("image-width") ||
typeName.equals("image-height") || typeName.equals("image-size") ||
typeName.equals("row-index") || typeName.equals("image-mime-type")) {
/** these column types are automatically generated so it's ok
**/
} else {
statement.setNull(position, typeObject.intValue());
return;
}
}
if ("".equals(value)) {
switch (typeObject.intValue()) {
case Types.CHAR:
case Types.CLOB:
case Types.VARCHAR:
/** If the value is an empty string and the column is
a string type, we can continue **/
break;
case Types.INTEGER:
if (typeName.equals("image-width") ||
typeName.equals("image-height") || typeName.equals("image-size") ||
typeName.equals("row-index")) {
/** again, these types are okay to be absent **/
break;
}
default:
/** If the value is an empty string and the column
is something else, we treat it as a null value **/
statement.setNull(position, typeObject.intValue());
return;
}
}
/** Store the column value in the request attribute
keyed by the request parameter name. we do this so possible future
actions can access this data. not sure about the key tho... **/
setRequestAttribute(request,param,value);
File file;
switch (typeObject.intValue()) {
case Types.CLOB:
int length = -1;
InputStream asciiStream = null;
if (value instanceof File) {
File asciiFile = (File) value;
asciiStream = new BufferedInputStream(new
FileInputStream(asciiFile));
length = (int) asciiFile.length();
} else {
String asciiText = (String) value;
asciiStream = new BufferedInputStream(new
ByteArrayInputStream(asciiText.getBytes()));
length = asciiText.length();
}
statement.setAsciiStream(position, asciiStream, length);
break;
case Types.BIGINT:
BigDecimal bd = null;
if (value instanceof BigDecimal) {
bd = (BigDecimal) value;
} else {
bd = new BigDecimal((String) value);
}
statement.setBigDecimal(position, bd);
break;
case Types.TINYINT:
Byte b = null;
if (value instanceof Byte) {
b = (Byte) value;
} else {
b = new Byte((String) value);
}
statement.setByte(position, b.byteValue());
break;
case Types.DATE:
Date d = null;
if (value instanceof Date) {
d = (Date) value;
} else if (value instanceof java.util.Date) {
d = new Date(((java.util.Date) value).getTime());
} else {
d = new Date(this.dateValue((String) value,
entry.getAttribute("format", "M/d/yyyy")));
}
statement.setDate(position, d);
break;
case Types.DOUBLE:
Double db = null;
if (value instanceof Double) {
db = (Double) value;
} else {
db = new Double((String) value);
}
statement.setDouble(position, db.doubleValue());
break;
case Types.FLOAT:
Float f = null;
if (value instanceof Float) {
f = (Float) value;
} else {
f = new Float((String) value);
}
statement.setFloat(position, f.floatValue());
break;
case Types.NUMERIC:
Long l = null;
if (value instanceof Long) {
l = (Long) value;
} else {
l = new Long((String) value);
}
statement.setLong(position, l.longValue());
break;
case Types.SMALLINT:
Short s = null;
if (value instanceof Short) {
s = (Short) value;
} else {
s = new Short((String) value);
}
statement.setShort(position, s.shortValue());
break;
case Types.TIME:
Time t = null;
if (value instanceof Time) {
t = (Time) value;
} else {
t = new Time(this.dateValue((String) value,
entry.getAttribute("format", "h:m:s a")));
}
statement.setTime(position, t);
break;
case Types.TIMESTAMP:
Timestamp ts = null;
if (value instanceof Time) {
ts = (Timestamp) value;
} else {
ts = new Timestamp(this.dateValue((String) value,
entry.getAttribute("format", "M/d/yyyy h:m:s a")));
}
statement.setTimestamp(position, ts);
break;
case Types.ARRAY:
statement.setArray(position, (Array) value); // no way to
convert string to array
break;
case Types.STRUCT:
case Types.OTHER:
statement.setObject(position, value);
break;
case Types.LONGVARBINARY:
statement.setTimestamp(position, new Timestamp((new
java.util.Date()).getTime()));
break;
case Types.VARCHAR:
if ("string".equals(typeName)) {
statement.setString(position, (String) value);
break;
} else if ("image-mime-type".equals(typeName)) {
String imageAttr = param.substring(0, (param.length() -
"-mime-type".length()));
file = (File) request.get(imageAttr);
synchronized (this.files) {
Parameters parameters = (Parameters)
this.files.get(file);
String imageMimeType =
parameters.getParameter("image-mime-type",
(String) settings.get("image-mime-type",""));
statement.setString(position, imageMimeType);
/** Store the image mime type in the request
attributes.
Why do we do this? **/
setRequestAttribute(request, param, imageMimeType);
}
break;
}
case Types.BLOB:
if (value instanceof File) {
file = (File)value;
} else if (value instanceof String) {
file = new File((String)value);
} else {
throw new SQLException("Invalid type for blob:
"+value.getClass().getName());
}
//InputStream input = new BufferedInputStream(new
FileInputStream(file));
FileInputStream input = new FileInputStream(file);
statement.setBinaryStream(position, input,
(int)file.length());
if ("image".equals(typeName)) {
/** If this column type is an image, store the
size, width, and height in a static table **/
Parameters parameters = new Parameters();
parameters.setParameter("image-size",
Long.toString(file.length()));
int [] dimensions = ImageDirectoryGenerator.getSize(file);
String type = ImageDirectoryGenerator.getFileType(file);
parameters.setParameter("image-width",
Integer.toString(dimensions[0]));
parameters.setParameter("image-height",
Integer.toString(dimensions[1]));
parameters.setParameter("image-mime-type",type);
synchronized (this.files) {
this.files.put(file, parameters);
}
}
break;
case Types.INTEGER:
if ("int".equals(typeName)) {
Integer i = null;
if (value instanceof Integer) {
i = (Integer) value;
} else {
i = new Integer((String) value);
}
statement.setInt(position, i.intValue());
break;
} else if ("image-width".equals(typeName)) {
/** Get the image width from the cached image data **/
/** Is this why we store the values in the request
attributes? **/
String imageAttr = param.substring(0, (param.length() -
"-width".length()));
file = (File) request.get(imageAttr);
synchronized (this.files) {
Parameters parameters = (Parameters)
this.files.get(file);
statement.setInt(position,
parameters.getParameterAsInteger("image-width",
Integer.parseInt((String)settings.get("image-width","-1"))));
/** Store the image width in the request attributes.
Why do we do this? **/
setRequestAttribute(request,
param,
parameters.getParameter("image-width",
(String) settings.get("image-width","")));
}
break;
} else if ("image-height".equals(typeName)) {
/** Get the image height from the cached image data **/
String imageAttr = param.substring(0, (param.length() -
"-height".length()));
file = (File) request.get(imageAttr);
synchronized (this.files) {
Parameters parameters = (Parameters)
this.files.get(file);
statement.setInt(position,
parameters.getParameterAsInteger("image-height",
Integer.parseInt((String)settings.get("image-height","-1"))));
setRequestAttribute(request,
param,
parameters.getParameter("image-height",
(String)
settings.get("image-height","")));
}
break;
} else if ("image-size".equals(typeName)) {
/** Get the image file size from the cached image data **/
String imageAttr = param.substring(0, (param.length() -
"-size".length()));
file = (File) request.get(imageAttr);
synchronized (this.files) {
Parameters parameters = (Parameters)
this.files.get(file);
statement.setInt(position,
parameters.getParameterAsInteger("image-size",
Integer.parseInt((String)settings.get("image-height","-1"))));
setRequestAttribute(request,
param,
parameters.getParameter("image-size",
(String) settings.get("image-size","")));
}
break;
} else if ("row-index".equals(typeName)) {
statement.setInt(position,rowIndex);
break;
}
default:
throw new SQLException("Impossible exception - invalid type
"+typeName);
}
}
/**
* Convert a String to a long value.
*/
private final long dateValue(String value, String format) throws
Exception {
DateFormat formatter = new SimpleDateFormat(format);
return formatter.parse(value).getTime();
}
/**
* dispose
*/
public void dispose() {
this.manager.release(dbselector);
}
/**
* Store a key/value pair in the request attributes. We prefix the key
* with the name of this class to prevent potential name collisions.
*/
protected void setRequestAttribute(Request request, String key, Object
value) {
request.setAttribute("org.apache.cocoon.acting.AbstractDatabaseAction:"+key,value);
}
/**
* Retreive a value from the request attributes.
*/
protected Object getRequestAttribute(Request request, String key) {
return
request.getAttribute("org.apache.cocoon.acting.AbstractDatabaseAction:"+key);
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseAddAction.java
Index: DatabaseAddAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
/**
* Adds record in a database. The action can update one or more tables,
* and can add more than one row to a table at a time. The form descriptor
* semantics for this are still in a bit of a state of flux. Note
* that if a secondary table relies on the value of a new primary key in a
* primary table, the primary key must be created using manual mode.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
* @version CVS $Id: DatabaseAddAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseAddAction extends AbstractDatabaseAction implements
ThreadSafe {
protected static final Map addStatements = new HashMap();
private static final Map selectStatements = new HashMap();
/**
* Add a record to the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
Map results = new HashMap();
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor",
(String) this.settings.get("descriptor")), resolver,
param.getParameterAsBoolean("reloadable",reloadable));
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
Configuration[] tables = conf.getChildren("table");
for (int i=0; i<tables.length; i++) {
Configuration table = tables[i];
processTable(table,conn,request,results);
}
conn.commit();
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException se) {
getLogger().debug("There was an error rolling back the
transaction", se);
}
}
//throw new ProcessingException("Could not add record :position =
" + currentIndex, e);
throw new ProcessingException("Could not add record",e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null) this.dbselector.release(datasource);
}
return Collections.unmodifiableMap(results);
}
/**
* Inserts a row or a set of rows into the given table based on the
* request parameters
*
* @param table the table's configuration
* @param conn the database connection
* @param request the request
*/
void processTable(Configuration table, Connection conn, Request request,
Map results) throws SQLException,ConfigurationException,Exception {
PreparedStatement statement = null;
try {
String query = this.getAddQuery(table);
getLogger().debug("Add query: "+query);
statement = conn.prepareStatement(query);
Configuration[] keys = table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
int currentIndex = 1;
boolean manyrows = false;
int wildcardIndex = -1;
String wildcardParam = null;
for (int i=0; i<keys.length; i++) {
wildcardParam = keys[i].getAttribute("param");
if ((wildcardIndex = wildcardParam.indexOf('*')) != -1) {
manyrows = true;
break;
}
}
if (manyrows) {
/**
* This table has a column with a wildcard, so we're going
* to be inserting n rows, where 0 <= n
*/
String prefix = wildcardParam.substring(0,wildcardIndex);
String suffix;
if (wildcardParam.length() >= wildcardIndex+1) {
suffix = wildcardParam.substring(wildcardIndex+1);
} else {
suffix = "";
}
Enumeration names = request.getParameterNames();
SortedSet matchset = new TreeSet();
while (names.hasMoreElements()) {
String name = (String)names.nextElement();
if (name.startsWith(prefix) && name.endsWith(suffix)) {
String wildcard = name.substring(prefix.length());
wildcard =
wildcard.substring(0,wildcard.length()-suffix.length());
matchset.add(wildcard);
}
}
Iterator iterator = matchset.iterator();
int rowIndex = 1;
while (iterator.hasNext()) {
String wildcard = (String)iterator.next();
currentIndex = 1;
for (int j=0; j<keys.length; j++) {
String myparam =
getActualParam(keys[j].getAttribute("param"),wildcard);
currentIndex +=
setKey(table,keys[j],conn,statement,currentIndex,request,myparam,results);
}
for (int j=0; j<values.length; j++) {
String myparam =
getActualParam(values[j].getAttribute("param"),wildcard);
this.setColumn(statement,currentIndex,request,values[j],myparam,request.getParameter(myparam),rowIndex);
currentIndex++;
}
statement.execute();
rowIndex++;
}
} else {
/**
* This table has no wildcard columns, so we're going to
* be inserting 1 row.
*/
for (int i = 0; i < keys.length; i++) {
currentIndex +=
setKey(table,keys[i],conn,statement,currentIndex,request,keys[i].getAttribute("param",""),results);
}
for (int i = 0; i < values.length; i++, currentIndex++) {
this.setColumn(statement, currentIndex, request, values[i]);
}
statement.execute();
/** Done processing table **/
}
} finally {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {}
}
}
/**
* Sets the key value on the prepared statement. There are four modes:
*
* <dl>
* <dt>automatic (default)</dt>
* <dd>let the database automatically create the key. note this
* prohibits the action from storing the key value anywhere.</dd>
* <dt>manual</dt>
* <dd>create the key value using SELECT(dbcol)+1 from TABLE</dd>
* <dt>form</dt>
* <dd>look for the key value in the request parameters</dd>
* <dt>request-attribute</dt>
* <dd>look for the key value in the request attributes</dd>
* </dl>
*
* This method has a couple of side effects. If the mode is manual,
* the key value is stored in the request object's attributes for use
* by other inserts. The key is the string "key:TABLENAME:DBCOL".
* This method also puts the value of manually created keys in the results
* map. That key is simply the value of the dbcol attribute. Note this
* stuff is definitely up in the air.
*
* @param table the table's configuration object
* @param key the key's configuration object
* @param conn the database connection
* @param statement the insert statement
* @param currentIndex the position of the key column
* @param request the request object
* @param param the actual name of the request parameter
* @return the number of columns by which to increment the currentIndex
*/
int setKey(Configuration table, Configuration key, Connection conn,
PreparedStatement statement, int currentIndex, Request request, String param,
Map results) throws ConfigurationException, SQLException,Exception {
String mode = key.getAttribute("mode","automatic");
String keyname = new
StringBuffer("key:").append(table.getAttribute("name"))
.append(':').append(key.getAttribute("dbcol")).toString();
if ("manual".equals(mode)) {
/** Set the key value using SELECT MAX(keyname)+1 **/
String selectQuery = this.getSelectQuery(key);
PreparedStatement select_statement =
conn.prepareStatement(selectQuery);
ResultSet set = select_statement.executeQuery();
set.next();
int value = set.getInt("maxid") + 1;
statement.setInt(currentIndex, value);
getLogger().debug("Manually setting key to "+value);
setRequestAttribute(request,keyname,new Integer(value));
results.put(key.getAttribute("dbcol"),String.valueOf(value));
set.close();
select_statement.close();
return 1;
} else if ("form".equals(mode)) {
/** Set the key value from the request **/
getLogger().debug("Setting key from form");
this.setColumn(statement, currentIndex, request, key, param);
return 1;
} else if ("request-attribute".equals(mode)) {
Integer value =
(Integer)getRequestAttribute(request,key.getAttribute("request-attribute-name"));
getLogger().debug("Setting key from request attribute "+value);
statement.setInt(currentIndex,value.intValue());
return 1;
} else {
getLogger().debug("Automatically setting key");
/** The database automatically creates a key value **/
return 0;
}
}
/**
* Returns the actual name of the parameter. If the name contains
* no wildcard, the param is returned untouched, otherwise the
* wildcard value is substituted for the * character. This probably
* doesn't deserve a method unto itself, but I can imagine wanting
* to use a more sophisticated matching and substitution algorithm.
*
* @param param the name of the parameter, possibly with a wildcard char
* @param wildcard the wildcard value
* @return the actual name of the parameter
*/
String getActualParam(String param, String wildcard) {
int index;
if ((index = param.indexOf('*')) != -1) {
return param.substring(0,index)+wildcard+param.substring(index+1);
} else {
return param;
}
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected String getAddQuery(Configuration table) throws
ConfigurationException {
String query = null;
synchronized (DatabaseAddAction.addStatements) {
query = (String) DatabaseAddAction.addStatements.get(table);
if (query == null) {
Configuration[] values =
table.getChild("values").getChildren("value");
Configuration[] keys =
table.getChild("keys").getChildren("key");
StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" (");
int numKeys = 0;
for (int i = 0; i < keys.length; i++) {
String mode = keys[i].getAttribute("mode", "automatic");
if ("manual".equals(mode) || "form".equals(mode) ||
"request-attribute".equals(mode)) {
if (i > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
this.setSelectQuery(table.getAttribute("name"),
keys[i]);
numKeys++;
}
}
int numValues = 0;
for (int i = 0; i < values.length; i++) {
if ((numKeys + numValues) > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
numValues++;
}
queryBuffer.append(") VALUES (");
int numParams = numValues + numKeys;
for (int i = 0; i < numParams; i++) {
if (i > 0) {
queryBuffer.append(", ");
}
queryBuffer.append("?");
}
queryBuffer.append(")");
query = queryBuffer.toString();
DatabaseAddAction.addStatements.put(table, query);
}
}
return query;
}
/**
* Set the String representation of the MaxID lookup statement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected final synchronized void setSelectQuery(String tableName,
Configuration entry) throws ConfigurationException {
StringBuffer queryBuffer = new StringBuffer("SELECT max(");
queryBuffer.append(entry.getAttribute("dbcol"));
queryBuffer.append(") AS maxid FROM ");
queryBuffer.append(tableName);
DatabaseAddAction.selectStatements.put(entry, queryBuffer.toString());
}
protected final synchronized String getSelectQuery(Configuration entry)
throws ConfigurationException {
return (String) DatabaseAddAction.selectStatements.get(entry);
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseAuthenticatorAction.java
Index: DatabaseAuthenticatorAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* This action is used to authenticate user by comparing several request
* fields (username, password) with the values in database. The description of
* the process is given via external xml description file simiar to the one
* used for all actions derived from AbstractDatabaseAction.
* <pre>
* <root>
* <connection>personnel</connection>
* <table name="users_table>
* <select dbcol="username" request-param="username"
* to-session="username"/>
* <select dbcol="password" request-param="password"
* nullable="yes"/>
* <select dbcol="role" to-session="role"
type="string"/>
* <select dbcol="skin" to-session="skin"
type="string"/>
* </table>
* </root>
* </pre>
* The values specified via "request-param" describe the name of HTTP request
* parameter, "dbcol" indicates matching database column, "nullable" means
* that request-param which is null or empty will not be included in the WHERE
* clause. This way you can enable accounts with empty passwords, etc.
* "to-session" attribute indicates under which name the value obtained from
* database should be stored in the session. Of course new session is created
* when authorization is successfull. The "type" attribute can be either
* string, long or double and alters the type of object stored in session.
* Additionally all parameters that are
* propagated to the session are made available to the sitemap via {name}
* expression.
*
* If there is no need to touch the session object, providing just one-time
* verification, you can specify action parameter "create-session" to "no" or
* "false". No values are then propagated to the sesion and session object is
* not verified.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Martin Man</a>
* @version CVS $Id: DatabaseAuthenticatorAction.java,v 1.1 2002/10/18
14:04:27 haul Exp $
*/
public class DatabaseAuthenticatorAction extends AbstractDatabaseAction
implements ThreadSafe
{
/**
* Main invocation routine.
*/
public Map act (Redirector redirector, SourceResolver resolver, Map
objectModel, String src,
Parameters parameters) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
Statement st = null;
ResultSet rs = null;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable")) {
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
}
// read local settings
try {
Configuration conf = this.getConfiguration (
parameters.getParameter ("descriptor", (String)
this.settings.get("descriptor")),
resolver,
parameters.getParameterAsBoolean("reloadable",reloadable));
boolean cs = true;
String create_session = parameters.getParameter ("create-session",
(String)
this.settings.get("create-session"));
if (create_session != null &&
("no".equals (create_session.trim ()) || "false".equals
(create_session.trim ()))) {
cs = false;
}
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request req = ObjectModelHelper.getRequest(objectModel);
/* check request validity */
if (req == null) {
getLogger ().debug ("DBAUTH: no request object");
return null;
}
String query = this.getAuthQuery (conf, req);
if (query == null) {
getLogger ().debug ("DBAUTH: have not got query");
req.setAttribute("message", "The authenticator is
misconfigured");
return null;
}
getLogger ().debug ("DBAUTH: query is: " + query);
st = conn.createStatement ();
rs = st.executeQuery (query);
if (rs.next ()) {
getLogger ().debug ("DBAUTH: authorized successfully");
Session session = null;
if (cs) {
session = req.getSession (false);
if (session != null)
session.invalidate ();
session = req.getSession (true);
if (session == null)
return null;
getLogger ().debug ("DBAUTH: session created");
} else {
getLogger ().debug ("DBAUTH: leaving session untouched");
}
HashMap actionMap = this.propagateParameters (conf, rs,
session);
if(!conn.getAutoCommit()) {
conn.commit();
}
return Collections.unmodifiableMap (actionMap);
}
if(!conn.getAutoCommit()) {
conn.rollback();
}
req.setAttribute("message", "The username or password were
incorrect, please check your CAPS LOCK key and try again.");
getLogger ().debug ("DBAUTH: no results for query");
} catch (Exception e) {
if (conn != null) {
try {
if(!conn.getAutoCommit()) {
conn.rollback();
}
} catch (Exception se) {/* ignore */}
}
getLogger().debug ("exception: ", e);
return null;
} finally {
if (rs != null) rs.close();
if (st != null) st.close();
if (conn != null) {
try {
conn.close();
} catch (Exception e) {/* ignore */}
}
}
return null;
}
private String getAuthQuery (Configuration conf, Request req) {
boolean first_constraint = true;
StringBuffer queryBuffer = new StringBuffer ("SELECT ");
StringBuffer queryBufferEnd = new StringBuffer ("");
String dbcol, request_param, request_value, nullstr;
boolean nullable = false;
Configuration table = conf.getChild ("table");
Configuration[] select = table.getChildren ("select");
try {
for (int i = 0; i < select.length; i ++) {
if (i != 0)
queryBuffer.append (", ");
dbcol = select[i].getAttribute ("dbcol");
queryBuffer.append (dbcol);
try {
request_param = select[i].getAttribute ("request-param");
if (request_param == null ||
request_param.trim().equals ("")) {
continue;
}
} catch (Exception e) {
continue;
}
try {
nullstr = select[i].getAttribute ("nullable");
if (nullstr != null) nullstr = nullstr.trim ();
if ("yes".equals (nullstr) || "true".equals (nullstr)) {
nullable = true;
}
} catch (Exception e1) {
}
/* if there is a request parameter name,
* but not the value, we exit immediately do
* that authorization fails authomatically */
request_value = req.getParameter (
request_param);
if (request_value == null || request_value.trim().equals
("")) {
// value is null
if (!nullable) {
getLogger ().debug ("DBAUTH: request-param "
+ request_param + " does not exist");
return null;
}
} else {
if (!first_constraint)
queryBufferEnd.append (" AND ");
queryBufferEnd.append
(dbcol).append("='").append(request_value).append("'");
first_constraint = false;
}
}
queryBuffer.append (" FROM ");
queryBuffer.append (table.getAttribute ("name"));
if (!queryBufferEnd.toString ().trim ().equals (""))
queryBuffer.append (" WHERE ").append
(queryBufferEnd.toString ());
return queryBuffer.toString ();
} catch (Exception e) {
getLogger ().debug ("DBAUTH: got exception: " + e);
return null;
}
}
private HashMap propagateParameters (Configuration conf, ResultSet rs,
Session session) {
Configuration table = conf.getChild ("table");
Configuration[] select = table.getChildren ("select");
String dbcol, session_param, type;
HashMap map = new HashMap();
try {
for (int i = 0; i < select.length; i ++) {
dbcol = select[i].getAttribute ("dbcol");
try {
session_param = select[i].getAttribute ("to-session");
if (session_param != null &&
!session_param.trim().equals ("")) {
String s = rs.getString (i + 1);
/* propagate to session */
try {
type = select[i].getAttribute ("type");
} catch (Exception e) {
type = null;
}
if (type == null || "".equals (type.trim ())) {
type = "string";
}
Object o = null;
if ("string".equals (type)) {
o = s;
} else if ("long".equals (type)) {
Long l = Long.decode (s);
o = l;
} else if ("double".equals (type)) {
Double d = Double.valueOf (s);
o = d;
}
if (session != null) {
session.setAttribute (session_param, o);
getLogger ().debug ("DBAUTH: propagating param "
+ session_param + "=" + s);
}
map.put (session_param, o);
}
} catch (Exception e) {
}
}
return map;
} catch (Exception e) {
getLogger().debug("exception: ", e);
}
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseCookieAuthenticatorAction.java
Index: DatabaseCookieAuthenticatorAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.components.language.markup.xsp.XSPCookieHelper;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* This action is used to authenticate user by comparing several cookie
values
* (username, password) with the values in database. The description of the
* process is given via external xml description file simiar to the one used
* for all actions derived from AbstractDatabaseAction. <pre>
* <root>
* <connection>personnel</connection>
* <table name="users_table>
* <select dbcol="username" cookie-name="username"
* to-session="username"/>
* <select dbcol="password" cookie-name="password"
* nullable="yes"/>
* <select dbcol="role" to-session="role"
type="string"/>
* <select dbcol="skin" to-session="skin"
type="string"/>
* </table>
* </root>
* </pre> The values specified via "cookie-name" describe the name of the
* cookie, "dbcol" indicates matching database column, "nullable" means that
* cookie-name which is null or empty will not be included in the WHERE
clause.
* This way you can enable accounts with empty passwords, etc. "to-session"
* attribute indicates under which name the value obtained from database
should
* be stored in the session. Of course new session is created when
* authorization is successfull. The "type" attribute can be either string,
* long or double and alters the type of object stored in session.
Additionally
* all parameters that are propagated to the session are made available to
the
* sitemap via {name} expression. If there is no need to touch the session
* object, providing just one-time verification, you can specify action
* parameter "create-session" to "no" or "false". No values are then
propagated
* to the sesion and session object is not verified. If you want to append
* attributes to the session without creating a new one, specify action
* parameter "append-session" to "yes" or "true".
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paolo Scaffardi</a>
* @version CVS $Id: DatabaseCookieAuthenticatorAction.java,v 1.1 2002/10/18
14:04:27 haul Exp $
*/
public class DatabaseCookieAuthenticatorAction extends AbstractDatabaseAction
implements ThreadSafe {
/**
* Main invocation routine.
*
* @param redirector Description of Parameter
* @param resolver Description of Parameter
* @param objectModel Description of Parameter
* @param src Description of Parameter
* @param parameters Description of Parameter
* @return Description of the Returned Value
* @exception Exception Description of Exception
*/
public Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String src,
Parameters parameters)
throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
Statement st = null;
ResultSet rs = null;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable")) {
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
}
// read local settings
try {
Configuration conf = this.getConfiguration(
parameters.getParameter("descriptor", (String)
this.settings.get("descriptor")),
resolver,
parameters.getParameterAsBoolean("reloadable",
reloadable));
boolean cs = true;
boolean as = false;
String create_session = parameters.getParameter("create-session",
(String) this.settings.get("create-session"));
String
append_session = parameters.getParameter("append-session",
(String) this.settings.get("append-session"));
if (create_session != null &&
("no".equals(create_session.trim()) ||
"false".equals(create_session.trim()))) {
cs = false;
}
if (append_session != null &&
("yes".equals(append_session.trim()) ||
"true".equals(append_session.trim()))) {
as = true;
}
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request req = ObjectModelHelper.getRequest(objectModel);
/*
* check request validity
*/
if (req == null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: no request object");
}
return null;
}
String query = this.getAuthQuery(objectModel, conf, req);
if (query == null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: have not got query");
}
req.setAttribute("message", "The authenticator is
misconfigured");
return null;
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: query is: " + query);
}
st = conn.createStatement();
rs = st.executeQuery(query);
if (rs.next()) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: authorized
successfully");
}
Session session = null;
if (cs) {
session = req.getSession(false);
if (session != null) {
if (as == false) {
session.invalidate();
session = req.getSession(true);
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: session
invalidated");
}
}
} else {
session = req.getSession(true);
}
if (session == null) {
return null;
}
if (getLogger().isDebugEnabled()) {
if (as) {
getLogger().debug("DBCOOKIEAUTH: appending to
session");
} else {
getLogger().debug("DBCOOKIEAUTH: session
created");
}
}
} else {
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: leaving session
untouched");
}
}
HashMap actionMap = this.propagateParameters(conf, rs,
session);
if (!conn.getAutoCommit()) {
conn.commit();
}
return Collections.unmodifiableMap(actionMap);
}
if (!conn.getAutoCommit()) {
conn.rollback();
}
req.setAttribute("message", "The username or password were
incorrect, please check your CAPS LOCK key and try again.");
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: no results for query");
}
} catch (Exception e) {
if (conn != null) {
try {
if (!conn.getAutoCommit()) {
conn.rollback();
}
} catch (Exception se) {
/*
* ignore
*/
}
}
getLogger().error("Exception: ", e);
return null;
} finally {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
/*
* ignore
*/
}
}
}
return null;
}
/**
* Gets the authQuery attribute of the DatabaseCookieAuthenticatorAction
* object
*
* @param objectModel Description of Parameter
* @param conf Description of Parameter
* @param req Description of Parameter
* @return The authQuery value
*/
private String getAuthQuery(Map objectModel, Configuration conf, Request
req) {
boolean first_constraint = true;
StringBuffer queryBuffer = new StringBuffer("SELECT ");
StringBuffer queryBufferEnd = new StringBuffer("");
String dbcol;
String cookie_name;
String cookie_value;
String nullstr;
boolean nullable = false;
Configuration table = conf.getChild("table");
Configuration[] select = table.getChildren("select");
try {
for (int i = 0; i < select.length; i++) {
if (i != 0) {
queryBuffer.append(", ");
}
dbcol = select[i].getAttribute("dbcol");
queryBuffer.append(dbcol);
try {
cookie_name = select[i].getAttribute("cookie-name");
if (cookie_name == null ||
cookie_name.trim().equals("")) {
continue;
}
} catch (Exception e) {
continue;
}
try {
nullstr = select[i].getAttribute("nullable");
if (nullstr != null) {
nullstr = nullstr.trim();
}
if ("yes".equals(nullstr) || "true".equals(nullstr)) {
nullable = true;
}
} catch (Exception e1) {
}
/*
* if there is a cookie name,
* but not the value, we exit immediately do
* that authorization fails authomatically
*/
cookie_value = XSPCookieHelper.getCookie(objectModel,
cookie_name, -1).getValue();
if (cookie_value == null || cookie_value.trim().equals("")) {
// value is null
if (!nullable) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: cookie-name "
+ cookie_name + " does not exist");
}
return null;
}
} else {
if (!first_constraint) {
queryBufferEnd.append(" AND ");
}
queryBufferEnd.append(dbcol + "='" + cookie_value + "'");
first_constraint = false;
}
}
queryBuffer.append(" FROM ");
queryBuffer.append(table.getAttribute("name"));
if (!queryBufferEnd.toString().trim().equals("")) {
queryBuffer.append(" WHERE ").append(queryBufferEnd);
}
return queryBuffer.toString();
} catch (Exception e) {
getLogger().error("Exception: ",e);
return null;
}
}
/**
* Description of the Method
*
* @param conf Description of Parameter
* @param rs Description of Parameter
* @param session Description of Parameter
* @return Description of the Returned Value
*/
private HashMap propagateParameters(Configuration conf, ResultSet rs,
Session session) {
Configuration table = conf.getChild("table");
Configuration[] select = table.getChildren("select");
String dbcol;
String session_param;
String type;
HashMap map = new HashMap();
try {
for (int i = 0; i < select.length; i++) {
dbcol = select[i].getAttribute("dbcol");
try {
session_param = select[i].getAttribute("to-session");
if (session_param != null &&
!session_param.trim().equals("")) {
String s = rs.getString(i + 1);
/*
* propagate to session
*/
try {
type = select[i].getAttribute("type");
} catch (Exception e) {
type = null;
}
if (type == null || "".equals(type.trim())) {
type = "string";
}
Object o = null;
if ("string".equals(type)) {
o = s;
} else if ("long".equals(type)) {
Long l = Long.decode(s);
o = l;
} else if ("double".equals(type)) {
Double d = Double.valueOf(s);
o = d;
}
if (session != null) {
session.setAttribute(session_param, o);
if (getLogger().isDebugEnabled()) {
getLogger().debug("DBCOOKIEAUTH: propagating
param "
+ session_param + "=" + s);
}
}
map.put(session_param, o);
}
} catch (Exception e) {
}
}
return map;
} catch (Exception e) {
getLogger().error("Exception: ", e);
}
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseDeleteAction.java
Index: DatabaseDeleteAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Delete a record from a database. This Action assumes that all
* dependant data is either automatically cleaned up by cascading
* deletes, or that multiple instances of this action are being used
* in the correct order. In other words, it removes one record by
* the keys.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Id: DatabaseDeleteAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public final class DatabaseDeleteAction extends AbstractDatabaseAction
implements ThreadSafe {
private static final Map deleteStatements = new HashMap();
/**
* Delete a record from the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public final Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
int currentIndex = 0;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor",
(String) this.settings.get("descriptor")), resolver,
param.getParameterAsBoolean("reloadable",reloadable));
String query = this.getDeleteQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
PreparedStatement statement = conn.prepareStatement(query);
Configuration[] keys =
conf.getChild("table").getChild("keys").getChildren("key");
for (int i = 0; i < keys.length; i++) {
this.setColumn(statement, i + 1, request, keys[i]);
}
int rows = statement.executeUpdate();
conn.commit();
statement.close();
if(rows > 0){
request.setAttribute("rows", Integer.toString(rows));
return EMPTY_MAP;
}
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
throw new ProcessingException("Could not delete record :position
= " + currentIndex, e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null) this.dbselector.release(datasource);
}
return null;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
private final String getDeleteQuery(Configuration conf) throws
ConfigurationException {
String query = null;
synchronized (DatabaseDeleteAction.deleteStatements) {
query = (String) DatabaseDeleteAction.deleteStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] keys =
table.getChild("keys").getChildren("key");
StringBuffer queryBuffer = new StringBuffer("DELETE FROM ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" WHERE ");
for (int i = 0; i < keys.length; i++) {
if (i > 0) {
queryBuffer.append(" AND ");
}
queryBuffer.append((keys[i]).getAttribute("dbcol"));
queryBuffer.append(" = ?");
}
query = queryBuffer.toString();
DatabaseDeleteAction.deleteStatements.put(conf, query);
}
}
return query;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseSelectAction.java
Index: DatabaseSelectAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Select a record from a database. If request parameters are present,
* their values are used to populate request attributes. Otherwise,
* values from database are used.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a>
* @version CVS $Id: DatabaseSelectAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseSelectAction extends AbstractDatabaseAction implements
ThreadSafe {
private static final Map selectStatements = new HashMap();
/**
* Select a record from the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
int currentIndex = 0;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor",
(String) this.settings.get("descriptor")),
resolver,
param.getParameterAsBoolean("reloadable",reloadable));
Request request = ObjectModelHelper.getRequest(objectModel);
Configuration[] keys =
conf.getChild("table").getChild("keys").getChildren("key");
Configuration[] values =
conf.getChild("table").getChild("values").getChildren("value");
PreparedStatement statement = null;
ResultSet rset = null;
boolean result = false;
for (int i = 0; i < keys.length; i++) {
final String parameter = keys[i].getAttribute("param");
Object value = request.getParameter(parameter);
if (value == null || "".equals(value)) {
if (statement == null) {
final String query = this.getSelectQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
statement = conn.prepareStatement(query);
currentIndex = 1;
for (int j = 0; j < keys.length; j++, currentIndex++)
{
this.setColumn(statement, currentIndex, request,
keys[j]);
}
rset = statement.executeQuery();
result = rset.next();
}
if (result)
value = this.getColumn(rset, request, keys[i]);
}
if (value != null)
request.setAttribute(parameter, value.toString());
}
for (int i = 0; i < values.length; i++) {
final String parameter = values[i].getAttribute("param");
Object value = request.getParameter(parameter);
if (value == null || "".equals(value)) {
if (statement == null) {
final String query = this.getSelectQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
statement = conn.prepareStatement(query);
currentIndex = 1;
for (int j = 0; j < keys.length; j++, currentIndex++)
{
this.setColumn(statement, currentIndex, request,
keys[j]);
}
rset = statement.executeQuery();
result = rset.next();
}
if (result)
value = this.getColumn(rset, request, values[i]);
}
if (value != null)
request.setAttribute(parameter, value.toString());
}
if(statement != null)
statement.close();
return EMPTY_MAP;
} catch (Exception e) {
throw new ProcessingException("Could not prepare statement
:position = " + currentIndex, e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null) this.dbselector.release(datasource);
}
// Result is empty map or exception. No null.
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected String getSelectQuery(Configuration conf) throws
ConfigurationException {
String query = null;
synchronized (DatabaseSelectAction.selectStatements) {
query = (String) DatabaseSelectAction.selectStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] keys =
table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
StringBuffer queryBuffer = new StringBuffer("SELECT ");
int index = 0;
for (int i = 0; i < keys.length; i++, index++) {
if (index > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
}
for (int i = 0; i < values.length; i++,index++) {
if (index > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
}
queryBuffer.append(" FROM ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" WHERE ");
for (int i = 0; i < keys.length; i++) {
if (i > 0) {
queryBuffer.append(" AND ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
queryBuffer.append(" = ?");
}
query = queryBuffer.toString();
DatabaseSelectAction.selectStatements.put(conf, query);
}
}
return query;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseUpdateAction.java
Index: DatabaseUpdateAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Update a record in a database. This Action assumes that there is
* only one table at a time to update.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Id: DatabaseUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseUpdateAction extends AbstractDatabaseAction implements
ThreadSafe {
private static final Map updateStatements = new HashMap();
/**
* Update a record in the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
int currentIndex = 0;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor",
(String) this.settings.get("descriptor")), resolver,
param.getParameterAsBoolean("reloadable",reloadable));
String query = this.getUpdateQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
PreparedStatement statement = conn.prepareStatement(query);
Configuration[] keys =
conf.getChild("table").getChild("keys").getChildren("key");
Configuration[] values =
conf.getChild("table").getChild("values").getChildren("value");
currentIndex = 1;
for (int i = 0; i < values.length; i++, currentIndex++) {
this.setColumn(statement, currentIndex, request, values[i]);
}
for (int i = 0; i < keys.length; i++, currentIndex++) {
this.setColumn(statement, currentIndex, request, keys[i]);
}
int rows = statement.executeUpdate();
conn.commit();
statement.close();
if(rows > 0){
request.setAttribute("rows", Integer.toString(rows));
return EMPTY_MAP;
}
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
throw new ProcessingException("Could not update record :position
= " + currentIndex, e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null) this.dbselector.release(datasource);
}
return null;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected String getUpdateQuery(Configuration conf) throws
ConfigurationException {
String query = null;
synchronized (DatabaseUpdateAction.updateStatements) {
query = (String) DatabaseUpdateAction.updateStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] keys =
table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
StringBuffer queryBuffer = new StringBuffer("UPDATE ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" SET ");
for (int i = 0; i < values.length; i++) {
if (i > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
queryBuffer.append(" = ?");
}
queryBuffer.append(" WHERE ");
for (int i = 0; i < keys.length; i++) {
if (i > 0) {
queryBuffer.append(" AND ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
queryBuffer.append(" = ?");
}
query = queryBuffer.toString();
DatabaseUpdateAction.updateStatements.put(conf, query);
}
}
return query;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DbXMLAuthenticatorAction.java
Index: DbXMLAuthenticatorAction.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache Cocoon" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Node;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import org.xmldb.api.modules.XPathQueryService;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* This action is used to authenticate user by comparing several request
* fields (username, password) with the values in a DBXML compliant database.
* The description of the process is given via external xml description file
* simiar to the one used for all actions derived from AbstractDatabaseAction.
*
* <pre>
* <root>
*
* <connection>
* <driver>org.apache.xindice.client.xmldb.DatabaseImpl</driver>
* <base>xmldb:xindice:///db/beta</base>
* </connection>
*
* <root name="users>
* <select element="username" request-param="username"
to-session="username"/>
* <select element="password" request-param="password" nullable="yes"/>
*
* <select element="role" to-session="role" type="string"/>
* <select element="skin" to-session="skin" type="string"/>
* </root>
*
* </root>
* </pre>
*
* The values specified via "request-param" describe the name of HTTP request
* parameter, "element" indicates matching document node, "nullable" means
* that request-param which is null or empty will not be included in the WHERE
* clause. This way you can enable accounts with empty passwords, etc.
* "to-session" attribute indicates under which name the value obtained from
* database should be stored in the session. Of course new session is created
* when authorization is successfull. The "type" attribute can be either
* string, long or double and alters the type of object stored in session.
* Additionally all parameters that are
* propagated to the session are made available to the sitemap via {name}
* expression.
*
* If there is no need to touch the session object, providing just one-time
* verification, you can specify action parameter "create-session" to "no" or
* "false". No values are then propagated to the sesion and session object is
* not verified.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Zoffoli</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Martin Man</a>
* @version 0.2 -- 2002/02/03
*
* based on DatabaseAuthenticatorAction created by Martin Man <[EMAIL
PROTECTED]>
*/
public class DbXMLAuthenticatorAction extends AbstractDatabaseAction
implements ThreadSafe
{
/**
* Main invocation routine.
*/
public Map act (Redirector redirector, SourceResolver resolver, Map
objectModel, String src,
Parameters parameters) throws Exception {
ResourceSet rs = null;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable")) {
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
}
// read local settings
try {
Configuration conf = this.getConfiguration (
parameters.getParameter ("descriptor", (String)
this.settings.get("descriptor")),
resolver,
parameters.getParameterAsBoolean("reloadable",
reloadable));
boolean cs = true;
String create_session = parameters.getParameter ("create-session",
(String) this.settings.get("create-session"));
if (create_session != null && ("no".equals (create_session.trim ())
|| "false".equals (create_session.trim ()))) {
cs = false;
}
Request req = ObjectModelHelper.getRequest(objectModel);
/* check request validity */
if (req == null) {
getLogger ().debug ("DBXMLAUTH: no request object");
return null;
}
rs = this.Authenticate( conf, req );
if (rs != null )
{
getLogger ().debug ("DBXMLAUTH: authorized successfully");
Session session = null;
if (cs) {
session = req.getSession (false);
if (session != null)
session.invalidate ();
session = req.getSession (true);
if (session == null)
return null;
getLogger ().debug ("DBXMLAUTH: session created");
} else {
getLogger ().debug ("DBXMLAUTH: leaving session untouched");
}
HashMap actionMap = this.propagateParameters (conf, rs, session);
return Collections.unmodifiableMap (actionMap);
} else {
//getLogger ().debug ("DBXMLAUTH: error ResourceSet is null");
}
req.setAttribute("message", "The username or password were incorrect,
please check your CAPS LOCK key and try again.");
getLogger ().debug ("DBXMLAUTH: no results for query");
} catch (Exception e) {
getLogger().debug ("exception: ", e);
return null;
}
return null;
}
private String getAuthQuery ( Configuration conf, Request req )
{
boolean first_constraint = true;
StringBuffer queryBuffer = new StringBuffer ("//");
StringBuffer queryBufferEnd = new StringBuffer ("");
String dbcol, request_param, request_value, nullstr;
boolean nullable = false;
Configuration table = conf.getChild ("root");
Configuration[] select = table.getChildren ("select");
try {
queryBuffer.append (table.getAttribute ("name"));
for (int i = 0; i < select.length; i ++)
{
dbcol = "[" + select[i].getAttribute ("element");
try {
request_param = select[i].getAttribute ("request-param");
if (request_param == null ||
request_param.trim().equals ("")) {
continue;
}
} catch (Exception e) {
continue;
}
try {
nullstr = select[i].getAttribute ("nullable");
if (nullstr != null) nullstr = nullstr.trim ();
if ("yes".equals (nullstr) || "true".equals (nullstr)) {
nullable = true;
}
} catch (Exception e1) {
}
/* if there is a request parameter name,
* but not the value, we exit immediately do
* that authorization fails authomatically */
request_value = req.getParameter (request_param);
if (request_value == null || request_value.trim().equals ("")) {
// value is null
if (!nullable) {
getLogger ().debug ("DBXMLAUTH: request-param " +
request_param + " does not exist");
return null;
}
} else {
queryBufferEnd.append
(dbcol).append("='").append(request_value).append("']");
first_constraint = false;
}
}
if (!queryBufferEnd.toString ().trim ().equals (""))
queryBuffer.append (queryBufferEnd);
return queryBuffer.toString ();
} catch (Exception e) {
getLogger ().debug ("DBXMLAUTH: got exception: " + e);
return null;
}
}
private ResourceSet Authenticate( Configuration conf, Request req) throws
Exception, XMLDBException {
ResourceSet rs = null;
String query = this.getAuthQuery (conf, req);
if (query == null) {
getLogger ().debug ("DBXMLAUTH: have not got query");
req.setAttribute("message", "The authenticator is misconfigured");
return null;
}
getLogger ().debug ("DBXMLAUTH: query is: " + query);
Collection col = CreateConnection( conf );
if ( col != null )
{
if ( col.isOpen() )
{
try
{
XPathQueryService service = (XPathQueryService)
col.getService("XPathQueryService", "1.0");
rs = service.query(query);
ResourceIterator results = rs.getIterator();
if (results.hasMoreResources() == false)
{
getLogger ().debug ("DBXMLAUTH: auth failed");
return null;
} else {
getLogger ().debug ("DBXMLAUTH: auth OK");
return rs;
}
} catch (XMLDBException e) {
getLogger ().debug ("DBXMLAUTH: got exception: " + e);
return null;
} finally {
// close col
if (col != null) {
try {
col.close();
} catch (Exception e) { /* ignore */ }
}
getLogger ().debug ("DBXMLAUTH: collection closed");
}
} else {
getLogger ().debug ("DBXMLAUTH: error: collection closed !!");
}
} else {
getLogger ().debug ("DBXMLAUTH: couldn't open a connection with DB");
}
return null;
}
private Collection CreateConnection( Configuration conf ) throws Exception,
XMLDBException {
Collection col = null;
Configuration conn = conf.getChild ("connection");
try {
Class c = Class.forName( conn.getChild("driver").getValue() );
Database database = (Database) c.newInstance();
DatabaseManager.registerDatabase(database);
col = DatabaseManager.getCollection( conn.getChild("base").getValue() );
} catch (XMLDBException e) {
getLogger ().debug ("DBXMLAUTH: Exception occured " + e.errorCode);
}
return col;
}
private HashMap propagateParameters (Configuration conf, ResourceSet
resultSet, Session session) {
Configuration table = conf.getChild ("root");
Configuration[] select = table.getChildren ("select");
String dbcol, session_param, type;
HashMap map = new HashMap();
XObject xo;
Node originalnode = null;
try {
ResourceIterator results = resultSet.getIterator();
// Create an XObject to be used in Xpath query
xo = new XObject();
// Retrieve the next node
XMLResource resource = (XMLResource) results.nextResource();
originalnode = resource.getContentAsDOM();
}
catch (Exception e) {
getLogger ().debug ("DBXMLAUTH: error creating XObject ");
}
try {
for (int i = 0; i < select.length; i ++) {
dbcol = select[i].getAttribute ("element");
try {
session_param = select[i].getAttribute ("to-session");
if (session_param != null && !session_param.trim().equals (""))
{
String s = "";
try {
// Use Xalan xpath parser to extract data
xo = XPathAPI.eval(originalnode, "/" + table.getAttribute
("name") + "/" + select[i].getAttribute ("element") );
s = xo.toString();
}
catch (Exception e) {
}
/* propagate to session */
try {
type = select[i].getAttribute ("type");
} catch (Exception e) {
type = null;
}
if (type == null || "".equals (type.trim ())) {
type = "string";
}
Object o = null;
if ("string".equals (type)) {
o = s;
} else if ("long".equals (type)) {
Long l = Long.decode (s);
o = l;
} else if ("double".equals (type)) {
Double d = Double.valueOf (s);
o = d;
}
if (session != null) {
session.setAttribute (session_param, o);
getLogger ().debug ("DBXMLAUTH: propagating param " +
session_param + "=" + s);
}
map.put (session_param, o);
}
} catch (Exception e) {
}
}
return map;
} catch (Exception e) {
getLogger().debug("exception: ", e);
}
return null;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/OraAddAction.java
Index: OraAddAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import oracle.jdbc.OracleResultSet;
import oracle.sql.BLOB;
import oracle.sql.CLOB;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.generation.ImageDirectoryGenerator;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Add a record in a database. This Action assumes that there is
* only one table at a time to update.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Id: OraAddAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
*/
public class OraAddAction extends DatabaseAddAction {
private static final Map selectLOBStatements = new HashMap();
/**
* Add a record to the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map
objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
int currentIndex = 0;
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor", null));
String query = this.getAddQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
PreparedStatement statement = conn.prepareStatement(query);
getLogger().info(query);
Configuration[] keys =
conf.getChild("table").getChild("keys").getChildren("key");
Configuration[] values =
conf.getChild("table").getChild("values").getChildren("value");
currentIndex = 1;
// Insert the keys into the query
for (int i = 0; i < keys.length; i++) {
String mode = keys[i].getAttribute("mode", "automatic");
if ("manual".equals(mode)) {
String selectQuery = this.getSelectQuery(keys[i]);
ResultSet set =
conn.createStatement().executeQuery(selectQuery);
set.next();
int value = set.getInt("maxid") + 1;
statement.setInt(currentIndex, value);
request.setAttribute(keys[i].getAttribute("param"),
String.valueOf(value));
set.close();
set.getStatement().close();
currentIndex++;
} else if ("form".equals(mode)) {
String parameter = keys[i].getAttribute("param");
request.setAttribute(parameter,
request.getParameter(parameter));
this.setColumn(statement, currentIndex, request, keys[i]);
currentIndex++;
}
}
// insert the values into the query
for (int i = 0; i < values.length; i++) {
String type = values[i].getAttribute("type");
String parameter = values[i].getAttribute("param");
if (type.equals("image")) {
File binaryFile = (File) request.get(parameter);
Parameters iparam = new Parameters();
iparam.setParameter("image-size",
String.valueOf(binaryFile.length()));
int [] dimensions =
ImageDirectoryGenerator.getSize(binaryFile);
iparam.setParameter("image-width",
String.valueOf(dimensions[0]));
iparam.setParameter("image-height",
String.valueOf(dimensions[1]));
synchronized (this.files) {
this.files.put(binaryFile, param);
}
}
if (! this.isLargeObject(type)) {
this.setColumn(statement, currentIndex, request,
values[i]);
currentIndex++;
}
}
statement.execute();
statement.close();
query = this.getSelectLOBQuery(conf);
// Process the large objects if they exist
if (query != null) {
PreparedStatement LOBstatement = conn.prepareStatement(query);
getLogger().info(query);
if (keys.length > 0) {
currentIndex = 1;
for (int i = 0; i < keys.length; i++) {
this.setColumn(LOBstatement, currentIndex, request,
keys[i]);
currentIndex++;
}
}
OracleResultSet set = (OracleResultSet)
LOBstatement.executeQuery();
if (set.next()) {
int index = 0;
for (int i = 0; i < values.length; i++) {
String type = values[i].getAttribute("type", "");
if (this.isLargeObject(type)) {
Object attr =
request.get(values[i].getAttribute("param"));
int length = -1;
InputStream stream = null;
OutputStream output = null;
int bufSize = 1024;
index++;
if (type.equals("ascii")) {
CLOB ascii = set.getCLOB(index);
if (attr instanceof File) {
File asciiFile = (File) attr;
stream = new BufferedInputStream(new
FileInputStream(asciiFile));
} else {
String asciiText = (String) attr;
stream = new BufferedInputStream(new
ByteArrayInputStream(asciiText.getBytes()));
}
output = new
BufferedOutputStream(ascii.getAsciiOutputStream());
bufSize = ascii.getBufferSize();
} else {
BLOB binary = set.getBLOB(index);
File binaryFile = (File) attr;
stream = new BufferedInputStream(new
FileInputStream(binaryFile));
length = (int) binaryFile.length();
output = new
BufferedOutputStream(binary.getBinaryOutputStream());
bufSize = binary.getBufferSize();
}
byte[] buffer = new byte[bufSize];
while ((length = stream.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
stream.close();
output.close();
}
}
}
set.close();
set.getStatement().close();
}
conn.commit();
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException se) {
getLogger().debug("There was an error rolling back the
transaction", se);
}
}
throw new ProcessingException("Could not add record :position = "
+ (currentIndex - 1), e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null) this.dbselector.release(datasource);
}
return null;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected final String getAddQuery(Configuration conf) throws
ConfigurationException {
String query = null;
synchronized (DatabaseAddAction.addStatements) {
query = (String) DatabaseAddAction.addStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] values =
table.getChild("values").getChildren("value");
Configuration[] keys =
table.getChild("keys").getChildren("key");
StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" (");
int numKeys = 0;
for (int i = 0; i < keys.length; i++) {
String mode = keys[i].getAttribute("mode", "automatic");
if (numKeys > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
if ("manual".equals(mode)) {
this.setSelectQuery(table.getAttribute("name"),
keys[i]);
}
numKeys++;
}
for (int i = 0; i < values.length; i++) {
if ((numKeys + i) > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
}
queryBuffer.append(") VALUES (");
numKeys = 0;
ArrayList sequences = new ArrayList();
for (int i = 0; i < keys.length; i++) {
if (numKeys > 0) queryBuffer.append(", ");
if ("automatic".equals(keys[i].getAttribute("mode",
"automatic"))) {
String sequence = keys[i].getAttribute("sequence",
"");
queryBuffer.append(sequence);
if (sequences.contains(sequence)) {
queryBuffer.append(".CURRVAL");
} else {
sequences.add(sequence);
queryBuffer.append(".NEXTVAL");
}
numKeys++;
} else {
queryBuffer.append("?");
numKeys++;
}
}
for (int i = 0; i < values.length; i++) {
if ((numKeys + i) > 0) {
queryBuffer.append(", ");
}
if (this.isLargeObject(values[i].getAttribute("type"))) {
if (values[i].getAttribute("type").equals("ascii")) {
queryBuffer.append("empty_clob()");
} else {
queryBuffer.append("empty_blob()");
}
} else {
queryBuffer.append("?");
}
}
queryBuffer.append(")");
query = queryBuffer.toString();
DatabaseAddAction.addStatements.put(conf, query);
}
}
if ("".equals(query)) return null;
return query;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
private final String getSelectLOBQuery (Configuration conf)
throws ConfigurationException {
String query = null;
synchronized (OraAddAction.selectLOBStatements) {
query = (String) OraAddAction.selectLOBStatements.get(conf);
// executes only if query is null.
if (query == null) {
StringBuffer queryBuffer = new StringBuffer("SELECT ");
Configuration table = conf.getChild("table");
Configuration[] values =
table.getChild("values").getChildren("value");
Configuration[] keys =
table.getChild("keys").getChildren("key");
int numLobs = 0;
// Add the values to the query
for (int i = 0; i < values.length; i++) {
if (this.isLargeObject(values[i].getAttribute("type"))) {
numLobs++;
if (numLobs > 1) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
}
}
if (numLobs < 1) {
// if query is set to "", then the Action won't
// try to process it again.
query = "";
OraAddAction.selectLOBStatements.put(conf, query);
return null;
}
queryBuffer.append(" FROM
").append(table.getAttribute("name"));
// Process the WHERE clause
if (keys.length > 0) {
queryBuffer.append(" WHERE ");
// Add the keys to the query
for (int i = 0; i < keys.length; i++) {
if (i > 0) {
queryBuffer.append(" AND ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
queryBuffer.append(" = ?");
}
}
query = queryBuffer.toString().trim();
OraAddAction.selectLOBStatements.put(conf, query);
}
}
if ("".equals(query)) return null;
return query;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/OraUpdateAction.java
Index: OraUpdateAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
/**
* Update a record in a database. This Action assumes that there is
* only one table at a time to update.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Id: OraUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
*/
public class OraUpdateAction extends DatabaseUpdateAction {
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseAction.java
Index: DatabaseAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Class;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Enumeration;
import java.util.Collections;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.io.IOException;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentSelector;
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.configuration.DefaultConfiguration;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.avalon.excalibur.component.RoleManager;
import org.apache.avalon.excalibur.component.DefaultRoleManager;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.classloader.RepositoryClassLoader;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.generation.ImageDirectoryGenerator;
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.HashMap;
import org.apache.cocoon.util.JDBCTypeConversions;
import org.apache.cocoon.selection.Selector;
import org.apache.cocoon.acting.AbstractComplementaryConfigurableAction;
import org.apache.cocoon.components.modules.database.AutoIncrementModule;
import org.apache.cocoon.components.modules.input.InputModule;
import org.apache.cocoon.components.modules.output.OutputModule;
/**
* Abstract action for common function needed by database actions.
* The difference to the other Database*Actions is, that the actions
* in this package use additional components ("modules") for reading
* and writing parameters. In addition the descriptor format has
* changed to accomodate the new features.
*
* <p>This action is heavily based upon the original DatabaseAddActions.</p>
*
* <p>Modes have to be configured in cocoon.xconf. Mode names from
* descriptor.xml file are looked up in the component service. Default
* mode names can only be set during action setup. </p>
*
* <p>The number of affected rows is returned to the sitemap with the
* "row-count" parameter if at least one row was affected.</p>
* <table>
* <tr><td colspan="2">Configuration options (setup):</td></tr>
* <tr><td>input </td><td>default mode name for reading
values</td></tr>
* <tr><td>autoincrement </td><td>default mode name for obtaining values
from autoincrement columns</td></tr>
* </table>
*
* <table>
* <tr><td colspan="2">Configuration options (setup and per
invocation):</td></tr>
* <tr><td>throw-exception </td><td>throw an exception when an error occurs
(default: false)</td></tr>
* <tr><td>descriptor </td><td>file containing database
description</td></tr>
* <tr><td>table-set </td><td>table-set name to work with
</td></tr>
* <tr><td>output </td><td>mode name for writing values
</td></tr>
* </table>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
* @see org.apache.cocoon.components.modules.input
* @see org.apache.cocoon.components.modules.output
* @see org.apache.cocoon.components.modules.database
*/
public abstract class DatabaseAction extends
AbstractComplementaryConfigurableAction implements Configurable, Disposable {
//
========================================================================
// constants
//
========================================================================
static final Integer MODE_AUTOINCR = new Integer( 0 );
static final Integer MODE_OTHERS = new Integer( 1 );
static final Integer MODE_OUTPUT = new Integer( 2 );
static final String ATTRIBUTE_KEY =
"org.apache.cocoon.action.modular.DatabaseAction.outputModeName";
// These can be overidden from cocoon.xconf
static final String inputHint = "request-param"; // default to request
parameters
static final String outputHint = "request-attr"; // default to request
attributes
static final String databaseHint = "manual"; // default to manual auto
increments
static final String INPUT_MODULE_SELECTOR = InputModule.ROLE + "Selector";
static final String OUTPUT_MODULE_SELECTOR = OutputModule.ROLE +
"Selector";
static final String DATABASE_MODULE_SELECTOR = AutoIncrementModule.ROLE +
"Selector";
//
========================================================================
// instance vars
//
========================================================================
protected ComponentSelector dbselector;
protected Map defaultModeNames = new HashMap( 3 );
protected final HashMap cachedQueryData = new HashMap();
//
========================================================================
// inner helper classes
//
========================================================================
/**
* Structure that takes all processed data for one column.
*/
protected class Column {
boolean isKey = false;
boolean isSet = false;
boolean isAutoIncrement = false;
String mode = null;
Configuration modeConf = null;
Configuration columnConf = null;
}
/**
* Structure that takes all processed data for a table depending
* on current default modes
*/
protected class CacheHelper {
/**
* Generated query string
*/
public String queryString = null;
/**
* if a set is used, column number which is used to determine
* the number of rows to insert.
*/
public int setMaster = -1;
public boolean isSet = false;
public int noOfKeys = 0;
public Column[] columns = null;
public CacheHelper( int cols ) {
this(0,cols);
}
public CacheHelper( int keys, int cols ) {
noOfKeys = keys;
columns = new Column[cols];
for ( int i=0; i<cols; i++ ) {
columns[i] = new Column();
}
}
}
/**
* Structure that takes up both current mode types for database
* operations and table configuration data. Used to access parsed
* configuration data.
*/
protected class LookUpKey {
public Configuration tableConf = null;
public Map modeTypes = null;
public LookUpKey( Configuration tableConf, Map modeTypes ) {
this.tableConf = tableConf;
this.modeTypes = modeTypes;
}
}
// set up default modes
// <input/>
// <output/>
// <autoincrement/>
//
// all other modes need to be declared in cocoon.xconf
// no need to declare them per action (anymore!)
public void configure(Configuration conf) throws ConfigurationException {
super.configure(conf);
if (this.settings != null) {
this.defaultModeNames.put(MODE_OTHERS, (String)
this.settings.get("input", inputHint));
this.defaultModeNames.put(MODE_OUTPUT, (String)
this.settings.get("output", outputHint));
this.defaultModeNames.put(MODE_AUTOINCR, (String)
this.settings.get("autoincrement", databaseHint));
}
}
//
========================================================================
// Avalon methods
//
========================================================================
/**
* Compose the Actions so that we can select our databases.
*/
public void compose(ComponentManager manager) throws ComponentException {
this.dbselector = (ComponentSelector)
manager.lookup(DataSourceComponent.ROLE + "Selector");
super.compose(manager);
}
/**
* dispose
*/
public void dispose() {
this.manager.release(dbselector);
}
//
========================================================================
// protected utility methods
//
========================================================================
/**
* Get the Datasource we need.
*/
protected DataSourceComponent getDataSource( Configuration conf,
Parameters parameters )
throws ComponentException {
String sourceName = parameters.getParameter( "connection", (String)
settings.get( "connection" ) );
if ( sourceName == null ) {
Configuration dsn = conf.getChild("connection");
return (DataSourceComponent)
this.dbselector.select(dsn.getValue(""));
} else {
if (getLogger().isDebugEnabled())
getLogger().debug("Using datasource: "+sourceName);
return (DataSourceComponent) this.dbselector.select(sourceName);
}
}
/**
* Return whether a type is a Large Object (BLOB/CLOB).
*/
protected final boolean isLargeObject (String type) {
if ("ascii".equals(type)) return true;
if ("binary".equals(type)) return true;
if ("image".equals(type)) return true;
return false;
}
/**
* Store a key/value pair in the output attributes. We prefix the key
* with the name of this class to prevent potential name collisions.
*/
protected void setOutputAttribute(Map objectModel, String outputMode,
String key, Object value) {
ComponentSelector outputSelector = null;
OutputModule output = null;
try {
outputSelector=(ComponentSelector)
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
if (outputMode != null && outputSelector != null &&
outputSelector.hasComponent(outputMode)){
output = (OutputModule) outputSelector.select(outputMode);
}
output.setAttribute( null, objectModel, key, value );
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger()
.warn( "Could not select output mode "
+ (String) outputMode
+ ":" + e.getMessage() );
} finally {
if (outputSelector != null) {
if (output != null)
outputSelector.release(output);
this.manager.release(outputSelector);
}
}
}
/**
* Inserts a row or a set of rows into the given table based on the
* request parameters
*
* @param table the table's configuration
* @param conn the database connection
* @param objectModel the objectModel
*/
protected int processTable( Configuration table, Connection conn, Map
objectModel,
Map results, Map modeTypes )
throws SQLException, ConfigurationException, Exception {
PreparedStatement statement = null;
int rows = 0;
try {
LookUpKey luk = new LookUpKey(table, modeTypes);
CacheHelper queryData = null;
if (getLogger().isDebugEnabled())
getLogger().debug("modeTypes : "+ modeTypes);
// get cached data
// synchronize complete block since we don't want 100s of threads
// generating the same cached data set. In the long run all data
// is cached anyways so this won't cost much.
synchronized (this.cachedQueryData) {
queryData = (CacheHelper) this.cachedQueryData.get(luk,null);
if (queryData == null) {
queryData = this.getQuery( table, modeTypes,
defaultModeNames );
this.cachedQueryData.put(luk,queryData);
}
};
if (getLogger().isDebugEnabled())
getLogger().debug("query: "+queryData.queryString);
statement = conn.prepareStatement(queryData.queryString);
Object[][] columnValues = this.getColumnValues( table, queryData,
objectModel );
int setLength = 1;
if ( queryData.isSet ) {
if ( columnValues[ queryData.setMaster ] != null ) {
setLength = columnValues[ queryData.setMaster ].length;
} else {
setLength = 0;
}
}
for ( int rowIndex = 0; rowIndex < setLength; rowIndex++ ) {
if (getLogger().isDebugEnabled())
getLogger().debug( "====> row no. " + rowIndex );
rows += processRow( objectModel, conn, statement, (String)
modeTypes.get(MODE_OUTPUT), table, queryData, columnValues, rowIndex, results );
}
} finally {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {}
}
return rows;
}
/**
* Choose a mode configuration based on its name.
* @param conf Configuration (i.e. a column's configuration) that might
have
* several children configurations named "mode".
* @param type desired type (i.e. every mode has a type
* attribute), find the first mode that has a compatible type.
* Special mode "all" matches all queried types.
* @return configuration that has desired type or type "all" or null.
*/
protected Configuration getMode( Configuration conf, String type )
throws ConfigurationException {
String modeAll = "all";
Configuration[] modes = conf.getChildren("mode");
Configuration modeConfig = null;;
for ( int i=0; i<modes.length; i++ ) {
String modeType = modes[i].getAttribute("type", "others");
if ( modeType.equals(type) || modeType.equals(modeAll)) {
if (getLogger().isDebugEnabled())
getLogger().debug("requested mode was \""+type+"\"
returning \""+modeType+"\"");
modeConfig = modes[i];
break;
};
}
return modeConfig;
}
/**
* compose name for output a long the lines of "table.column"
*/
protected String getOutputName ( Configuration tableConf, Configuration
columnConf ) {
return getOutputName( tableConf, columnConf, -1 );
}
/**
* compose name for output a long the lines of "table.column[row]" or
* "table.column" if rowIndex is -1.
* If the section of the sitemap corresponding to the action contains
* <append-table-name>false</append-table-name>
* the name for output is "column[row]"
* If the section of the sitemap corresponding to the action contains
* <append-row>false</append-row>
* the name for output is "column"
*/
protected String getOutputName ( Configuration tableConf, Configuration
columnConf, int rowIndex ) {
if ( rowIndex != -1 && this.settings.containsKey("append-row") &&
(this.settings.get("append-row").toString().equalsIgnoreCase("false") ||
this.settings.get("append-row").toString().equalsIgnoreCase("0")) ) {
rowIndex = -1;
}
if ( this.settings.containsKey("append-table-name") &&
(this.settings.get("append-table-name").toString().equalsIgnoreCase("false") ||
this.settings.get("append-table-name").toString().equalsIgnoreCase("0")) )
{
return ( columnConf.getAttribute("name",null)
+ ( rowIndex == -1 ? "" : "[" + rowIndex + "]" ) );
}
else
{
return ( tableConf.getAttribute("alias",
tableConf.getAttribute("name", null) )
+ "." + columnConf.getAttribute("name",null)
+ ( rowIndex == -1 ? "" : "[" + rowIndex + "]" ) );
}
}
/*
* Read all values for a column from an InputModule
*
* If the given column is an autoincrement column, an empty array
* is returned, otherwise if it is part of a set, all available
* values are fetched, or only the first one if it is not part of
* a set.
*
*/
protected Object[] getColumnValue( Configuration tableConf, Column
column, Map objectModel )
throws ConfigurationException, ComponentException {
if ( column.isAutoIncrement ) {
return new Object[1];
} else {
Object[] values;
String cname = getOutputName( tableConf, column.columnConf );
// obtain input module and read values
ComponentSelector inputSelector = null;
InputModule input = null;
try {
inputSelector=(ComponentSelector)
this.manager.lookup(INPUT_MODULE_SELECTOR);
if (column.mode != null && inputSelector != null &&
inputSelector.hasComponent(column.mode)){
input = (InputModule) inputSelector.select(column.mode);
}
if ( column.isSet ){
if (getLogger().isDebugEnabled())
getLogger().debug( "Trying to set column " + cname +"
from "+column.mode+" using getAttributeValues method");
values = input.getAttributeValues( cname,
column.modeConf, objectModel );
} else {
if (getLogger().isDebugEnabled())
getLogger().debug( "Trying to set column " + cname +"
from "+column.mode+" using getAttribute method");
values = new Object[1];
values[0] = input.getAttribute( cname, column.modeConf,
objectModel );
}
if ( values != null ) {
for ( int i = 0; i < values.length; i++ ) {
if (getLogger().isDebugEnabled())
getLogger().debug( "Setting column " + cname + "
[" + i + "] " + values[i] );
}
}
} finally {
if (inputSelector != null) {
if (input != null)
inputSelector.release(input);
this.manager.release(inputSelector);
}
}
return values;
}
}
/**
* Setup parsed attribute configuration object
*/
protected void fillModes ( Configuration[] conf, boolean isKey, Map
defaultModeNames,
Map modeTypes, CacheHelper set )
throws ConfigurationException {
String setMode = null;
int setMaster = -1;
String setMastersMode = null;
boolean manyrows = false;
int offset = ( isKey ? 0: set.noOfKeys);
for ( int i = offset; i < conf.length + offset; i++ ) {
if (getLogger().isDebugEnabled())
getLogger().debug("i="+i);
set.columns[i].columnConf = conf[ i - offset ];
set.columns[i].isSet = false;
set.columns[i].isKey = isKey;
set.columns[i].isAutoIncrement = false;
if ( isKey & this.honourAutoIncrement() )
set.columns[i].isAutoIncrement =
set.columns[i].columnConf.getAttributeAsBoolean("autoincrement",false);
set.columns[i].modeConf = getMode( set.columns[i].columnConf,
selectMode(
set.columns[i].isAutoIncrement, modeTypes ) );
set.columns[i].mode = ( set.columns[i].modeConf != null ?
set.columns[i].modeConf.getAttribute(
"name", selectMode( isKey, defaultModeNames ) ) :
selectMode( isKey, defaultModeNames ) );
// Determine set mode for a whole column ...
setMode = set.columns[i].columnConf.getAttribute("set", null);
// master vs slave vs null
if ( setMode == null && set.columns[i].modeConf != null ) {
// ... or for each mode individually
setMode = set.columns[i].modeConf.getAttribute("set", null);
}
if ( setMode != null ) {
manyrows = true;
set.columns[i].isSet = true;
set.isSet = true;
if ( setMode.equals("master") ) {
set.setMaster = i;
}
}
}
}
/**
* create a unique name using the getOutputName method and write
* the value to the output module and the results map if present.
*
*/
protected void setOutput( Map objectModel, String outputMode, Map results,
Configuration table, Configuration column, int
rowIndex, Object value ) {
String param = this.getOutputName( table, column, rowIndex );
if (getLogger().isDebugEnabled())
getLogger().debug( "Setting column " + param + " to " + value );
this.setOutputAttribute(objectModel, outputMode, param, value);
if (results != null)
results.put( param, String.valueOf( value ) );
}
/**
* set a column in a statement using the appropriate JDBC setXXX method.
*
*/
protected void setColumn ( PreparedStatement statement, int position,
Configuration entry, Object value ) throws Exception {
JDBCTypeConversions.setColumn(statement, position, value, (Integer)
JDBCTypeConversions.typeConstants.get(entry.getAttribute("type")));
}
/**
* set a column in a statement using the appropriate JDBC setXXX
* method and propagate the value to the output module and results
* map if present. Effectively combines calls to setColumn and
* setOutput.
*
*/
protected void setColumn ( Map objectModel, String outputMode, Map
results,
Configuration table, Configuration column, int
rowIndex,
Object value, PreparedStatement statement, int
position ) throws Exception {
if (results!=null) this.setOutput( objectModel, outputMode, results,
table, column, rowIndex, value );
this.setColumn( statement, position, column, value );
}
//
========================================================================
// main method
//
========================================================================
/**
* Add a record to the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act( Redirector redirector, SourceResolver resolver, Map
objectModel,
String source, Parameters param ) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
Map results = new HashMap();
int rows = 0;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
// call specific default modes apart from output mode are not
supported
// set request attribute
String outputMode = param.getParameter("output", (String)
defaultModeNames.get(MODE_OUTPUT));
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String)
this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor",
(String) this.settings.get("descriptor")),
resolver,
param.getParameterAsBoolean("reloadable",reloadable));
// get database connection and try to turn off autocommit
datasource = this.getDataSource(conf, param);
conn = datasource.getConnection();
if (conn.getAutoCommit() == true) {
try {
conn.setAutoCommit(false);
} catch (Exception ex) {
String tmp =
param.getParameter("use-transactions",(String)
this.settings.get("use-transactions",null));
if (tmp != null && (tmp.equalsIgnoreCase("no") ||
tmp.equalsIgnoreCase("false") || tmp.equalsIgnoreCase("0"))) {
if (getLogger().isErrorEnabled())
getLogger().error("This DB connection does not
support transactions. If you want to risk your data's integrity by continuing
nonetheless set parameter \"use-transactions\" to \"no\".");
throw ex;
}
}
}
// find tables to work with
Configuration[] tables = conf.getChildren("table");
String tablesetname = param.getParameter("table-set", (String)
this.settings.get("table-set"));
Map set_tables = null; // default to old behaviour
Map modeTypes = null;
if (tablesetname == null) {
modeTypes = new HashMap(6);
modeTypes.put( MODE_AUTOINCR, "autoincr" );
modeTypes.put( MODE_OTHERS, "others" );
modeTypes.put( MODE_OUTPUT, outputMode );
for (int i=0; i<tables.length; i++) {
rows += processTable( tables[i], conn, objectModel,
results, modeTypes );
}
} else {
// new set based behaviour
// create index for table names / aliases
Map tableIndex = new HashMap(2*tables.length);
String tableName = null;
Object result = null;
for (int i=0; i<tables.length; i++) {
tableName =
tables[i].getAttribute("alias",tables[i].getAttribute("name",""));
result = tableIndex.put(tableName,new Integer(i));
if (result != null) {
throw new IOException("Duplicate table entry for
"+tableName+" at positions "+result+" and "+i);
}
}
Configuration[] tablesets = conf.getChildren("table-set");
String setname = null;
boolean found = false;
// find tables contained in tableset
int j = 0;
for (j=0; j<tablesets.length; j++) {
setname = tablesets[j].getAttribute ("name", "");
if (tablesetname.trim().equals (setname.trim ())) {
found = true;
break;
}
}
if (!found) {
throw new IOException(" given set " + tablesetname + "
does not exists in a description file.");
}
Configuration[] set = tablesets[j].getChildren("table");
for (int i=0; i<set.length; i++) {
// look for alternative mode types
modeTypes = new HashMap(6);
modeTypes.put( MODE_AUTOINCR, set[i].getAttribute(
"autoincr-mode", "autoincr" ) );
modeTypes.put( MODE_OTHERS, set[i].getAttribute(
"others-mode", "others" ) );
modeTypes.put( MODE_OUTPUT, outputMode );
tableName=set[i].getAttribute("name","");
if (tableIndex.containsKey(tableName)) {
j = ((Integer)tableIndex.get(tableName)).intValue();
rows += processTable( tables[j], conn, objectModel,
results, modeTypes );
} else {
throw new IOException(" given table " + tableName + "
does not exists in a description file.");
}
}
}
if (conn.getAutoCommit()==false)
conn.commit();
// obtain output mode module and rollback output
ComponentSelector outputSelector = null;
OutputModule output = null;
try {
outputSelector=(ComponentSelector)
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
if (outputMode != null && outputSelector != null &&
outputSelector.hasComponent(outputMode)){
output = (OutputModule) outputSelector.select(outputMode);
}
output.commit( null, objectModel );
} catch (Exception e) {
if (getLogger().isWarnEnabled())
getLogger()
.warn( "Could not select output mode "
+ (String) outputMode
+ ":" + e.getMessage() );
} finally {
if (outputSelector != null) {
if (output != null)
outputSelector.release(output);
this.manager.release(outputSelector);
}
}
} catch (Exception e) {
if ( conn != null ) {
try {
if (getLogger().isDebugEnabled()) {
getLogger().debug( "Rolling back transaction. Caused
by " + e.getMessage() );
e.printStackTrace();
}
conn.rollback();
results = null;
// obtain output mode module and commit output
ComponentSelector outputSelector = null;
OutputModule output = null;
try {
outputSelector=(ComponentSelector)
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
if (outputMode != null && outputSelector != null &&
outputSelector.hasComponent(outputMode)){
output = (OutputModule)
outputSelector.select(outputMode);
}
output.rollback( null, objectModel, e);
} catch (Exception e2) {
if (getLogger().isWarnEnabled())
getLogger()
.warn( "Could not select output mode "
+ (String) outputMode
+ ":" + e2.getMessage() );
} finally {
if (outputSelector != null) {
if (output != null)
outputSelector.release(output);
this.manager.release(outputSelector);
}
}
} catch (SQLException se) {
if (getLogger().isDebugEnabled())
getLogger().debug("There was an error rolling back
the transaction", se);
}
}
//throw new ProcessingException("Could not add record :position =
" + currentIndex, e);
// don't throw an exception, an error has been signalled, that
should suffice
String throwException = (String) this.settings.get(
"throw-exception",
param.getParameter( "throw-exception", null ) );
if ( throwException != null &&
( throwException.equalsIgnoreCase( "true" ) ||
throwException.equalsIgnoreCase( "yes" ) ) ) {
throw new ProcessingException("Could not add record",e);
}
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the
datasource", sqe);
}
}
if (datasource != null)
this.dbselector.release(datasource);
}
if (results != null) {
if (rows>0) {
results.put("row-count",new Integer(rows));
} else {
results = null;
}
} else {
if (rows>0) {
results = new HashMap(1);
results.put("row-count",new Integer(rows));
}
}
return results; // (results == null? results :
Collections.unmodifiableMap(results));
}
//
========================================================================
// abstract methods
//
========================================================================
/**
* set all necessary ?s and execute the query
* return number of rows processed
*
* This method is intended to be overridden by classes that
* implement other operations e.g. delete
*/
protected abstract int processRow( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper
queryData, Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception;
/**
* determine which mode to use as default mode
*
* This method is intended to be overridden by classes that
* implement other operations e.g. delete
*/
protected abstract String selectMode( boolean isAutoIncrement, Map modes
);
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*
* This method is intended to be overridden by classes that
* implement other operations e.g. delete
*/
protected abstract boolean honourAutoIncrement();
/**
* Fetch all values for all columns that are needed to do the
* database operation.
*
* This method is intended to be overridden by classes that
* implement other operations e.g. delete
*/
abstract Object[][] getColumnValues( Configuration tableConf, CacheHelper
queryData, Map objectModel )
throws ConfigurationException, ComponentException;
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* This method is intended to be overridden by classes that
* implement other operations e.g. delete
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected abstract CacheHelper getQuery( Configuration table, Map
modeTypes, Map defaultModeNames )
throws ConfigurationException, ComponentException;
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseAddAction.java
Index: DatabaseAddAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.util.Map;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.apache.cocoon.util.HashMap;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentSelector;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.cocoon.components.modules.database.AutoIncrementModule;
/**
* Adds record in a database. The action can update one or more
* tables, and can add more than one row to a table at a time. See
* [EMAIL PROTECTED] DatabaseAction} for details.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseAddAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseAddAction extends DatabaseAction {
/**
* set all necessary ?s and execute the query
*/
protected int processRow ( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper queryData,
Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception {
int currentIndex = 1;
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( col.isAutoIncrement && col.isKey ) {
currentIndex += setKeyAuto( table, col, currentIndex,
rowIndex,
conn, statement, objectModel,
outputMode, results );
} else {
this.setOutput( objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ]);
this.setColumn( statement, currentIndex, col.columnConf,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ]);
currentIndex++;
}
}
int rowCount = statement.executeUpdate();
// get resulting ids for autoincrement columns
for (int i = 0; i < queryData.columns.length; i++) {
if ( queryData.columns[i].isAutoIncrement &&
queryData.columns[i].isKey ) {
storeKeyValue( table, queryData.columns[i], rowIndex,
conn, statement, objectModel, outputMode,
results );
}
}
return rowCount;
}
/**
* Sets the key value on the prepared statement for an autoincrement type.
*
* @param table the table's configuration object
* @param column the key's configuration object
* @param currentIndex the position of the key column
* @param rowIndex the position in the current row set
* @param conn the database connection
* @param statement the insert statement
* @param objectModel the objectModel object
* @param outputMode name of the requested output module
* @param result sitemap result object
* @return the number of columns by which to increment the currentIndex
*/
protected int setKeyAuto ( Configuration table, Column column, int
currentIndex, int rowIndex,
Connection conn, PreparedStatement statement,
Map objectModel, String outputMode, Map results )
throws ConfigurationException, SQLException, ComponentException,
Exception {
int columnCount = 0;
ComponentSelector autoincrSelector = null;
AutoIncrementModule autoincr = null;
try {
autoincrSelector=(ComponentSelector)
this.manager.lookup(DATABASE_MODULE_SELECTOR);
if (column.mode != null && autoincrSelector != null &&
autoincrSelector.hasComponent(column.mode)){
autoincr = (AutoIncrementModule)
autoincrSelector.select(column.mode);
}
if ( autoincr.includeInQuery() ) {
if ( autoincr.includeAsValue() ) {
Object value = autoincr.getPreValue( table,
column.columnConf, column.modeConf, conn, objectModel );
this.setColumn(objectModel, outputMode, results, table,
column.columnConf, rowIndex, value, statement, currentIndex);
columnCount = 1;
}
} else {
if (getLogger().isDebugEnabled())
getLogger().debug( "Automatically setting key" );
}
} finally {
if (autoincrSelector != null) {
if (autoincr != null)
autoincrSelector.release(autoincr);
this.manager.release(autoincrSelector);
}
}
return columnCount;
}
/**
* Put key values into request attributes. Checks whether the
* value needs to be retrieved from the database module first.
*
*/
protected void storeKeyValue( Configuration tableConf, Column key, int
rowIndex, Connection conn,
Statement statement, Map objectModel,
String outputMode, Map results )
throws SQLException, ConfigurationException, ComponentException {
ComponentSelector autoincrSelector = null;
AutoIncrementModule autoincr = null;
try {
autoincrSelector=(ComponentSelector)
this.manager.lookup(DATABASE_MODULE_SELECTOR);
if (key.mode != null && autoincrSelector != null &&
autoincrSelector.hasComponent(key.mode)){
autoincr = (AutoIncrementModule)
autoincrSelector.select(key.mode);
}
if (!autoincr.includeAsValue()) {
Object value = autoincr.getPostValue( tableConf,
key.columnConf, key.modeConf, conn, statement, objectModel );
this.setOutput(objectModel, outputMode, results, tableConf,
key.columnConf, rowIndex, value);
}
} finally {
if (autoincrSelector != null) {
if (autoincr != null)
autoincrSelector.release(autoincr);
this.manager.release(autoincrSelector);
}
}
}
/**
* determine which mode to use as default mode
* here: INSERT
* highly specific to operation INSERT / UPDATE / DELETE / SELECT
*/
protected String selectMode ( boolean isAutoIncrement, Map modes ) {
if ( isAutoIncrement )
return (String) modes.get( MODE_AUTOINCR );
else
return (String) modes.get( MODE_OTHERS );
}
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*/
protected boolean honourAutoIncrement() { return true; }
/**
* Fetch all values for all columns that are needed to do the
* database operation.
*/
protected Object[][] getColumnValues( Configuration tableConf,
CacheHelper queryData,
Map objectModel )
throws ConfigurationException, ComponentException {
Object[][] columnValues = new Object[ queryData.columns.length ][];
for ( int i = 0; i < queryData.columns.length; i++ ){
columnValues[i] = this.getColumnValue( tableConf,
queryData.columns[i], objectModel );
}
return columnValues;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
* @param table the table's configuration object
* @return the insert query as a string
*/
protected CacheHelper getQuery( Configuration table, Map modeTypes, Map
defaultModeNames )
throws ConfigurationException, ComponentException {
LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
CacheHelper queryData = null;
synchronized( this.cachedQueryData ) {
queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
if (queryData == null) {
Configuration[] values =
table.getChild("values").getChildren("value");
Configuration[] keys =
table.getChild("keys").getChildren("key");
queryData = new CacheHelper( keys.length, keys.length +
values.length );
fillModes( keys, true, defaultModeNames, modeTypes,
queryData );
fillModes( values, false, defaultModeNames, modeTypes,
queryData );
StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
StringBuffer valueBuffer = new StringBuffer(") VALUES (");
AutoIncrementModule dah;
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" (");
int actualColumns = 0;
for (int i = 0; i < queryData.columns.length; i++) {
if ( actualColumns > 0 ) {
queryBuffer.append( ", " );
valueBuffer.append( ", " );
}
if ( queryData.columns[i].isKey &&
queryData.columns[i].isAutoIncrement ) {
ComponentSelector autoincrSelector = null;
AutoIncrementModule autoincr = null;
try {
autoincrSelector=(ComponentSelector)
this.manager.lookup(DATABASE_MODULE_SELECTOR);
if (queryData.columns[i].mode != null &&
autoincrSelector != null &&
autoincrSelector.hasComponent(queryData.columns[i].mode)){
autoincr = (AutoIncrementModule)
autoincrSelector.select(queryData.columns[i].mode);
if ( autoincr.includeInQuery() ) {
actualColumns++;
queryBuffer.append(
queryData.columns[i].columnConf.getAttribute( "name" ) );
if ( autoincr.includeAsValue() ) {
valueBuffer.append( "?" );
} else {
valueBuffer.append(
autoincr.getSubquery( table, queryData.columns[i].columnConf,
queryData.columns[i].modeConf ) );
}
}
} else {
if (getLogger().isErrorEnabled())
getLogger().error("Could not find mode
description "
+
queryData.columns[i].mode + " for column #"+i);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Column data
"+queryData.columns[i]);
}
throw new ConfigurationException("Could not
find mode description "+queryData.columns[i].mode+" for column "+i);
}
} finally {
if (autoincrSelector != null) {
if (autoincr != null)
autoincrSelector.release(autoincr);
this.manager.release(autoincrSelector);
}
}
} else {
actualColumns++;
queryBuffer.append(
queryData.columns[i].columnConf.getAttribute( "name" ) );
valueBuffer.append( "?" );
}
}
valueBuffer.append(")");
queryBuffer.append(valueBuffer);
queryData.queryString = queryBuffer.toString();
this.cachedQueryData.put( lookUpKey, queryData );
}
}
return queryData;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseDeleteAction.java
Index: DatabaseDeleteAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.util.Map;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.apache.cocoon.util.HashMap;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Updates a record in a database. The action can update one or more
* tables, and can update more than one row to a table at a time.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseDeleteAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseDeleteAction extends DatabaseAction {
/**
* determine which mode to use as default mode
* here: DELETE
* highly specific to operation INSERT / UPDATE / DELETE / SELECT
*/
protected String selectMode ( boolean isAutoIncrement, Map modes ) {
return (String) modes.get( MODE_OTHERS );
}
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*/
protected boolean honourAutoIncrement() { return false; }
/**
* Fetch all values for all key columns that are needed to do the
* database operation.
*/
protected Object[][] getColumnValues( Configuration tableConf,
CacheHelper queryData, Map objectModel )
throws ConfigurationException, ComponentException {
Object[][] columnValues = new Object[ queryData.columns.length ][];
for ( int i = 0; i < queryData.columns.length; i++ ){
if ( queryData.columns[i].isKey ) {
columnValues[i] = this.getColumnValue( tableConf,
queryData.columns[i], objectModel );
} else {
// columnValues[i] = new Object[1]; // this should not be
needed
}
}
return columnValues;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected CacheHelper getQuery( Configuration table, Map modeTypes, Map
defaultModeNames )
throws ConfigurationException, ComponentException {
LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
CacheHelper queryData = null;
synchronized( this.cachedQueryData ) {
queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
if (queryData == null) {
Configuration[] keys =
table.getChild("keys").getChildren("key");
queryData = new CacheHelper( keys.length, keys.length );
fillModes( keys, true, defaultModeNames, modeTypes, queryData
);
StringBuffer queryBuffer = new StringBuffer("DELETE FROM ");
queryBuffer.append(table.getAttribute("name")).append(" WHERE
");
for (int i = 0; i < queryData.columns.length; i++) {
if ( i > 0 ) {
queryBuffer.append(" AND ");
}
queryBuffer
.append(
queryData.columns[i].columnConf.getAttribute( "name" ) )
.append( "= ?" );
}
queryData.queryString = queryBuffer.toString();
this.cachedQueryData.put( lookUpKey, queryData );
}
}
return queryData;
}
/**
* set all necessary ?s and execute the query
*/
protected int processRow ( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper queryData,
Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception {
int currentIndex = 1;
// ordering is different for DELETE just needs keys
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( col.isKey ) {
this.setColumn( objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ],
statement, currentIndex );
currentIndex++;
}
}
int rowCount = statement.executeUpdate();
return rowCount;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseQueryAction.java
Index: DatabaseQueryAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.util.Map;
import java.sql.Connection;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Struct;
import java.sql.Types;
import java.io.InputStream;
import java.io.BufferedInputStream;
import org.apache.cocoon.util.HashMap;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.cocoon.util.JDBCTypeConversions;
/**
* Executes an arbitrary query. The query is associated with a table
* and selected through the others mode. All keys and values are set
* in order of appearance, starting with keys, thus the query needs to
* have as many placeholders for prepared statement parameters. If it
* is an update query, the number of affected rows is returned to the
* sitemap.
*
*<pre>
* <table name="example">
* <queries>
* <query mode="one">update example set count=count+1 where
id=?</query>
* <query mode="two">select count, name from example where
id=?</query>
* </queries>
* <keys>
* <key name="id"/>
* </keys>
* <values/>
* </table>
*</pre>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseQueryAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseQueryAction extends DatabaseAction {
/**
* determine which mode to use as default mode
* here: SELECT
* highly specific to operation INSERT / UPDATE / DELETE / SELECT
*/
protected String selectMode ( boolean isAutoIncrement, Map modes ) {
return (String) modes.get( MODE_OTHERS );
}
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*/
protected boolean honourAutoIncrement() { return false; }
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected CacheHelper getQuery( Configuration table, Map modeTypes, Map
defaultModeNames )
throws ConfigurationException, ComponentException {
LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
CacheHelper queryData = null;
synchronized( this.cachedQueryData ) {
queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
if (queryData == null) {
Configuration[] queries =
table.getChild("queries").getChildren("query");
Configuration[] keys =
table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
boolean found = false;
String queryModeName = "";
String query = "";
boolean useValues = true;
for (int i=0; i<queries.length; i++) {
queryModeName = queries[i].getAttribute("mode",null);
if (
queryModeName.equals((String)modeTypes.get(MODE_OTHERS)) ||
"all".equals(queryModeName)) {
query = queries[i].getValue();
useValues =
queries[i].getAttributeAsBoolean("use-values", useValues);
found = true;
break;
}
}
if (!found) {
throw new ConfigurationException("Could not find query
mode " +
modeTypes.get(MODE_OTHERS) +
" for table " +
table.getAttribute("name",null));
}
queryData = new CacheHelper( keys.length, keys.length +
(useValues ? values.length : 0));
queryData.queryString = query;
fillModes( keys , true , defaultModeNames, modeTypes,
queryData );
if (useValues) fillModes( values, false, defaultModeNames,
modeTypes, queryData );
this.cachedQueryData.put( lookUpKey, queryData );
}
}
return queryData;
}
/**
* Fetch all values for all columns that are needed to do the database
operation.
*/
protected Object[][] getColumnValues( Configuration tableConf,
CacheHelper queryData, Map objectModel )
throws ConfigurationException, ComponentException {
Object[][] columnValues = new Object[ queryData.columns.length ][];
for ( int i = 0; i < queryData.columns.length; i++ ){
columnValues[i] = this.getColumnValue( tableConf,
queryData.columns[i], objectModel );
}
return columnValues;
}
/**
* set all necessary ?s and execute the query
*/
protected int processRow ( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper queryData,
Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception {
int currentIndex = 1;
// ordering is different for SELECT just needs keys
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( col.isKey ) {
this.setColumn(objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ], statement, currentIndex );
currentIndex++;
}
}
boolean hasResult = statement.execute();
if (!hasResult) {
return statement.getUpdateCount();
} else {
// retrieve values
ResultSet resultset = statement.getResultSet();
ResultSetMetaData metadata = resultset.getMetaData();
rowIndex = 0;
while ( resultset.next() ){
//if ( ! ( rowIndex == -1 && resultset.isLast() ) ) {
rowIndex++;
//}
String tableName = "";
String columnName = "";
for (int i = 1; i <= metadata.getColumnCount(); i++) {
Object value = resultset.getObject(i);
tableName = metadata.getTableName(i);
columnName = metadata.getColumnLabel(i) +
"["+rowIndex+"]";
if (tableName != "") columnName = tableName + "." +
columnName;
if (this.getLogger().isDebugEnabled())
this.getLogger().debug("retrieving "+columnName+" as
"+value);
results.put(metadata.getTableName(i)+"."+metadata.getColumnLabel(i),value);
}
}
return rowIndex;
}
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseSelectAction.java
Index: DatabaseSelectAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.util.Map;
import java.sql.Connection;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Struct;
import java.sql.Types;
import java.io.InputStream;
import java.io.BufferedInputStream;
import org.apache.cocoon.util.HashMap;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.cocoon.util.JDBCTypeConversions;
/**
* Selects a record from a database. The action can select one or more
* tables, and can select from more than one row of a table at a
* time.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseSelectAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseSelectAction extends DatabaseAction {
/**
* determine which mode to use as default mode
* here: SELECT
* highly specific to operation INSERT / UPDATE / DELETE / SELECT
*/
protected String selectMode ( boolean isAutoIncrement, Map modes ) {
return (String) modes.get( MODE_OTHERS );
}
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*/
protected boolean honourAutoIncrement() { return false; }
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected CacheHelper getQuery( Configuration table, Map modeTypes, Map
defaultModeNames )
throws ConfigurationException, ComponentException {
LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
CacheHelper queryData = null;
synchronized( this.cachedQueryData ) {
queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
if (queryData == null) {
Configuration[] keys =
table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
queryData = new CacheHelper( keys.length, keys.length +
values.length );
fillModes( keys , true , defaultModeNames, modeTypes,
queryData );
fillModes( values, false, defaultModeNames, modeTypes,
queryData );
StringBuffer queryBuffer = new StringBuffer("SELECT ");
//queryBuffer.append(table.getAttribute("name")).append("
WHERE ");
int count = 0;
for (int i = 0; i < queryData.columns.length; i++) {
if ( !queryData.columns[i].isKey ) {
if ( count > 0 ) {
queryBuffer.append(", ");
}
queryBuffer
.append(
queryData.columns[i].columnConf.getAttribute( "name" ) );
count++;
}
}
queryBuffer.append(" FROM
").append(table.getAttribute("name")).append(" WHERE ");
count = 0;
for (int i = 0; i < queryData.columns.length; i++) {
if ( queryData.columns[i].isKey ) {
if ( count > 0 ) {
queryBuffer.append(" AND ");
}
queryBuffer
.append(
queryData.columns[i].columnConf.getAttribute( "name" ) )
.append( "= ?");
count++;
}
}
queryData.queryString = queryBuffer.toString();
this.cachedQueryData.put( lookUpKey, queryData );
}
}
return queryData;
}
/**
* Fetch all values for all key columns that are needed to do the
* database operation.
*/
protected Object[][] getColumnValues( Configuration tableConf,
CacheHelper queryData, Map objectModel )
throws ConfigurationException, ComponentException {
Object[][] columnValues = new Object[ queryData.columns.length ][];
for ( int i = 0; i < queryData.columns.length; i++ ){
if ( queryData.columns[i].isKey ) {
columnValues[i] = this.getColumnValue( tableConf,
queryData.columns[i], objectModel );
} else {
// columnValues[i] = new Object[1]; // this should not be
needed
}
}
return columnValues;
}
/**
* set all necessary ?s and execute the query
*/
protected int processRow ( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper queryData,
Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception {
int currentIndex = 1;
// ordering is different for SELECT just needs keys
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( col.isKey ) {
this.setColumn(objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ], statement, currentIndex );
currentIndex++;
}
}
statement.execute();
// retrieve values
ResultSet resultset = statement.getResultSet();
rowIndex = 0;
while ( resultset.next() ){
for (int i = 0; i < queryData.columns.length; i++) {
if ( !queryData.columns[i].isKey ) {
Object value = JDBCTypeConversions.getColumn( resultset,
queryData.columns[i].columnConf );
this.setOutput(objectModel, outputMode, results, table,
queryData.columns[i].columnConf, rowIndex, value);
}
}
rowIndex++;
}
if (rowIndex == 0) { results = EMPTY_MAP;}
return rowIndex;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseUpdateAction.java
Index: DatabaseUpdateAction.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting.modular;
import java.util.Map;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.apache.cocoon.util.HashMap;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Updates a record in a database. The action can update one or more
* tables, and can update more than one row to a table at a time.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
* @version CVS $Id: DatabaseUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul
Exp $
*/
public class DatabaseUpdateAction extends DatabaseAction {
/**
* determine which mode to use as default mode
* here: UPDATE
* highly specific to operation INSERT / UPDATE / DELETE / SELECT
*/
protected String selectMode ( boolean isAutoIncrement, Map modes ) {
return (String) modes.get( MODE_OTHERS );
}
/**
* determine whether autoincrement columns should be honoured by
* this operation. This is usually snsible only for INSERTs.
*/
protected boolean honourAutoIncrement() { return false; }
/**
* Fetch all values for all columns that are needed to do the
* database operation.
*/
protected Object[][] getColumnValues( Configuration tableConf,
CacheHelper queryData, Map objectModel )
throws ConfigurationException, ComponentException {
Object[][] columnValues = new Object[ queryData.columns.length ][];
for ( int i = 0; i < queryData.columns.length; i++ ){
columnValues[i] = this.getColumnValue( tableConf,
queryData.columns[i], objectModel );
}
return columnValues;
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*
* @param table the table's configuration object
* @return the insert query as a string
*/
protected CacheHelper getQuery( Configuration table, Map modeTypes, Map
defaultModeNames )
throws ConfigurationException, ComponentException {
LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
CacheHelper queryData = null;
synchronized( this.cachedQueryData ) {
queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
if (queryData == null) {
Configuration[] keys =
table.getChild("keys").getChildren("key");
Configuration[] values =
table.getChild("values").getChildren("value");
queryData = new CacheHelper( keys.length, keys.length +
values.length );
fillModes( keys, true, defaultModeNames, modeTypes,
queryData );
fillModes( values, false, defaultModeNames, modeTypes,
queryData );
StringBuffer queryBuffer = new StringBuffer("UPDATE ");
queryBuffer.append(table.getAttribute("name")).append(" SET
");
int cols = 0;
for (int i = 0; i < queryData.columns.length; i++) {
if ( !queryData.columns[i].isKey ) {
if ( cols > 0 ) {
queryBuffer.append(", ");
}
cols++;
queryBuffer
.append(
queryData.columns[i].columnConf.getAttribute( "name" ) )
.append( "= ?" );
}
}
queryBuffer.append(" WHERE ");
for (int i = 0; i < queryData.columns.length; i++) {
if ( queryData.columns[i].isKey ) {
if ( i > 0 ) {
queryBuffer.append(" AND ");
}
queryBuffer
.append(
queryData.columns[i].columnConf.getAttribute( "name" ) )
.append( "= ?" );
}
}
queryData.queryString = queryBuffer.toString();
this.cachedQueryData.put( lookUpKey, queryData );
}
}
return queryData;
}
/**
* set all necessary ?s and execute the query
*/
protected int processRow ( Map objectModel, Connection conn,
PreparedStatement statement, String outputMode,
Configuration table, CacheHelper queryData,
Object[][] columnValues,
int rowIndex, Map results )
throws SQLException, ConfigurationException, Exception {
int currentIndex = 1;
// ordering is different for UPDATE than for INSERT: values, keys
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( !col.isKey ) {
this.setColumn( objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ], statement, currentIndex );
currentIndex++;
}
}
for (int i = 0; i < queryData.columns.length; i++) {
Column col = queryData.columns[i];
if ( col.isKey ) {
this.setColumn( objectModel, outputMode, results, table,
col.columnConf, rowIndex,
columnValues[ i ][ ( col.isSet ? rowIndex : 0
) ], statement, currentIndex );
currentIndex++;
}
}
int rowCount = statement.executeUpdate();
return rowCount;
}
}
1.1
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/package.html
Index: package.html
===================================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>modular</title>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
</head>
<body>
<h1>modular</h1>
<p>These sitemap components use modules to obtain values and are thus very
flexible in use.<br>
</p>
</body>
</html>
1.1
xml-cocoon2/src/blocks/databases/conf/databases-trans.xmap
Index: databases-trans.xmap
===================================================================
<?xml version="1.0"?>
<xmap xpath="/sitemap/components/transformers" unless="[EMAIL
PROTECTED]'sql']">
<map:transformer logger="sitemap.transformer.sql" name="sql"
src="org.apache.cocoon.transformation.SQLTransformer"/>
</xmap>
1.1 xml-cocoon2/src/blocks/databases/conf/datasources.xconf
Index: datasources.xconf
===================================================================
<?xml version="1.0"?>
<xconf xpath="/cocoon/datasources" unless="[EMAIL PROTECTED]'personnel']">
<jdbc logger="core.datasources.personnel" name="personnel">
<!--
If you have an Oracle database, and are using the the
pool-controller below, you should add the attribute
"oradb" and set it to true.
<pool-controller min="5" max="10" oradb="true"/>
That way the test to see if the server has disconnected
the JdbcConnection will function properly.
-->
<pool-controller max="10" min="5"/>
<!--
If you need to ensure an autocommit is set to true or
false, then create the "auto-commit" element below.
<auto-commit>false</auto-commit>
The default is true.
-->
<dburl>@db_url@</dburl>
<user>@db_user@</user>
<password>@db_password@</password>
</jdbc>
</xconf>
1.1
xml-cocoon2/src/blocks/databases/conf/db-modules-input.xconf
Index: db-modules-input.xconf
===================================================================
<?xml version="1.0"?>
<xconf xpath="/cocoon/input-modules" unless="[EMAIL
PROTECTED]'org.apache.cocoon.components.modules.input.CollectionMetaModule']">
<component-instance logger="core.modules.input" name="collection"
class="org.apache.cocoon.components.modules.input.CollectionMetaModule"/>
</xconf>
1.1 xml-cocoon2/src/blocks/databases/conf/db-modules.xconf
Index: db-modules.xconf
===================================================================
<?xml version="1.0"?>
<xconf xpath="/cocoon" unless="autoincrement-modules">
<!-- =============== Database Modules ==================== -->
<autoincrement-modules>
<component-instance logger="core.modules.auto" name="auto"
class="org.apache.cocoon.components.modules.database.HsqlIdentityAutoIncrementModule"/>
<!--
Choose the one suitable for your DBMS. You *can* have more than
one at a time, but they need to have different names. You then
need to specify explicitly, which one to use in your descriptor
file.
<component-instance logger="core.modules.auto" name="auto"
class="org.apache.cocoon.components.modules.database.ManualAutoIncrementModule"/>
<component-instance logger="core.modules.auto" name="auto"
class="org.apache.cocoon.components.modules.database.IfxSerialAutoIncrementModule"/>
<component-instance logger="core.modules.auto" name="auto"
class="org.apache.cocoon.components.modules.database.MysqlAutoIncrementModule"/>
-->
</autoincrement-modules>
</xconf>
1.1 xml-cocoon2/src/blocks/databases/conf/db-modules.xroles
Index: db-modules.xroles
===================================================================
<?xml version="1.0"?>
<xroles xpath="/role-list" unless="[EMAIL
PROTECTED]'org.apache.cocoon.components.modules.database.AutoIncrementModuleSelector']">
<!-- database modules -->
<role
name="org.apache.cocoon.components.modules.database.AutoIncrementModuleSelector"
shorthand="autoincrement-modules"
default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"/>
</xroles>
1.1 xml-cocoon2/src/blocks/databases/conf/esql.xconf
Index: esql.xconf
===================================================================
<?xml version="1.0"?>
<xconf xpath="/cocoon/markup-languages/[EMAIL PROTECTED]'xsp']/[EMAIL
PROTECTED]'java']" unless="builtin-logicsheet/[EMAIL PROTECTED]'prefix' and
@value='esql']">
<!-- The ESQL logicsheet is an XSP logicsheet that performs sql
queries and
serializes their results as XML. This allows you to work with
data from a
wide variety of different sources when using Apache Cocoon. -->
<builtin-logicsheet>
<parameter name="prefix" value="esql"/>
<parameter name="uri" value="http://apache.org/cocoon/SQL/v2"/>
<parameter name="href"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/esql.xsl"/>
</builtin-logicsheet>
</xconf>
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]