diff options
Diffstat (limited to 'branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc')
3 files changed, 519 insertions, 0 deletions
diff --git a/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCHelper.java b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCHelper.java new file mode 100644 index 0000000000..265f250717 --- /dev/null +++ b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCHelper.java @@ -0,0 +1,215 @@ +/* + * 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.tuscany.sca.implementation.data.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; + +import org.apache.tuscany.das.rdb.exception.DataSourceInitializationException; +import org.apache.tuscany.sca.data.engine.config.ConnectionInfo; + +/** + * JDBC Helper + * - JDBC Connection utility methods + * - JDBC Resource cleanup methods + * + * @version $Rev$ $Date$ + */ +public class JDBCHelper { + + /** + * protected constructor + */ + protected JDBCHelper() { + + } + + /** + * + * @param connectionInfo + * @return + */ + public static Connection getConnection(ConnectionInfo connectionInfo) { + if (connectionInfo.getDataSource() == null && connectionInfo.getConnectionProperties() == null) { + throw new IllegalArgumentException("Not enough information to create Database Connection."); + } + + if(connectionInfo.getDataSource() != null && connectionInfo.getConnectionProperties() != null) { + throw new IllegalArgumentException("Use either dataSource or ConnectionProperties. Can't use both !"); + } + + if(connectionInfo.getDataSource() != null) { + return getDataSourceConnection(connectionInfo); + } else { + return getDriverManagerConnection(connectionInfo); + } + } + + /** + * Initializes a DB connection on a managed environment (e.g inside Tomcat) + * + * @param connectionInfo + * @return + */ + private static Connection getDataSourceConnection(ConnectionInfo connectionInfo) { + Connection connection = null; + + InitialContext ctx; + try { + ctx = new InitialContext(); + } catch (NamingException e) { + throw new RuntimeException(e); + } + try { + DataSource ds = (DataSource) ctx.lookup(connectionInfo.getDataSource()); + try { + connection = ds.getConnection(); + if (connection == null) { + throw new RuntimeException("Could not obtain a Connection from DataSource"); + } + connection.setAutoCommit(false); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } catch (NamingException e) { + throw new RuntimeException(e); + } + + return connection; + } + + /** + * Initialize a DB connection on a J2SE environment + * For more info, see http://java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/drivermanager.html + * + * @param connectionInfo + * @return + */ + private static Connection getDriverManagerConnection(ConnectionInfo connectionInfo) { + Connection connection = null; + + if (connectionInfo.getConnectionProperties() == null) { + throw new RuntimeException("No existing context and no connection properties"); + } + + if (connectionInfo.getConnectionProperties().getDriverClass() == null) { + throw new RuntimeException("No jdbc driver class specified!"); + } + + try { + Properties p = System.getProperties(); + p.put("derby.system.home", "target"); + + //initialize driver and register it with DriverManager + Class.forName(connectionInfo.getConnectionProperties().getDriverClass()); + + //prepare to initialize connection + String databaseUrl = connectionInfo.getConnectionProperties().getDatabaseURL(); + String userName = connectionInfo.getConnectionProperties().getUsername(); + String userPassword = connectionInfo.getConnectionProperties().getPassword(); + int loginTimeout = connectionInfo.getConnectionProperties().getLoginTimeout(); + + DriverManager.setLoginTimeout(loginTimeout); + if( (userName == null || userName.length() ==0) && (userPassword == null || userPassword.length()==0) ){ + //no username or password supplied + connection = DriverManager.getConnection(databaseUrl); + }else{ + connection = DriverManager.getConnection(databaseUrl, userName, userPassword); + } + + if(connection == null){ + throw new DataSourceInitializationException("Error initializing connection : null"); + } + + //FIXME we should make this flexible, we can't autocommit when participating in transactions + connection.setAutoCommit(true); + + }catch(ClassNotFoundException cnf){ + throw new DataSourceInitializationException("JDBC Driver '" + connectionInfo.getConnectionProperties().getDriverClass() + "' not found", cnf); + }catch(SQLException sqle){ + throw new DataSourceInitializationException(sqle.getMessage(), sqle); + } + + return connection; + } + + /** + * Cleanup and close all JDBC resources in the proper order and ignoring erros + * @param connection The connection to be closed + * @param queryStatement The statement to be closed + * @param resultSet The ResultSet to be closed + */ + public static void cleanupResources(Connection connection, PreparedStatement queryStatement, ResultSet resultSet) { + cleanupResultSet(resultSet); + cleanupPreparedStatement(queryStatement); + cleanupConnection(connection); + } + + /** + * Proper cleanup the ResultSet + * @param resultSet + */ + private static void cleanupResultSet(ResultSet resultSet) { + if (resultSet != null) { + try { + resultSet.close(); + } catch (SQLException e) { + // We should log the error. Since we're trying to close, we don't re-throw. + } + } + } + + /** + * Proper cleanup the prepared statement + * @param queryStatement + */ + private static void cleanupPreparedStatement(PreparedStatement queryStatement) { + if (queryStatement != null) { + try { + queryStatement.close(); + } catch (SQLException e) { + // We should log the error. Since we're trying to close, we don't re-throw. + } + } + } + + /** + * proper cleanup the connection + * @param connection + */ + private static void cleanupConnection(Connection connection) { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // We should log the error. Since we're trying to close, we don't re-throw. + } + } + } + +} diff --git a/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCResultSetStreamReader.java b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCResultSetStreamReader.java new file mode 100644 index 0000000000..316330243b --- /dev/null +++ b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/JDBCResultSetStreamReader.java @@ -0,0 +1,53 @@ +/* + * 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.tuscany.sca.implementation.data.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import javax.xml.stream.XMLStreamException; + +import org.apache.tuscany.sca.databinding.xml.XmlTreeStreamReaderImpl; + +/** + * JDBCResultSetStreamReader perform streaming of database tables as XML + * + * @version $Rev$ $Date$ + */ +public class JDBCResultSetStreamReader extends XmlTreeStreamReaderImpl { + private ResultSet resultSet; + + /** + * @param root + */ + public JDBCResultSetStreamReader(ResultSet resultSet) { + super(new ResultSetXmlNodeImpl(resultSet)); + this.resultSet = resultSet; + } + + @Override + public void close() throws XMLStreamException { + try { + resultSet.close(); + } catch (SQLException e) { + } + } +} + diff --git a/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/ResultSetXmlNodeImpl.java b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/ResultSetXmlNodeImpl.java new file mode 100644 index 0000000000..576fe5605d --- /dev/null +++ b/branches/sca-android/modules/implementation-data-xml/src/main/java/org/apache/tuscany/sca/implementation/data/jdbc/ResultSetXmlNodeImpl.java @@ -0,0 +1,251 @@ +/* + * 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.tuscany.sca.implementation.data.jdbc; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.databinding.xml.SimpleXmlNodeImpl; +import org.apache.tuscany.sca.databinding.xml.XmlNode; + +/** + * @version $Rev$ $Date$ + */ +public class ResultSetXmlNodeImpl implements XmlNode { + private static final String NS = ""; + private static final QName RESULT_SET = new QName(NS, "resultSet"); + private static final QName RECORD = new QName(NS, "record"); + private static final QName COLUMN = new QName(NS, "column"); + private static final QName NAME = new QName(NS, "name"); + + private ResultSet resultSet; + private String[] columnNames; + + /** + * @param resultSet + */ + public ResultSetXmlNodeImpl(ResultSet resultSet) { + super(); + this.resultSet = resultSet; + try { + ResultSetMetaData metaData = resultSet.getMetaData(); + columnNames = new String[metaData.getColumnCount()]; + for (int i = 0; i < columnNames.length; i++) { + columnNames[i] = metaData.getColumnName(i + 1); + } + } catch (SQLException e) { + throw new IllegalStateException(e); + } + } + + /** + * @see org.apache.tuscany.sca.databinding.xml.XmlNode#attributes() + */ + public List<XmlNode> attributes() { + return Collections.emptyList(); + } + + public Type getType() { + return Type.ELEMENT; + } + + + /** + * @see org.apache.tuscany.sca.databinding.xml.XmlNode#children() + */ + public Iterator<XmlNode> children() { + return new ResultSetIteraror(); + } + + private class ResultSetIteraror implements Iterator<XmlNode> { + private Boolean hasNext; + + public ResultSetIteraror() { + } + + public boolean hasNext() { + try { + if (hasNext == null) { + hasNext = resultSet.next(); + } + return hasNext; + } catch (SQLException e) { + throw new IllegalStateException(e); + } + } + + public XmlNode next() { + hasNext(); + hasNext = null; + return new RecordXmlNodeImpl(); + } + + public void remove() { + } + } + + /** + * @see org.apache.tuscany.sca.databinding.xml.XmlNode#getName() + */ + public QName getName() { + return RESULT_SET; + } + + /** + * @see org.apache.tuscany.sca.databinding.xml.XmlNode#getValue() + */ + public String getValue() { + return null; + } + + /** + * @see org.apache.tuscany.sca.databinding.xml.XmlNode#namespaces() + */ + public Map<String, String> namespaces() { + return Collections.emptyMap(); + } + + private class RecordXmlNodeImpl extends XmlNodeImpl { + int index = 0; + + @Override + public Iterator<XmlNode> children() { + return new Iterator<XmlNode>() { + + public boolean hasNext() { + return index < columnNames.length; + } + + public XmlNode next() { + return new ColumnXmlNodeImpl(index++); + } + + public void remove() { + } + + }; + } + + @Override + public QName getName() { + return RECORD; + } + + } + + private class ColumnXmlNodeImpl extends XmlNodeImpl { + private int index; + + /** + * @param index + */ + public ColumnXmlNodeImpl(int index) { + super(); + this.index = index; + } + + @Override + public List<XmlNode> attributes() { + XmlNode attr = new SimpleXmlNodeImpl(NAME, columnNames[index], XmlNode.Type.ATTRIBUTE); + return Arrays.asList(attr); + } + + @Override + public Iterator<XmlNode> children() { + XmlNode[] nodes = {new ValueXmlNodeImpl(index)}; + return Arrays.asList(nodes).iterator(); + } + + @Override + public QName getName() { + return COLUMN; + } + + } + + private class ValueXmlNodeImpl extends XmlNodeImpl { + private int index; + + /** + * @param index + */ + public ValueXmlNodeImpl(int index) { + super(); + this.index = index; + } + + @Override + public String getValue() { + try { + return String.valueOf(resultSet.getObject(index + 1)); + } catch (SQLException e) { + throw new IllegalStateException(e); + } + } + + @Override + public Type getType() { + return Type.CHARACTERS; + } + + } + + private static abstract class XmlNodeImpl implements XmlNode { + + public List<XmlNode> attributes() { + return Collections.emptyList(); + } + + public Iterator<XmlNode> children() { + return null; + } + + public QName getName() { + return null; + } + + public String getValue() { + return null; + } + + public boolean isLeaf() { + return false; + } + + public Map<String, String> namespaces() { + return Collections.emptyMap(); + } + + public Type getType() { + return Type.ELEMENT; + } + + } + + +} |