/* * 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.util; import hk.hku.cecid.piazza.commons.Sys; import hk.hku.cecid.piazza.commons.ejb.EjbConnection; import hk.hku.cecid.piazza.commons.ejb.EjbConnectionFactory; import hk.hku.cecid.piazza.commons.util.ArrayUtilities; import hk.hku.cecid.piazza.commons.util.Instance; import hk.hku.cecid.piazza.commons.util.InstanceException; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.UnknownHostException; import java.rmi.RemoteException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; /** * RemoteCommandHandler is a handler class for invoking the RemoteCommand bean. It * invokes the bean by using the command name and parameters specified by the * caller. The given command must be registered beforehand on both side with a * set of command properties in Java properties format: * <p> * <table border=1> * <tr> * <th>Key</th> * <th>Value</th> * </tr> * <tr> * <td>url</td> * <td>The connection URL (see EjbConnection)</td> * </tr> * <tr> * <td>username</td> * <td>The username for the connection</td> * </tr> * <tr> * <td>password</td> * <td>The password for the connection</td> * </tr> * <tr> * <td>class</td> * <td>The class name/object to be excuted</td> * </tr> * <tr> * <td>method</td> * <td>The method of the class to be excuted</td> * </tr> * <tr> * <td>parameters</td> * <td>The parameter types, separated by comma, of the method to be excuted</td> * </tr> * </table> * <p> * If it fails to invoke the bean, it will invoke the target class locally. * * @author Hugo Y. K. Lam * * @see RemoteCommandBean * @see EjbConnection */ public final class RemoteCommandHandler { private static Hashtable commands = new Hashtable(); /** * Creates a new instance of RemoteCommandHandler. */ private RemoteCommandHandler() { super(); } /** * Register a command to this handler. * * @param cmdName the command name. * @param command the command properties. */ public static void register(String cmdName, Properties command) { if (cmdName != null) { if (command == null) { unregister(cmdName); } else { commands.put(cmdName, command); } } } /** * Unregister a command from this handler. * * @param cmdName the command name. */ public static void unregister(String cmdName) { if (cmdName != null) { commands.remove(cmdName); } } /** * Gets the names of the regsitered commands. * * @return the names of the regsitered commands. */ public static Enumeration getCommandNames() { return commands.keys(); } /** * Gets the command properties by its name. * * @param name the command name. * @return the command properties. * @throws NullPointerException if the command is not registered. */ public static Properties getCommand(String name) { Properties command = name == null? null : (Properties) commands.get(name); if (command == null) { throw new NullPointerException("Non-registered command: " + name); } else return command; } /** * Executes a registered command with the given parameters. * * @param cmdName the command name. * @param parameters parameters for the target method invocation. * @return the object returned by the invoked method. * @throws RemoteException if there is a remote exception occurred. * @throws InstanceException if the instance of the target class cannot be * created or the method could not be invoked. * @throws InvocationTargetException if the invoked method has thrown an * exception. * @throws NullPointerException if the command is not registered. */ public static Object execute(String cmdName, Object[] parameters) throws RemoteException, InstanceException, InvocationTargetException { Properties command = getCommand(cmdName); boolean useLocalClass = false; String url = command.getProperty("url"); String username = command.getProperty("username"); String password = command.getProperty("password"); if (url == null || "".equals((url = url.trim()))) { useLocalClass = true; } else { try { InetAddress addr = InetAddress.getByName(url); useLocalClass = addr.isLoopbackAddress(); } catch (UnknownHostException e) { useLocalClass = false; } } if (!useLocalClass) { RemoteCommand runner = null; try { EjbConnection conn = EjbConnectionFactory.createConnection(url); conn.connect(username, password); RemoteCommandHome home = (RemoteCommandHome) conn.lookupHome( "java:comp/env/ejb/RemoteCommand", RemoteCommandHome.class); runner = home.create(); } catch (Throwable e) { Sys.main.log.error("Unable to create remote RemoteCommand. Local instance will be invoked.", e); useLocalClass = true; } if (!useLocalClass) { Sys.main.log.debug("Using remote instance for command: "+cmdName); return runner.execute(cmdName, parameters); } } Sys.main.log.debug("Using local instance for command: "+cmdName); return executeLocal(cmdName, parameters); } /** * Executes a registered command locally with the given parameters. * * @param cmdName the command name. * @param parameters parameters for the target method invocation. * @return the object returned by the invoked method. * @throws InstanceException if the instance of the target class cannot be * created or the method could not be invoked. * @throws InvocationTargetException if the invoked method has thrown an * exception. * @throws NullPointerException if the command is not registered. */ static Object executeLocal(String cmdName, Object[] parameters) throws InstanceException, InvocationTargetException { Properties command = getCommand(cmdName); Object clazz = command.get("class"); String methodName = command.getProperty("method"); String[] parameterTypeNames = ArrayUtilities.toArray(command .getProperty("parameters"), ", "); return new Instance(clazz).invoke(methodName, parameterTypeNames, parameters); } }