/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.server.rmi;
// Java 2 standard packages
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.mulgara.config.MulgaraConfig;
import org.mulgara.server.AbstractServer;
import org.mulgara.util.Rmi;
/**
* Java RMI server.
*
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
* @created 2002-01-12
* @copyright © 2002-2003 <A href="http://www.PIsoftware.com/">Plugged In Software Pty Ltd</A>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
* @see <a href="http://developer.java.sun.com/developer/JDCTechTips/2001/tt0327.html#jndi"/>
* <cite>JNDI lookup in distributed systems</cite> </a>
*/
public class RmiServer extends AbstractServer implements RmiServerMBean {
/** Logger. This is named after the classname. */
private final static Logger logger = Logger.getLogger(RmiServer.class.getName());
/** The name of the URL protocol handler package property. */
private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
// Initialize the system to know about RMI URLs
static {
String handler = System.getProperty(PROTOCOL_HANDLER);
String thisPackage = RmiServer.class.getPackage().getName();
assert thisPackage.endsWith(".rmi");
String parentPackage = thisPackage.substring(0, thisPackage.lastIndexOf('.'));
System.setProperty(PROTOCOL_HANDLER, (handler == null) ? parentPackage : handler + "|" + parentPackage);
}
/** The default port used for RMI. */
public static final int DEFAULT_PORT = 1099;
/** The Java RMI registry naming context. */
private Context rmiRegistryContext;
/** The RMI registry name of this server. */
private String name;
/**
* The local copy of the RMI session factory. This reference must be held
* because the garbage collector isn't aware of remote stubs on distant JVMs.
*/
private RemoteSessionFactory remoteSessionFactory;
/**
* An RMI stub that proxies for {@link #remoteSessionFactory}. This instance
* can be serialized and distributed to remote JVMs.
*/
private RemoteSessionFactory exportedRemoteSessionFactory;
/**
* Set the name the server is bound to in the RMI registry. It's possible to
* set <var>name</var> to <code>null</code>, but the
* {@link org.mulgara.server.ServerMBean#start} action can't be used in that
* case. The <var>name</var> cannot be set while the server is started.
* @param name the new value
* @throws IllegalStateException if the server is started or if the database already has a fixed URI
*/
public void setName(String name) {
// Prevent the name from being changed while the server is up
if (this.getState() == ServerState.STARTED) {
throw new IllegalStateException("Can't change name without first stopping the server");
}
// Set field
this.name = name;
updateURI();
}
/**
* Sets the hostname of the server.
*
* @param hostname the hostname of the server, if <code>null</code> <code>localhost</code> will be used
* @throws IllegalStateException if the service is started or if the underlying session factory already has a fixed hostname
*/
public void setHostname(String hostname) {
// Prevent the hostname from being changed while the server is up
if (this.getState() == ServerState.STARTED) {
throw new IllegalStateException("Can't change hostname without first stopping the server");
}
// Reset the field
if (hostname == null) {
this.hostname = "localhost";
logger.warn("Hostname supplied is null, defaulting to localhost");
} else {
this.hostname = hostname;
}
updateURI();
}
/**
* Sets the server port.
* @param newPortNumber The new port to bind to.
*/
public void setPortNumber(int newPortNumber) {
super.setPortNumber(newPortNumber);
updateURI();
}
//
// MBean properties
//
/**
* Read the name the server is bound to in the RMI registry.
* @return The bound name of the server.
*/
public String getName() {
return name;
}
//
// Methods implementing AbstractServer
//
/* (non-Javadoc)
* @see org.mulgara.server.AbstractServer#setConfig(org.mulgara.config.MulgaraConfig)
*/
@Override
public void setConfig(MulgaraConfig config) {
super.setConfig(config);
Rmi.configure(config);
}
/**
* Start the server.
* @throws IllegalStateException if <var>name</var> is <code>null</code>
* @throws NamingException Error accessing RMI registry.
* @throws RemoteException Error accessing RMI services.
*/
protected void startService() throws NamingException, RemoteException {
// Validate "name" property
if (name == null) throw new IllegalStateException("Must set \"name\" property");
// Initialize fields
rmiRegistryContext = new InitialContext();
remoteSessionFactory = new RemoteSessionFactoryImpl(getSessionFactory(), Rmi.getDefaultInterrupt());
exportedRemoteSessionFactory = (RemoteSessionFactory)Rmi.export(remoteSessionFactory);
// Bind the service to the RMI registry
rmiRegistryContext.rebind(name, exportedRemoteSessionFactory);
}
/**
* Stop the server.
* @throws NamingException Error accessing the registry.
* @throws NoSuchObjectException The current server is not registered in the registry.
*/
protected void stopService() throws NamingException, NoSuchObjectException {
try {
rmiRegistryContext.unbind(name);
Rmi.unexportObject(remoteSessionFactory, true);
} catch (Exception e) {
if (e.getCause() instanceof javax.naming.ServiceUnavailableException) {
logger.warn("RMI Server no longer available to be stopped. Abandoning.");
} else {
logger.warn("Unabled to deregister the RMI service. Abandoning.");
}
}
}
/**
* Creates a new URI for the current hostname/servicename/port and sets this service
* to register with that name.
* @throws Error if the hostname or service name cannot be encoded in a URI.
*/
private void updateURI() {
URI newURI = null;
if (hostname == null) {
// try to use the local host name
try {
hostname = InetAddress.getLocalHost().getCanonicalHostName();
} catch (UnknownHostException e) {
logger.warn("Problem getting host name! - using \"localhost\"");
hostname = "localhost";
}
}
// Generate new server URI
try {
String path = "/" + (name == null ? "" : name);
int portNr = getPortNumber();
if (portNr == DEFAULT_PORT || portNr == -1) {
newURI = new URI("rmi://" + hostname + path);
} else {
newURI = new URI("rmi://" + hostname + ":" + portNr + path);
}
} catch (URISyntaxException e) {
throw new Error("Bad generated URI", e);
}
// Set URI.
setURI(newURI);
}
/** @see org.mulgara.server.AbstractServer#getDefaultPort() */
protected int getDefaultPort() {
return DEFAULT_PORT;
}
}