You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ode.apache.org by ms...@apache.org on 2007/11/13 22:31:01 UTC
svn commit: r594645 - in
/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc:
./ DbExternalVariable.java EVarId.java GenType.java InitType.java
JdbcExternalVariableModule.java
Author: mszefler
Date: Tue Nov 13 13:31:00 2007
New Revision: 594645
URL: http://svn.apache.org/viewvc?rev=594645&view=rev
Log:
Added missing files.
Added:
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java (with props)
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java (with props)
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java (with props)
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java (with props)
ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java (with props)
Added: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java
URL: http://svn.apache.org/viewvc/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java?rev=594645&view=auto
==============================================================================
--- ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java (added)
+++ ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java Tue Nov 13 13:31:00 2007
@@ -0,0 +1,529 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ode.bpel.extvar.jdbc;
+
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import javax.sql.DataSource;
+import javax.xml.namespace.QName;
+
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.GUID;
+import org.apache.ode.utils.ISO8601DateParser;
+import org.apche.ode.bpel.evar.ExternalVariableModuleException;
+import org.apche.ode.bpel.evar.IncompleteKeyException;
+import org.apche.ode.bpel.evar.ExternalVariableModule.Locator;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+
+/**
+ * Configuration for an external variable.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ */
+class DbExternalVariable {
+
+ private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
+
+ EVarId evarId;
+
+ DataSource dataSource;
+
+ final ArrayList<Column> columns = new ArrayList<Column>();
+
+ private final HashMap<String, Column> colmap = new HashMap<String, Column>();
+
+ final ArrayList<Column> keycolumns = new ArrayList<Column>();
+
+ final ArrayList<Column> inscolumns = new ArrayList<Column>();
+
+ final ArrayList<Column> updcolumns = new ArrayList<Column>();
+
+ InitType initType = InitType.update_insert;
+
+ public String[] autoColNames;
+
+ String select;
+
+ String insert;
+
+ String update;
+
+ String table;
+
+ String schema;
+
+ /** Does the database support retrieval of generated keys? */
+ boolean generatedKeys;
+
+ QName rowname = new QName(null, "row");
+
+ DbExternalVariable(EVarId evar, DataSource ds) {
+ this.evarId = evar;
+ this.dataSource = ds;
+ }
+
+ Column getColumn(String key) {
+ return colmap.get(key);
+ }
+
+ void addColumn(Column c) {
+ c.idx = columns.size();
+ colmap.put(c.name, c);
+ columns.add(c);
+ if (c.key) {
+ keycolumns.add(c);
+ autoColNames = new String[keycolumns.size()];
+ for (int i = 0; i < autoColNames.length; ++i)
+ autoColNames[i] = keycolumns.get(i).colname;
+ }
+ createSelect();
+ createInsert();
+ createUpdate();
+ }
+
+ public int numColumns() {
+ return columns.size();
+ }
+
+ /**
+ * Create a key from a locator.
+ *
+ * @param locator
+ * row locator
+ * @param rowval
+ * (optional) row value
+ * @return
+ */
+ RowKey generateKey(Locator locator, RowVal rowval) throws ExternalVariableModuleException {
+ RowKey rc = new RowKey();
+ for (Column kc : keycolumns) {
+ String s;
+ switch (kc.genType) {
+ case pid:
+ s = locator.pid.toString();
+ break;
+ case iid:
+ s = locator.iid.toString();
+ break;
+ default:
+ s = locator.get(kc.name);
+ }
+
+ Object rv = rowval == null ? null : rowval.get(kc.name);
+ if (s == null && rv == null) {
+ throw new IncompleteKeyException(Collections.singleton(kc.name));
+ } else if (s != null && rv != null) {
+ // TODO: make sure the keys don't conflict with the rows.
+ rc.add(kc.fromText(s));
+ } else if (s != null) {
+ rc.add(kc.fromText(s));
+ } else {
+ rc.add(rv);
+ }
+
+ }
+
+ return rc;
+ }
+
+ private void createSelect() {
+ StringBuilder sb = new StringBuilder("select ");
+ boolean first = true;
+ for (Column c : columns) {
+ if (!first) {
+ sb.append(',');
+ }
+ first = false;
+
+ sb.append(c.colname);
+ }
+ sb.append(" from " + table);
+ if (keycolumns.size() > 0) {
+ sb.append(" where ");
+ first = true;
+
+ for (Column kc : keycolumns) {
+ if (!first) {
+ sb.append(" and ");
+ }
+ first = false;
+
+ sb.append(kc.colname);
+ sb.append(" = ?");
+ }
+ select = sb.toString();
+
+ } else {
+ select = null;
+ }
+ }
+
+ private void createUpdate() {
+ updcolumns.clear();
+ StringBuilder sb = new StringBuilder("update ");
+ sb.append(table);
+ sb.append(" set ");
+ boolean first = true;
+ for (Column c : columns) {
+ // Don't ever update keys or sequences or create time stamps
+ if (c.genType == GenType.sequence || c.key || c.genType == GenType.ctimestamp)
+ continue;
+
+ if (!first)
+ sb.append(", ");
+ first = false;
+
+ sb.append(c.colname);
+ sb.append(" = ");
+ if (c.genType == GenType.expression)
+ sb.append(c.expression);
+ else {
+ sb.append(" ?");
+ updcolumns.add(c);
+ }
+ }
+
+ if (keycolumns.size() > 0) {
+ sb.append(" where ");
+ first = true;
+
+ for (Column kc : keycolumns) {
+ if (!first) {
+ sb.append(" and ");
+ }
+ first = false;
+
+ sb.append(kc.colname);
+ sb.append(" = ?");
+ }
+
+ }
+
+ // If we have no key columns, we cannot do an update
+ if (keycolumns.size() == 0)
+ update = null;
+ else
+ update = sb.toString();
+
+ }
+
+ private void createInsert() {
+ inscolumns.clear();
+ StringBuilder sb = new StringBuilder("insert into ");
+ sb.append(table);
+ sb.append(" ( ");
+ boolean first = true;
+ for (Column c : columns) {
+ if (c.genType == GenType.sequence)
+ continue;
+
+ if (!first)
+ sb.append(',');
+
+ first = false;
+ sb.append(c.colname);
+ }
+ sb.append(" ) ");
+
+ sb.append(" values ( ");
+
+ first = true;
+ for (Column c : columns) {
+ if (c.genType == GenType.sequence)
+ continue;
+ if (!first)
+ sb.append(',');
+ first = false;
+
+ if (c.genType == GenType.expression)
+ sb.append(c.expression);
+ else {
+ sb.append(" ? ");
+ inscolumns.add(c);
+ }
+ }
+ sb.append(" ) ");
+
+ insert = sb.toString();
+
+ }
+
+ class Column {
+
+ int idx;
+
+ /** name of the column */
+ String name;
+
+ /** database name of the column (in case we need to override */
+ String colname;
+
+ /** Is this a key column? */
+ boolean key;
+
+ /** Type of value generator to use for creating values for this column. */
+ GenType genType;
+
+ /** The (SQL) expression used to populate the column. */
+ String expression;
+
+ /** The SQL data type of this column, one of java.sql.Types */
+ int dataType;
+
+ /** Indicates NULL values are OK */
+ boolean nullok;
+
+ QName elname;
+
+ Column(String name, String colname, boolean key, GenType genType, String expression) {
+ this.name = name;
+ this.colname = colname == null ? name : colname;
+ this.key = key;
+ this.genType = genType;
+ this.expression = expression;
+ elname = new QName(null, name);
+ }
+
+ public Object getValue(String name, RowVal values, Long iid) {
+ switch (genType) {
+ case ctimestamp:
+ case utimestamp:
+ return isTimeStamp() ? new Timestamp(new Date().getTime()) : new Date();
+ case uuid:
+ return new GUID().toString();
+ case pid:
+ return evarId.pid.toString();
+ case iid:
+ return iid;
+ case none:
+ default:
+ return values.get(name);
+ }
+ }
+
+ /**
+ * Return <code>true</code> if column is a date-like type.
+ *
+ * @return
+ */
+ boolean isDate() {
+ return dataType == Types.DATE;
+ }
+
+ boolean isTimeStamp() {
+ return dataType == Types.TIMESTAMP;
+ }
+
+ boolean isTime() {
+ return dataType == Types.TIME;
+ }
+
+ /**
+ * Is this column best represented as an integer?
+ *
+ * @return
+ */
+ boolean isInteger() {
+ switch (dataType) {
+ case Types.BIGINT:
+ case Types.INTEGER:
+ case Types.SMALLINT:
+ case Types.TINYINT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Is this column best represented as a real number?
+ *
+ * @return
+ */
+ boolean isReal() {
+ switch (dataType) {
+ case Types.DECIMAL:
+ case Types.REAL:
+ case Types.NUMERIC:
+ return true;
+ default:
+ return false;
+ }
+
+ }
+
+ boolean isBoolean() {
+ switch (dataType) {
+ case Types.BIT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ String toText(Object val) {
+ if (val == null)
+ return null;
+
+ if (isDate())
+ return ISO8601DateParser.format((Date) val);
+ else if (isTime())
+ return ISO8601DateParser.format((Date) val);
+ else if (isTimeStamp())
+ return ISO8601DateParser.format((Date) val);
+ else
+ return val.toString();
+ }
+
+ Object fromText(String val) throws ExternalVariableModuleException {
+ try {
+ // TODO: use xsd:date and xsd:time conversions
+ if (isDate())
+ return new java.sql.Date(ISO8601DateParser.parse(val).getTime());
+ else if (isTime())
+ return new java.sql.Time(ISO8601DateParser.parse(val).getTime());
+ else if (isTimeStamp())
+ return new java.sql.Timestamp(ISO8601DateParser.parse(val).getTime());
+ else if (isInteger())
+ return Long.valueOf(val);
+ else if (isReal())
+ return Double.valueOf(val);
+ else if (isBoolean())
+ return Boolean.valueOf(val);
+
+ return val;
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("Unable to convert value \"" + val + "\" for column \"" + name + "\" !",
+ ex);
+ }
+ }
+ }
+
+ /**
+ *
+ * Key used to identify a row.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ *
+ */
+ class RowKey extends ArrayList<Object> {
+
+ /**
+ * Create empty row key.
+ */
+ RowKey() {
+ }
+
+ /**
+ * Write the key to a locator.
+ *
+ * @param locator
+ */
+ void write(Locator locator) {
+ locator.clear();
+ int idx = 0;
+ for (Column kc : keycolumns)
+ locator.put(kc.name, kc.toText(get(idx++)));
+ }
+
+ }
+
+ /**
+ * Row values.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ *
+ */
+ class RowVal extends ArrayList<Object> {
+ RowVal() {
+ super(columns.size());
+ for (int i = 0; i < columns.size(); ++i)
+ add(null);
+ }
+
+ Object get(String name) {
+ Column c = colmap.get(name);
+ if (c == null)
+ return null;
+ int idx = columns.indexOf(c);
+ return get(idx);
+ }
+
+ public void put(String name, Object val) {
+ Column c = colmap.get(name);
+ if (c == null)
+ return;
+
+ int idx = columns.indexOf(c);
+ this.set(idx, val);
+ }
+ }
+
+ Element renderXmlRow(RowVal value) {
+ Document doc = DOMUtils.newDocument();
+ Element el = doc.createElementNS(rowname.getNamespaceURI(), rowname.getLocalPart());
+ doc.appendChild(el);
+ for (Column c : columns) {
+ Object data = value.get(c.idx);
+ Element cel = doc.createElementNS(c.elname.getNamespaceURI(), c.elname.getLocalPart());
+ String strdat = c.toText(data);
+ if (strdat != null)
+ cel.appendChild(doc.createTextNode(strdat));
+ else
+ cel.setAttributeNS(XSI_NS, "xsi:nil", "true");
+
+ el.appendChild(cel);
+ }
+
+ return el;
+ }
+
+ RowVal parseXmlRow(Element rowel) throws ExternalVariableModuleException {
+ RowVal ret = new RowVal();
+ NodeList nl = rowel.getChildNodes();
+ for (int i = 0; i < nl.getLength(); ++i) {
+ Node n = nl.item(i);
+ if (n.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+ String key = n.getLocalName();
+ String val = n.getTextContent();
+
+ Column column = getColumn(key);
+ if (column == null)
+ continue;
+
+ String nil = ((Element) n).getAttributeNS(XSI_NS, "nil");
+ if (nil != null && "true".equalsIgnoreCase(nil))
+ ret.put(key, null);
+ else
+ ret.put(key, column.fromText(val));
+ }
+ return ret;
+ }
+
+}
\ No newline at end of file
Propchange: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/DbExternalVariable.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java
URL: http://svn.apache.org/viewvc/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java?rev=594645&view=auto
==============================================================================
--- ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java (added)
+++ ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java Tue Nov 13 13:31:00 2007
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ode.bpel.extvar.jdbc;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Key for identifiying an external variable.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ *
+ */
+class EVarId {
+ final QName pid;
+ final String varId;
+
+
+ EVarId(QName pid, String varId) {
+ this.pid = pid;
+ this.varId = varId;
+ }
+
+ public boolean equals(Object o) {
+ return ((EVarId)o).varId.equals(varId ) && ((EVarId)o).pid.equals(pid);
+ }
+
+ public int hashCode() {
+ return varId.hashCode() ^ pid.hashCode();
+ }
+
+ public String toString() {
+ return pid + "#" + varId;
+ }
+}
Propchange: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/EVarId.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java
URL: http://svn.apache.org/viewvc/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java?rev=594645&view=auto
==============================================================================
--- ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java (added)
+++ ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java Tue Nov 13 13:31:00 2007
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ode.bpel.extvar.jdbc;
+
+/**
+ * Generator type enumaration.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ *
+ */
+enum GenType {
+ /** plain old column */
+ none,
+
+ /** sequence column */
+ sequence,
+
+ /** SQL expression column */
+ expression,
+
+ /** server-generated uuid column */
+ uuid,
+
+ /** process-id column */
+ pid,
+
+ /** instance-id column */
+ iid,
+
+ /** create timestamp */
+ ctimestamp,
+
+ /** update timestamp */
+ utimestamp
+}
\ No newline at end of file
Propchange: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/GenType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java
URL: http://svn.apache.org/viewvc/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java?rev=594645&view=auto
==============================================================================
--- ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java (added)
+++ ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java Tue Nov 13 13:31:00 2007
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ode.bpel.extvar.jdbc;
+
+/**
+ * Enumeration of methods in which a new external variable row initialization is handled.
+ *
+ * @author Maciej Szefler <mszefler at gmail dot com>
+ *
+ */
+public enum InitType {
+ /** Just try to update the row, if does not already exist, fails. */
+ update,
+
+ /** Just insert the row, if already exist fails. */
+ insert,
+
+ /** Try updating the row, if no exist, then try inserting. */
+ update_insert,
+
+ /** First delete the row, then insert a new one. */
+ delete_insert
+
+}
Propchange: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/InitType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java
URL: http://svn.apache.org/viewvc/ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java?rev=594645&view=auto
==============================================================================
--- ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java (added)
+++ ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java Tue Nov 13 13:31:00 2007
@@ -0,0 +1,395 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ode.bpel.extvar.jdbc;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ode.bpel.extvar.jdbc.DbExternalVariable.Column;
+import org.apache.ode.bpel.extvar.jdbc.DbExternalVariable.RowKey;
+import org.apache.ode.bpel.extvar.jdbc.DbExternalVariable.RowVal;
+import org.apache.ode.utils.DOMUtils;
+import org.apche.ode.bpel.evar.ExternalVariableModule;
+import org.apche.ode.bpel.evar.ExternalVariableModuleException;
+import org.w3c.dom.Element;
+
+public class JdbcExternalVariableModule implements ExternalVariableModule {
+
+ private static final Log __log = LogFactory.getLog(JdbcExternalVariableModule.class);
+
+ /** Unique QName for the engine, this should be the element used for the external-variable configuration. */
+ public static final QName NAME = new QName("http://www.apache.org/ode/extensions/externalVariables", "jdbc");
+
+ /** Manually configured data sources. */
+ private final HashMap<String, DataSource> _dataSources = new HashMap<String, DataSource>();
+
+ /** Variables we know about via configure() method calls. */
+ private final HashMap<EVarId, DbExternalVariable> _vars = new HashMap<EVarId, DbExternalVariable>();
+
+ public void configure(QName pid, String extVarId, Element config) throws ExternalVariableModuleException {
+ EVarId evarId = new EVarId(pid, extVarId);
+ DataSource ds = null;
+
+ Element jndiDs = DOMUtils.findChildByName(config, new QName(null, "datasource-jndi"));
+ Element jndiRef = DOMUtils.findChildByName(config, new QName(null, "datasource-ref"));
+ Element initMode = DOMUtils.findChildByName(config, new QName(null, "init-mode"));
+ if (jndiRef != null) {
+ String refname = jndiRef.getTextContent().trim();
+ ds = _dataSources.get(refname);
+ if (ds == null)
+ throw new ExternalVariableModuleException("Data source reference \"" + refname
+ + "\" not found for external variable " + evarId
+ + "; make sure to register the data source with the engine!");
+ } else if (jndiDs != null) {
+ String name = jndiDs.getTextContent().trim();
+ Object dsCandidate;
+ InitialContext ctx;
+ try {
+ ctx = new InitialContext();
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("Unable to access JNDI context for external variable " + evarId, ex);
+ }
+
+ try {
+ dsCandidate = ctx.lookup(name);
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("Lookup of data source for " + evarId + " failed.", ex);
+ } finally {
+ try {
+ ctx.close();
+ } catch (NamingException e) {
+ ;
+ ;
+ }
+ }
+
+ if (dsCandidate == null)
+ throw new ExternalVariableModuleException("Data source \"" + name + "\" not found in JNDI!");
+
+ if (!(dsCandidate instanceof DataSource))
+ throw new ExternalVariableModuleException("JNDI object \"" + name + "\" does not implement javax.sql.DataSource");
+
+ ds = (DataSource) dsCandidate;
+ }
+
+ if (ds == null) {
+ throw new ExternalVariableModuleException("No valid data source configuration for JDBC external varible " + evarId);
+ }
+
+ Connection conn;
+ DatabaseMetaData metaData;
+ try {
+ conn = ds.getConnection();
+ metaData = conn.getMetaData();
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("Unable to open database connection for external variable " + evarId, ex);
+ }
+
+ try {
+ DbExternalVariable dbev = new DbExternalVariable(evarId, ds);
+ if (initMode != null)
+ try {
+ dbev.initType = InitType.valueOf(initMode.getTextContent().trim());
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("Invalid <init-mode> value: " + initMode.getTextContent().trim());
+ }
+
+ Element tableName = DOMUtils.findChildByName(config, new QName(null, "table"));
+ if (tableName == null || tableName.getTextContent().trim().equals(""))
+ throw new ExternalVariableModuleException("Must specify <table> for external variable " + evarId);
+ String table = tableName.getTextContent().trim();
+ String schema = null;
+ if (table.indexOf('.') != -1) {
+ schema = table.substring(0, table.indexOf('.'));
+ table = table.substring(table.indexOf('.') + 1);
+ }
+
+ if (metaData.storesLowerCaseIdentifiers()) {
+ table = table.toLowerCase();
+ if (schema != null)
+ schema = table.toLowerCase();
+ } else if (metaData.storesUpperCaseIdentifiers()) {
+ table = table.toUpperCase();
+ if (schema != null)
+ schema = schema.toUpperCase();
+ }
+
+ dbev.generatedKeys = metaData.supportsGetGeneratedKeys();
+ ResultSet tables = metaData.getTables(null, schema, table, null);
+ if (tables.next()) {
+ dbev.table = tables.getString("TABLE_NAME");
+ dbev.schema = tables.getString("TABLE_SCHEM");
+ } else
+ throw new ExternalVariableModuleException("Table \"" + table + "\" not found in database.");
+
+ tables.close();
+
+ List<Element> columns = DOMUtils.findChildrenByName(config, new QName(null, "column"));
+
+ for (Element col : columns) {
+ String name = col.getAttribute("name");
+ String colname = col.getAttribute("column-name");
+ String key = col.getAttribute("key");
+ String gentype = col.getAttribute("generator");
+ String expression = col.getAttribute("expression");
+
+ if (key == null || "".equals(key))
+ key = "no";
+ if (gentype == null || "".equals(gentype))
+ gentype = GenType.none.toString();
+ if (colname == null || "".equals(colname))
+ colname = name;
+
+ if (name == null || "".equals(name))
+ throw new ExternalVariableModuleException("External variable " + evarId
+ + " <column> element must have \"name\" attribute. ");
+
+ if (metaData.storesLowerCaseIdentifiers())
+ colname = colname.toLowerCase();
+ else if (metaData.storesUpperCaseIdentifiers())
+ colname = colname.toUpperCase();
+
+ GenType gtype;
+ try {
+ gtype = GenType.valueOf(gentype);
+ } catch (Exception ex) {
+ throw new ExternalVariableModuleException("External variable " + evarId + " column \"" + name
+ + "\" generator type \"" + gentype + "\" is unknown.");
+
+ }
+
+ if (gtype == GenType.expression && (expression == null || "".equals(expression)))
+ throw new ExternalVariableModuleException("External variable " + evarId + " column \"" + name
+ + "\" used \"expression\" generator, but did not specify an expression");
+
+ Column c = dbev.new Column(name, colname, key.equalsIgnoreCase("yes"), gtype, expression);
+ ResultSet cmd = metaData.getColumns(null, dbev.schema, dbev.table, colname);
+ if (cmd.next()) {
+ c.dataType = cmd.getInt("DATA_TYPE");
+ c.nullok = cmd.getInt("NULLABLE") != 0;
+ } else
+ throw new ExternalVariableModuleException("External variable " + evarId + " referenced "
+ + "non-existant column \"" + colname + "\"!");
+
+ dbev.addColumn(c);
+
+ }
+
+ if (dbev.numColumns() == 0)
+ throw new ExternalVariableModuleException("External variable " + evarId + " did not have any <column> elements!");
+
+ _vars.put(evarId, dbev);
+ } catch (SQLException se) {
+ throw new ExternalVariableModuleException("SQL Error", se);
+ } finally {
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ }
+ }
+ }
+
+ public QName getName() {
+ return NAME;
+ }
+
+ public boolean isTransactional() {
+ return true;
+ }
+
+ public void shutdown() {
+ }
+
+ public void start() {
+ }
+
+ public void stop() {
+ }
+
+ public Value writeValue(Value newval) throws ExternalVariableModuleException {
+ EVarId evarId = new EVarId(newval.locator.pid, newval.locator.varId);
+ DbExternalVariable evar = _vars.get(evarId);
+ if (evar == null)
+ throw new ExternalVariableModuleException("No such variable. "); // todo
+
+ RowVal val = evar.parseXmlRow((Element) newval.value);
+ RowKey key = evar.generateKey(newval.locator, val);
+
+ if (key != null && evar.initType == InitType.delete_insert) {
+ // do delete...
+ // TODO
+ }
+
+ // should we try an update first? to do this we need to have all the required keys
+ // and there should be some keys
+ boolean tryupdatefirst = (evar.initType == InitType.update || evar.initType == InitType.update_insert)
+ && !evar.keycolumns.isEmpty() && key != null;
+
+ boolean insert = evar.initType != InitType.update;
+
+ try {
+ if (tryupdatefirst)
+ insert = execUpdate(evar, val) == 0;
+ if (insert) {
+ key = execInsert(evar, val);
+ // Transfer the keys obtained from the db.
+ key.write(newval.locator);
+ }
+ } catch (SQLException se) {
+ throw new ExternalVariableModuleException("Error updating row.", se);
+ }
+
+ return newval;
+
+ }
+
+ public Value readValue(Locator locator) throws ExternalVariableModuleException {
+ EVarId evarId = new EVarId(locator.pid, locator.varId);
+ DbExternalVariable evar = _vars.get(evarId);
+ if (evar == null)
+ throw new ExternalVariableModuleException("No such variable. "); // todo
+
+ Element val;
+ try {
+ RowVal rowval = execSelect(evar, locator);
+ if (rowval == null)
+ return null;
+ val = evar.renderXmlRow(rowval);
+ } catch (SQLException se) {
+ throw new ExternalVariableModuleException("SQL Error.", se);
+ }
+
+ return new Value(locator, val, null);
+
+ }
+
+ /**
+ * Manually register a data source. Handy if you don't want to use JDBC to look these up.
+ *
+ * @param dsName
+ * @param ds
+ */
+ public void registerDataSource(String dsName, DataSource ds) {
+ _dataSources.put(dsName, ds);
+ }
+
+ int execUpdate(DbExternalVariable dbev, RowVal values) throws SQLException {
+ Connection conn = dbev.dataSource.getConnection();
+ try {
+ PreparedStatement stmt = conn.prepareStatement(dbev.update);
+ int idx = 1;
+ for (Column c : dbev.updcolumns) {
+ Object val = values.get(c.name);
+ stmt.setObject(idx, val);
+ idx++;
+ }
+
+ for (Column ck : dbev.keycolumns) {
+ Object val = values.get(ck.name);
+ stmt.setObject(idx, val);
+ idx++;
+ }
+
+ return stmt.executeUpdate();
+
+ } finally {
+ conn.close();
+ }
+
+ }
+
+ RowVal execSelect(DbExternalVariable dbev, Locator locator) throws SQLException, ExternalVariableModuleException {
+ RowKey rowkey = dbev.generateKey(locator, null);
+ RowVal ret = dbev.new RowVal();
+ Connection conn = dbev.dataSource.getConnection();
+ try {
+ PreparedStatement stmt = conn.prepareStatement(dbev.select);
+ int idx = 1;
+ for (Object k : rowkey)
+ stmt.setObject(idx++, k);
+
+ ResultSet rs = stmt.executeQuery();
+ try {
+ if (rs.next()) {
+ for (Column cr : dbev.columns)
+ ret.set(cr.idx,rs.getObject(cr.idx+1));
+
+ } else
+ return null;
+ } finally {
+ rs.close();
+ }
+ } finally {
+ conn.close();
+ }
+
+ return ret;
+ }
+
+ RowKey execInsert(DbExternalVariable dbev, RowVal values) throws SQLException {
+ RowKey keys = dbev.new RowKey();
+ Connection conn = dbev.dataSource.getConnection();
+ try {
+ PreparedStatement stmt = dbev.generatedKeys ? conn.prepareStatement(dbev.insert, dbev.autoColNames) : conn
+ .prepareStatement(dbev.insert);
+ int idx = 1;
+ for (Column c : dbev.inscolumns) {
+ Object val = c.getValue(c.name, values, null);
+ values.put(c.name, val);
+ stmt.setObject(idx, val);
+ idx++;
+ }
+
+ stmt.execute();
+
+ if (dbev.generatedKeys) {
+ // With JDBC 3, we can get the values of the key columns (if the db supports it)
+ ResultSet keyRS = stmt.getResultSet();
+ keyRS.next();
+ for (Column ck : dbev.keycolumns)
+ keys.add(keyRS.getObject(ck.colname));
+ } else {
+ for (Column ck : dbev.keycolumns) {
+ Object val = values.get(ck.name);
+ if (val != null)
+ keys.add(val);
+ }
+ }
+
+ return keys;
+
+ } finally {
+ conn.close();
+ }
+
+ }
+
+}
Propchange: ode/branches/extvar/bpel-runtime/src/main/java/org/apache/ode/bpel/extvar/jdbc/JdbcExternalVariableModule.java
------------------------------------------------------------------------------
svn:eol-style = native