Package com.almende.eve.monitor

Source Code of com.almende.eve.monitor.ResultMonitorFactory

/*
* Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
* License: The Apache Software License, Version 2.0
*/
package com.almende.eve.monitor;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.almende.eve.agent.AgentInterface;
import com.almende.eve.agent.annotation.EventTriggered;
import com.almende.eve.rpc.annotation.Access;
import com.almende.eve.rpc.annotation.AccessType;
import com.almende.eve.rpc.annotation.Name;
import com.almende.eve.rpc.annotation.Optional;
import com.almende.eve.rpc.annotation.Sender;
import com.almende.eve.rpc.jsonrpc.JSONRPC;
import com.almende.eve.rpc.jsonrpc.JSONRPCException;
import com.almende.eve.rpc.jsonrpc.JSONRequest;
import com.almende.eve.rpc.jsonrpc.JSONResponse;
import com.almende.eve.rpc.jsonrpc.jackson.JOM;
import com.almende.eve.state.TypedKey;
import com.almende.util.AnnotationUtil;
import com.almende.util.AnnotationUtil.AnnotatedClass;
import com.almende.util.AnnotationUtil.AnnotatedMethod;
import com.almende.util.NamespaceUtil;
import com.almende.util.NamespaceUtil.CallTuple;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.TypeFactory;

/**
* A factory for creating ResultMonitor objects.
*/
public class ResultMonitorFactory implements ResultMonitorFactoryInterface {
  private static final Logger                    LOG      = Logger.getLogger(ResultMonitorFactory.class
                                            .getCanonicalName());
  private static final TypedKey<HashMap<String, ResultMonitor>>  MONITORS  = new TypedKey<HashMap<String, ResultMonitor>>(
      "_monitors") {
  };
  private AgentInterface                      myAgent    = null;
 
