package com.ibm.able.examples.ablebean;

//====================================================================
//
// Licensed Materials - Property of IBM
//
// "Restricted Materials of IBM"
//
// Product: com.ibm.able.examples.ablebean
//
// (C) Copyright IBM Corp. 2000 All Rights Reserved.
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with
// IBM Corp.
//
//
//                             DISCLAIMER
//                             ----------
//
// This material contains programming source code for your consideration.
// These examples have not been thoroughly tested under all conditions.
// IBM, therefore, cannot guarantee or imply reliability, serviceability,
// performance or function of these programs.  All programs contained
// herein are provided to you "AS IS".  THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
// DISCLAIMED.
//
//====================================================================

//====================================================================
// Imports
//====================================================================
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import com.ibm.able.Able;
import com.ibm.able.AbleBufferConnection;
import com.ibm.able.AbleEvent;
import com.ibm.able.AbleEventListener;
import com.ibm.able.AbleException;
import com.ibm.able.AbleObject;
import com.ibm.able.examples.ableagent.SimpleAbleAgent;

/**
 * This class provides an application for the SimpleAbleBean. On a timed interval,
 * a value is received and passed to the SimpleAbleBean for processing. It uses
 * the the SimpleAbleAgent to generate these timed events and the data to be processed.
 * <p>
 * The SimpleAbleAgent generates events on a timer interval.  When its timer
 * expires, it updates an instance variable and puts the new value in its outputBuffer.
 * It then sends a datachanged event.  This SimpleAbleApp
 * class listens for events sent by the SimpleAbleAgent so that it can trace activity.
 * <p>
 * When SimpleAbleApp receives any dataChanged event, it prints out the classname of
 * the source of the event and the value of the event argument object.  If the
 * event was sent by its instance of the SimpleAbleAgent, it calls process on its
 * SimpleAbleBean object.
 * <p>
 * SimpleAbleApp also listens for PropertyChangeEvents sent by its SimpleAbleBean object.
 * The property and value of these events are simply written to the
 * console as proof that the SimpleAbleBean's instance variable now matches the
 * value provided from the SimpleAbleAgent.
 * <p>
 * All processing and events are handled on the thread owned by the SimpleAbleAgent's
 * event queue processor.  The thread running main in this class only creates the
 * objects and starts that thread running.  It ends the event queue processor thread
 * after a finite interval.
 * <p>
 * Here is a summary of data flow processing:
 * <sl>
 * <li>SimpleAbleAgent is configured to create an AbleEvent every n seconds and
 *     call its process method at the end of the interval.  The process method
 *     populates the buffer and sends a dataChanged event.
 * <li>SimpleAbleApp listens for dataChanged events from the SimpleAbleAgent and
 *     calls the process method on the SimpleAbleBean on receipt.
 * <li>SimpleAbleBean's process method takes the value from its inputBuffer and
 *     uses it to change a property.  This sends a propertyChange event to
 *     registered listeners.
 * <li>SimpleAbleApp listens for propertyChange events from the SimpleAbleBean
 *     and displays the old and new values for the property.
 * </sl>
 *
 * @version  $Revision: 1.6 $, $Date: 2002/01/22 21:38:45 $
 *
 * @author   Joe Bigus
 */
public class SimpleAbleApp implements AbleEventListener, PropertyChangeListener {

    //-----------------------------------------------------------------
    // Member variables
    //-----------------------------------------------------------------
    private SimpleAbleBean  myBean = null;
    private SimpleAbleAgent myAgent= null ;

    //-----------------------------------------------------------------
    // Constructors
    //-----------------------------------------------------------------
    private SimpleAbleApp() {
    }


    //-----------------------------------------------------------------
        // Main method
    //-----------------------------------------------------------------
    public static void main(String[] args) {
      Able.startMessageAndTraceLogging();
      SimpleAbleApp test = new SimpleAbleApp() ;
      // messages are generally retrieved from message bundle
      // use error level just to avoid displaying extra messages
      Able.MessageLog.text(Able.MSG_ERROR,"Starting test");
      test.test() ;
    }


