/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.piazza.commons.ejb;
import java.net.InetAddress;
import java.util.Hashtable;
import javax.naming.InitialContext;
/**
* An EjbConnection represents a connection to the initial context by which the
* specified EJBHome can be looked up.
*
* The URL connection string for an EJBConnection should comply the following
* format: PROVIDER_URL@INITIAL_CONTEXT_FACTORY {@SECURITY_PROTOCOL}
*
* @author Hugo Y. K. Lam
*/
public class EjbConnection {
private boolean connected, closed;
private String url;
private String username;
private String password;
private InitialContext initialContext;
private String host;
/**
* Creates a new instance of EjbConnection.
*/
public EjbConnection(String url, String username, String password) {
super();
this.url = url;
this.username = username;
this.password = password;
}
/**
* Gets the URL of this connection.
*
* @return the URL of this connection.
*/
public String getUrl() {
return url;
}
/**
* Gets the username used for this connection.
*
* @return the username used in this connection.
*/
public String getUsername() {
return username;
}
/**
* Returns a string representation of this object, which is the URL.
*
* @see java.lang.Object#toString()
*/
public String toString() {
return getUrl(); //+", username: "+username+", password: "+password;
}
/**
* Connects to the destination URL using the username and password stored in
* this connection.
*
* @throws EjbConnectionException if errors occurred during the
* establishment of connection.
*/
public synchronized void connect() throws EjbConnectionException {
connect(username, password);
}
/**
* Connects to the destination URL using the specified username and
* password.
*
* @param username the username used to connect. null if authentication is
* not required.
* @param password the password used to connect. null if authentication is
* not required.
* @throws EjbConnectionException if errors occurred during the
* establishment of connection or, the connection has been
* connected or closed already.
*/
public synchronized void connect(String username, String password)
throws EjbConnectionException {
if (!connected && !closed) {
try {
String[] connStrings = getConnectionStrings();
Hashtable props = new Hashtable();
props.put(InitialContext.PROVIDER_URL, connStrings[0]);
props.put(InitialContext.INITIAL_CONTEXT_FACTORY,
connStrings[1]);
// This establishes the security for
// authorization/authentication
if (username != null && !"".equals(username)) {
props.put(InitialContext.SECURITY_PRINCIPAL, username);
props.put(InitialContext.SECURITY_CREDENTIALS,
password == null ? "" : password);
if (connStrings.length > 2) {
props.put(InitialContext.SECURITY_PROTOCOL,
connStrings[2]);
}
}
InetAddress localhost = InetAddress.getLocalHost();
host = localhost.getHostName() + "@"
+ localhost.getHostAddress();
InitialContext context = new InitialContext(props);
context.rebind(host, "connected");
initialContext = context;
connected = true;
closed = false;
}
catch (Exception e) {
throw new EjbConnectionException(
"Unable to establish connection.", e);
}
}
else {
throw new EjbConnectionException(
"Connection has been connected or closed already.");
}
}
/**
* Closes this connection and releases any resources associated.
*
* @throws EjbConnectionException if errors occurred during closing the
* connection or, the connection has not yet been connected or
* has been closed already.
*/
public synchronized void close() throws EjbConnectionException {
if (connected && !closed) {
try {
initialContext.unbind(host);
initialContext.close();
connected = false;
closed = true;
}
catch (Exception e) {
throw new EjbConnectionException("Unable to close connection.",
e);
}
}
else {
throw new EjbConnectionException(
"Connection has not yet been connected or has been closed already.");
}
}
/**
* Closes this connection in finalization.
*
* @see java.lang.Object#finalize()
*/
protected void finalize() throws Throwable {
super.finalize();
if (!closed) {
close();
}
}
/**
* Parses the URL connection string.
*
* @return an array of String which contains the PROVIDER_URL,
* INITIAL_CONTEXT_FACTORY, and, if any, the SECURITY_PROTOCOL.
* @throws EjbConnectionException if the URL has less than two connection
* tokens.
*/
private String[] getConnectionStrings() throws EjbConnectionException {
String[] connStrings = url == null ? null : url.split("@");
if (connStrings == null || connStrings.length < 2) {
throw new EjbConnectionException("Invalid URL: " + url);
}
else {
return connStrings;
}
}
/**
* Retrieves the EJBHome by looking it up using the specified JNDI name. The
* EJBHome will be narrowed to the specified class if it is a remote
* interface.
*
* @param jndiName the JNDI name for the EJBHome to be looked up.
* @param narrowTo the class to which the EJBHome should be narrowed.
* @return the EJBHome bound to the specified JNDI name.
* @throws EjbConnectionException if there is a naming or narrowing error.
* @throws NullPointerException if <code>narrowTo<code> is null.
*/
public Object lookupHome(String jndiName, Class narrowTo)
throws EjbConnectionException {
try {
Object objRef = initialContext.lookup(jndiName);
// only narrow if necessary
if (narrowTo.isInstance(java.rmi.Remote.class)) {
return javax.rmi.PortableRemoteObject.narrow(objRef, narrowTo);
}
else {
return objRef;
}
}
catch (Exception e) {
throw new EjbConnectionException(
"Unable to lookup the home interface for jndi name: "
+ jndiName, e);
}
}
}