| /* |
| * 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); |
| } |
| |
| } |