Package org.nebulaframework.core.job.future

Source Code of org.nebulaframework.core.job.future.GridJobFutureClientProxy

/*
* 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.core.job.future;

import java.io.Serializable;
import java.util.Date;
import java.util.UUID;

import javax.jms.ConnectionFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nebulaframework.core.job.GridJobState;
import org.nebulaframework.core.job.ResultCallback;
import org.nebulaframework.grid.GridExecutionException;
import org.nebulaframework.grid.GridTimeoutException;
import org.nebulaframework.grid.cluster.node.GridNode;
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.util.hashing.SHA1Generator;
import org.nebulaframework.util.jms.JMSRemotingSupport;

/**
* Client-side proxy for GridJobFuture. This proxy wraps the remote
* InternalGridJobFuture service proxy returned after submitting a
* {@code GridJob}.
* <p>
* This delegates most of the operations to the remote service, but
* provides additional support which is not supported by the remote
* service, such as {@code #getResult} methods. Furthermore, this proxy
* attempts to minimize the remote calls.
*
* @author Yohan Liyanage
* @version 1.0
*
* @see GridJobFuture
*/
public class GridJobFutureClientProxy implements GridJobFuture {

  private static Log log = LogFactory.getLog(GridJobFutureClientProxy.class);
 
  // Subject of this Proxy
  private InternalGridJobFuture future;
 
  private Object mutex = new Object();
  private Serializable result = null;
  private boolean jobFinished = false;
 
  /**
   * Constructs a {@code GridJobFutureClientProxy} which
   * will act as a proxy for the given {@code GridJobFuture}
   * instance.
   *
   * @param future subject of this proxy
   */
  public GridJobFutureClientProxy(InternalGridJobFuture future) {
    super();
    this.future = future;
   
    // Attach a ResultCallback to track results
    if (future.isFinalResultSupported()) {
     
      addFinalResultCallback(new ResultCallback () {
       
        public void onResult(Serializable result) {
          GridJobFutureClientProxy.this.result = result;
          jobFinished = true;
         
          // Notify all waiting threads
          synchronized (mutex) {
            mutex.notifyAll();
          }
        }
       
      });
    }
   
    // Job End / Cancel Hook to update finished flag
    ServiceEventsSupport.addServiceHook(new ServiceHookCallback() {

      @Override
      public void onServiceEvent(ServiceMessage message) {
        jobFinished = true;
      }
     
    }, future.getJobId() , ServiceMessageType.JOB_CANCEL, ServiceMessageType.JOB_END);
  }

  /**
   * {@inheritDoc}
   */
  public boolean cancel() throws IllegalStateException {
    if (jobFinished) {
      throw new IllegalStateException("Job has finished. Cancel not supported");
    }
    return future.cancel();
  }

  /**
   * {@inheritDoc}
   */
  public Exception getException() {
    if (!jobFinished) {
      throw new IllegalStateException("Job has finished. getException not supported");
    }
    return (result instanceof Exception) ? (Exception) result : null;
  }

  /**
   * {@inheritDoc}
   */
  public Serializable getResult() throws GridExecutionException, IllegalStateException {
    try {
      return getResult(0);
    } catch (GridTimeoutException e) {
      throw new AssertionError("Unexpected GridTimeoutException");
    }
  }
 
  /**
   * {@inheritDoc}
   */
  public Serializable getResult(long timeout) throws GridExecutionException,
      GridTimeoutException, IllegalStateException {
   
    // If final result is not supported, exception (i.e. Unbounded Jobs)
    if (!future.isFinalResultSupported()) {
       throw new IllegalStateException("GridJob does not support final results");
    }
   
    // This sync block waits until result is available.
   
    // Note that in case of timeouts, our own time tracking is needed
    // as a waking up due to unknown reasons may reset the timeouts
    synchronized (mutex) {
      try {
        // If job is not finished, wait till it finishes
        while (!isJobFinished()) {
         
          // Mark start time
          long tStart = new Date().getTime();
         
          // Wait for result
          mutex.wait(timeout);
         
          // Mark current time
          long tNow = new Date().getTime();
         
          // Check for timeout
          if (timeout > 0 && !isJobFinished()) {
           
            if ((tNow - tStart) > timeout ) {
              // timeout has occurred
              throw new GridTimeoutException("Timeout, Result Not Available");
            }
            else {
              // notified before timeout, update timeout
              timeout -= (tNow - tStart);
            }
          }
        }
      } catch (InterruptedException e) {
        log.error(e);
        throw new RuntimeException(
            "Interrupted while waiting for Result");
      }
    }

      if ( !(result instanceof Exception)) {
        return result;
      } else {
        throw new GridExecutionException("Execution Failed", (Exception) result);

    }
  }

  /**
   * {@inheritDoc}
   */
  public boolean isJobFinished() {
    return jobFinished;
  }

  /**
   * {@inheritDoc}
   */
  public GridJobState getState() {
    if (!isJobFinished()) {
      return future.getState();
    }
    else {
      if (!( result instanceof Exception)) {
        return GridJobState.COMPLETE;
      }
      else {
        return GridJobState.FAILED;
      }
    }
  }
 
  /**
   * {@inheritDoc}
   */
  public void addFinalResultCallback(ResultCallback callback) {
    // Remote Enable callback and add it
    String queueName = exposeCallback(callback);
    future.addFinalResultCallback(queueName);
  }

  /**
   * Exposes the given {@code ResultCallback} by remote
   * enabling it using JMS Remoting API.
   *
   * @param callback {@code ResultCallback} to be remote
   * enabled
   *
   * @return Name of the Queue to be used for communication
   * with callback
   */
  private String exposeCallback(ResultCallback callback) {

    // Generate QueueName [nebula.job.callback.<SHA1>]
    String queueName = "nebula.job.callback."
        + SHA1Generator.generate("" + GridNode.getInstance().getClusterId()
            + GridNode.getInstance().getId() + UUID.randomUUID());

    ConnectionFactory cf = GridNode.getInstance().getConnectionFactory();
    JMSRemotingSupport.createService(cf, queueName, callback, ResultCallback.class);
   
    return queueName;
  }
}
TOP

Related Classes of org.nebulaframework.core.job.future.GridJobFutureClientProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.