    //-----------------------------------------------------------------
        // Methods
    //-----------------------------------------------------------------
    private void test() {

        try {
           myBean = new SimpleAbleBean("bean1") ;
           myAgent = new SimpleAbleAgent("agent") ;   // calls super.init(), starts timer thread
           new AbleBufferConnection(myAgent, myBean) ;
           myAgent.addAbleEventListener(this);
           myBean.addPropertyChangeListener(this);

           String[] outBuf1 = (String[])myAgent.getOutputBuffer() ;
           Able.MessageLog.text(Able.MSG_ERROR,"initial Agent color property   = " + myAgent.getSimpleBeanColor());
           Able.MessageLog.text(Able.MSG_ERROR,"initial Agent output Buffer = " + displayBuffer(outBuf1)) ;

           String[] outBuf2 = (String[])myBean.getOutputBuffer() ;
           Able.MessageLog.text(Able.MSG_ERROR,"initial Bean color property   = " + myBean.getSimpleBeanColor());
           Able.MessageLog.text(Able.MSG_ERROR,"initial Bean output Buffer = " + displayBuffer(outBuf2)) ;

           Able.MessageLog.text(Able.MSG_ERROR,"Let agent autonomous thread drive processing from this point. ") ;
           delay(30) ; // wait 30 seconds
           // stop the agent and all its beans
           myAgent.quitAll();
           // remove all listeners for cleanup
           myBean.removePropertyChangeListener(this);
           myAgent.removeAbleEventListener(this);
        } catch (AbleException e) {
            Able.MessageLog.text(Able.MSG_ERROR,e.getLocalizedMessage());
            if (Able.TraceLog.isLogging()) {
                Able.TraceLog.exception(Able.TRC_LOW,this,"test",e);
            }
        }
        Able.MessageLog.text(Able.MSG_ERROR,"Done!");
    }


   /**
    *   Convert an array of objects to a string delimited by
    *   a blank and a newline.
    */
    protected static String displayBuffer(Object[] buf) {
        StringBuffer buffer = new StringBuffer("Buffer: ") ;
        for (int i=0 ; i < buf.length ; i++) {
            buffer.append(buf[i] + " " ) ;
        }
        buffer.append(Able.LS);
        return buffer.toString();
    }

   /**
    *   Convert an objects to a string. If an array, convert to string of
    *   objects delimited by a blank and a newline.
    */
    protected static String displayBuffer(Object obj) {
        if (obj instanceof Object[]) return displayBuffer((Object[])obj);
        else return obj.toString();
    }

   /**
    *   Display changes when agent modifies its output buffer.
    */
    public void processAbleEvent(AbleEvent e) throws AbleException {
        if (Able.TraceLog.isLogging()) Able.TraceLog.entry(Able.TRC_MEDIUM,this,"processAbleEvent");
        if (e.getId() == AbleEvent.EOF) {
            Able.MessageLog.text(Able.MSG_ERROR,"received AbleEvent " + e) ;
        } else if (e.getId() == AbleEvent.DATACHANGED) {
            Able.MessageLog.text(Able.MSG_ERROR,"received DataChanged AbleEvent ") ;
            AbleObject obj = (AbleObject)e.getGenSource();
            Able.MessageLog.text(Able.MSG_ERROR,obj.getClass().getName() +": OutputBuffer = " + displayBuffer(obj.getOutputBufferAsStringArray()));
            Able.MessageLog.text(Able.MSG_ERROR,obj.getClass().getName() +": Event argObject = " + displayBuffer(e.getArgObject()));
            if (obj == myAgent) {
                // agent timer interval expired and its output buffer is populated
                // so call the bean's process method
                myBean.process();
            }
        }
    }

   /**
    *   Process an Able event.  Required by AbleEventListener interface.
    */
    public void handleAbleEvent(AbleEvent e) throws AbleException {
        processAbleEvent(e) ; // handle all events synchronously regardless of event flag !!!
    }

   /**
    *   Handle a property change event. Required by AbleEventListener interface.
    *   This implementation just displays the property name and its old and new values.
    */
    public void propertyChange(PropertyChangeEvent e) {
       AbleObject obj = (AbleObject)e.getSource();
       Able.MessageLog.text(Able.MSG_ERROR,"received PropertyChangeEvent ") ;
       Able.MessageLog.text(Able.MSG_ERROR,obj.getClass().getName() +": Property '" + e.getPropertyName() + "' changed from '" + e.getOldValue() + "' to '" + e.getNewValue()+"'");
    }

   /**
    *   Wait a number of seconds.
    */
    private void delay(int sec) {
        try {
            Able.MessageLog.text(Able.MSG_ERROR,"Test case pause for " + sec + " seconds");
            Thread.sleep(sec * 1000) ;
        } catch (Exception e) { }
    }


    /**
     * Determine the copyright of this class.
     *
     * @return    A String containing this class's copyright statement.
     *            <p>
     */
    private static String Copyright() {
      return Able.Copyright;
    }


}
