Package org.jboss.fresh.shell.commands

Source Code of org.jboss.fresh.shell.commands.EventNetShellAgentConnector

package org.jboss.fresh.shell.commands;

import org.jboss.fresh.io.BufferObjectReader;
import org.jboss.fresh.io.BufferObjectWriter;

import org.jboss.fresh.io.BufferWriter;
import org.jboss.fresh.io.PrintWriter2;
import org.jboss.fresh.shell.AbstractExecutable;
import org.jboss.fresh.events.Event;
import org.jboss.fresh.events.EventCentral;
import org.jboss.fresh.events.EventListener;
import org.jboss.fresh.events.net.EventNetRouter;
import org.jboss.fresh.events.net.EventNetConnector;
import org.jboss.fresh.events.net.EventNetRouterImpl;
import org.jboss.fresh.events.net.TakenOverException;
import org.jboss.fresh.ctx.Context;

import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
//import javax.naming.Context;


/**
*  This class is a server side part of RemoteShellEventNetConnector client side class.
*
*  The two classes together form a communication layer thar maintains an open channel
*  between two hosts.
*
*  This class runs inside a shell on what we'll refer to as server side. The other side is initiator side.
*  Initiator establishes a connection to the server side, starts a shell and invokes this executable.
*
*  Once this executable is running - bothways data pipe is established and simultaneous reads and writes
*  of data can begin.
*
*  This infrastructure strives to connect servers into an events network (EventNet). Servers do get restarted and connections
*  do drop. For that reason every initiator in the EventNet must have a permanent unique name assigned and
*  it communicates this name to the server during channel establishing phase.
*
*  For each initiator there exists an EventNetRouter on the server. If it does not exist yet it is created. If it exists already
*  that means that it hasn't been destroyed since initiator's last disconnect. Initiator can continue using the same EventNetRouter.
*  This also means it can catch up on all the events it has missed. In this case initiator must choose whether he wants to receive
*  all the saved events or will he discard them and tap into realtime event stream right away.
*
*  EventNetAgentExe only provides IN/OUT channel. All the logic is performed by EventNetRouter. That means that once reference to
*  the EventNetRouter is available BufferObjectReader around StdIn and BufferObjectWriter around StdOut are passed to it and
*  EventNetRouter takes over on executable process' thread.
*
*  If we let execute() method exit then StdOut and StdIn will get closed, so we must use the invocation thread for EventNetRouter's
*  processing. Processing will fail if any of the buffers fails.
*
*  To assure consistency EventNetRouter must disable any internal buffering inside output buffers. If the chunk can not be sent over then
*  if must be backed up to secondary it must not get lost in the buffer that will eventually just be garbage-collected.
*
*  Invocation thread polls a local outgoing events buffer on a regular periodic basis and writes complete buffers to out in blocking
*  write operations. Either a complete buffer write succedes or it fails. It never gets partially tranferred.
*
*  Server-side has it's own connector called EventNetAgentConnector that knows how to handle Buffers. On the initiator side RemoteShellEventNetConnector
*  doesn't work with buffers but with RemoteShell writeBuffer readBuffer methods.
*
*  API allows RemoteShell client to request a buffer that is smaller than server's buffer. That would cause partial buffer being transferred so we must
*  not use that feature. Initiator and server-side should negotiate buffer size.
*
*  There is a tradeoff between buffer size and speed. In best-case scenario data never comes fast enough to fill up buffer size so you can always do a data
*  transfer in one remote call.
*
*
*  eventnetagent -host nasser_1 -name nasser1_hirohito_remoter -keepeventsoncondrop
*
*/




//
// They handshake. They exchange info on registered broadcasters/listeners - so they are in sync with regards to that. If registrations happen during handshake they are communikated to the other side after the handshake via ECentral event.
//
// After the handshake and ECentral events that occured during hand shake events start to go bothways - depending on registration and filtering.
//
// Kako povemo katerega EC uporabiti? Normalno je EC bound v shell contextu. Po mojem zado��a �e to implementiramo.
//
public class EventNetAgentExe extends AbstractExecutable {

  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(EventNetAgentExe.class);

