package context.arch;
import java.io.IOException;
import java.io.Reader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import context.arch.comm.CommunicationsHandler;
import context.arch.comm.CommunicationsObject;
import context.arch.comm.DataObject;
import context.arch.comm.DataObjects;
import context.arch.comm.RequestObject;
import context.arch.comm.clients.IndependentCommunication;
import context.arch.comm.language.DecodeException;
import context.arch.comm.language.EncodeException;
import context.arch.comm.language.InvalidDecoderException;
import context.arch.comm.language.InvalidEncoderException;
import context.arch.comm.language.MessageHandler;
import context.arch.comm.language.ParserObject;
import context.arch.comm.protocol.InvalidProtocolException;
import context.arch.comm.protocol.ProtocolException;
import context.arch.comm.protocol.RequestData;
import context.arch.discoverer.ComponentDescription;
import context.arch.discoverer.Discoverer;
import context.arch.discoverer.DiscovererDescription;
import context.arch.discoverer.lease.Lease;
import context.arch.discoverer.query.AbstractQueryItem;
import context.arch.handler.AsyncServiceHandler;
import context.arch.handler.AsyncServiceHandlerInfo;
import context.arch.handler.AsyncServiceHandlers;
import context.arch.handler.Handler;
import context.arch.handler.HandlerInfo;
import context.arch.handler.Handlers;
import context.arch.service.Service;
import context.arch.service.helper.FunctionDescription;
import context.arch.service.helper.ServiceInput;
//import context.arch.storage.AttributeFunctions;
import context.arch.storage.Attributes;
import context.arch.storage.Retrieval;
import context.arch.storage.StorageObject;
import context.arch.subscriber.AbstractSubscriber;
import context.arch.subscriber.ClientSideSubscriber;
import context.arch.subscriber.DiscovererSubscriber;
import context.arch.subscriber.Subscriber;
import context.arch.util.Constants;
import context.arch.util.Error;
import context.arch.widget.Widget;
/**
* This class is the base object for the context-aware infrastructure.
* It is able to poll and subscribe to other components and can be
* polled and subscribed to by other components. It also can generate
* and handle RPC-style requests. It consists of 2 main objects, the
* CommunicationsObject and ParserObject. It also maintains a list of
* subscribers and a list of handlers.
*
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handler
* @author Anind
*/
public class BaseObject implements MessageHandler, CommunicationsHandler {
/**
* Debug flag. Set to true to see debug messages.
*/
public static boolean DEBUG = false;
/** Indicates that the exit condition is normal */
public static final int EXIT_OK = 1;
/** Disables the communications */
public static final int DISABLE_PORT = -1;
/**
* Tag for id of this component
*/
public static final String ID = Constants.ID;
/**
* Tag for a ping
*/
public static final String PING = "ping";
/**
* Tag for a ping reply
*/
public static final String PING_REPLY = "pingReply";
/**
* Tag for getting the description
*/
public static final String QUERY_DESCRIPTION = "queryDescription";
/**
* Tag for reply to a query_description
*/
public static final String QUERY_DESCRIPTION_REPLY = "queryDescriptionReply";
/**
* The tag for the type of this object
*/
public static final String BASEOBJECT_TYPE = "baseobject";
/**
* Object to handle communications between components
*
* @see context.arch.comm.CommunicationsObject
*/
public CommunicationsObject communications;
/**
* Object to handle the encoding and decoding of communications
*
* @see context.arch.comm.language.ParserObject
*/
public ParserObject parser;
/**
* Object to keep track of context widget handlers
*
* @see context.arch.handler.Handlers
* @see context.arch.handler.Handler
*/
public Handlers handlers;
/**
* Object to keep track of asynchronous service handlers
*
* @see context.arch.handler.AsyncServiceHandlers
* @see context.arch.handler.AsyncServiceHandler
*/
public AsyncServiceHandlers serviceHandlers;
/**
* Name or IP address of the host
*/
protected String host = null;
/**
* Id of the object
*/
protected String id;
/**
* Version of the object
*/
private String version = "undefined";
/**
* The lease defined by the component, to be sent to the discoverer
*/
private Lease myLease;
/**
* This field specifies if the lease is automatically renewed or not.
* By default, the lease is renewed.
*/
private boolean automaticRenewal = true;
/**
* The description of the discoverer that the base object has found
*
* @see context.arch.discoverer.Discoverer
*/
public DiscovererDescription discoverer = null;
/**
* Basic constructor that creates a CommunicationsObject
* with the given port and protocol, and creates a
* ParserObject with the given encoder and decoder. It also
* creates a Handlers object to keep track of context widget handlers.
*
* @param communicationClientClass Class to use for client communications
* @param communicationServerClass Class to use for server communications
* @param localServerPort Port to use for server communications
* @param encoderClass Class to use for communications encoding
* @param decoderClass Class to use for communications decoding
* @param threadPoolNumber The number of client threads in the clients pool
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject(String communicationClientClass, String communicationServerClass,
int localServerPort, String encoderClass,
String decoderClass, int threadPoolNumber) {
try {
// starts the server and the multicast connection
if (localServerPort != BaseObject.DISABLE_PORT){
communications = new CommunicationsObject(this,
communicationClientClass, communicationServerClass,
localServerPort, threadPoolNumber);
communications.start();
}
parser = new ParserObject(encoderClass,decoderClass);
handlers = new Handlers();
serviceHandlers = new AsyncServiceHandlers();
discoverer = null; // the discoverer's information
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject InvalidProtocolException: "+ipe);
}
}
/**
* Basic constructor that creates a CommunicationsObject
* with the given port and protocol, and creates a
* ParserObject with the given encoder and decoder. It also
* creates a Handlers object to keep track of context widget handlers.
*
* @param communicationClientClass Class to use for client communications
* @param communicationServerClass Class to use for server communications
* @param localServerPort Port to use for server communications
* @param encoderClass Class to use for communications encoding
* @param decoderClass Class to use for communications decoding
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject(String communicationClientClass, String communicationServerClass,
int localServerPort, String encoderClass,
String decoderClass) {
this(communicationClientClass, communicationServerClass, localServerPort, encoderClass, decoderClass, -1);
}
/**
* Basic constructor that creates a CommunicationsObject,
* ParserObject and Handlers object.
*
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject() {
this(null,null,-1,null,null, -1);
}
/**
* Constructor that just creates a CommunicationsObject
* with the given port and ParserObject.
* It also creates a Handlers
* object to keep track of context widget handlers.
*
* @param localServerPort Port number to communicate on
*
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject(int localServerPort) {
this(null,null,localServerPort,null,null, -1);
debugprintln(DEBUG, "BO constructor (int)");
}
/**
* Constructor that just creates a CommunicationsObject
* with the given protocol handler class, and
* a ParserObject. It also creates a Handlers object to keep track
* of context widget handlers.
*
* @param protocolHandlerClass Protocol handler class to communicate with
*
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject(String protocolHandlerClass) {
this(null,protocolHandlerClass,-1,null,null, -1);
}
/**
* Constructor that just creates a CommunicationsObject
* with the given port and protocol handler class, and
* ParserObject. It also creates a Handlers object to keep track
* of context widget handlers.
*
* @param localServerPort Port number to communicate on
* @param protocolHandlerClass Protocol handler class name to communicate with
*
* @see context.arch.comm.CommunicationsObject
* @see context.arch.comm.CommunicationsObject#start()
* @see context.arch.comm.language.ParserObject
* @see context.arch.handler.Handlers
*/
public BaseObject(int localServerPort, String protocolHandlerClass) {
this(null,protocolHandlerClass,localServerPort,null,null, -1);
}
/**
* Stub method that decodes the given string using ParserObject
*
* @param communicationData String to be decoded
* @return the decoded data
* @exception context.arch.comm.language.DecodeException thrown if the parser can't decode the given string
* @exception context.arch.comm.language.InvalidDecoderException thrown if the parser can't create the necessary decoder
* @see context.arch.comm.language.ParserObject#decodeData(java.io.Reader)
*/
public DataObject decodeData(Reader communicationData) throws DecodeException, InvalidDecoderException {
return parser.decodeData(communicationData);
}
/**
* Stub method that encodes the given string using ParserObject
*
* @param communicationData String to be decoded
* @return the encoded data
* @exception context.arch.comm.language.EncodeException thrown if the parser can't encode the given string
* @exception context.arch.comm.language.InvalidEncoderException thrown if the parser can't create the necessary encoder
* @see context.arch.comm.language.ParserObject#encodeData(context.arch.comm.DataObject)
*/
public String encodeData(DataObject communicationData) throws EncodeException, InvalidEncoderException {
//System.out.println("communicationData = " + communicationData);
return parser.encodeData(communicationData);
}
/**
* Method that submits a user request for polling/subscription. The request
* is in the form of a DataObject. It is encoded, sent out and the reply is
* decoded, if necessary, and returned.
*
* @param data DataObject that contains the request
* @param requestType RPC tag that indicates the type of request
* @return DataObject containing the reply to the request
* @exception EncodeException when the encoding can't be completed successfully
* @exception DecodeException when the decoding can't be completed successfully
* @exception InvalidEncoderException when the encoder can't be created
* @exception InvalidDecoderException when the decoder can't be created
* @exception ProtocolException when the request can't be sent successfully
* @exception InvalidProtocolException when the request can't be sent successfully due to invalid protocol use
*
* @deprecated
*/
public DataObject userRequest(DataObject data, String requestType) throws EncodeException, InvalidProtocolException, ProtocolException, DecodeException, InvalidDecoderException, InvalidEncoderException, IOException {
DataObject decoded = null;
RequestObject request = new RequestObject(data, requestType);
request.setEncodedData(encodeData(request.getNonEncodedData()));
RequestData replydata = communications.sendRequest(request);
//println("BaseObject <userRequest deprecated> : wants to send \n"+data + "\nto "+requestType);
if (replydata.getType().equals(RequestData.DECODE)) {
decoded = parser.decodeData(replydata.getData());
}
//println("and receive reply :\n"+decoded);
return decoded;
}
/**
* Sends a message to a remote component
*
* @param request The RequestObject that contains all information about the
* remote component and the data to send
* @return DataObject The reply
*/
public DataObject userRequest(RequestObject request)
throws EncodeException, InvalidProtocolException, ProtocolException,
DecodeException, InvalidDecoderException, InvalidEncoderException, IOException {
RequestData replydata = null;
DataObject decoded = null;
//Encode if necessary
request.setEncodedData(encodeData(request.getNonEncodedData()));
debugprintln(DEBUG, "userRequest=" + request);
replydata = communications.sendRequest(request);
if (replydata != null && replydata.getType().equals(RequestData.DECODE)) {
decoded = parser.decodeData(replydata.getData());
}
return decoded;
}
/**
* Method that submits a user request for polling/subscription. The request
* is in the form of a DataObject. It is encoded, sent out and the reply is
* decoded, if necessary, and returned.
*
* @param data DataObject that contains the request
* @param requestType RPC tag that indicates the type of request
* @param remoteHostname Hostname of the component the request is being sent to
* @return DataObject containing the reply to the request
* @exception EncodeException when the encoding can't be completed successfully
* @exception DecodeException when the decoding can't be completed successfully
* @exception InvalidEncoderException when the encoder can't be created
* @exception InvalidDecoderException when the decoder can't be created
* @exception ProtocolException when the request can't be sent successfully
* @exception InvalidProtocolException when the request can't be sent successfully due to invalid protocol use
*
* @deprecated
*/
public DataObject userRequest(DataObject data, String requestType, String remoteHostname) throws EncodeException, InvalidProtocolException, ProtocolException, DecodeException, InvalidDecoderException, InvalidEncoderException, IOException {
DataObject decoded = null;
RequestObject request = new RequestObject(data, requestType, remoteHostname);
request.setEncodedData(encodeData(request.getNonEncodedData()));
RequestData replydata = communications.sendRequest(request);
if (replydata.getType().equals(RequestData.DECODE)) {
decoded = parser.decodeData(replydata.getData());
}
return decoded;
}
/**
* Method that submits a user request for polling/subscription. The request
* is in the form of a DataObject. It is encoded, sent out and the reply is
* decoded, if necessary, and returned.
*
* @param data DataObject that contains the request
* @param requestType RPC tag that indicates the type of request
* @param remoteHostname Hostname of the component the request is being sent to
* @param remotePort Port number of the component the request is being sent to
* @return DataObject containing the reply to the request
* @exception EncodeException when the encoding can't be completed successfully
* @exception DecodeException when the decoding can't be completed successfully
* @exception InvalidEncoderException when the encoder can't be created
* @exception InvalidDecoderException when the decoder can't be created
* @exception ProtocolException when the request can't be sent successfully
* @exception InvalidProtocolException when the request can't be sent successfully due to invalid protocol use
*/
public DataObject userRequest(DataObject data, String requestType, String remoteHostname, int remotePort)
throws EncodeException, ProtocolException, InvalidProtocolException, DecodeException, InvalidDecoderException, InvalidEncoderException, IOException {
RequestObject request = new RequestObject(data, requestType, remoteHostname, remotePort);
request.setEncodedData(encodeData(request.getNonEncodedData()));
RequestData replydata = communications.sendRequest(request);
// System.out.println
if (replydata != null && replydata.getType().equals(RequestData.DECODE)) {
DataObject decoded = parser.decodeData(replydata.getData());
return decoded;
}
return null;
}
/**
* This method is used to send a message through a threaded communication.
* The request is sent by a thread in charge of the communication.
*
* The request is encapsulated in a IndependentCommunication that contains
* a RequestObject (data to send and the recipient of the data) and the
* reply message and the exceptions that occured during the communication.
* If the communication result is null, the baseObject won't be notified
* about how the communication ended. Actually, the thread in charge
* of the communication won't notify the baseObject, but update the request object.
*
* If the result is not null, result is the IndependentCommunications object that will
* contain the original request and the reply. At the end of the communication,
* the thread updates request
* with the reply message and the exception, and adds it into result.
*
* The base object is notified of the end of the threaded communication
* when the handleIndependentReply is called by the thread.
*
* @param comm The IndependentCommunication object that contain the RequestObject,
* and will contain after the communication the reply dataObject and the vector of exception
* @param result The IndependentCommunications object that may contain many IndependentCommunication
* object.
*
* @see context.arch.BaseObject#handleIndependentReply
* @see context.arch.comm.clients.IndependentCommunication
* @see context.arch.comm.clients.IndependentCommunications
* @see context.arch.util.RequesObject
*/
public void independentUserRequest(IndependentCommunication comm) throws EncodeException, InvalidEncoderException {
RequestObject request = comm.getRequest();
DataObject dobj = request.getNonEncodedData();
if (dobj != null) {
request.setEncodedData(encodeData(dobj));
}
communications.sendIndependentRequest(comm);
}
/**
* This method is called after the independentUserRequest has been called.
* The thread in charge of the communication sends the results to this method.
*
* This method should be overridden by classes that need to handle the responses.
*
* @param originalRequest The request sent by the thread
* @param reply The reply of the message
* @param exception If an exception occured during the communication, a copy of it
* @see context.arch.comm.clients.ClientsPool
* @see context.arch.comm.clients.Client
* @see context.arch.util.RequestObject
* @see context.arch.comm.DataObject
*/
public void handleIndependentReply(IndependentCommunication independentCommunication){
debugprintln(DEBUG, "BO <handleIndependentReply> " + independentCommunication);
//IndependentCommunication ic = (IndependentCommunication) independentCommunications.getNext ();
//println ("BO <handleIndependentReply> exceptions=" + ic.getExceptions ());
// Stores it... or call a method overridden by classes
return ;
}
/**
* This method allows a component to subscribe to changes in other components.
* The subscription includes the handler that will handle the callbacks,
* the subscriber's hostname and port, the subscription id, the remote component's
* hostname, port, and id, the remote component's callback, and the name of the
* subscriber's method that will handle the callback.
*
* @param handler Object that handles context widget callbacks
* @param remoteId Id of the context widget being subscribed to
* @param remoteHost Hostname of the widget being subscribed to
* @param remotePort Port number of the widget being subscribed to
* @param subscriber Subscriber object holding the subscription info
* @return Error to indicate success of subscription
* @see context.arch.handler.Handlers
* @see context.arch.handler.Handlers#addHandler(context.arch.handler.HandlerInfo)
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public Error subscribeTo(Handler handler, String remoteId, String remoteHost, int remotePort, ClientSideSubscriber subscriber) {
debugprintln(DEBUG, "\n\nBaseObject <subscribeTo>" + remoteId + " " + remotePort + " " + remoteHost + " - sub="+subscriber);
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, remoteId));
v.addElement(subscriber.toDataObject());
DataObject sub = new DataObject(Subscriber.ADD_SUBSCRIBER, v);
Error error = null;
try {
DataObject result = userRequest(new RequestObject(sub, Subscriber.ADD_SUBSCRIBER, remoteHost, remotePort));
debugprintln(DEBUG, "BO subscribeTo send=" + result);
error = new Error(result);
// Get the subscriber id sent by the widget
DataObject subId = result.getDataObject(AbstractSubscriber.SUBSCRIBER_ID);
if (subId != null) {
subscriber.setSubscriptionId(subId.getValue());
}
if (error.getError().equals(Error.NO_ERROR)) {
handlers.addHandler(new HandlerInfo(handler, subscriber.getSubscriptionId(), remoteId, remoteHost, remotePort,
subscriber.getSubscriptionCallback()));
}
return error;
} catch (EncodeException ee) {
System.out.println("BaseObject subscribeTo EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject subscribeTo DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject subscribeTo InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject subscribeTo InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject subscribeTo InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject subscribeTo ProtocolException: "+pe);
} catch (IOException ioe){
System.out.println("BaseObject subscribeTo IOException: "+ioe);
// set the error object
error = new Error(Error.IO_ERROR);
}
return error;
}
/**
* This method allows a component to unsubscribe from another component.
*
* @param handler Object that handles context widget callbacks
* @param remoteHost Hostname of the widget being unsubscribed from
* @param remotePort Port number of the widget being unsubscribed from
* @param remoteId Id of the context widget being unsubscribed from
* @param subscriber Subscriber object holding the subscription info
* @return Error to indicate success of unsubscription
* @see context.arch.handler.Handlers
* @see context.arch.handler.Handlers#removeHandler(context.arch.handler.HandlerInfo)
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public Error unsubscribeFrom(String subscriptionId) {
debugprintln(DEBUG, "BO <unsubscriberForm> id=" + subscriptionId);
DataObjects v = new DataObjects();
HandlerInfo info = handlers.getHandlerInfo(subscriptionId);
System.out.println("BO <unsubscriberFrom> info " + info);
v.addElement(new DataObject(ID, info.getRemoteId()));
v.addElement(new DataObject(Subscriber.SUBSCRIBER_ID, info.getSubId()));
DataObject sub = new DataObject(Subscriber.REMOVE_SUBSCRIBER, v);
Error error= null;
try {
DataObject result = userRequest(new RequestObject(sub, Subscriber.REMOVE_SUBSCRIBER, info.getRemoteHost(), info.getRemotePort()));
error = new Error(result);
if (error.getError().equals(Error.NO_ERROR)) {
handlers.removeHandler(subscriptionId);
}
return error;
} catch (EncodeException ee) {
System.out.println("BaseObject subscribeTo EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject subscribeTo DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject subscribeTo InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject subscribeTo InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject subscribeTo InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject subscribeTo ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject subscribeTo IOException: "+ioe);
error = new Error(Error.IO_ERROR);
}
return error;
}
/**
* This method allows a component to poll a remote widget for its attribute
* values. A list of attributes is provided to dictate which attribute
* values are wanted.
*
* @param widgetHost Hostname of the context widget being polled
* @param widgetPort Port number of the context widget being polled
* @param widgetId Id of the context widget being polled
* @param attributes Attributes being requested
* @return DataObject containing results of poll
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject pollWidget(String widgetHost, int widgetPort, String widgetId, Attributes attributes) {
debugprintln(DEBUG, "\nBaseObject <pollWidget> ");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, widgetId));
v.addElement(attributes.toDataObject());
DataObject poll = new DataObject(Constants.QUERY, v);
try {
return userRequest(new RequestObject(poll, Constants.QUERY, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject pollWidget EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject pollWidget DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject pollWidget InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject pollWidget InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject pollWidget InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject pollWidget ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject pollWidget IOException: "+ioe);
return ( new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method allows a component to force a remote widget to update its data
* and return it. A list of attributes is provided to dictate which attribute
* values are wanted.
*
* @param widgetHost Hostname of the context widget being polled
* @param widgetPort Port number of the context widget being polled
* @param widgetId Id of the context widget being polled
* @param attributes Attributes being requested
* @return DataObject containing results of poll
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject updateAndPollWidget(String widgetHost, int widgetPort, String widgetId, Attributes attributes) {
debugprintln(DEBUG, "\nBaseObject <updatePollWidget>");
// println("\nBaseObject <updatePollWidget> widgetId = " + widgetId + ", attributes = ");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, widgetId));
v.addElement(attributes.toDataObject());
DataObject poll = new DataObject(Constants.UPDATE_AND_QUERY, v);
try {
DataObject dataObj = userRequest(new RequestObject(poll, Constants.UPDATE_AND_QUERY, widgetHost, widgetPort));
return dataObj;
} catch (EncodeException ee) {
System.out.println("BaseObject pollWidget EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject pollWidget DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject pollWidget InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject pollWidget InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject pollWidget InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject pollWidget ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject pollWidget IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method allows a component to put context data in a remote
* widget. It is really intended for components that don't use
* the context toolkit, but is being included here for possible future
* use. The method takes a callback and an AttributeNameValues object.
* The callback is not necessary (can have a null value), and is only
* used by the remote widget to determine which of the widget's subscribers
* need to be updated.
*
* @param widgetHost Hostname of the context widget to use
* @param widgetPort Port number of the context widget to use
* @param widgetId Id of the context widget to use
* @param callback Callback of the context widget to associate the data with
* @param attributes AttributeNameValues to put in the widget
* @return DataObject containing results of put data
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject putDataInWidget(String widgetHost, int widgetPort, String widgetId,
String callback, Attributes attributes) {
debugprintln(DEBUG, "\nBaseObject <putDataInWidget>");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, widgetId));
if (callback != null) {
v.addElement(new DataObject(Subscriber.CALLBACK_NAME, callback));
}
v.addElement(attributes.toDataObject());
DataObject put = new DataObject(Constants.PUT_DATA, v);
try {
return userRequest(new RequestObject(put, Constants.PUT_DATA, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject putDataInWidget EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject putDataInWidget DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject putDataInWidget InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject putDataInWidget InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject putDataInWidget InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject putDataInWidget ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject putDataInWidget IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method gets the version of the given component (remoteHostname, widget, interpreter).
*
* @param remoteHost Hostname of the component being queried
* @param remotePort Port number of the component being queried
* @param remoteId Id of the component being queried
* @return DataObject containing version
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject getVersion(String remoteHost, int remotePort, String remoteId) {
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, remoteId));
DataObject query = new DataObject(Constants.QUERY_VERSION, v);
try {
return userRequest(new RequestObject(query, Constants.QUERY_VERSION, remoteHost, remotePort));
} catch (EncodeException ee) {
System.out.println("BaseObject getVersion EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject getVersion DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject getVersion InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject getVersion InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject getVersion InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject getVersion ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject getVersion IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method gets the callbacks of the given widget
*
* @param widgetHost Hostname of the widget being queried
* @param widgetPort Port number of the widget being queried
* @param widgetId Id of the widget being queried
* @return DataObject containing callbacks
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject getWidgetCallbacks(String widgetHost, int widgetPort, String widgetId) {
debugprintln(DEBUG, "\nBaseObject getWidgetCallbacks");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID,widgetId));
DataObject query = new DataObject(Constants.QUERY_CALLBACKS, v);
try {
return userRequest(new RequestObject(query, Constants.QUERY_CALLBACKS, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject getWidgetCallbacks EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject getWidgetCallbacks DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject getWidgetCallbacks InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject getWidgetCallbacks InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject getWidgetCallbacks InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject getWidgetCallbacks ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject getWidgetCallbacks IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method gets the services of the given widget
*
* @param widgetHost Hostname of the widget being queried
* @param widgetPort Port number of the widget being queried
* @param widgetId Id of the widget being queried
* @return DataObject containing services of the widget
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject getWidgetServices(String widgetHost, int widgetPort, String widgetId) {
debugprintln(DEBUG, "\nBaseObject getWidgetServices");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID,widgetId));
DataObject query = new DataObject(Constants.QUERY_SERVICES, v);
try {
return userRequest(new RequestObject(query, Constants.QUERY_SERVICES, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject getWidgetServices EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject getWidgetServices DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject getWidgetServices InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject getWidgetServices InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject getWidgetServices InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject getWidgetServices ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject getWidgetServices IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method gets the attributes of the given widget
*
* @param widgetHost Hostname of the widget being queried
* @param widgetPort Port number of the widget being queried
* @param widgetId Id of the widget being queried
* @return DataObject containing callbacks
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject getWidgetAttributes(String widgetHost, int widgetPort, String widgetId) {
debugprintln(DEBUG, "\nBaseObject getWidgetAttributes");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID,widgetId));
DataObject query = new DataObject(Constants.QUERY_ATTRIBUTES, v);
try {
return userRequest(new RequestObject(query, Constants.QUERY_ATTRIBUTES, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject getWidgetAttributes EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject getWidgetAttributes DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject getWidgetAttributes InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject getWidgetAttributes InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject getWidgetAttributes InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject getWidgetAttributes ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject getWidgetAttributes IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method gets the attributes of the given widget
*
* @param widgetHost Hostname of the widget being queried
* @param widgetPort Port number of the widget being queried
* @param widgetId Id of the widget being queried
* @return DataObject containing callbacks
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject getWidgetConstantAttributes(String widgetHost, int widgetPort, String widgetId) {
debugprintln(DEBUG, "\nBaseObject getWidgetConstantAttributes");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID,widgetId));
DataObject query = new DataObject(Widget.QUERY_CONSTANT_ATTRIBUTES, v);
try {
return userRequest(new RequestObject(query, Widget.QUERY_CONSTANT_ATTRIBUTES, widgetHost, widgetPort));
} catch (EncodeException ee) {
System.out.println("BaseObject getWidgetConstantAttributes EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject getWidgetConstantAttributes DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject getWidgetConstantAttributes InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject getWidgetConstantAttributes InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject getWidgetConstantAttributes InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject getWidgetConstantAttributes ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject getWidgetConstantAttributes IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method allows a component to retrieve data from other components.
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param retrieval Description of data to retrieve with any conditions
* @return DataObject containing data requested
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId, Retrieval retrieval) {
debugprintln(DEBUG, "\nBaseObject retrieveDataFrom");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, remoteId));
v.addElement(retrieval.toDataObject());
DataObject retrieve = new DataObject(StorageObject.RETRIEVE_DATA, v);
try {
return userRequest(new RequestObject(retrieve, StorageObject.RETRIEVE_DATA, remoteHost, remotePort));
} catch (EncodeException ee) {
System.out.println("BaseObject retrieveDataFrom EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject retrieveDataFrom DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject retrieveDataFrom InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject retrieveDataFrom InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject retrieveDataFrom InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject retrieveDataFrom ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject retrieveDataFrom IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method allows a component to retrieve data from other components.
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param myId Id of the "user" trying to access the data
* @param retrieval Description of data to retrieve with any conditions
* @return DataObject containing data requested
* @see #userRequest(context.arch.comm.DataObject, String, String, int)
*/
public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId, String myId, Retrieval retrieval) {
debugprintln(DEBUG, "\nBaseObject retrieveDataFrom");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, remoteId));
v.addElement(new DataObject("requestorId", myId));
v.addElement(retrieval.toDataObject());
DataObject retrieve = new DataObject(StorageObject.RETRIEVE_DATA, v);
try {
return userRequest(new RequestObject(retrieve, StorageObject.RETRIEVE_DATA, remoteHost, remotePort));
} catch (EncodeException ee) {
System.out.println("BaseObject retrieveDataFrom EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject retrieveDataFrom DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject retrieveDataFrom InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject retrieveDataFrom InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject retrieveDataFrom InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject retrieveDataFrom ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject retrieveDataFrom IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method returns a vector containing AttributeNameValues objects for all the
* the data of a given attribute.
* e.g. SQL query would be "SELECT attribute FROM table"
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param attribute Attribute to retrieve
* @return DataObject containing data requested
*/
// public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId, String attribute) {
// AttributeFunctions attributes = new AttributeFunctions();
// attributes.addAttributeFunction(attribute);
// return retrieveDataFrom(remoteHost,remotePort,remoteId,attributes);
// }
/**
* This method returns a vector containing AttributeNameValues objects for all the
* the data of the given attributes.
* e.g. SQL query would be "SELECT attribute1,attribute2,...,attributeN FROM table"
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param attributes Names of the attributes to retrieve data for
* @return DataObject containing data requested
*/
// public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId, AttributeFunctions attributes) {
// return retrieveDataFrom(remoteHost,remotePort,remoteId,new Retrieval(attributes, new Conditions()));
// }
/**
* This method returns a vector containing AttributeNameValues objects for all the
* the data of the given attributes and a single condition.
* e.g. SQL query would be "SELECT attribute1,attribute2,...,attributeN FROM table
* WHERE attributeX > valueY"
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param attributes Names of the attributes to retrieve data for
* @param attribute Name of the attribute to do conditional on
* @param compare Comparison flag
* @param value Comparison value to use
* @return DataObject containing data requested
*/
// public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId,
// AttributeFunctions attributes, String attribute, int compare, Object value) {
// Conditions conditions = new Conditions();
// conditions.addCondition(attribute,compare,value);
// return retrieveDataFrom(remoteHost,remotePort,remoteId,new Retrieval(attributes, conditions));
// }
/**
* This method returns a vector containing AttributeNameValues objects for all the
* the data.
* e.g. SQL query would be "SELECT * FROM table
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @return DataObject containing data requested
*/
// public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId) {
// return retrieveDataFrom(remoteHost,remotePort,remoteId,Attributes.ALL);
// }
/**
* This method returns a vector containing AttributeNameValues objects for all the
* the data and a single condition.
* e.g. SQL query would be "SELECT * FROM table WHERE attributeX > valueY
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param attribute Name of the attribute to do conditional on
* @param compare Comparison flag
* @param value Comparison value to use
* @return DataObject containing data requested
*/
// public DataObject retrieveDataFrom(String remoteHost, int remotePort, String remoteId,
// String attribute, int compare, Object value) {
// AttributeFunctions attributes = new AttributeFunctions();
// attributes.addAttributeFunction(Attributes.ALL);
// Conditions conditions = new Conditions();
// conditions.addCondition(attribute,compare,value);
// return retrieveDataFrom(remoteHost,remotePort,remoteId,new Retrieval(attributes, conditions));
// }
/**
* This method asks an interpreter to interpret some data. It passes the
* data to be interpreted and gets back the interpreted data.
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @param data AttributeNameValues object containing the data to be interpreted
* @return DataObject containing the interpreted data
*/
public DataObject askInterpreter(String remoteHost, int remotePort, String remoteId,
Attributes data) {
debugprintln(DEBUG, "\nBaseObject askInterpreter");
DataObjects v = new DataObjects();
DataObject interpret = new DataObject(Constants.INTERPRET, v);
v.addElement(new DataObject(ID, remoteId));
v.addElement(data.toDataObject());
try {
return userRequest(new RequestObject(interpret, Constants.INTERPRET, remoteHost, remotePort));
} catch (DecodeException de) {
System.out.println("BaseObject askInterpreter() Decode: "+de);
} catch (EncodeException ee) {
System.out.println("BaseObject askInterpreter() Encode: "+ee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject askInterpreter() InvalidDecoder: "+ide);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject askInterpreter() InvalidEncoder: "+iee);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject askInterpreter() InvalidProtocol: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject askInterpreter() Protocol: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject askInterpreter IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method asks an component to run some non-standard method. It passes
* id of the component, attributes, and parameters and gets back the result
* of the method.
*
* @param remoteHost Hostname of the component
* @param remotePort Port number of the component
* @param remoteId Id of the component
* @param methodName Name of the method to run
* @param parameters AttributeNameValues object that is parameters with values
* @param attributes Attributes object that is parameters with values
* @return DataObject containing the interpreted data
*/
public DataObject runComponentMethod(String remoteHost, int remotePort, String remoteId,
String methodName,Attributes parameters, Attributes attributes) {
debugprintln(DEBUG, "\nBaseObject runcomponentMethod");
DataObjects v = new DataObjects();
DataObject method = new DataObject(methodName, v);
v.addElement(new DataObject(ID, remoteId));
if (parameters != null) {
v.addElement(parameters.toDataObject());
}
if (attributes != null) {
v.addElement(attributes.toDataObject());
}
try {
return userRequest(new RequestObject(method, methodName, remoteHost, remotePort));
} catch (DecodeException de) {
System.out.println("BaseObject runComponentMethod() Decode: "+de);
} catch (EncodeException ee) {
System.out.println("BaseObject runComponentMethod() Encode: "+ee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject runComponentMethod() InvalidDecoder: "+ide);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject runComponentMethod() InvalidEncoder: "+iee);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject runComponentMethod() InvalidProtocol: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject runComponentMethod() Protocol: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject runComponentMethod IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method requests that a widget execute an asynchronous service
*
* @param handler Handler to handle the results of the service
* @param serviceHost Hostname of the widget with the service
* @param servicePort Port number of the widget with the service
* @param serviceId Id of the widget with the service
* @param service Name of the widget service to run
* @param function Name of the particular service function to run
* @param input AttributeNameValues object to use to execute the service
* @param requestTag Unique tag provided by caller to identify result
* @return DataObject containing the results of the execution request
*/
@Override
public DataObject executeAsynchronousWidgetService(AsyncServiceHandler handler, String serviceHost, int servicePort,
String serviceId, String service, String function, Attributes input, String requestTag) {
debugprintln(DEBUG, "\nBaseObject executeAsynchronousWidgetService");
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, serviceId));
v.addElement(new DataObject(FunctionDescription.FUNCTION_SYNCHRONICITY, FunctionDescription.FUNCTION_ASYNC));
v.addElement(new ServiceInput(
serviceId, service, function, input, getHostAddress(), communications.getServerPort(),
getId(),requestTag).toDataObject());
DataObject request = new DataObject(Service.SERVICE_REQUEST, v);
try {
DataObject result = userRequest(new RequestObject(request, Service.SERVICE_REQUEST, serviceHost, servicePort));
Error error = new Error(result);
if (error.getError().equals(Error.NO_ERROR)) {
serviceHandlers.addHandler(new AsyncServiceHandlerInfo(handler,getId(),serviceId,service,function,requestTag));
}
return result;
} catch (DecodeException de) {
System.out.println("BaseObject executeWidgetService() Decode: "+de);
} catch (EncodeException ee) {
System.out.println("BaseObject executeWidgetService() Encode: "+ee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject executeWidgetService() InvalidDecoder: "+ide);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject executeWidgetService() InvalidEncoder: "+iee);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject executeWidgetService() InvalidProtocol: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject executeWidgetService() Protocol: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject executeWidgetService IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method requests that a widget execute a synchronous service
*
* @param remoteHost Hostname of the widget
* @param remotePort Port number of the widget
* @param remoteId Id of the widget
* @param service Name of the widget service to run
* @param function Name of the particular service function to run
* @param input AttributeNameValues object to use to execute the service
* @return DataObject containing the results of the execution request
*/
@Override
public DataObject executeSynchronousWidgetService(
String remoteHost, int remotePort, String remoteId,
ServiceInput serviceInput) {
DataObjects v = new DataObjects();
v.addElement(new DataObject(ID, remoteId));
v.addElement(new DataObject(FunctionDescription.FUNCTION_SYNCHRONICITY, FunctionDescription.FUNCTION_SYNC));
v.addElement(serviceInput.toDataObject());
DataObject request = new DataObject(Service.SERVICE_REQUEST, v);
try {
return userRequest(new RequestObject(request, Service.SERVICE_REQUEST, remoteHost, remotePort));
} catch (DecodeException de) {
System.out.println("BaseObject executeWidgetService() Decode: "+de);
} catch (EncodeException ee) {
System.out.println("BaseObject executeWidgetService() Encode: "+ee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject executeWidgetService() InvalidDecoder: "+ide);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject executeWidgetService() InvalidEncoder: "+iee);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject executeWidgetService() InvalidProtocol: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject executeWidgetService() Protocol: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject executeWidgetService IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method pings a component (widget,remoteHostname, or interpreter)
* to make sure that it is functioning ok.
*
* @param remoteHost Hostname of the component being asked for data
* @param remotePort Port number of the component being asked for data
* @param remoteId Id of the component being asked for data
* @return DataObject containing the results of the ping
*/
public DataObject pingComponent(String remoteHost, int remotePort, String remoteId, boolean independentCom) {
DataObjects v = new DataObjects();
DataObject ping = new DataObject(PING, v);
v.addElement(new DataObject(ID, remoteId));
try {
return userRequest(new RequestObject(ping, PING, remoteHost, remotePort));
} catch (DecodeException de) {
System.out.println("BaseObject pingComponent() Decode: "+de);
} catch (EncodeException ee) {
System.out.println("BaseObject pingComponent() Encode: "+ee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject pingComponent() InvalidDecoder: "+ide);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject pingComponent() InvalidEncoder: "+iee);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject pingComponent() InvalidProtocol: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject pingComponent() Protocol: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject pingComponent IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
public void pingComponent(IndependentCommunication independentCommunication){
debugprintln(DEBUG, "baseObject <ping independent> ");
DataObjects v = new DataObjects();
DataObject ping = new DataObject(PING, v);
v.addElement(new DataObject(ID, independentCommunication.getRequest().getReceiverId()));
independentCommunication.getRequest().setUrl(BaseObject.PING);
independentCommunication.getRequest().setData(ping);
try {
independentUserRequest(independentCommunication);
return ;
}
catch (EncodeException ee) {
System.out.println("BaseObject <pingComponent> Encode: "+ee);
} catch (InvalidEncoderException ide) {
System.out.println("BaseObject <pingComponent> InvalidEncoder: "+ide);
}
}
/**
* This method should be called when the object is going to exit
* under normal conditions. It stops the CommunicationsObject from
* receiving any more requests and exits.
*
* @see context.arch.comm.CommunicationsObject#quit()
*/
public void quit() {
communications.quit();
//System.exit(EXIT_OK);
}
/**
* This is an empty method that should be overridden by the object that
* extends this class. It will contain the user-defined RPCs.
*
* @param data DataObject containing data for user-defined RPC
* @return result of RPC
* @exception context.arch.InvalidMethodException thrown if specified RPC couldn't be found
* @exception context.arch.MethodException thrown if specified RPC had an error
* @see #runMethod(String, DataObject)
*/
public DataObject runUserMethod(DataObject data) throws InvalidMethodException, MethodException {
String name = data.getName();
Error err = new Error();
err.setError(Error.UNKNOWN_METHOD_ERROR);
DataObjects v = new DataObjects();
v.addElement(err.toDataObject());
return new DataObject(name, v);
}
/**
* This method handles both the system-defined, callbacks and user-defined RPCs.
* If a user-defined RPC is called, this method calls runUserMethods. If a
* callback is specified, this method runs userCallback. Currently, the only
* system-defined methods are queryVersion, and userCallback.
*
* @param methodType Name of method to run
* @param data DataObject containing data for the method call
* @exception context.arch.InvalidMethodException thrown if specified RPC couldn't be found
* @exception context.arch.MethodException thrown if specified RPC had an error
* @see #userCallback(context.arch.comm.DataObject)
* @see #runUserMethod(context.arch.comm.DataObject)
* @see #queryVersion(context.arch.comm.DataObject)
* @see #setDiscoverer(context.arch.comm.DataObject)
*/
public DataObject runMethod(String methodType, DataObject data) throws InvalidMethodException, MethodException {
debugprintln(DEBUG, "\nBaseObject runMethod " + methodType);
// System.out.println("BaseObject.runMethod methodType = " + methodType);
// System.out.println("BaseObject.runMethod data = " + data);
if (methodType.equals(AbstractSubscriber.SUBSCRIPTION_CALLBACK)) {
return userCallback(data);
}
if (methodType.equals(Constants.QUERY_VERSION)) {
return queryVersion(data);
}
else if (methodType.equals(PING)) {
return returnPing(data);
}
else if (methodType.equals(Service.SERVICE_RESULT)) {
return serviceResult(data);
}
else if (methodType.equals(Discoverer.LOOKUP_DISCOVERER_REPLY)){
return setDiscoverer(data);
}
else if (methodType.equals(Lease.LEASE_END_NOTIFICATION)){
return leaseEndNotified(data);
}
else if (methodType.equals(QUERY_DESCRIPTION)){
return toDataObject();
}
/*else if (methodType.equals (DiscovererSubscriber.SUBSCRIPTION_CALLBACK)){
return discovererSubscriptionNotification(data);
}*/
return runUserMethod(data);
}
/**
* This method is called when a callback message is received. It determines which
* of its registered handlers should receive the callback message and passes it on
* accordingly. It creates a reply message to the callback request in the form
* of a DataObject. It handles all error checking.
*
* @param data DataObject containing the callback request
* @return DataObject containing the callback reply
* @see context.arch.handler.Handlers#getHandler(String)
* @see context.arch.handler.Handler#handleSubscriptionCallback(String, context.arch.comm.DataObject)
*/
public DataObject userCallback(DataObject data) {
debugprintln(DEBUG, "\nBaseObject <userCallback> get a subscription notification");
DataObjects v = new DataObjects();
Error error = new Error();
String subId = null;
DataObject subIdObj = data.getChild(Subscriber.SUBSCRIBER_ID);
//DataObject callbackObj = data.getDataObject(Subscriber.CALLBACK_TAG);
DataObject value = data.getChild(Discoverer.REGISTERER); //For callback from widget, contains the component ID
DataObject discoValue = data.getChild(Discoverer.DISCOVERER_QUERY_REPLY_CONTENT); // For callback from discoverer
// TODO: try to separate processing discoValue and value
debugprintln(DEBUG, "BO subId = " + subIdObj + "\nBO- att value " + value + "\nBO- discoValue" + discoValue);
// new RuntimeException("BaseObject.userCallback value = " + value).printStackTrace();
if (subIdObj == null || (value == null && discoValue == null)) {
if (subIdObj != null) {
v.addElement(new DataObject(Subscriber.SUBSCRIBER_ID, subIdObj.getValue()));
}
error.setError(Error.MISSING_PARAMETER_ERROR);
}
else {
subId = subIdObj.getValue();
//String callback = (String)callbackObj.getValue().firstElement();
Handler handler = handlers.getHandler(subId);
DataObject result = null; // the result returned by the handler
if (handler != null) {
try {
if (discoValue != null) { // discoverer callback
debugprintln(DEBUG, "\nBO userCallback comes from discoverer");
debugprintln(DEBUG, "\n\n\nBO sends disco notification to Handler id" + subId);
result = handler.handleSubscriptionCallback(subId, discoValue);
} else { // any widget callback
result = handler.handleCallback(subId, value);
}
} catch (InvalidMethodException ime) {
System.out.println("BaseObject <userCallback> error: InvalidMethod: " + ime);
error.setError(Error.UNKNOWN_CALLBACK_ERROR);
return new DataObject(Subscriber.SUBSCRIPTION_CALLBACK_REPLY, v);
} catch (MethodException me) {
System.out.println("BaseObject <userCallback> error Method: " + me);
error.setError(Error.MISSING_PARAMETER_ERROR);
}
if (error.getError() == null) {
error.setError(Error.NO_ERROR);
if (result != null) {
v.addElement(result);
}
}
}
else {
error.setError(Error.UNKNOWN_SUBSCRIBER_ERROR);
}
v.addElement(new DataObject(Subscriber.SUBSCRIBER_ID,subId));
}
v.addElement(error.toDataObject());
return new DataObject(Subscriber.SUBSCRIPTION_CALLBACK_REPLY,v);
}
/**
* Returns the list of handlers this object made. A handler is defined
* for a subscription to a widget, or the discoverer
*/
public String getListOfHandlers() {
StringBuffer sb = new StringBuffer();
for (HandlerInfo hInfo : handlers.getHandlers()) {
sb.append("\n");
sb.append(hInfo.toString());
}
return sb.toString();
}
/**
* This method returns the version number of this component.
*
* @param query DataObject containing the query
* @return DataObject containing the results of the query
*/
public DataObject queryVersion(DataObject query) {
DataObject component = query.getDataObject(ID);
Error error = new Error();
if (component == null) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
String queryId = component.getValue();
if (!queryId.equals(getId())) {
error.setError(Error.INVALID_ID_ERROR);
}
}
DataObjects v = new DataObjects();
if (error.getError() == null) {
v.addElement(new DataObject(Constants.VERSION, getVersion()));
error.setError(Error.NO_ERROR);
}
v.addElement(error.toDataObject());
return new DataObject(Constants.QUERY_VERSION_REPLY, v);
}
/**
* This method returns an error message as an answer to a ping.
*
* @param ping DataObject containing the ping request
* @return DataObject containing the results of the ping
*/
public DataObject returnPing(DataObject ping) {
DataObject component = ping.getDataObject(ID);
Error error = new Error();
if (component == null) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
String pingId = component.getValue();
if (!pingId.equals(getId())) {
error.setError(Error.INVALID_ID_ERROR);
}
}
DataObjects v = new DataObjects();
if (error.getError() == null) {
error.setError(Error.NO_ERROR);
}
v.addElement(error.toDataObject());
return new DataObject(PING_REPLY, v);
}
/**
* This method handles the results of an asynchronous service request.
*
* @param result DataObject containing the results of the aysnchronous service request
* @return DataObject containing a reply to the results message
*/
public DataObject serviceResult(DataObject result) {
debugprintln(DEBUG, "\nBaseObject serviceResult");
DataObject component = result.getDataObject(ID);
Error error = new Error();
DataObjects v = new DataObjects();
DataObject result2 = null;
if (component == null) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
String resultId = component.getValue();
if (!resultId.equals(getId())) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
ServiceInput si = new ServiceInput(result);
AsyncServiceHandler handler = serviceHandlers.getHandler(resultId+si.getServiceId()+si.getServiceName()+si.getFunctionName()+si.getRequestTag());
if (handler != null) {
try {
result2 = handler.asynchronousServiceHandle(si.getRequestTag(),result);
} catch (InvalidMethodException ime) {
System.out.println("BaseObject serviceResult InvalidMethod: "+ime);
error.setError(Error.INVALID_REQUEST_ERROR);
} catch (MethodException me) {
System.out.println("BaseObject serviceResult Method: "+me);
error.setError(Error.MISSING_PARAMETER_ERROR);
}
if (error.getError() == null) {
error.setError(Error.NO_ERROR);
if (result2 != null) {
v.addElement(result2);
}
}
serviceHandlers.removeHandler(new AsyncServiceHandlerInfo(handler,resultId,si.getServiceId(),
si.getServiceName(),si.getFunctionName(),si.getRequestTag()));
}
else {
error.setError(Error.INVALID_REQUEST_ID_ERROR);
}
}
}
v.addElement(error.toDataObject());
return new DataObject(Service.SERVICE_RESULT_REPLY, v);
}
/**
* This method returns the version number of this object.
*
* @return version number
*/
public String getVersion() {
return version;
}
/**
* This method sets the version number of this object.
*
* @param version of the object
*/
public void setVersion(String version) {
this.version = version;
}
/**
* This method sets the id of classes that subclass this object, for use
* in sending messages.
*
* @param id ID of the class
*/
public void setId(String id) {
this.id = id;
}
/**
* This method returns the id of the class that subclass this object, for use
* in sending messages.
*
* @return id of the class
*/
public String getId() {
return id;
}
/**
* Returns a uniq id constructed as classname_hostname_port_givenUserLocation,
* or if there is an error, returns the user location given by the user.
*
* @param location The location string used as indentifier for a context component
* @param className The classname of the object
* @param port The port of the object
* @return String The uniq identification
* @author Agathe
*/
public static String createId(String className, int port){
return BaseObject.createId(className, String.valueOf(port));
}
/**
* Convenience method to create an ID for the base object.
* @param className
* @param suffix
* @return className + {@link Constants.SPACER} + hostname + Constants.SPACER + suffix
*/
public static String createId(String className, String suffix) {
String hostname;
try {
InetAddress inet = InetAddress.getLocalHost();
hostname = inet.getHostName();
return className + Constants.SPACER + hostname + Constants.SPACER + suffix;
}
catch(UnknownHostException uhe){
System.out.println("Discoverer getId(String, int) UnknownHostException " + uhe.toString());
}
return className + suffix;
}
/**
* Returns the type of the component in the Context Toolkit framework.
* This method should be overridden.
*
* @return String
*/
public String getType() {
return BaseObject.BASEOBJECT_TYPE;
}
/**
* This method gets the address of the machine this component is running on.
*
* @return the address of the machine this component is running on
*/
public String getHostAddress() {
if (host != null) {
return host;
}
try {
host = InetAddress.getLocalHost().getHostAddress();
InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException uhe) {
System.out.println("BaseObject UnknownHost: "+uhe);
}
if (host == null) {
return new String("127.0.0.1");
}
return host;
}
private static String hostname;
/**
* This method gets the name of the machine this component is running on.
* @return the name of the machine this component is running on
*/
public static String getHostName() {
if (hostname != null) { return hostname; }
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException uhe) {
System.out.println("BaseObject UnknownHost : "+uhe);
}
if (hostname == null) {
return new String("localhost");
}
return hostname;
}
/**
*
*/
public int getPort(){
return communications.getServerPort();
}
/**
* This method handles the lookup response from the discoverer. It sets the discoverer
* description. And returns an error code
*
* @param result DataObject containing the results of the discoverer description
* @return DataObject En error code
* @see context.arch.discoverer.DiscovererDescription
* @author Agathe
*/
public DataObject setDiscoverer(DataObject data){
debugprintln(DEBUG, "\nBaseObject <setDiscoverer>");
DataObject component = data.getDataObject(ID);
Error error = new Error();
DataObjects v = new DataObjects();
// DataObject result = null; // was not being used
if (component == null) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
String resultId = component.getValue();
if (!resultId.equals(getId())) {
error.setError(Error.INVALID_ID_ERROR);
}
else {
// Get the information about the discoverer from the data
DataObject disco = data.getDataObject(Discoverer.DISCOVERER);
if (discoverer == null){
discoverer = new DiscovererDescription();
}
Error errDisco = discoverer.setDescription(disco);
error.setError(errDisco.getError());
}
}
v.addElement(new DataObject(ID, discoverer.getName()));
v.addElement(error.toDataObject());
return new DataObject(Discoverer.LOOKUP_DISCOVERER_OK, v);
}
/**
* This method is used to send the component description to the discoverer.
* It sends a DISCOVERER_REGISTRATION message to the discoverer
* with the object description.
* It
*
* @return Error The error code of the registration
* @see context.arch.discoverer.ComponentDescription
* @author Agathe
*/
public Error discovererRegistration(){
// For the first call without specified lease
if (myLease != null)
return discovererRegistration(new Lease());
else
return discovererRegistration(myLease);
}
/**
* This method is used to send the component description to the discoverer.
* It sends a DISCOVERER_REGISTRATION message to the discoverer
* with the object description
*
* @param lease The lease specified for the registration
* @return Error The error code of the registration
* @see context.arch.discoverer.ComponentDescription
* @author Agathe
*/
public Error discovererRegistration(Lease registrationLease){
// If discoverer == null, we don't register, because it has not been found
if (discoverer == null){
return new Error("Discoverer not enabled");
}
// Update myLease field
if (registrationLease != null){
myLease = registrationLease;
}
else {
myLease = new Lease();
}
// Get the description of this object (list of attributes,...)
Error error = null;
DataObject description = toDataObject();
try {
DataObject result = userRequest(new RequestObject(description,Discoverer.DISCOVERER_REGISTRATION,discoverer.getHostname(),discoverer.getPort()));
error = new Error(result);
debugprintln(DEBUG, "\nBaseObject <discovererRegistration> error:" + error.toString());
return error;
} catch (IOException ioe) {
System.out.println("BaseObject discovererRegistration IOException: "+ioe);
error = new Error(Error.IO_ERROR);
} catch (Exception e) {
System.out.println("BaseObject discovererRegistration: " + e);
}
return error;
}
/**
* Get the ComponentDescription representation of the BaseObject
* @return
*/
public ComponentDescription getComponentDescription() {
return ComponentDescription.fromDataObject(toDataObject());
}
/**
* Returns the common description of the component in DataObject form.
*
* @return DataObject It contains the component description
* @see context.arch.discoverer.ComponentDescription
* @see #getUserDataObject()
* @author Agathe
*/
public synchronized DataObject toDataObject() {
if (discoverer==null){
return null;
}
else {
//<id>
DataObject discoId = new DataObject(ID,discoverer.getName());
//<registerId>
DataObject regId = new DataObject(Discoverer.ID, getId());
//<hostname>
DataObject regHost = new DataObject(Discoverer.HOSTNAME, getHostName());
//<hostAddress>
DataObject regAddress = new DataObject(Discoverer.HOSTADDRESS, getHostAddress());
//<port>
DataObject regPort = new DataObject(Discoverer.PORT, new Integer(communications.getServerPort()).toString());
//<className>
DataObject regClass = new DataObject(Discoverer.COMPONENT_CLASSNAME,
// getClass().getName()); // using some proprietary naming method
getClassname());
//<version>
DataObject regVersion = new DataObject(Discoverer.VERSION, getVersion());
// Returns the type : application
DataObject regType = new DataObject(Discoverer.TYPE, getType());
DataObjects v1 = new DataObjects();
v1.addElement(regId);
v1.addElement(regHost);
v1.addElement(regAddress);
v1.addElement(regPort);
v1.addElement(regClass);
v1.addElement(regVersion);
v1.addElement(regType);
//Get the specific description
DataObject doDescrip = getUserDataObject();
if (doDescrip != null) {
// Add the content of vDescrip to v1
for (DataObject child : doDescrip.getChildren()){
v1.addElement(child);
}
}
DataObject regist = new DataObject(Discoverer.REGISTERER, v1);
DataObjects v2 = new DataObjects();
v2.addElement(discoId); // the disco Id
v2.addElement(regist); // the description
v2.addElement(myLease.toDataObject()); // the lease
DataObject result = new DataObject(Discoverer.DISCOVERER_REGISTRATION, v2);
return result;
}
}
/**
* Essentially equivalent to Object.getClass().getName(), but may be overridden,
* particularly, for surrogate components that use other methods (e.g. Reflection, or XML)
* to create instances.
*
* @return
*/
public String getClassname() {
return this.getClass().getName();
}
/**
* Returns the added description of the component
* That method should be overriden. If not, we deduct that
* the current object is an application
*
* @return DataObject The description
* @see context.arch.discoverer.Discoverer
* @author Agathe
*/
public DataObject getUserDataObject(){
// Does nothing
return null;
}
/**
* This method allows to find a discoverer. The component sends a multicast
* message containing its id, port, hostname. The response of the existing
* discoverer is handled by another method. It sends a LOOOKUP_DISCOVERER
* message.
* By default, the component registers the discoverer and the end of the lease
* is confirmed automatically.
*
* @return Error The error object
*/
protected Error findDiscoverer() {
return findDiscoverer(false, getLease(), true);
}
/**
* This method allows to find a discoverer. The component sends a multicast
* message containing its id, port, hostname. The response of the existing
* discoverer is handled by another method. It sends a LOOOKUP_DISCOVERER
* message.
* The component register the discoverer if registration is set true.
* It sends a default lease
*
* @param registration True if the component registers the discoverer
* @return Error The error object
* @see context.arch.discoverer.lease.Lease
*/
protected Error findDiscoverer(boolean registration){
return findDiscoverer(registration, getLease(), true);
}
/**
* This method allows to find a discoverer. The component sends a multicast
* message containing its id, port, hostname. The response of the existing
* discoverer is handled by another method. It sends a LOOOKUP_DISCOVERER
* message.
*
* /lookup
* caller
* callerId
* type
* hostname
* port
* /caller
* /lookup
*
* @return Error An error code
* @see #setDiscoverer(context.arch.comm.DataObject)
* @see context.arch.discoverer.Discoverer
* @author Agathe
*/
protected Error findDiscoverer(boolean registration, Lease registrationLease, boolean automaticRenewal) {
debugprintln(DEBUG, "BO <findDiscoverer>");
discoverer = new DiscovererDescription();
debugprintln(DEBUG, discoverer);
this.automaticRenewal = automaticRenewal;
if (discoverer != null && discoverer.getName() == null) {
debugprintln(DEBUG, "in loop");
// DataObject callerId, type, hostname, port; // type was not being used
DataObject callerId, hostname, port;
Error error = new Error();
callerId = new DataObject(Discoverer.CALLER_ID, getId());
hostname = new DataObject(Discoverer.HOSTNAME, getHostAddress());
port = new DataObject(Discoverer.PORT, new Integer(communications.getServerPort()).toString());
DataObjects v = new DataObjects();
v.addElement(callerId);
v.addElement(hostname);
v.addElement(port);
DataObject caller = new DataObject(Discoverer.CALLER, v);
DataObjects vCaller = new DataObjects();
vCaller.addElement(caller);
DataObject lookup = new DataObject(Discoverer.LOOKUP_DISCOVERER, vCaller);
try {
/* Find the discoverer */
String encoded = encodeData(lookup);
// Delay for sending a new multicast message each (delay * inc*=2)
long delay = 1000l;
int inc = 1;
externLoop:
do {
communications.sendMulticastRequest(encoded, Discoverer.LOOKUP_DISCOVERER);
debugprintln(DEBUG, "BO <findDiscoverer> has sent a multicast message and now is waiting for = " + delay * (long)inc);
// TODO: this looping wait functionality should be delegated to DiscovererDescription
synchronized (discoverer) {
discoverer.waitAvailable(delay * (long)inc);
}
if (discoverer.available) {
break externLoop;
}
inc *= 2; // lengthen waiting time
} while (discoverer.getName() == null && inc < 10); // Wait for discoverer' information
// Registers to the discoverer if asked
Error err = null;
if (registration) {
err = discovererRegistration(registrationLease);
}
if (err == null){
return null;
}
else {
error.setError(err.getError());
return error;
}
}
catch (EncodeException ee){
System.out.println("BaseObject findDiscoverer EncodeException " + ee);
}
catch (ProtocolException pe){
System.out.println("BaseObject findDiscoverer ProtocolException " + pe);
}
catch (InvalidEncoderException iee){
System.out.println("BaseObject findDiscoverer InvalidEncoderException " + iee);
}
catch(NullPointerException npe){
System.out.println("BaseObject findDiscoverer NullPointerException " + npe);
System.out.println("Vector v="+v.toString());
System.out.println("lookup="+lookup.toString());
npe.printStackTrace();
}
}
return null;
}
/**
* Must call this method to start the BaseObject.
* It calls {@link #init()} and finds the discover.
* @param register whether to register when finding the Discoverer.
* If register == null, then it doesn't find the discoverer.
*/
public void start(Boolean register) {
findDiscoverer(register);
}
/**
* This method allows to send a message to the discoverer
* to update its own description stored in the discoverer.
* It sends a DISCOVERER_UPDATE message.
*
* @param data The DataObject containing the modified fields
* @param updateType The update type used by the discoverer : it may be
* the add type or the replace type. (Discoverer.UPDATE_ADD_TYPE or Discoverer.UPDATE_REPLACE_TYPE)
* @return Error The error code received from the discoverer
* @see context.arch.discoverer.Discoverer
* @author Agathe
*/
public Error discovererUpdate() {
// Do nothing if the discoverer is null. That is: the discovery system has
// not been enabled
if (discoverer == null){
return new Error("Discoverer not enabled");
}
else {
DataObject data = toDataObject();
debugprintln(DEBUG, "BaseObject <discovererUpdate>");
// Add the tag ID
DataObjects v1 = new DataObjects();
v1.addElement(new DataObject(ID, discoverer.getName()));
DataObjects v2 = new DataObjects();
v2.addElement(new DataObject(Discoverer.ID, getId()));
v2.addElement(data);
v1.addElement(new DataObject(Discoverer.REGISTERER, v2));
DataObject toSend = new DataObject(Discoverer.DISCOVERER_UPDATE, v1);
// IndependentCommunication
RequestObject r = new RequestObject(toSend, Discoverer.DISCOVERER_UPDATE,
discoverer.getHostname(), discoverer.getPort());
try {
IndependentCommunication ic = new IndependentCommunication(r);
independentUserRequest(ic);
}
catch (EncodeException e) {
System.out.println("BaseObject <discovererUpdate> EncodeException");
}
catch (InvalidEncoderException e) {
System.out.println("BaseObject <discovererUpdate> InvalidEncoderException");
}
return new Error();
}
}
/**
* This method is used to subscribe to the discoverer.
*
*
*
*/
public void discovererSubscribe(Handler handler, DiscovererSubscriber discoSub){
if (discoverer == null){
return ;
}
debugprintln(DEBUG, "\nBO <discovererSubscribe>");
// Sends the subscription to the discoverer
DataObject result = discovererSendSubscription(handler, discoSub);
// Has got the result, converts it into a Response object
if (result != null){
DataObject doError = result.getDataObject(Error.ERROR_CODE);
if ( doError != null){
debugprintln(DEBUG, "BO <discovererSubscribe> error = " + doError.toString());
}
else {
DataObject answer = result.getDataObject(Discoverer.DISCOVERER_QUERY_REPLY_CONTENTS);
debugprintln(DEBUG, "\nBO discoverQuery answer (discoqueryreplycontent) = " + answer);
}
}
}
/**
*
*
* to improve
*/
protected DataObject discovererSendSubscription(Handler handler, DiscovererSubscriber discoSub){
if (discoverer == null){
return null;
}
DataObject result;
// Specifies the id of the discoverer
DataObjects v1 = new DataObjects();
v1.addElement(new DataObject(ID, discoverer.getName()));
v1.addElement(discoSub.toDataObject());
DataObjects v = new DataObjects();
v.addElement(discoSub.getQuery().toDataObject());
v1.addElement(new DataObject(Discoverer.DISCOVERER_QUERY_CONTENT, v));
DataObject toSend = new DataObject(Discoverer.DISCOVERER_SUBSCRIBE, v1);
//println("BaseObject discovererSubscribe - description :"+toSend.toString ());
try {
Error error;
result = userRequest(toSend, Discoverer.DISCOVERER_SUBSCRIBE,discoverer.getHostname(), discoverer.getPort());
error = new Error(result);
if (error.getError().equals(Error.NO_ERROR)) {
//Update the sub id
discoSub.setSubscriptionId(result.getDataObject(AbstractSubscriber.SUBSCRIBER_ID).getValue());
handlers.addHandler(new HandlerInfo(handler, discoSub.getSubscriptionId(), discoverer.getName(), discoverer.getHostname(),
discoverer.getPort(), discoSub.getSubscriptionCallback()));
}
return result;
} catch (EncodeException ee) {
System.out.println("BaseObject discovererQuery EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject discovererQuery DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject discovererQuery InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject discovererQuery InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject discovererQuery InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject discovererQuery ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject discovererQuery IOException: "+ioe);
return (new Error(Error.IO_ERROR)).toDataObject();
}
return null;
}
/**
* This method allows to send a query to the discoverer.
*
* @param query The Query object containing the request for the discoverer
* @return ComponentDescription When the discoverer has found a context object corresponding to
* the request, the ComponentDescription object contains information about it, else it is null
* @author Agathe
* @see #discovererQuery(DataObject)
*/
public Collection<ComponentDescription> discovererQuery(AbstractQueryItem<?,?> query){
// System.err.println("BaseObject.discovererQuery query " + query);
if (discoverer == null){ return null; }
debugprintln(DEBUG, "BO discovererQuery");
DataObject result = discovererQuery(query.toDataObject());
// System.err.println("BaseObject.discovererQuery result " + result);
// Converts the result into a Response object
if (result != null){
DataObject doError = result.getDataObject(Error.ERROR_CODE);
if (doError != null) {
debugprintln(DEBUG, "BO discoverer Query error = " + doError.toString());
return null;
}
else {
DataObject reply = result.getDataObject(Discoverer.DISCOVERER_QUERY_REPLY_CONTENTS);
debugprintln(DEBUG, "\nBO discoverQuery answer = " + reply);
DataObjects replyChildren = reply.getChildren();
Collection<ComponentDescription> compResults = null;
if (replyChildren != null){
compResults = new ArrayList<ComponentDescription>(); // extract ComponentDescription's from DataObject's
for (DataObject replyChild : replyChildren){
compResults.add(ComponentDescription.fromDataObject(replyChild));
}
}
return compResults;
}
}
// no result
return null;
}
/**
* This method allows to send a query to the discoverer containing the
* description of the context component the object would like to know.
* It sends a DISCOVERER_QUERY message
*
* @param query The Query containing the asked component description
* @return DataObject The result from the discoverer containing the first
* component description fitting the request
* @see context.arch.discoverer.Discoverer
* @author Agathe
*/
protected DataObject discovererQuery(DataObject data){
DataObject result;
// Adds the tag ID
DataObjects v1 = new DataObjects();
v1.addElement(new DataObject(ID, discoverer.getName()));
DataObjects v2 = new DataObjects();
v2.addElement(new DataObject(Discoverer.CALLER_ID, getId()));
v2.addElement(new DataObject(Discoverer.HOSTNAME, getHostAddress()));
v2.addElement(new DataObject(Discoverer.PORT, new Integer(communications.getServerPort()).toString()));
v1.addElement(new DataObject(Discoverer.CALLER, v2));
DataObjects v = new DataObjects();
v.addElement(data);
v1.addElement(new DataObject(Discoverer.DISCOVERER_QUERY_CONTENT, v));
DataObject toSend = new DataObject(Discoverer.DISCOVERER_QUERY, v1);
// System.out.println("BaseObject.discovererQuery toSend: " + toSend);
try {
result = userRequest(toSend, Discoverer.DISCOVERER_QUERY, discoverer.getHostname(), discoverer.getPort());
// System.out.println("BaseObject.discovererQuery result: " + result);
return result;
} catch (EncodeException ee) {
System.out.println("BaseObject discovererQuery EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject discovererQuery DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject discovererQuery InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject discovererQuery InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject discovererQuery InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject discovererQuery ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject discovererQuery IOException: "+ioe);
return new Error(Error.IO_ERROR).toDataObject();
}
return null; // some exception happened
}
/**
* This method allows to unregister from the discoverer
*
* @return Error The error message
* @see context.arch.discoverer.Discoverer
*/
public Error discovererUnregistration(){
// Do nothing if the discoverer is null
if (discoverer == null){
return new Error("Discoverer not enabled");
}
Error error = new Error();
DataObject toSend;
// Adds the tag ID
DataObjects v1 = new DataObjects();
v1.addElement(new DataObject(ID, discoverer.getName()));
// Adds the context object information
DataObjects v2 = new DataObjects();
v2.addElement(new DataObject(Discoverer.ID, getId()));
v2.addElement(new DataObject(Discoverer.HOSTNAME, getHostAddress()));
v2.addElement(new DataObject(Discoverer.PORT, new Integer(communications.getServerPort()).toString()));
v1.addElement(new DataObject(Discoverer.REGISTERER, v2));
toSend = new DataObject(Discoverer.DISCOVERER_UNREGISTRATION, v1);
if (toSend != null) {
debugprintln(DEBUG, "BaseObject discovererUnregistration :"+toSend.toString());
try {
DataObject result = userRequest(toSend,Discoverer.DISCOVERER_UNREGISTRATION,discoverer.getHostname(),discoverer.getPort());
DataObject err;
if ((err = result.getDataObject(Error.ERROR_CODE)) != null) {
error.setError(err.toString());
}
debugprintln(DEBUG, "\nBaseObject discovererUnregistration - result : " + error);
return error;
} catch (EncodeException ee) {
System.out.println("BaseObject discovererUnregistration EncodeException: "+ee);
} catch (DecodeException de) {
System.out.println("BaseObject discovererUnregistration DecodeException: "+de);
} catch (InvalidEncoderException iee) {
System.out.println("BaseObject discovererUnregistration InvalidEncoderException: "+iee);
} catch (InvalidDecoderException ide) {
System.out.println("BaseObject discovererUnregistration InvalidDecoderException: "+ide);
} catch (InvalidProtocolException ipe) {
System.out.println("BaseObject discovererUnregistration InvalidProtocolException: "+ipe);
} catch (ProtocolException pe) {
System.out.println("BaseObject discovererUnregistration ProtocolException: "+pe);
} catch (IOException ioe) {
System.out.println("BaseObject discovererUnregistration IOException: "+ioe);
error = new Error(Error.IO_ERROR);
}
}
return null;
}
/**
*
*/
public DataObject discovererSubscriptionNotification(DataObject data){
debugprintln(DEBUG, "BO <discovererSubscriptionNotification>");
DataObject res;
DataObjects v = new DataObjects();
Error e = new Error();
e.setError(Error.NO_ERROR);
v.addElement(e.toDataObject());
res = new DataObject(DiscovererSubscriber.SUBSCRIPTION_CALLBACK_REPLY, v);
debugprintln(DEBUG, "BO <discovererSubscriptionNotification> " + data);
return res;
}
/**
* This method sends a lease end confirmation if necessary.
*
* @param data The data object specifying the lease end
* @return DataObject The reply to the notification
*/
protected DataObject leaseEndNotified(DataObject data){
DataObject result = null;
DataObjects v = new DataObjects();
Error err = new Error();
err.setError(Error.NO_ERROR);
v.addElement(new DataObject(Discoverer.ID, discoverer.getName()));
v.addElement(err.toDataObject());
if (this.automaticRenewal){
v.addElement(this.myLease.toDataObject());
result = new DataObject(Lease.LEASE_RENEWAL,v);
}
else {
result = new DataObject(Lease.LEASE_END, v);
}
return result;
}
/**
* This method allows to specify a lease used to register the discoverer.
* Each time the component has to register or to renew its registration, it
* uses this lease.
* This method has to be overridden by inheriting classes.
* If not, it returns the default lease
*
* ??? : is it useful after all???
*
* @return Lease The specified lease
*/
public Lease getLease(){
if (this.myLease == null)
return new Lease();
else
return myLease;
}
/**
* Set the lease used to register the discoverer
*/
public void setLease(Lease lease){
myLease = lease;
}
/** Print a message if the DEBUG mode is active
*
* @param s Any object, even null
*/
public static void debugprintln(boolean DEBUG_flag, Object s){
if (DEBUG_flag) {
System.out.println("" + s);
System.out.flush();
}
}
/** Set the CTK classes in the DEBUG status
*
*/
public void setAllDebug(boolean baseObjectDebug, boolean communicationDebug, boolean componentDebug ) {
if (baseObjectDebug){
BaseObject.DEBUG = true;
}
if (communicationDebug) {
BaseObject.DEBUG = true;
context.arch.comm.CommunicationsObject.DEBUG = true;
context.arch.comm.clients.Client.DEBUG = true;
context.arch.comm.protocol.TCPServerSocket.DEBUG = true;
context.arch.comm.protocol.HTTPMulticastUDPSocket.DEBUG = true;
context.arch.comm.clients.DiscovererClient.DEBUG = true;
context.arch.comm.protocol.HTTPClientSocket.DEBUG = true;
context.arch.comm.protocol.MulticastUDPSocket.DEBUG = true;
context.arch.comm.language.ParserObject.DEBUG = true;
context.arch.comm.DataObject.DEBUG = true;
context.arch.comm.protocol.HTTPServerSocket.DEBUG = true;
context.arch.comm.language.SAX_XMLDecoder.DEBUG = true;
context.arch.comm.clients.ClientsPool.DEBUG = true;
}
}
/**
* Print a string, on the displayed frame if it is activated or on the
* default output stream. Flushes the output stream
*/
public void println(String s){
// if (display==true && gFrame!=null)
// gFrame.addObservation(s + "\n");
// else {
System.out.println(s);
//System.out.flush();
// }
}
/**
* Rather than manually specifying a port, use this method to find a free port for the widget.
* @return
*/
public static int findFreePort() {
try {
ServerSocket server = new ServerSocket(0);
int port = server.getLocalPort();
server.close();
return port;
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}