/*
* Copyright 2008 Fedora Commons, Inc.
*
* 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 org.mulgara.protocol.http;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.mulgara.connection.Connection;
import org.mulgara.connection.ConnectionException;
import org.mulgara.connection.ConnectionFactory;
import org.mulgara.connection.SessionConnection;
import org.mulgara.query.QueryException;
import org.mulgara.server.SessionFactory;
import org.mulgara.server.SessionFactoryProvider;
public abstract class MulgaraServlet extends HttpServlet {
/** Serialization ID. */
private static final long serialVersionUID = -8019499041312491482L;
/** The logger. */
final static Logger logger = Logger.getLogger(MulgaraServlet.class.getName());
/** Session value for database connection. */
static final String CONNECTION = "session.connection";
/** The name of the parameter for the host name. */
protected static final String HOST_NAME_PARAM = "mulgara.config.hostname";
/** The name of the parameter for the server name. */
protected static final String SERVER_NAME_PARAM = "mulgara.config.servername";
/** The default name to use for the host. */
protected static final String DEFAULT_HOSTNAME = "localhost";
/** The default name to use for the server. */
protected static final String DEFAULT_SERVERNAME = "server1";
/** The name of the servlet that will create a database instance, in a WAR file. */
protected static final String SERVLET_MULGARA_SERVER = "org.mulgara.server.ServletMulgaraServer";
/** The server for finding a session factory. */
protected SessionFactoryProvider server;
/** A URI for the server, to be used if no server is provided. */
private URI serverUri;
/** Session factory for accessing the database. */
protected SessionFactory cachedSessionFactory;
/** Factory for building and caching connections, based on URI. */
private ConnectionFactory connectionFactory;
public MulgaraServlet() {
server = null;
cachedSessionFactory = null;
connectionFactory = null;
serverUri = null;
}
public MulgaraServlet(SessionFactoryProvider server) {
this.server = server;
cachedSessionFactory = null;
connectionFactory = null;
serverUri = null;
}
/**
* This is irrelevant except when the server is not provided, for instance, when deployed
* in a Web ARchive (WAR) file.
* @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
*/
public void init(ServletConfig config) {
ServletContext context = config.getServletContext();
String host = context.getInitParameter(HOST_NAME_PARAM);
if (host == null) host = DEFAULT_HOSTNAME;
String servername = context.getInitParameter(SERVER_NAME_PARAM);
if (servername == null) servername = DEFAULT_SERVERNAME;
String uri = "rmi://" + host + "/" + servername;
try {
serverUri = new URI(uri);
} catch (URISyntaxException e) {
logger.error("Badly formed server URI: " + uri);
}
cachedSessionFactory = getServletDatabase();
}
/**
* Gets the connection for the current session, creating it if it doesn't exist yet.
* @param req The current request environment.
* @return A connection that is tied to this HTTP session.
* @throws IOException When an error occurs creating a new session.
*/
protected Connection getConnection(HttpServletRequest req) throws IOException, IllegalStateException {
HttpSession httpSession = req.getSession();
Connection connection = (Connection)httpSession.getAttribute(CONNECTION);
if (connection == null) {
try {
connection = getConnection();
} catch (QueryException qe) {
throw new IOException("Unable to create a connection to the database. " + qe.getMessage());
}
httpSession.setAttribute(CONNECTION, connection);
}
return connection;
}
/**
* Get an existing connection to the configured server, or else create a new one.
* @return A Connection to the required server.
* @throws QueryException If there was an error asking an internal server for a connection.
*/
private Connection getConnection() throws QueryException, IOException {
SessionFactory sessionFactory = getSessionFactory();
if (sessionFactory != null) {
return new SessionConnection(sessionFactory.newSession(), null, null, false);
} else {
try {
return getConnectionFactory().newConnection(serverUri);
} catch (ConnectionException e) {
throw new IOException("Unable to create a connection to the database identified by: " + serverUri + " (" + e.getMessage() + ")");
}
}
}
/**
* This method allows us to put off getting a session factory until the server is
* ready to provide one. The session factory will be a local database, or a database
* created by another servlet called ServletMulgaraServer.
* @return A new session factory, or <code>null</code> if one cannot be created.
*/
private SessionFactory getSessionFactory() throws IllegalStateException {
if (cachedSessionFactory == null) {
cachedSessionFactory = (server == null)
? getServletDatabase()
: server.getSessionFactory();
}
return cachedSessionFactory;
}
/**
* Use reflection to ask the ServletMulgaraServer for a reference to the Database.
* @return The database that was set up by the server-servlet.
*/
private SessionFactory getServletDatabase() {
try {
Class<?> dbServlet = Class.forName(SERVLET_MULGARA_SERVER);
return (SessionFactory)dbServlet.getMethod("getDatabase", (Class<?>[])null).invoke(null, (Object[])null);
} catch (ClassNotFoundException e) {
logger.error("Unable to find Database provider servlet", e);
} catch (SecurityException e) {
logger.error("Security Error while accessing Database provider servlet", e);
} catch (NoSuchMethodException e) {
logger.error("Missing functionality on Database provider servlet", e);
} catch (IllegalArgumentException e) {
logger.error("Bad method structure in Database provider servlet", e);
} catch (IllegalAccessException e) {
logger.error("Access Error while accessing Database provider servlet", e);
} catch (InvocationTargetException e) {
logger.error("Error encountered accessing Database provider servlet", e);
}
return null;
}
/**
* Gets the connection factory, creating it if it has not been initialized.
* @return A new or cached connection factory.
*/
private ConnectionFactory getConnectionFactory() {
if (connectionFactory == null) connectionFactory = new ConnectionFactory();
return connectionFactory;
}
}