  public void process(String exename, String[] params) throws Exception {

     try {

    getStdIn().setMaxSize(1000);
    getStdOut().setMaxSize(1000);


    // this could as well be part of EventRouter configuration on the server-side
    boolean keepEvents = false;

    // process events

    String [] invalid = getInvalidSwitches(params, "haick", new String[] {"host", "app", "id", "conid", "cchk"});
    if(invalid!=null && invalid.length > 0) {
      error("Unrecoginzed switches: " + java.util.Arrays.asList(invalid));
      return;
    }

    // client tells what host he is
    String hostLabel = getSwitchValue(params, "h", "host");

    // client tells who exactly he is - agent name specified as param
    String app = getSwitchValue(params, "a", "app");

    // application if specified
    String initorID = getSwitchValue(params, "i", "id");

    // application if specified
    String conID = getSwitchValue(params, "c", "conid");
   
    boolean checkCon = isSwitchActive(params, "k", "cchk");

    if(conID == null) {
      error("conID not specified. You must use conid parameter");
      return;
    }

//__hackBindEventCentral();
/*
    for(int i=0; i<params.length; i++) {
      String tmp = params[i];

      switch(i) {
        case 0:
          hostLabel = tmp;
          break;
        case 1:
          app = tmp;
          break;
        case 2:
          initorID = tmp;
          break;
        default:
          usage();
          if(canThrowEx()) {
            throw new RuntimeException("Too many parameters. Use --help for usage information.");
          }
          return;
      }
    }
*/

//    if(hostLabel==null || app==null || initorID==null) {
//      error("Parameter(s) missing. Use --help for usage information.");
//      return;
//    }

    // get ref to EventCentral
    Context ctx = getShell().getContext();

    // we could also specify lookup name on cmdline or as ENV variable
    EventCentral ec = (EventCentral) ctx.get("EventCentral");

    if(ec == null) {
      error(new org.jboss.fresh.shell.UninitializedEnvironmentException("EventCentral not bound in context"));
      return;
    }

    log.info("EC1 Listeners: " + ec.getListeners());
    log.info("EC1 Broadcasters: " + ec.getBroadcasters());

    // lookup EventNetRouter for our name
    EventNetRouter router = ec.getEventNetRouter(initorID);

//    Thread t = null;

log.info("=== processid: " + getProcess().getID());
    // if exists take over : tell it to stop, get Connector from it and set Buffers on it, then tell EventNetRouter to start
    if(router!=null) {
log.info("router != null  checkCon: " + checkCon + ", conID: " + conID + ", existing conID: " + router.getConID());
      if(checkCon && !conID.equals(router.getConID())) {
        try {
          error("Agent (" + conID + ") has been taken over by another agent (" + router.getConID() + ")");
        } catch(Exception e) {
          throw new TakenOverException(e.getMessage());
        }
        return;
      }
      router.setConID(conID);

log.info("Stopping current router ...");
      router.stop(true);
log.info("ok.  getting connector and replacing buffers ...");
      EventNetShellAgentConnector con = (EventNetShellAgentConnector) router.getConnector();
      con.setOutput(new BufferObjectWriter(getStdOut()));
      con.setInput(new BufferObjectReader(getStdIn()));
log.info("ok. Creating new ProcessorThread");
      router.start();
log.info("### YAK! This shouldn'0t happen :(.");
      return;

       // (this will take over our thread and our job is done)

    } else {
      // if it doesn't exist then we need to instanciate a new EventNetRouter and register it with EventCentral
      // Then do same things as with taking over which eventually takes executable's thread inside the last method we call.
      if(hostLabel == null) {
        error("Host not specified");
        return;
      }

      if(app==null) app = shell.getEnvProperty("PROJECT");

      router = new EventNetRouterImpl(ec, initorID, hostLabel, app, keepEvents);
      router.setConID(conID);
     
      //ec.registerEventNetRouter(initorID, router);
      EventNetShellAgentConnector con = new EventNetShellAgentConnector();
      con.setOutput(new BufferObjectWriter(getStdOut()));
      con.setInput(new BufferObjectReader(getStdIn()));

      router.setConnector(con);
      router.start();
//      t = new ProcessorThread(router);
//      t.start();
    }


      } catch(Exception e) {
    try {
      Thread.sleep(10000);
    } catch(Exception ex) {
    }
    throw e;
      }



//    Thread.sleep(10000);
//    org.jboss.fresh.events.EventBroadcaster eb = new org.jboss.fresh.events.EventBroadcaster(ec, "CMSPersistence");

//    while(true) {
//      Event ev = new Event("CMS", "onAfterCreate");
//log.info("dispatchEvent: " + ev);
//      eb.dispatchEvent(ev);
//      Thread.sleep(10000);
//    }
/*
    log.info(" * * * * * * * * * * * * * * * ");
    log.info("  EC2 Broadcasters: " + ec2.getBroadcasters());
    log.info("  EC2 Listeners: " + ec2.getListeners());
    log.info("   * *");
    log.info("  EC1 Broadcasters: " + ec.getBroadcasters());
    log.info("  EC1 Listeners: " + ec.getListeners());
   
    t.join();
*/
  }
/*
  private void __hackBindEventCentral() throws NamingException {

    RegistryContext ctx = new RegistryContext();

    Context c = null;

    try {
      c = (Context) ctx.lookup("java:");
    } catch(NameNotFoundException ex) {
      c = ctx.createSubcontext("java:");
    }

    try {
      c = (Context) ctx.lookup("java:/CP2");
    } catch(NameNotFoundException ex) {
      c = c.createSubcontext("CP2");
    }

    try {
      ctx.lookup("java:/CP2/EventCentral");
    } catch(NameNotFoundException ex) {
      EventCentral ec = new EventCentralImpl("nasser_0", null);
      c.bind("EventCentral", ec);
    }
   
   
    try {
      ctx.lookup("java:/CP2/proj/EventCentral");
    } catch(NameNotFoundException ex) {
      try {
        c = c.createSubcontext("proj");
      } catch(Exception e) {
        log.error("Failed to create subcontext proj: ", e);
      }

      try {
        EventCentral ec2 = new EventCentralImpl("nasser_0", "proj");

        EventCentral ec = (EventCentral) ctx.lookup("java:/CP2/EventCentral");
        //ec.registerEventCentral(ec2, "nasser_0/proj/EventCentral(" + ec2.generateID() + ")", new ECListener(ec2));
        ctx.bind("java:/CP2/proj/EventCentral", ec2);
      } catch(Exception e) {
        log.error("Failed to bind proj EventCentral: ", e);
      }
    }
  }
*/


