/*
* � Copyright IBM Corp. 2010, 2015
*
* Licensed 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 com.ibm.xsp.extlib.relational.component.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.binding.MethodBindingEx;
import com.ibm.xsp.extlib.relational.util.JdbcUtil;
import com.ibm.xsp.util.StateHolderUtil;
/**
* JDBC Connection Manager component.
*
* This component provide a connection that can be used by DataSources to execute
* multiple requests within the same transaction
*
* @author priand
*/
public class UIJdbcConnectionManager extends UIComponentBase implements IJdbcConnectionManager {
public static final String COMPONENT_FAMILY = "com.ibm.xsp.extlib.relational.jdbc.JdbcConnectionManager"; // $NON-NLS-1$
public static final String COMPONENT_TYPE = "com.ibm.xsp.extlib.relational.jdbc.JdbcConnectionManager"; // $NON-NLS-1$
public static final String RENDERER_TYPE = "com.ibm.xsp.extlib.relational.jdbc.JdbcConnectionManager"; // $NON-NLS-1$
private String connectionName;
private String connectionUrl;
private Boolean autoCommit;
private String transactionIsolation;
private MethodBinding initConnection;
public UIJdbcConnectionManager() {
super();
// Should not exists as it never render anything.
setRendererType(RENDERER_TYPE);
}
@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
public String getConnectionName() {
if (null != connectionName) {
return connectionName;
}
ValueBinding valueBinding = getValueBinding("connectionName"); // $NON-NLS-1$
if (valueBinding != null) {
String value = (String)valueBinding.getValue(getFacesContext());
return value;
}
return null;
}
public void setConnectionName(String connectionName) {
this.connectionName = connectionName;
}
public String getConnectionUrl() {
if (null != connectionUrl) {
return connectionUrl;
}
ValueBinding valueBinding = getValueBinding("connectionUrl"); // $NON-NLS-1$
if (valueBinding != null) {
String value = (String)valueBinding.getValue(getFacesContext());
return value;
}
return null;
}
public void setConnectionUrl(String connectionUrl) {
this.connectionUrl = connectionUrl;
}
public boolean isAutoCommit() {
if (null != this.autoCommit) {
return this.autoCommit;
}
ValueBinding _vb = getValueBinding("autoCommit"); //$NON-NLS-1$
if (_vb != null) {
Boolean val = (java.lang.Boolean) _vb.getValue(FacesContext.getCurrentInstance());
if(val!=null) {
return val;
}
}
return false;
}
public void setAutoCommit(boolean autoCommit) {
this.autoCommit = autoCommit;
}
public String getTransactionIsolation() {
if (null != transactionIsolation) {
return transactionIsolation;
}
ValueBinding valueBinding = getValueBinding("transactionIsolation"); // $NON-NLS-1$
if (valueBinding != null) {
String value = (String)valueBinding.getValue(getFacesContext());
return value;
}
return null;
}
public void setTransactionIsolation(String transactionIsolation) {
this.transactionIsolation = transactionIsolation;
}
public MethodBinding getInitConnection() {
return initConnection;
}
public void setInitConnection(MethodBinding initConnection) {
this.initConnection = initConnection;
}
@Override
public Object saveState(FacesContext context) {
if (isTransient()) {
return null;
}
Object[] state = new Object[6];
state[0] = super.saveState(context);
state[1] = connectionName;
state[2] = connectionUrl;
state[3] = autoCommit;
state[4] = transactionIsolation;
state[5] = StateHolderUtil.saveMethodBinding(context, initConnection);
return state;
}
@Override
public void restoreState(FacesContext context, Object state) {
Object[] values = (Object[])state;
super.restoreState(context, values[0]);
this.connectionName = (String)values[1];
this.connectionUrl = (String)values[2];
this.autoCommit = (Boolean)values[3];
this.transactionIsolation = (String)values[4];
this.initConnection = StateHolderUtil.restoreMethodBinding(context, this, values[5]);
}
// =================================================================
// JDBC Connection Management
// =================================================================
// Connection object being shared
// Not that it doesn't support to be in an iterator
private transient Connection connection;
// A new connection should be recreated when the page is rendered
// This ensures that the consumers have the fresher data
@Override
public void encodeBegin(FacesContext context) throws IOException {
super.encodeBegin(context);
this.connection = null;
}
@Override
public void _xspCleanTransientData() {
super._xspCleanTransientData();
// Ensure that the connection is not kept after the page is processed
this.connection = null;
}
protected Connection createConnection() throws SQLException {
FacesContext context = FacesContext.getCurrentInstance();
String url = getConnectionUrl();
if(StringUtil.isNotEmpty(url)) {
Connection c = JdbcUtil.createConnectionFromUrl(context, url);
initConnection(context,c);
return c;
}
String name = getConnectionName();
if(StringUtil.isNotEmpty(name)) {
Connection c = JdbcUtil.createNamedConnection(context, name);
initConnection(context,c);
return c;
}
throw new SQLException("No connection name nor URL is provided in the ConnectionManager"); // $NLX-UIJdbcConnectionManager.NoconnectionnamenorURLisprovidedi-1$
}
protected void initConnection(FacesContext context, Connection c) throws SQLException {
c.setAutoCommit(isAutoCommit());
String ti = getTransactionIsolation();
if(StringUtil.isNotEmpty(ti)) {
if(ti.equals("TRANSACTION_NONE")) { // $NON-NLS-1$
c.setTransactionIsolation(Connection.TRANSACTION_NONE);
} else if(ti.equals("TRANSACTION_READ_COMMITTED")) { // $NON-NLS-1$
c.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} else if(ti.equals("TRANSACTION_READ_UNCOMMITTED")) { // $NON-NLS-1$
c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
} else if(ti.equals("TRANSACTION_REPEATABLE_READ")) { // $NON-NLS-1$
c.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
} else if(ti.equals("TRANSACTION_SERIALIZABLE")) { // $NON-NLS-1$
c.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
} else {
throw new SQLException(StringUtil.format("Unknown transaction isolation {0}", ti)); // $NLX-UIJdbcConnectionManager.Unknowntransactionisolation0-1$
}
}
MethodBinding init = getInitConnection();
if(init!=null) {
Object[] params = null;
if(init instanceof MethodBindingEx){
params = new Object[] { c };
((MethodBindingEx)init).setComponent(this);
((MethodBindingEx)init).setParamNames(s_initParamNames);
}
init.invoke(context, params);
}
}
private static final String[] s_initParamNames = { "connection" }; // $NON-NLS-1$
/**
* Get a connection from the manager.
* @return
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
if(connection==null) {
connection = createConnection();
}
return connection;
}
/**
* Commit all the changes to the Connection.
* @throws SQLException
*/
public void commit() throws SQLException {
if(connection!=null) {
connection.commit();
}
}
/**
* Rollback all the changes from the Connection.
* @throws SQLException
*/
public void rollback() throws SQLException {
if(connection!=null) {
connection.rollback();
}
}
}