Java tutorial
/* * Copyright (C) 2008 Yohan Liyanage. * * 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.nebulaframework.grid; import java.io.Serializable; import java.util.Map; import java.util.Properties; import javax.jms.Connection; import javax.swing.JOptionPane; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nebulaframework.configuration.ConfigurationKeys; import org.nebulaframework.configuration.ConfigurationSupport; import org.nebulaframework.core.job.GridJob; import org.nebulaframework.core.job.ResultCallback; import org.nebulaframework.core.job.archive.GridArchive; import org.nebulaframework.core.job.exceptions.GridJobRejectionException; import org.nebulaframework.core.job.future.GridJobFuture; import org.nebulaframework.discovery.ClusterDiscoverySupport; import org.nebulaframework.discovery.DiscoveryFailureException; import org.nebulaframework.discovery.GridNodeDiscoverySupport; import org.nebulaframework.grid.cluster.manager.ClusterManager; import org.nebulaframework.grid.cluster.node.GridNode; import org.nebulaframework.grid.cluster.node.services.job.execution.TaskExecutor; import org.nebulaframework.grid.cluster.node.services.job.submission.JobSubmissionService; import org.nebulaframework.grid.service.event.ServiceEventsSupport; import org.nebulaframework.grid.service.event.ServiceHookCallback; import org.nebulaframework.grid.service.message.ServiceMessage; import org.nebulaframework.grid.service.message.ServiceMessageType; import org.nebulaframework.ui.swing.UISupport; import org.nebulaframework.util.spring.NebulaApplicationContext; import org.springframework.util.StopWatch; /** * The general access point to Nebula Grid. Allows to configure * and start {@link ClusterManager} and {@link GridNode} instances. * <p> * This class implements the JobSubmissionService to allow easy access * to grid job submission operations. Note that the Job submission methods * delegate to the actual {@link JobSubmissionService} implementation. * These methods are only available when the Grid has an active Grid Node. * * @author Yohan Liyanage * @version 1.0 */ public class Grid implements JobSubmissionService { /** * Nebula Version. */ public static final String VERSION = "1.0 RC 1"; /** Cluster Configuration Properties File */ public static final String CLUSTER_PROPERTY_CONFIGURATION = "conf/nebula-cluster.properties"; /** Cluster XML Properties File */ public static final String CLUSTER_XML_CONFIGURATION = "conf/nebula-cluster.xml"; /** Grid Node Configuration Properties File */ public static final String GRIDNODE_PROPERTY_CONFIGURATION = "conf/nebula-client.properties"; /** Grid Node XML Properties File */ public static final String GRIDNODE_XML_CONFIGURATION = "conf/nebula-client.xml"; /** Cluster Spring Beans Configuration File */ public static final String CLUSTER_SPRING_CONTEXT = "org/nebulaframework/grid/cluster/manager/cluster-manager.xml"; /** Grid Node Spring Beans Configuration File */ public static final String GRIDNODE_CONTEXT = "org/nebulaframework/grid/cluster/node/grid-node.xml"; /** Light Weight (Non-worker) Grid Node Spring Beans Configuration File */ public static final String GRIDNODE_LIGHT_CONTEXT = "org/nebulaframework/grid/cluster/node/grid-nonworker-node.xml"; private static Log log = LogFactory.getLog(Grid.class); private static NebulaApplicationContext applicationContext = null; private static boolean clusterManager = false; private static boolean node = false; private static boolean lightweight = false; /** * No instantiation */ private Grid() { // No instantiation } /** * Starts {@link ClusterManager} instance with default settings, * read from default properties file. * * @return ClusterManager * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static ClusterManager startClusterManager() throws IllegalStateException { if (isInitialized()) { // A Grid Member has already started in this VM throw new IllegalStateException("A Grid Memeber Already Started in VM"); } initializeDefaultExceptionHandler(); StopWatch sw = new StopWatch(); try { sw.start(); log.info("ClusterManager Starting..."); // Set Security Manager System.setSecurityManager(new SecurityManager()); // Detect Configuration Properties config = ConfigurationSupport.detectClusterConfiguration(); // Register with any Colombus Servers ClusterDiscoverySupport.registerColombus(config); clusterManager = true; log.debug("Starting up Spring Container..."); applicationContext = new NebulaApplicationContext(CLUSTER_SPRING_CONTEXT, config); log.debug("Spring Container Started"); return (ClusterManager) applicationContext.getBean("clusterManager"); } finally { sw.stop(); log.info("ClusterManager Started Up. " + sw.getLastTaskTimeMillis() + " ms"); } } private static void initializeDefaultExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { log.fatal("[Uncaught Thread Exception] on Thread " + t.getName() + " - " + e, e); e.printStackTrace(); } }); } /** * Starts a {@link GridNode} with default settings, read from * default properties file. This version invokes the {@link #startGridNode(boolean)} * with value true. * * @return GridNode * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static GridNode startGridNode() throws IllegalStateException { return startGridNode(true); } /** * Starts a {@link GridNode} with default settings, read from * default properties file. * * @param useConfigDiscovery indicates whether to use information * from configuration to discover * * @return GridNode * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static GridNode startGridNode(boolean useConfigDiscovery) throws IllegalStateException { if (isInitialized()) { // A Grid Member has already started in this VM throw new IllegalStateException("A Grid Memeber Already Started in VM"); } initializeDefaultExceptionHandler(); StopWatch sw = new StopWatch(); try { sw.start(); // Set Security Manager System.setSecurityManager(new SecurityManager()); // Detect Configuration Properties config = ConfigurationSupport.detectNodeConfiguration(); log.info("GridNode Attempting Discovery..."); // Discover Cluster If Needed GridNodeDiscoverySupport.discover(config, useConfigDiscovery); checkJMSBroker(config.getProperty(ConfigurationKeys.CLUSTER_SERVICE.value())); log.debug("Starting up Spring Container..."); applicationContext = new NebulaApplicationContext(GRIDNODE_CONTEXT, config); log.debug("Spring Container Started"); node = true; sw.stop(); log.info("GridNode Started Up. " + sw.getLastTaskTimeMillis() + " ms"); return (GridNode) applicationContext.getBean("localNode"); } finally { if (sw.isRunning()) { sw.stop(); } } } /** * Starts a Light-weight {@link GridNode} (a GridNode without * Job Execution Support, that is non-worker) with default * settings, read from default properties file. * * This version invokes the {@link #startLightGridNode(boolean)} * with value true. * * @return GridNode * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static GridNode startLightGridNode() throws IllegalStateException { return startLightGridNode(true, false); } /** * Starts a Light-weight {@link GridNode} (a GridNode without * Job Execution Support, that is non-worker) with default * settings, read from default properties file. * * @param useConfigDiscovery indicates whether to use information * from configuration to discover * * @return GridNode * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static GridNode startLightGridNode(boolean useConfigDiscovery) throws IllegalStateException { return startLightGridNode(useConfigDiscovery, false); } /** * Starts a Light-weight {@link GridNode} (a GridNode without * Job Execution Support, that is non-worker) with default * settings, read from default properties file. * * @param useConfigDiscovery indicates whether to use information * from configuration to discover * * @param isGui indicates that the application is a GUI based * application and any disconnection notifications should be * done through message boxes. * * @return GridNode * * @throws IllegalStateException if a Grid Member (Cluster / Node) has * already started with in the current VM. Nebula supports only one Grid * Member per VM. */ public synchronized static GridNode startLightGridNode(boolean useConfigDiscovery, final boolean isGui) throws IllegalStateException { if (isInitialized()) { // A Grid Member has already started in this VM throw new IllegalStateException("A Grid Memeber Already Started in VM"); } initializeDefaultExceptionHandler(); StopWatch sw = new StopWatch(); try { sw.start(); // Set Security Manager System.setSecurityManager(new SecurityManager()); Properties config = ConfigurationSupport.detectNodeConfiguration(); log.info("GridNode Attempting Discovery..."); // Discover Cluster If Needed GridNodeDiscoverySupport.discover(config, useConfigDiscovery); checkJMSBroker(config.getProperty(ConfigurationKeys.CLUSTER_SERVICE.value())); // If we reach here, connection test succeeded log.debug("Starting up Spring Container..."); applicationContext = new NebulaApplicationContext(GRIDNODE_LIGHT_CONTEXT, config); log.debug("Spring Container Started"); node = true; lightweight = true; sw.stop(); log.info("GridNode Started Up. " + sw.getLastTaskTimeMillis() + " ms"); GridNode node = (GridNode) applicationContext.getBean("localNode"); ServiceEventsSupport.addServiceHook(new ServiceHookCallback() { @Override public void onServiceEvent(ServiceMessage message) { log.warn("[GridNode] Disconnected from Cluster"); log.warn("[GridNode] Shutting Down"); if (isGui) { JOptionPane.showMessageDialog(UISupport.activeWindow(), "Disconnected from Cluster, terminating VM"); } System.exit(0); } }, node.getClusterId().toString(), ServiceMessageType.NODE_DISCONNECTED); return node; } finally { if (sw.isRunning()) { sw.stop(); } } } /** * Checks the given Service URL to see if the * Broker is running. * * @param url connection url */ private static void checkJMSBroker(String url) { try { log.debug("Attempting to establish connection with Cluster " + url); ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(url); Connection testConnection = cf.createConnection(); testConnection.start(); testConnection.close(); log.debug("Connection established"); } catch (Exception e) { log.warn("Unable to establish cluster connection"); throw new DiscoveryFailureException("Unable to connect to Cluster", e); } } /** * Returns the {@link NebulaApplicationContext} for this * Grid Member, if available. * * @return NebulaApplicationContext * * @throws IllegalStateException if not initialized (started) */ public static NebulaApplicationContext getApplicationContext() throws IllegalStateException { if (applicationContext == null) throw new IllegalStateException("Not Initialized"); return applicationContext; } /** * Returns true if the current node is * a {@code ClusterManager}. * * @return true if the current node is * a {@code ClusterManager}. */ public static boolean isClusterManager() { return clusterManager; } /** * Returns true if the current node is * a {@code GridNode}. * * @return true if the current node is * a {@code GridNode}. */ public static boolean isNode() { return node; } /** * Returns true if the current node is * a lightweight (no {@link TaskExecutor}} {@code GridNode}. * * @return true if the current node is lightweight */ public static boolean isLightweight() { return lightweight; } /** * Returns true if this Grid has been initialized before. * * @return true if this Grid has been initialized. */ protected static boolean isInitialized() { return applicationContext != null; } /** * Invoked by GridNodes to notify that the GridNode has * disconnected from Cluster. */ public static void nodeDisconnected() { applicationContext = null; node = false; lightweight = false; } /** * {@inheritDoc} */ @Override public Map<String, GridJobFuture> submitArchive(GridArchive archive) throws IllegalStateException, GridJobRejectionException { return GridNode.getInstance().getJobSubmissionService().submitArchive(archive); } /** * {@inheritDoc} */ @Override public Map<String, GridJobFuture> submitArchive(GridArchive archive, Map<String, ResultCallback> callbacks) throws IllegalStateException, GridJobRejectionException { return GridNode.getInstance().getJobSubmissionService().submitArchive(archive, callbacks); } /** * {@inheritDoc} */ @Override public GridJobFuture submitJob(Serializable annotatedJob) throws GridJobRejectionException, IllegalStateException { return GridNode.getInstance().getJobSubmissionService().submitJob(annotatedJob); } /** * {@inheritDoc} */ @Override public GridJobFuture submitJob(Serializable annotatedJob, ResultCallback callback) throws GridJobRejectionException, IllegalStateException { return GridNode.getInstance().getJobSubmissionService().submitJob(annotatedJob, callback); } /** * {@inheritDoc} */ @Override public GridJobFuture submitJob(GridJob<?, ?> job) throws GridJobRejectionException, IllegalStateException { return GridNode.getInstance().getJobSubmissionService().submitJob(job); } /** * {@inheritDoc} */ @Override public GridJobFuture submitJob(GridJob<?, ?> job, ResultCallback callback) throws GridJobRejectionException, IllegalStateException { return GridNode.getInstance().getJobSubmissionService().submitJob(job, callback); } }