Java tutorial
/** * Copyright 2011 rkehoe * * 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 com.rk.grid.cluster.master; import java.io.Serializable; import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingQueue; import org.springframework.remoting.rmi.RmiServiceExporter; import com.rk.grid.cluster.shared.BrokerInfo; import com.rk.grid.cluster.shared.GridConfig; import com.rk.grid.cluster.shared.IBroker; import com.rk.grid.cluster.shared.IExecutable; import com.rk.grid.cluster.shared.IRemoteResult; import com.rk.grid.cluster.shared.IRemoteResultsHandler; import com.rk.grid.cluster.shared.ITaskMonitor; import com.rk.grid.cluster.shared.IWorkQueue; import com.rk.grid.server.ITaskObserver; import com.rk.grid.util.BlockingMap; import com.rk.grid.util.GateLatch; /** * Enables/Controls access (via RMI) to remote * JVMs. There is one broker per cluster. * * The broker is responsible for creating the JVM cluster * with the given library name. * * @author rkehoe * */ public class Broker<V> implements IBroker<V> { private static final long serialVersionUID = -7711272717758613782L; private static void log(String x) { System.out.println(x); } transient private LinkedBlockingQueue<IExecutable<V>> blockingTransferWorkQueue = new LinkedBlockingQueue<IExecutable<V>>( 100); transient private WorkQueue workQueue; transient private ResultsHandler resultsHandler; transient private BlockingMap<String, IRemoteResult<V>> blockingMap; transient private RmiServiceExporter rmiServiceExporter; transient private List<Process> processList = new ArrayList<Process>(); transient private final List<String> jvmNodeParams; transient private int connectionID = 0; transient private ProgressMonitor progressMonitor = new ProgressMonitor(); private final int port; private int workQueueCallNumber; private final int clusterSize; private final String libraryName; private final String serviceName; private final BrokerInfo brokerInfo; private GateLatch pauseGate = new GateLatch(); public Broker(int port, List<String> jvmNodeParams, GridConfig gridConfig, ResultsHandler resultsHandler, String serviceName) throws RemoteException { this(port, jvmNodeParams, gridConfig, serviceName); this.resultsHandler = resultsHandler; } public Broker(int port, List<String> jvmNodeParams, GridConfig gridConfig, String serviceName) throws RemoteException { this.port = port; this.jvmNodeParams = jvmNodeParams; this.serviceName = serviceName; this.clusterSize = gridConfig.getClusterSize(); this.libraryName = gridConfig.getLibraryName(); this.blockingMap = new BlockingMap<String, IRemoteResult<V>>(2 * clusterSize); this.resultsHandler = new ResultsHandler(); this.workQueue = new WorkQueue(); this.brokerInfo = new BrokerInfo(gridConfig, jvmNodeParams, serviceName, port); } /** * @return the clusterSize */ public int getClusterSize() { return this.clusterSize; } /** * @return the port */ public int getPort() { return this.port; } /** * @return the libraryName */ public String getLibraryName() { return this.libraryName; } public void start() throws Exception { doRMIExport(); creatCluster(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Broker [clusterSize=" + this.clusterSize + ", libraryName=" + this.libraryName + ", port=" + this.port + "]"; } /** * Only used to collect results and insert them into blocking results Map. * @author rkehoe */ private final class ResultsHandler extends UnicastRemoteObject implements IRemoteResultsHandler<V>, Serializable { private static final long serialVersionUID = 2362910027458128946L; protected ResultsHandler() throws RemoteException { super(); } @Override public void accept(IRemoteResult<V> r) throws RemoteException { blockingMap.putIfAbsent(r.getUID(), r); } } private List<ITaskObserver> observers = new ArrayList<ITaskObserver>(); public void add(ITaskObserver o) { this.observers.add(o); } public void remove(ITaskObserver o) { this.observers.remove(o); } private final class ProgressMonitor extends UnicastRemoteObject implements ITaskMonitor<String> { private static final long serialVersionUID = 2362910027458128946L; protected ProgressMonitor() throws RemoteException { super(); } /* (non-Javadoc) * @see grid.cluster.shared.ITaskMonitor#notify(java.lang.Object, java.lang.String) */ @Override public void notify(String msg, String taskID) throws RemoteException { for (ITaskObserver o : observers) { o.update(taskID, msg); } } } private final FutureTask<V> getFutureRemoveTask(final String key) { Callable<V> task = new Callable<V>() { @Override public V call() throws Exception { IRemoteResult<V> result = blockingMap.removeWhenPresent(key); return result.getResult(); } }; return new FutureTask<V>(task); } public FutureTask<V> dispatch(IExecutable<V> exe) { try { System.out.println("Enqueue: UID-" + exe.getUID() + "; " + exe.toString()); this.blockingTransferWorkQueue.put(exe); // ... to the tail of the queue FutureTask<V> future = getFutureRemoveTask(exe.getUID()); return future; } catch (Exception e) { throw new RuntimeException(e); } } /* (non-Javadoc) * @see grid.cluster.shared.IBroker#unPause() */ @Override public void unPause() throws RemoteException { pauseGate.open(); } /* (non-Javadoc) * @see grid.cluster.shared.IBroker#pause() */ @Override public void pause() throws RemoteException { pauseGate.close(); } /* (non-Javadoc) * @see grid.common.IBroker#getWorkQueue() */ @Override public IWorkQueue<V> getWorkQueue() throws RemoteException { workQueueCallNumber++; return (IWorkQueue<V>) this.workQueue; } private final class WorkQueue extends UnicastRemoteObject implements IWorkQueue<V> { private static final long serialVersionUID = 3288781574087157091L; protected WorkQueue() throws RemoteException { super(); } /* (non-Javadoc) * @see grid.common.IWorkQueue#take(grid.common.IExecutable) */ @Override public IExecutable<V> take() throws RemoteException { try { pauseGate.await(); IExecutable<V> take = blockingTransferWorkQueue.take(); //... from the head of the queue return take; } catch (InterruptedException e) { throw new RemoteException("Error retrieving work task.", e); } } } private void creatCluster() { for (int i = 0; i < clusterSize; i++) { Process process = NodeProcessFactory.createClusterNode(port, libraryName, jvmNodeParams, this.serviceName); this.processList.add(process); } } private void doRMIExport() throws RemoteException { /* * <bean id="broker" class="grid.client.Broker"></bean> <bean class="org.springframework.remoting.rmi.RmiServiceExporter"> <property name="serviceName" value="clustered-executor-service" /> <property name="service" ref="broker" /> <property name="serviceInterface" value="grid.common.IBroker"/> <property name="registryPort" value="1234" /> </bean> */ try { RmiServiceExporter s = new RmiServiceExporter(); s.setServiceName(this.serviceName); s.setService(this); s.setServiceInterface(IBroker.class); s.setRegistryPort(this.port); s.afterPropertiesSet(); this.rmiServiceExporter = s; } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * @throws RemoteException * @throws InterruptedException * @throws NoSuchObjectException * */ @SuppressWarnings("unchecked") public void shutDown() throws RemoteException, InterruptedException { for (int ii = 0; ii <= this.processList.size(); ii++) { this.dispatch((IExecutable<V>) IExecutable.POISON); } for (Process process : this.processList) { if (process != null) { int exitValue = process.waitFor(); Broker.log("Exit value for Process " + process + " = " + exitValue); } } try { UnicastRemoteObject.unexportObject(workQueue, true); } catch (NoSuchObjectException e) { e.printStackTrace(); } try { UnicastRemoteObject.unexportObject(resultsHandler, true); } catch (NoSuchObjectException e) { e.printStackTrace(); } try { UnicastRemoteObject.unexportObject(progressMonitor, true); } catch (NoSuchObjectException e) { e.printStackTrace(); } this.rmiServiceExporter.destroy(); Broker.log("Shutting down"); } /* (non-Javadoc) * @see grid.common.IBroker#getCallback() */ @Override public IRemoteResultsHandler<V> getCallback() throws RemoteException { return (IRemoteResultsHandler<V>) this.resultsHandler; } /* (non-Javadoc) * @see grid.cluster.shared.IBroker#getConnectionID() */ @Override public Integer getConnectionID() throws RemoteException { return connectionID++; } /* (non-Javadoc) * @see grid.cluster.shared.IBroker#getBrokerInfo() */ @Override public BrokerInfo getBrokerInfo() throws RemoteException { return brokerInfo; } /* (non-Javadoc) * @see grid.cluster.shared.IBroker#getProgressMonitor() */ @Override public ITaskMonitor<?> getProgressMonitor() throws RemoteException { return this.progressMonitor; } }