  /**
   * Instantiates a new result monitor factory.
   *
   * @param agent the agent
   */
  public ResultMonitorFactory(final AgentInterface agent) {
    myAgent = agent;
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#create(java.lang.String, java.net.URI, java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode, java.lang.String, com.almende.eve.monitor.ResultMonitorConfigType[])
   */
  @Override
  public String create(final String monitorId, final URI url, final String method,
      final ObjectNode params, final String callbackMethod,
      final ResultMonitorConfigType... confs) {
   
    final ResultMonitor old = getMonitorById(monitorId);
    if (old != null) {
      old.cancel();
    }
   
    final ResultMonitor monitor = new ResultMonitor(monitorId, myAgent.getId(),
        url, method, params, callbackMethod);
    for (final ResultMonitorConfigType config : confs) {
      monitor.add(config);
    }
    return store(monitor);
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#getResult(java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode, java.lang.Class)
   */
  @Override
  public <T> T getResult(final String monitorId, final ObjectNode filterParms,
      final Class<T> returnType) throws IOException, JSONRPCException {
    return getResult(monitorId, filterParms, JOM.getTypeFactory()
        .constructSimpleType(returnType, new JavaType[0]));
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#getResult(java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode, com.fasterxml.jackson.databind.JavaType)
   */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T getResult(final String monitorId, final ObjectNode filterParms,
      final JavaType returnType) throws JSONRPCException, IOException {
    T result = null;
    final ResultMonitor monitor = getMonitorById(monitorId);
    if (monitor != null) {
      if (monitor.hasCache() && monitor.getCache() != null
          && monitor.getCache().filter(filterParms)) {
        result = (T) monitor.getCache().getValue();
      }
      if (result == null) {
        result = myAgent.send(monitor.getUrl(), monitor.getMethod(),
            JOM.getInstance().readTree(monitor.getParams()),
            returnType);
        if (monitor.hasCache()) {
          monitor.getCache().store(result);
        }
      }
    } else {
      LOG.severe("Failed to find monitor!" + monitorId);
    }
    return result;
   
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#cancel(java.lang.String)
   */
  @Override
  public void cancel(final String monitorId) {
    final ResultMonitor monitor = getMonitorById(monitorId);
    if (monitor != null) {
      monitor.cancel();
      delete(monitor.getId());
    } else {
      LOG.warning("Trying to cancel non existing monitor:"
          + myAgent.getId() + "." + monitorId);
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#doPoll(java.lang.String)
   */
  @Access(AccessType.SELF)
  @Override
  public final void doPoll(@Name("monitorId") final String monitorId)
      throws JSONRPCException, IOException {
    final ResultMonitor monitor = getMonitorById(monitorId);
    if (monitor != null) {
      if (monitor.getUrl() == null || monitor.getMethod() == null) {
        LOG.warning("Monitor data invalid:" + monitor);
      }
      final Object result = myAgent.send(monitor.getUrl(), monitor.getMethod(),
          JOM.getInstance().readTree(monitor.getParams()),
          TypeFactory.unknownType());
      if (monitor.getCallbackMethod() != null) {
        final ObjectNode params = JOM.createObjectNode();
        params.put("result",
            JOM.getInstance().writeValueAsString(result));
        myAgent.send(URI.create("local:" + myAgent.getId()),
            monitor.getCallbackMethod(), params);
      }
      if (monitor.hasCache()) {
        monitor.getCache().store(result);
      }
    }
  }
 
  // TODO: doesn't work!
  /** The last res. */
  private JsonNode  lastRes  = null;
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#doPush(java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode)
   */
  @Access(AccessType.SELF)
  @Override
  public final void doPush(@Name("pushKey") final String pushKey,
      @Optional @Name("params") final ObjectNode triggerParams)
      throws JSONRPCException, IOException {
   
    if (myAgent.getState().containsKey(pushKey)) {
      final ObjectNode pushParams = (ObjectNode) JOM.getInstance()
          .readTree(myAgent.getState().get(pushKey, String.class))
          .get("config");
      if (!(pushParams.has("method") && pushParams.has("params"))) {
        throw new JSONRPCException("Missing push configuration fields:"
            + pushParams);
      }
      final String method = pushParams.get("method").textValue();
      final ObjectNode params = (ObjectNode) JOM.getInstance().readTree(
          pushParams.get("params").textValue());
      final JSONResponse res = JSONRPC.invoke(myAgent, new JSONRequest(method,
          params), myAgent);
     
      final JsonNode result = res.getResult();
      if (pushParams.has("onChange")
          && pushParams.get("onChange").asBoolean()) {
        if (lastRes != null && lastRes.equals(result)) {
          return;
        }
        lastRes = result;
      }
     
      final ObjectNode parms = JOM.createObjectNode();
      parms.put("result", result);
      parms.put("pushId", pushParams.get("pushId").textValue());
     
      parms.put("callbackParams", triggerParams == null ? pushParams
          : pushParams.putAll(triggerParams));
     
      String callbackMethod = "monitor.callbackPush";
      if (pushParams.has("callback")) {
        callbackMethod = pushParams.get("callback").textValue();
      }
      myAgent.sendAsync(URI.create(pushParams.get("url").textValue()),
          callbackMethod, parms, null, Void.class);
      // TODO: If callback reports "old", unregisterPush();
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#callbackPush(java.lang.Object, java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode)
   */
  @Access(AccessType.PUBLIC)
  @Override
  public final void callbackPush(@Name("result") final Object result,
      @Name("pushId") final String pushId,
      @Name("callbackParams") final ObjectNode callbackParams)
      throws JSONRPCException {
   
    // TODO: THis is unclean!
    final String[] ids = pushId.split("_");
   
    if (ids.length != 2) {
      throw new JSONRPCException("PushId is invalid!");
    }
    final String monitorId = ids[0];
   
    try {
     
      final ResultMonitor monitor = getMonitorById(monitorId);
      if (monitor != null) {
        if (monitor.getCallbackMethod() != null) {
         
          ObjectNode params = JOM.createObjectNode();
          if (callbackParams != null) {
            params = callbackParams;
          }
          params.put("result",
              JOM.getInstance().writeValueAsString(result));
          myAgent.send(URI.create("local:" + myAgent.getId()),
              monitor.getCallbackMethod(), params);
        }
        if (monitor.hasCache()) {
          monitor.getCache().store(result);
        }
      } else {
        LOG.severe("Couldn't find local monitor by id:" + monitorId);
      }
    } catch (final Exception e) {
      LOG.log(Level.WARNING,
          "Couldn't run local callbackMethod for push!" + monitorId,
          e);
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#registerPush(java.lang.String, com.fasterxml.jackson.databind.node.ObjectNode, java.lang.String)
   */
  @Access(AccessType.PUBLIC)
  @Override
  public final void registerPush(@Name("pushId") final String id,
      @Name("config") final ObjectNode pushParams, @Sender final String senderUrl) {
    final String pushKey = "_push_" + senderUrl + "_" + id;
    pushParams.put("url", senderUrl);
    pushParams.put("pushId", id);
   
    if (myAgent.getState().containsKey(pushKey)) {
      LOG.warning("reregistration of existing push, canceling old version.");
      try {
        unregisterPush(id, senderUrl);
      } catch (final Exception e) {
        LOG.warning("Failed to unregister push:" + e);
      }
    }
    final ObjectNode result = JOM.createObjectNode();
    result.put("config", pushParams);
   
    final ObjectNode params = JOM.createObjectNode();
    params.put("pushKey", pushKey);
   
    LOG.info("Register Push:" + pushKey);
    if (pushParams.has("interval")) {
      final int interval = pushParams.get("interval").intValue();
      final JSONRequest request = new JSONRequest("monitor.doPush", params);
      result.put(
          "taskId",
          myAgent.getScheduler().createTask(request, interval, true,
              false));
    }
    String event = "";
    if (pushParams.has("event")) {
      // Event param overrules
      event = pushParams.get("event").textValue();
    }
    if (pushParams.has("onChange")
        && pushParams.get("onChange").booleanValue()) {
      AnnotatedClass ac = null;
      event = "change";
      try {
        final CallTuple res = NamespaceUtil.get(myAgent,
            pushParams.get("method").textValue());
       
        ac = AnnotationUtil.get(res.getDestination().getClass());
        for (final AnnotatedMethod method : ac
            .getMethods(res.getMethodName())) {
          final EventTriggered annotation = method
              .getAnnotation(EventTriggered.class);
          if (annotation != null) {
            // If no Event param, get it from annotation, else
            // use default.
            event = annotation.value();
          }
        }
      } catch (final Exception e) {
        LOG.log(Level.WARNING, "", e);
      }
    }
    if (!event.equals("")) {
      try {
        result.put(
            "subscriptionId",
            myAgent.getEventsFactory().subscribe(
                myAgent.getFirstUrl(), event, "monitor.doPush",
                params));
      } catch (final Exception e) {
        LOG.log(Level.WARNING, "Failed to register push Event", e);
      }
    }
   
    myAgent.getState().put(pushKey, result.toString());
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#unregisterPush(java.lang.String, java.lang.String)
   */
  @Access(AccessType.PUBLIC)
  @Override
  public final void unregisterPush(@Name("pushId") final String id,
      @Sender final String senderUrl) throws IOException {
    ObjectNode config = null;
    if (myAgent.getState() != null
        && myAgent.getState().containsKey(
            "_push_" + senderUrl + "_" + id)) {
      config = (ObjectNode) JOM.getInstance().readTree(
          myAgent.getState().get("_push_" + senderUrl + "_" + id,
              String.class));
    }
    if (config == null) {
      return;
    }
    if (config.has("taskId") && myAgent.getScheduler() != null) {
      final String taskId = config.get("taskId").textValue();
      myAgent.getScheduler().cancelTask(taskId);
    }
    if (config.has("subscriptionId")) {
      try {
        myAgent.getEventsFactory().unsubscribe(myAgent.getFirstUrl(),
            config.get("subscriptionId").textValue());
      } catch (final Exception e) {
        LOG.severe("Failed to unsubscribe push:" + e);
      }
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#store(com.almende.eve.monitor.ResultMonitor)
   */
  @Override
  public String store(final ResultMonitor monitor) {
    try {
      final Map<String, ResultMonitor> monitors = myAgent.getState().get(
          MONITORS);
      final HashMap<String, ResultMonitor> newmonitors = new HashMap<String, ResultMonitor>();
      if (monitors != null) {
        newmonitors.putAll(monitors);
      }
      newmonitors.put(monitor.getId(), monitor);
      if (!myAgent.getState().putIfUnchanged(MONITORS.getKey(),
          newmonitors, monitors)) {
        // recursive retry.
        store(monitor);
      }
    } catch (final Exception e) {
      LOG.log(Level.WARNING, "Couldn't find monitors:" + myAgent.getId()
          + "." + monitor.getId(), e);
    }
    return monitor.getId();
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#delete(java.lang.String)
   */
  @Override
  public void delete(final String monitorId) {
   
    try {
      final Map<String, ResultMonitor> monitors = myAgent.getState().get(
          MONITORS);
      final Map<String, ResultMonitor> newmonitors = new HashMap<String, ResultMonitor>();
      if (monitors != null) {
        newmonitors.putAll(monitors);
      }
      newmonitors.remove(monitorId);
     
      if (!myAgent.getState().putIfUnchanged(MONITORS.getKey(),
          newmonitors, monitors)) {
        // recursive retry.
        delete(monitorId);
      }
    } catch (final Exception e) {
      LOG.log(Level.WARNING, "Couldn't delete monitor:" + myAgent.getId()
          + "." + monitorId, e);
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#getMonitorById(java.lang.String)
   */
  @Override
  public ResultMonitor getMonitorById(final String monitorId) {
    try {
      Map<String, ResultMonitor> monitors = myAgent.getState().get(
          MONITORS);
      if (monitors == null) {
        monitors = new HashMap<String, ResultMonitor>();
      }
      final ResultMonitor result = monitors.get(monitorId);
      if (result != null) {
        result.init();
      }
      return result;
    } catch (final Exception e) {
      LOG.log(Level.WARNING, "Couldn't find monitor:" + myAgent.getId()
          + "." + monitorId, e);
    }
    return null;
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#cancelAll()
   */
  @Override
  public void cancelAll() {
    for (final ResultMonitor monitor : getMonitors()) {
      delete(monitor.getId());
    }
  }
 
  /* (non-Javadoc)
   * @see com.almende.eve.monitor.ResultMonitorFactoryInterface#getMonitors()
   */
  @Access(AccessType.PUBLIC)
  @Override
  public List<ResultMonitor> getMonitors() {
   
    try {
      Map<String, ResultMonitor> monitors = myAgent.getState().get(
          MONITORS);
      if (monitors == null) {
        monitors = new HashMap<String, ResultMonitor>();
      }
      final List<ResultMonitor> result = new ArrayList<ResultMonitor>(
          monitors.size());
      result.addAll(monitors.values());
      return result;
    } catch (final Exception e) {
      LOG.log(Level.WARNING, "Couldn't find monitors.", e);
    }
    return null;
  }
}
TOP

Related Classes of com.almende.eve.monitor.ResultMonitorFactory

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.