//
// Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s).
// All rights reserved.
//
package openadk.library;
import java.net.URL;
import java.util.List;
import openadk.library.impl.Transport;
import openadk.library.infra.SIF_Ack;
import openadk.library.infra.SIF_AgentACL;
import openadk.library.infra.SIF_ZoneStatus;
import openadk.library.log.ServerLog;
import openadk.library.services.SIFZoneService;
import openadk.library.services.SIFZoneServiceProxy;
import openadk.library.services.ServiceRequestInfo;
import openadk.library.threadpool.ThreadPoolManager;
import org.apache.log4j.Logger;
/**
* A Zone is a logical grouping of applications that exchange data through the
* Schools Interoperability Framework. Each zone is managed by a Zone Integration
* Server (ZIS). Refer to the SIF Specifications for a more detailed definition.
* Agents developed with the ADK may connect to multiple zones concurrently.<p>
*
* Zones have the following characteristics:
* <p>
*
* <ul>
* <li>
* Each zone connects to a Zone Integration Server, which provides a
* reliable and persistent queue for the storage of messages pending
* delivery to the agent. The "connection" is a logical one. The ADK
* handles retrieving messages from the queue and dispatching them to
* the <i>Publisher</i>, <i>Subscriber</i>, and <i>QueryResults</i>
* interfaces registered with your agent's Zone or Topic objects.
* <br/><br/>
* </li>
* <li>
* The ADK provides a persistent and reliable Agent Local Queue (ALQ)
* for each zone. Messages retrieved from the Zone Integration Server
* are stored in the local queue before being processed. A given
* message exists in the local queue or in the server queue but never
* in both. The Agent Local Queue provides for enhanced reliability
* and supports disconnected communications with the server.<br><br>
* </li>
* <li>
* Each zone maintains its own set of properties. By default, a zone
* inherits its default properties from the agent. To set properties
* on a per-zone basis, call the <code>Zone.getProperties</code> method
* to obtain the zone's AgentProperties object, then call its accessor
* methods. Properties must be set prior to calling <code>connect</code>.
* <br><br>
* </li>
* </ul>
*
* In order to exchange messages with a zone, the agent must be <i>connected</i>
* to the zone. The act of connecting establishes local resources for transport
* protocols and queuing. Depending on the flags passed to the <code>connect</code>
* method, the agent may also send SIF registration messages to establish
* similar resources on the server.<p>
*
* An agent obtains a Zone instance by calling <code>Agent.getZoneFactory</code>.
* When finished interacting with a zone, call the <code>disconnect</code>
* method to release local resources held by the ADK as well as to optionally
* send a SIF_Unregister message to the server. Disconnecting all zones to
* which an agent is connected is easily done by calling the <code>Agent.shutdown</code>
* method when the agent exits.<p>
*
* Agents typically use <i>Topic</i> objects to aggregate publish, subscribe,
* and query activity across multiple zones. Refer to the Topic interface for
* details.
*
* @author Eric Petersn
* @version ADK 1.0
*/
public interface Zone extends Provisioner
{
/**
* Gets the properties for this zone.<p>
*
* By default, a zone inherits the default agent properties.
*
* @return The zone properties
*/
public AgentProperties getProperties();
/**
* Assigns a new properties object to this zone.<p>
*
* By default, a zone inherits the default agent properties. To change a
* property, first call the getProperties method to obtain the zone's
* properties object, then call any of the accessor methods available on
* that object. Because zones are constructed with a default AgentProperties
* object, it is typically not necessary to call this method.
*
* @param props A new properties object to replace the existing object
*/
public void setProperties( AgentProperties props );
/**
* Gets the Agent object<p>
* @return The Agent that created this Zone instance
*/
public Agent getAgent();
/**
* Gets the zone identifier<p>
* @return The name of the zone as defined by the Zone Integration Server
*/
public String getZoneId();
/**
* Gets the URL of the Zone Integration Server that manages this zone<p>
* @return The URL to the ZIS (e.g. "http://host:port/zoneId" is the URL
* convention employed by the SIFWorks ZIS)
*/
public URL getZoneUrl();
public void configure()
throws ADKException;
/**
* Connects the agent with this zone.<p>
*
* An agent must connect to a zone in order to perform messaging within the
* context of the ADK Class Framework. A typical agent calls this method at
* startup for each zone it will connect to, then optionally joins the Zone
* with one or more Topics.<p>
*
* The ADK's Provisioning Mode affects the messages sent by this method.
* Refer to the AgentProperties class for more information.<p>
*
* The ADK will send <code><SIF_Subscribe></code> and <code><SIF_Provide></code>
* messages to the zone to provision the SIF Data Objects for which the agent has registered a
* <i>Subscriber</i> and <i>Publisher</i> message handlers, respectively.
* The <code>adk.provisioning.batch</code> agent property (refer to the
* AgentProperties class) determines whether the ADK sends a single message
* or individual messages for each SIF Data Object. When individual messages
* are sent (the default), Category 4 Access Control errors are treated as
* warnings. Connect warnings can be retrieved by calling the
* <code>getConnectWarnings</code> method. When a single message is sent,
* any SIF Error will result in the raising of a SIFException.<p>
*
* Note the SIF_Wakeup and SIF_Ping system control messages are sent to
* the server upon successful connection.<p>
*
* @param flags One or more of the following flags:<p>
*
* <table border="1">
* <tr>
* <td>Flag</td>
* <td>Description</td>
* </tr>
* <tr>
* <td><code>ADKFlags.REGISTER</code></td>
* <td>Sends a SIF_Register message to the ZIS and wakes up the
* agent queue on the server if previously in sleep mode.</td>
* </tr>
* </table>
* </p>
*
* @exception IllegalStateException is thrown if this zone is already in
* the connected state (i.e. <i>connect</i> has already been called
* without a corresponding call to <i>disconnect</i>)
* @exception ADKException is thrown if there is a SIF Error acknowledgement
* to a <code><SIF_Register></code>, <code><SIF_Subscribe></code>,
* or <code><SIF_Provide></code> message as described above
*
* @see #disconnect
*/
public void connect( int flags )
throws ADKException;
/**
* Disconnects the agent from this zone.<p>
*
* Resources held by the Class Framework, including the Agent Local Queue,
* are closed. To ensure these resources are properly closed, agents should
* disconnect from zones even when not planning on sending a <code><
* SIF_Unregister></code> provisioning message.<p>
*
* Provisioning messages are sent as follows:<p>
*
* <ul>
* <li>
* If the agent is using ADK-managed provisioning, a <code><
* SIF_Unregister></code> message is sent to the ZIS when the
* ADKFlags.PROV_UNREGISTER flag is specified. When
* ADK-managed provisioning is disabled, no messages are sent to
* the zone.
* </li>
* <li>
* If Agent-managed provisioning is enabled, the flags
* flags have no affect. The agent must explicitly call the
* sifUnregister method to manually send those message to the zone.
* </li>
* <li>
* If ZIS-managed provisioning is enabled, no provisioning messages
* are sent by the agent regardless of the flags
* used and the methods are called.
* </li>
* </ul>
* <p>
*
* Note that SIF Agent sessions are long-lived and therefore an agent may
* remain registered with a ZIS even when it is "disconnected" from the
* perspective of the ADK Class Framework.<p>
*
* Disconnecting a zone also places the agent's server queue in sleep mode.
* This functionality can be disabled via the zone properties.<p>
*
* @param flags One or more flags as described above
*
* @exception IllegalStateException is thrown if this zone is not in the
* connected state (i.e. connect has not been called, or disconnect has
* already been called)
* @exception ADKException is thrown if there is an error sending a
* <code><SIF_Unregister></code> message
*
* @see #connect
*/
public void disconnect( int flags )
throws ADKException;
/**
* Gets a read-only list of any SIF Errors that resulted from the sending of provisioning
* messages to the zone. Only access control errors (Category 4) are treated as
* warnings rather than errors; all other SIF Errors result in an exception
* thrown by the <code>connect</code> method
*
* @return A List of SIFExceptions
*
*/
public List<SIFException> getConnectWarnings();
/**
* Gets the connection state of this zone<p>
* @return true if the <i>connect</i> method has been called but the <i>
* disconnect</i> method has not
*/
public boolean isConnected();
/**
* Report a SIF Event to the zone
* @param event An Event object describing the SIF Data Object that has
* changed and how it has changed (added, updated, or removed)
* @throws ADKException
*/
public void reportEvent( Event event )
throws ADKException;
/**
* Report a SIF Event to the zone
* @param obj The object that was added, changed, or deleted
* @param actionCode The action being taken on the object
* ( <code>ADD</code>, <code>CHANGE</code>, or <code>DELETE</code> )
* @throws ADKException
*/
public void reportEvent( SIFDataObject obj, EventAction actionCode )
throws ADKException;
/**
* Report a SIF Event to the zone in one or more specific SIF Contexts
* @param obj the object that was added, changed, or deleted
* @param actionCode The action being taken on the object
* @param contexts An array or sequence (varargs) of specific SIF Contexts to
* report this event in.
* @throws ADKException
*/
public void reportEvent( SIFDataObject obj, EventAction actionCode, SIFContext... contexts )
throws ADKException;
/**
* Report a directed SIF Event to the agent in the zone identified by
* <code>destinationId</code>. Note: Directed SIF Events may not be supported
* by all zone integration servers.<p>
*
* @param obj The object that was added, changed, or deleted
* @param action The action being taken on the object
* @param destinationId The SourceId of the agent to which the SIF Event
* will be routed by the zone integration server
* @throws ADKException If an error occurs while reporting the event
*/
public void reportEvent( SIFDataObject obj, EventAction action, String destinationId )
throws ADKException;
/**
* Query the zone.<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone.
* @throws ADKException If an error occurs while sending the Query to the zone
*/
public String query( Query query )
throws ADKException;
/**
* Query the zone and notify a MessagingListener<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions
* @param listener A MessagingListener that will be notified when the
* SIF_Request message is sent to the zone. Any other MessagingListeners
* registered with the zone will also be called.
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone.
* @throws ADKException If an error occurs while sending the query to the zone
*
* @since ADK 1.5
*/
public String query( Query query, MessagingListener listener )
throws ADKException;
/**
* Query the zone with options.<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions.
* @param queryOptions Reserved for future use.
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone
* @throws ADKException If an error occurs while sending the query to the zone
*/
public String query( Query query, int queryOptions )
throws ADKException;
/**
* Query the zone with options and notify a MessagingListener<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions.
* @param listener A MessagingListener that will be notified when the
* SIF_Request message is sent to the zone. Any other MessagingListeners
* registered with the zone will also be called.
* @param queryOptions Reserved for future use.
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone
*
* @since ADK 1.5
*/
public String query( Query query, MessagingListener listener, int queryOptions )
throws ADKException;
/**
* Query a specific agent registered with this zone (a <i>directed query</i>).<p>
*
* Directed queries are used primarily when the source of data is known
* because of a message previously received from that agent. For example,
* if your agent receives a SIF_Event and you wish to query the author of
* that event for additional data, a directed query is appropriate.<p>
*
* In addition, some kinds of SIF Data Objects in SIF 1.5 and later may be
* designed to require agents to send directed queries if more than one
* agent in a zone typically offers support for the object. This is necessary
* because only one agent can be the authoritative provider of a given object
* type in each zone.<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions
* @param destinationId The SourceId of the agent to which the SIF Request
* will be routed by the zone integration server
* @param queryOptions Reserved for future use
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone.
*/
public String query( Query query, String destinationId, int queryOptions )
throws ADKException;
/**
* Query using a service a specific agent registered with this zone (a <i>directed query</i>).<p>
*
* Directed queries are used primarily when the source of data is known
* because of a message previously received from that agent. For example,
* if your agent receives a SIF_Event and you wish to query the author of
* that event for additional data, a directed query is appropriate.<p>
*
* In addition, some kinds of SIF Data Objects in SIF 1.5 and later may be
* designed to require agents to send directed queries if more than one
* agent in a zone typically offers support for the object. This is necessary
* because only one agent can be the authoritative provider of a given object
* type in each zone.<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions
* @param destinationId The SourceId of the agent to which the SIF Request
* will be routed by the zone integration server
* @param queryOptions Reserved for future use
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone.
*/
public String invokeService( Zone zone, ServiceRequestInfo requestInfo, SIFElement payload )
throws ADKException;
/**
* Query a specific agent registered with this zone (a <i>directed query</i>)
* and notify a MessagingListener.<p>
*
* Directed queries are used primarily when the source of data is known
* because of a message previously received from that agent. For example,
* if your agent receives a SIF_Event and you wish to query the author of
* that event for additional data, a directed query is appropriate.<p>
*
* In addition, some kinds of SIF Data Objects in SIF 1.5 and later may be
* designed to require agents to send directed queries if more than one
* agent in a zone typically offers support for the object. This is necessary
* because only one agent can be the authoritative provider of a given object
* type in each zone.<p>
*
* @param query A Query object describing the parameters of the query,
* including optional conditions and field restrictions
* @param listener A MessagingListener that will be notified when the
* SIF_Request message is sent to the zone. Any other MessagingListeners
* registered with the zone will also be called.
* @param destinationId The SourceId of the agent to which the SIF Request
* will be routed by the zone integration server
* @param queryOptions Reserved for future use
*
* @return The SIF_MsgId of the SIF_Request that was sent to the zone.
* @throws ADKException Thrown if an error occurs while sending the query to the zone
*
* @since ADK 1.5
*/
public String query( Query query, MessagingListener listener, String destinationId, int queryOptions )
throws ADKException;
/**
* Gets the SIF_ZoneStatus object from the ZIS managing this zone. The
* method blocks until a result is received.
* @return The SIF_ZoneStatus object for the zone
* @throws ADKException If the ADK cannot connect to the zone to request
* the SIF_ZoneStatus object
*/
public SIF_ZoneStatus getZoneStatus()
throws ADKException;
/**
* Gets the SIF_ZoneStatus object from the ZIS managing this zone. The
* method blocks for the specified timeout period.
* @param timeout The amount of time to wait for a SIF_ZoneStatus object to
* be received by the agent (or -1 to wait infinitely)
* @return The SIF_ZoneStatus object for the zone
* @throws ADKException If the ADK cannot connect to the zone to request
* the SIF_ZoneStatus object
*/
public SIF_ZoneStatus getZoneStatus( int timeout )
throws ADKException;
/**
* Gets the SIF_AgentACL object from the ZIS managing this zone.
* @return The SIF_AgentACL specific to this agent from the zone
* @throws ADKException If the ADK cannot connect to the zone to request
* the SIF_AgentACL object
*/
public SIF_AgentACL getAgentACL()
throws ADKException;
/**
* Register a <i>MessagingListener</i> to listen to messages received by the
* message handlers of this class.<p>
*
* NOTE: Agents may register a MessagingListener with the Agent or Zone
* classes. When a listener is registered with both classes, it will be
* called twice. Consequently, it is recommended that most implementations
* choose to register MessagingListeners with only one of these classes
* depending on whether the agent is interested in receiving global
* notifications or notifications on only a subset of zones.<p>
*
* @param listener a MessagingListener implementation
*/
public void addMessagingListener( MessagingListener listener );
/**
* Remove a <i>MessagingListener</i> previously registered with the
* <code>addMessagingListener</code> method.<p>
*
* @param listener a MessagingListener implementation
*/
public void removeMessagingListener( MessagingListener listener );
/**
* Purge all pending incoming and/or outgoing messages from this agent's
* queue. Only messages associated with this zone are affected. See also
* the Agent.purgeQueue and Topic.purgeQueue methods to purge the queues of
* all zones with which the agent is connected, or all zones joined with a
* given topic, respectively.<p>
*
* <ul>
* <li>
* If the Agent Local Queue is enabled, messages are permanently
* and immediately removed from the queue. Any messages in transit
* are not affected.
* </li>
* <li>
* If the underlying messaging protocol offers a mechanism to clear
* the agent's queue, it is invoked. (SIF 1.0 does not have such a
* mechanism.)
* <li>
* Otherwise, all incoming messages received by the agent having a
* timestamp earlier than or equal to the time this method is called
* are discarded. This behavior persists until the agent is
* terminated or until a message is received having a later
* timestamp.
* </li>
* </ul>
*
* @param incoming true to purge incoming messages
* @param outgoing true to purge outgoing messages (e.g. pending SIF_Events)
* when the Agent Local Queue is enabled
* @throws ADKException Thrown if an error occurs while purging the queue
*/
public void purgeQueue( boolean incoming, boolean outgoing )
throws ADKException;
/**
* Puts this zone into sleep mode.<p>
*
* A SIF_Sleep message is sent to the Zone Integration Server to request
* that this agent's queue be put into sleep mode. If successful, the ZIS
* should not deliver further messages to this agent until it is receives
* a SIF_Register or SIF_Wakeup message from the agent. Note the ADK keeps
* an internal sleep flag for each zone, which is initialized when the
* <code>connect</code> method is called by sending a SIF_Ping to the ZIS.
* This flag is set so that the ADK will return a Status Code 8 ("Receiver
* is sleeping") in response to any message received by the ZIS for the
* duration of the session.
* <p>
*
* If the SIF_Sleep message is not successful, an exception is thrown and
* the ADK's internal sleep flag for this zone is not changed.
* <p>
*
* @exception ADKException thrown if the SIF_Sleep message is unsuccessful
*/
public void sleep()
throws ADKException;
/**
* Wakes up this zone if currently in sleep mode.<p>
*
* A SIF_Wakeup message is sent to the Zone Integration Server to request
* that sleep mode be removed from this agent's queue. Note the ADK keeps
* an internal sleep flag for each zone, which is initialized when the
* <code>connect</code> method is called by sending a SIF_Ping to the ZIS.
* This flag is cleared so that the ADK will no longer return a Status Code
* 8 ("Receiver is sleeping") in response to messages received by the ZIS.
* <p>
*
* If the SIF_Sleep message is not successful, an exception is thrown and
* the ADK's internal sleep flag for this zone is not changed.
* <p>
*
* @exception ADKException thrown if the SIF_Wakeup message is unsuccessful
*/
public void wakeup()
throws ADKException;
/**
* Sets the <i>UndeliverableMessageHandler</i> to be called when a dispatching
* error occurs on this zone. For more information, please refer to the
* UnderliverableMessageHandler class comments.<p>
*
* @param handler The handler to call when the ADK cannot dispatch an
* inbound message
*/
public void setErrorHandler( UndeliverableMessageHandler handler );
/**
* Gets the <i>UndeliverableMessageHandler</i> for this zone. If not set,
* the error handler of the Agent is used if defined.<p>
* @return The class that has been set as the {@link UndeliverableMessageHandler}
* for this zone
*
* @see #setErrorHandler
*/
public UndeliverableMessageHandler getErrorHandler();
/**
* Determines if the agent's queue for this zone is in sleep mode.<p>
*
* @param flags When ADKFlags.LOCAL_QUEUE is specified, returns true if the
* Agent Local Queue is currently in sleep mode. False is returned if
* the Agent Local Queue is disabled. When ADKFlags.SERVER_QUEUE is
* specified, queries the sleep mode of the Zone Integration Server
* by sending a SIF_Ping message.
* @return True if the zone is sleeping
* @throws ADKException Thrown if an error occurs while checking the zone's
* sleep status
*/
public boolean isSleeping( int flags )
throws ADKException;
/**
* Sends a SIF_Register message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.<p>
* @return The SIF_Ack returned from the ZIS
* @throws ADKException Thrown if an error occurs while sending the sif
*/
public SIF_Ack sifRegister()
throws ADKException;
/**
* Sends a SIF_Unregister message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.<p>
*/
public SIF_Ack sifUnregister()
throws ADKException;
/**
* Sends a SIF_Subscribe message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.
*/
public SIF_Ack sifSubscribe( String[] objectType )
throws ADKException;
/**
* Sends a SIF_Unsubscribe message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.
*/
public SIF_Ack sifUnsubscribe( String[] objectType )
throws ADKException;
/**
* Sends a SIF_Provide message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.
*/
public SIF_Ack sifProvide( String[] objectType )
throws ADKException;
/**
* Sends a SIF_Unprovide message to the ZIS. This method can be called by
* agents that have chosen to use Agent-managed provisioning. If ZIS-managed
* or ADK-managed provisioning is enabled for this zone, the method has no
* effect.
*/
public SIF_Ack sifUnprovide( String[] objectType )
throws ADKException;
/**
* Sends a SIF_Ping message to the ZIS that manages this zone.
*/
public SIF_Ack sifPing()
throws ADKException;
/**
* Sends arbitrary SIF_Message content to the zone. This method does not
* alter the message or wrap it in an envelope prior to sending it.<p>
*
* @param xml A valid SIF_Message complete with a SIF_Header header and a
* payload such as SIF_Register, SIF_Request, SIF_Event, etc.
* @return A SIF_Ack object encapsulating the SIF_Ack response that was
* returned from the Zone Integration Server
*/
public SIF_Ack sifSend( String xml )
throws ADKException;
/**
* Sends arbitrary SIF_Message content to the zone. This method does not
* alter the message or wrap it in an envelope prior to sending it.<p>
*
* @param xml A valid SIF_Message complete with a SIF_Header header and a
* payload such as SIF_Register, SIF_Request, SIF_Event, etc.
* @return A SIF_Ack object encapsulating the SIF_Ack response that was
* returned from the Zone Integration Server
*/
public SIF_Ack sifCancelRequests (String destinationId, String[] sif_MsgIds)
throws ADKException;
/**
* Assigns an application-supplied object to this Zone
* @param data Any object the application wishes to attach to this Zone instance
*/
public void setUserData( Object data );
/**
* Gets the application-supplied object for this Zone
* @return The object passed to the <code>setUserData</code> method
*/
public Object getUserData();
/**
* Gets the Log4j Logger for this zone.
*/
public Logger getLog();
/**
* Gets the ServerLog for this zone.<p>
* @return The ServerLog instance for the zone
* @since ADK 1.5
*/
public ServerLog getServerLog();
/**
* Returns the string representation of this zone as "zoneId@zoneUrl"
*/
public String toString();
public void setServiceProviders(String serviceName, SIFZoneService sifZoneService);
public void setServiceSubscribers(String serviceName, SIFZoneServiceProxy sifZoneServiceProxy);
public void reportServiceEvent(ServiceEvent event, String destinationId) throws ADKException;
public void setServiceNotifier(String serviceName, SIFZoneServiceProxy sifZoneServiceProxy);
}