blob: 2c8497a0f18df5351bfe61a6b9a86dc167d11103 [file] [log] [blame]
/*
* 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.das.rdb.impl;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.tuscany.das.rdb.Command;
import org.apache.tuscany.das.rdb.DAS;
import org.apache.tuscany.das.rdb.config.Config;
import org.apache.tuscany.das.rdb.config.ConfigFactory;
import org.apache.tuscany.das.rdb.config.ConnectionInfo;
import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper;
import org.apache.tuscany.das.rdb.exception.DataSourceInitializationException;
import org.apache.tuscany.das.rdb.util.ConfigUtil;
import commonj.sdo.DataObject;
/**
* An ConfiguredCommandFactory produces instances of Command and ApplyChangesCommand. This
* factory is initialized with a configuration that defines
* the commands it produces.
*
*/
public class DASImpl implements DAS {
private static final String KIND_SELECT = "select";
private static final String KIND_UPDATE = "update";
private static final String KIND_INSERT = "insert";
private static final String KIND_DELETE = "delete";
private static final String KIND_PROCEDURE = "procedure";
private MappingWrapper configWrapper;
private Connection connection;
private Map commands = new HashMap();
public DASImpl(InputStream stream) {
this(ConfigUtil.loadConfig(stream));
}
public DASImpl(Config inConfig) {
Config cfg = inConfig;
if (cfg == null) {
cfg = ConfigFactory.INSTANCE.createConfig();
}
this.configWrapper = new MappingWrapper(cfg);
Iterator i = configWrapper.getConfig().getCommand().iterator();
while (i.hasNext()) {
org.apache.tuscany.das.rdb.config.Command commandConfig =
(org.apache.tuscany.das.rdb.config.Command) i.next();
String kind = commandConfig.getKind();
if (kind.equalsIgnoreCase(KIND_SELECT)) {
commands.put(commandConfig.getName(), new ReadCommandImpl(commandConfig, configWrapper, commandConfig.getResultDescriptor()));
} else if (kind.equalsIgnoreCase(KIND_UPDATE)) {
commands.put(commandConfig.getName(), new UpdateCommandImpl(commandConfig));
} else if (kind.equalsIgnoreCase(KIND_INSERT)) {
commands.put(commandConfig.getName(), new InsertCommandImpl(commandConfig, new String[0]));
} else if (kind.equalsIgnoreCase(KIND_DELETE)) {
commands.put(commandConfig.getName(), new DeleteCommandImpl(commandConfig));
} else if (kind.equalsIgnoreCase(KIND_PROCEDURE)) {
commands.put(commandConfig.getName(), new SPCommandImpl(commandConfig.getSQL(), configWrapper, commandConfig.getParameter()));
} else {
throw new RuntimeException("Invalid kind of command: " + kind);
}
}
}
public DASImpl(Config inConfig, Connection inConnection) {
this(inConfig);
setConnection(inConnection);
}
public DASImpl(InputStream configStream, Connection inConnection) {
this(ConfigUtil.loadConfig(configStream), inConnection);
}
public DASImpl(Connection inConnection) {
this(ConfigFactory.INSTANCE.createConfig());
setConnection(inConnection);
}
/*
* (non-Javadoc)
*
* @see org.apache.tuscany.das.rdb.CommandGroup#getApplyChangesCommand()
*/
public ApplyChangesCommandImpl getApplyChangesCommand() {
ApplyChangesCommandImpl cmd = new ApplyChangesCommandImpl(configWrapper, getConnection());
return cmd;
}
/*
* (non-Javadoc)
*
* @see org.apache.tuscany.das.rdb.CommandGroup#getCommand(java.lang.String)
*/
public Command getCommand(String name) {
if (!commands.containsKey(name)) {
throw new RuntimeException("CommandGroup has no command named: " + name);
}
CommandImpl cmd = (CommandImpl) commands.get(name);
cmd.setConnection(getConnection(), configWrapper.getConfig());
return cmd;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
public Connection getConnection() {
if (connection == null) {
initializeConnection();
}
return connection;
}
private void initializeConnection() {
Config config = configWrapper.getConfig();
if (config == null || config.getConnectionInfo() == null ||
(config.getConnectionInfo().getDataSource() == null &&
(config.getConnectionInfo().getConnectionProperties() == null || config.getConnectionInfo().getConnectionProperties().getDatabaseURL() == null
|| config.getConnectionInfo().getConnectionProperties().getDriverClass() == null)) ) {
throw new RuntimeException("No connection has been provided and no data source has been specified");
}
if(config.getConnectionInfo().getDataSource() != null &&
(config.getConnectionInfo().getConnectionProperties() != null && config.getConnectionInfo().getConnectionProperties().getDatabaseURL() != null) ){
throw new RuntimeException("Use either dataSource or databaseURL. Can't use both !");
}
ConnectionInfo connectionInfo = configWrapper.getConfig().getConnectionInfo();
if(config.getConnectionInfo().getDataSource() != null){
initializeDatasourceConnection(connectionInfo);
}else{
initializeDriverManagerConnection(connectionInfo);
}
}
/**
* Initializes a DB connection on a managed environmet (e.g inside Tomcat)
*/
private void initializeDatasourceConnection(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 {
try {
if(connectionInfo.getConnectionProperties() != null &&
connectionInfo.getConnectionProperties().getUserName() != null &&
connectionInfo.getConnectionProperties().getPassword() != null ) {
connection = ds.getConnection(connectionInfo.getConnectionProperties().getUserName(), connectionInfo.getConnectionProperties().getPassword());
} else {
connection = ds.getConnection();
}
}catch(Exception e) {
connection = ds.getConnection();
}
if (connection == null) {
throw new RuntimeException("Could not obtain a Connection from DataSource");
}
connection.setAutoCommit(false);
setConnection(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} catch (NamingException e) {
throw new RuntimeException(e);
}
}
/**
* 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
*/
private void initializeDriverManagerConnection(ConnectionInfo connectionInfo) {
Connection connection = null;
if (connectionInfo.getConnectionProperties() == null) {
throw new DataSourceInitializationException("No existing context and no connection properties");
}
if (connectionInfo.getConnectionProperties().getDriverClass() == null) {
throw new DataSourceInitializationException("No jdbc driver class specified!");
}
try {
//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 suplied
connection = DriverManager.getConnection(databaseUrl);
}else{
connection = DriverManager.getConnection(databaseUrl, userName, userPassword);
}
if(connection == null){
throw new DataSourceInitializationException("Error initializing connection : null");
}
connection.setAutoCommit(false);
setConnection(connection);
}catch(ClassNotFoundException cnf){
throw new DataSourceInitializationException("JDBC Driver '" + connectionInfo.getConnectionProperties().getDriverClass() + "' not found", cnf);
}catch(SQLException sqle){
throw new DataSourceInitializationException(sqle.getMessage(), sqle);
}
}
public void releaseResources() {
if (managingConnections()) {
closeConnection();
}
}
private void closeConnection() {
if (connection != null) {
try {
connection.close();
connection = null;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
/**
* If the config has connection properties then we are "managing" the connection via DataSource
*/
private boolean managingConnections() {
if (configWrapper.getConfig().getConnectionInfo().getDataSource() == null) {
return false;
}
return true;
}
public Command createCommand(String sql) {
return baseCreateCommand(sql, null, this.configWrapper);
}
public Command createCommand(String sql, String kind) {
return baseCreateCommand(sql, kind, this.configWrapper);
}
public Command createCommand(String sql, Config config) {
return baseCreateCommand(sql, null, new MappingWrapper(config));
}
public Command createCommand(String sql, String kind, Config config) {
return baseCreateCommand(sql, kind, new MappingWrapper(config));
}
private Command baseCreateCommand(String inSql, String kind, MappingWrapper config) {
CommandImpl returnCmd = null;
String sql = inSql.trim(); // Remove leading white space
if (kind == null || kind.trim().length() == 0) kind = getKind(sql);
if (kind.equalsIgnoreCase(KIND_SELECT)) {
returnCmd = new ReadCommandImpl(sql, config, null);
} else if (kind.equalsIgnoreCase(KIND_INSERT)) {
returnCmd = new InsertCommandImpl(sql, new String[0]);
} else if (kind.equalsIgnoreCase(KIND_UPDATE)) {
returnCmd = new UpdateCommandImpl(sql);
} else if (kind.equalsIgnoreCase(KIND_DELETE)) {
returnCmd = new DeleteCommandImpl(sql);
} else if (kind.equalsIgnoreCase(KIND_PROCEDURE)) {
returnCmd = new SPCommandImpl(sql, config, Collections.EMPTY_LIST);
} else {
throw new RuntimeException("Invalid kind of command: " + kind);
}
returnCmd.setConnection(getConnection(), config.getConfig());
return returnCmd;
}
private String getKind(String sql) {
char firstChar = Character.toUpperCase(sql.charAt(0));
switch (firstChar) {
case 'S':
return KIND_SELECT;
case 'I':
return KIND_INSERT;
case 'U':
return KIND_UPDATE;
case 'D':
return KIND_DELETE;
case '{':
return KIND_PROCEDURE;
default:
throw new RuntimeException("SQL => " + sql + " does not match any command kind, pass command kind (select, insert, update, delete, procedure) explicitly");
}
}
public void applyChanges(DataObject root) {
getApplyChangesCommand().execute(root);
}
}