// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library.services; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import openadk.library.ADK; import openadk.library.ADKException; import openadk.library.DataObjectInputStream; import openadk.library.ElementDef; import openadk.library.Event; import openadk.library.MessageInfo; import openadk.library.Provisioner; import openadk.library.Query; import openadk.library.QueryResults; import openadk.library.SIFElement; import openadk.library.SIFErrorCategory; import openadk.library.SIFErrorCodes; import openadk.library.SIFException; import openadk.library.SIFMessageInfo; import openadk.library.SIFWriter; import openadk.library.Subscriber; import openadk.library.Zone; import openadk.library.infra.SIF_Element; import openadk.library.infra.SIF_Error; import openadk.library.services.impl.ServiceObjectInputStreamImpl; import openadk.util.ADKStringUtils; /** * Abstract Proxy class to a zone service. * * @author Andrew Elmhorst * @version ADK 2.3 * */ public abstract class SIFZoneServiceProxy implements QueryResults, Subscriber { private ElementDef fServiceDef; /** * Creates in instance of SIFZoneServiceProxy * * @param ElementDef */ protected SIFZoneServiceProxy(ElementDef serviceDef) { fServiceDef = serviceDef; } /** * Gets the service definition * * @return ElementDef */ public ElementDef getServiceDefinition() { return fServiceDef; } /** * Provision the service * @param Provisioner */ public void provision(Provisioner provisioningSource) throws ADKException { provisioningSource.setSubscriber(this, fServiceDef, null); provisioningSource.setQueryResults(this, fServiceDef, null); } /** * Invoke the service * * @param Zone * @param ServiceRequestInfo * @param SIFElement payload * * @return SIF_MsgID */ protected String invokeService(Zone zone, ServiceRequestInfo requestInfo, SIFElement payload) throws ADKException { // Assign a SIF_ServiceMsgId value requestInfo.setSIFServiceMsgId(ADK.makeGUID()); // JEN - use query if use old message types // Serialize the request object /* Query query = new Query(fServiceDef); StringWriter sw = new StringWriter(); SIFWriter writer = new SIFWriter(sw); writer.suppressNamespace(true); writer.write(payload); writer.flush(); writer.close(); String xml = sw.toString(); query.addCondition("Method", "EQ", requestInfo.getMethodName()); query.addCondition("Payload", "EQ", ADKStringUtils.encodeXML(xml)); query.addCondition("ServiceMsgId", "EQ", requestInfo.getSIFServiceMsgId()); */ // Note: When SIF Zone Service messages are used, the method name // and service name are header elements. However, we need to track that // information locally // query.setUserData(requestInfo); // JEN added String return to match ETF // Support for directed service requests String msgId = null; if( requestInfo.getDestinationId() != null ){ msgId=zone.invokeService(zone, requestInfo, payload); } // Set SIF_MsgId so the caller doesn't need to worry about it requestInfo.setSIFMsgId(msgId); return msgId; } public void onQueryPending(MessageInfo info, Zone zone) throws ADKException { // Do nothing for now... } public void onQueryResults(DataObjectInputStream data, SIF_Error error, Zone zone, MessageInfo info) throws ADKException { SIFMessageInfo smi = (SIFMessageInfo) info; /* ServiceRequestInfo sri = (ServiceRequestInfo) smi.getSIFRequestInfo() .getUserData(); if (sri == null) { // TODO: In "Real" SIF Zone Services, the service and method names // are always going to be defined // in the message header. For this implementation, just skip it if // we can't derive the method // name from our saved state System.out .println("No saved state for SIF_Response with RequestMsgId of: " + smi.getSIFRequestMsgId()); return; } smi.setSIFServiceMsgId(sri.getSIFServiceMsgId()); */ String methodName = (String) smi.getObjects().get("SIF_Operation"); Method proxyMethod = ServiceUtils.getMethod(this, "on" + methodName + "Response", zone); // TODO: Service methods can return either arrays, or a single object. // We need to tailor // this method to use a ServiceObjectInputStream instance for arrays and // to read just the single // object in other cases. Perhaps it could derive which method to use // from reflection data on the // method it finds in the client. ServiceObjectInputStream<SIFElement> sois; if (error != null) { sois = new ServiceObjectInputStreamImpl<SIFElement>(zone, info, error); } else { sois = new ServiceObjectInputStreamImpl<SIFElement>(zone, info, data); } try { proxyMethod.invoke(this, new Object[] { sois, error, zone, info }); } catch (IllegalAccessException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (IllegalArgumentException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (InvocationTargetException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } } public void onServiceEvent(DataObjectInputStream data, SIF_Error error, Zone zone, MessageInfo info) throws ADKException { SIFMessageInfo smi = (SIFMessageInfo) info; String methodName = (String) smi.getObjects().get("SIF_Operation"); Method proxyMethod = ServiceUtils.getMethod(this, "on" + methodName , zone); // TODO: Service methods can return either arrays, or a single object. // We need to tailor // this method to use a ServiceObjectInputStream instance for arrays and // to read just the single // object in other cases. Perhaps it could derive which method to use // from reflection data on the // method it finds in the client. ServiceObjectInputStream<SIFElement> sois; if (error != null) { sois = new ServiceObjectInputStreamImpl<SIFElement>(zone, info, error); } else { sois = new ServiceObjectInputStreamImpl<SIFElement>(zone, info, data); } try { proxyMethod.invoke(this, new Object[] { sois, zone, info }); } catch (IllegalAccessException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (IllegalArgumentException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (InvocationTargetException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } } public void onEvent(Event event, Zone zone, MessageInfo info) throws ADKException { SIFElement serviceElement = event.getData().readDataObject(); if (serviceElement == null) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new SIFException(SIFErrorCategory.GENERIC, SIFErrorCodes.GENERIC_GENERIC_ERROR_1, "The Event payload element cannot be empty.", zone); } List<SIFElement> children = serviceElement.getChildList(); if (children.size() == 0) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new SIFException(SIFErrorCategory.GENERIC, SIFErrorCodes.GENERIC_GENERIC_ERROR_1, "The <" + serviceElement.getElementDef().name() + "> element cannot be empty.", zone); } SIFElement eventElement = children.get(0); String methodName = "on" + eventElement.getElementDef().name(); Method proxyMethod = ServiceUtils.getMethod(this, methodName, zone); SIFElement eventPayload = eventElement.getChildList().get(0); try { proxyMethod.invoke(this, new Object[] { eventPayload, zone, info }); } catch (IllegalAccessException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (IllegalArgumentException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } catch (InvocationTargetException iae) { // TODO: Fix up error handling when SIF Services error codes are // defined throw new ADKException("Unable to process event: " + iae, zone, iae); } } }