  private void usage() {
    PrintWriter2 out = new PrintWriter2(new BufferWriter(getStdOut()));
    out.println("Usage: eventnet [-h <host_label>] [-a <application>] -i <agentid>");
    out.println("    -h,  --host : host label");
    out.println("    -a,  --app  : application (this parameter is optional)");
    out.println("    -i,  --id   : agent id");
    out.println("    --help : this help");
    out.println();
    out.println("  Agent id is required every time. It uniquely identifies remote agent which");
    out.println("  represents connection with remote EventCentral.");
    out.println("  Host label is required the first time remote agent establishes a connection.");
    out.println("  To continue an already established eventnet connection you only specify id.");
    out.println();
    out.close();
  }

/*
  class ProcessorThread extends Thread {

    EventNetRouter router;

    ProcessorThread(EventNetRouter router) {
      this.router = router;
    }

    public void run() {
      try {
        router.start();
      } catch(Exception ex) {
        log.error("Exception occured inside EventNetRouter start(): ", ex);
      }
    }
  }
*/
}


    class ECListener implements EventListener {

  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(ECListener.class);

  EventCentral ec;
 
  ECListener(EventCentral ec) {
    this.ec = ec;
  }
 
  public void event(Event ev) {
    // we are interested in registration events
    try {
      if("ECentral".equals(ev.getEventClass())) {
        if("RegisterListener".equals(ev.getEventName())) {
          Object [] dat = (Object []) ev.getValueObject();
          String id = (String) dat[0];
          EventCentral.ListenerData ld = (EventCentral.ListenerData) dat[1];
          ec.registerEventListener(id, ld.getListener(), ld.getFilter());
        }
      }
    } catch(Exception ex) {
      log.error("Exception occured while processing event: " + ev, ex);
    }
  }
    }

class EventNetShellAgentConnector implements EventNetConnector {

  private BufferObjectReader shin;
  private BufferObjectWriter shout;


  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(EventNetShellAgentConnector.class);
 
  public void setOutput(BufferObjectWriter out) {
    shout = out;
  }

  public void setInput(BufferObjectReader in) {
    shin = in;
  }

  public int getPingTime() {
    return Integer.MAX_VALUE;
  }

  public void ping() {
  }

  public void reinit() {

  }

  public void reset() {
    try {
      Thread.sleep(5000);
    } catch(Exception ex) {}
  }

  public void sendBuffer(List ls, int timeout)  {
log.info("Sending buffer to out: " + shout + " :: " + ls);
    try {
      shout.setTimeout(timeout);
      Iterator it = ls.iterator();
      while(it.hasNext()) {
        shout.writeObject(it.next());
      }

      shout.flush();
    } catch(IOException ex) {
      throw new RuntimeException(ex);
    }

log.info("  done sending.");

  }

  public List receiveBuffer(int timeout)  {
log.info("Receiving buffer from in: " + shin);
    try {
      shin.setTimeout(timeout);
      //List ls = in.getBuffer(timeout, 500);
      LinkedList ls = new LinkedList();
      ls.add(shin.readObject());

      int len = shin.available();
      for(int i=0; i<len; i++) {
        ls.add(shin.readObject());
      }

log.info("   received: " + ls);
      return ls;
    } catch(IOException ex) {
      throw new RuntimeException(ex);
    }

  }
}


TOP

Related Classes of org.jboss.fresh.shell.commands.EventNetShellAgentConnector

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.