/*
* Indiana University Extreme! Lab Software License, Version 1.2
*
* Copyright (C) 2002 The Trustees of Indiana University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1) All redistributions of source code must retain the above
* copyright notice, the list of authors in the original source
* code, this list of conditions and the disclaimer listed in this
* license;
*
* 2) All redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the disclaimer
* listed in this license in the documentation and/or other
* materials provided with the distribution;
*
* 3) Any documentation included with all redistributions must include
* the following acknowledgement:
*
* "This product includes software developed by the Indiana
* University Extreme! Lab. For further information please visit
* http://www.extreme.indiana.edu/"
*
* Alternatively, this acknowledgment may appear in the software
* itself, and wherever such third-party acknowledgments normally
* appear.
*
* 4) The name "Indiana Univeristy" or "Indiana Univeristy
* Extreme! Lab" shall not be used to endorse or promote
* products derived from this software without prior written
* permission from Indiana University. For written permission,
* please contact http://www.extreme.indiana.edu/.
*
* 5) Products derived from this software may not use "Indiana
* Univeristy" name nor may "Indiana Univeristy" appear in their name,
* without prior written permission of the Indiana University.
*
* Indiana University provides no reassurances that the source code
* provided does not infringe the patent or any other intellectual
* property rights of any other entity. Indiana University disclaims any
* liability to any recipient for claims brought by any other entity
* based on infringement of intellectual property rights or otherwise.
*
* LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
* NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA
* UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT
* SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR
* OTHER PROPRIETARY RIGHTS. INDIANA UNIVERSITY MAKES NO WARRANTIES THAT
* SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP
* DOORS", "WORMS", OR OTHER HARMFUL CODE. LICENSEE ASSUMES THE ENTIRE
* RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS,
* AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING
* SOFTWARE.
*/
/**
* @version $Revision: 1.28 $ $Author: srikrish $ $Date: 2004/09/09 06:55:32 $ (GMT)
* @author Sriram Krishnan [mailto:srikrish@extreme.indiana.edu]
*/
package xcat.mobile.ccacore;
import intf.mobile.ccacore.MobileServices;
import intf.mobile.ccacore.MobileComponentID;
import intf.mobile.storage.IndividualStorageService;
import intf.mobile.coordinator.AppCoordinatorCallback;
import xcat.ccacore.XCATComponentIDServerImpl;
import xcat.util.HandleResolver;
import xcat.util.URLToReference;
import xcat.exceptions.NonstandardException;
import soaprmi.server.UnicastRemoteObject;
import soaprmi.soaprpc.SoapServices;
import soaprmi.ogsi.util.XmlUtil;
import soaprmi.ogsi.sde.ServiceDataManagerInterface;
import soaprmi.ogsi.sde.ServiceDataElementFactory;
import soaprmi.ogsi.sde.ServiceDataElement;
import soaprmi.ogsi.sde.ServiceDataTypeMetadata;
import soaprmi.util.Util;
import org.gjt.xpp.XmlPullNode;
import org.gjt.xpp.XmlPullParser;
import org.gjt.xpp.XmlPullParserFactory;
import javax.xml.namespace.QName;
import java.io.StringReader;
import java.io.StringWriter;
/**
* The MobileComponentIDServerImpl implements the methods specified by the
* MobileComponentID interface on the server side
*/
public class MobileComponentIDServerImpl extends XCATComponentIDServerImpl
implements MobileComponentID {
/**
* Constructor
* @param name_ The name given to it by the builder service
* @param services_ The services object that contains this ComponentID
*/
public MobileComponentIDServerImpl(String name_, MobileServices services_)
throws Exception {
logger.finest("called");
name = name_;
services = services_;
// Export this object as a Grid Service
logger.finest("exporting ComponentID as a Grid service");
UnicastRemoteObject.exportObject(this,
new Class[]{MobileComponentID.class});
}
//-------------------------------------------------------------------//
// List of methods added to support migration on the uses side //
//-------------------------------------------------------------------//
/**
* An operation to notify the uses side that the provider component
* requests migration
* @param providesComponentName the name of the provides side requesting migration
* @param usingPortName the name of the uses port that is connected to
* the component requesting migration
* @param coordinatorHandle the GSH for the coordinator which is needed for
* a callback when the uses side has released the port
*/
public void requestMigration(String providesComponentName,
String usingPortName,
String coordinatorHandle)
throws gov.cca.CCAException {
logger.finest("called for uses port: " + usingPortName);
((MobileServices) services).requestMigration(providesComponentName,
usingPortName,
coordinatorHandle);
}
/**
* A notification that the component connected to this via the uses port is
* currently in migration
* @param usingPortName the name of the uses port that is connected to
* the component undergoing migration
*/
public void confirmMigration(String usingPortName)
throws gov.cca.CCAException {
logger.finest("called for uses port: " + usingPortName);
((MobileServices) services).confirmMigration(usingPortName);
}
/**
* A notification that the component connected to this via the uses port
* has completed its migration and is ready for use
* @param usingPortName the name of the uses port that is connected to
* the component undergoing migration
*/
public void migrationComplete(String usingPortName)
throws gov.cca.CCAException {
logger.finest("called for uses port: " + usingPortName);
((MobileServices) services).migrationComplete(usingPortName);
}
//-------------------------------------------------------------//
// List of methods to support migration on the provides side //
//-------------------------------------------------------------//
/**
* A request from the Application Coordinator to freeze THIS component.
* Sends a notification to the coordinator after all outgoing calls are complete,
* and the component is frozen.
* @param coordinatorHandle the GSH for the coordinator to callback after
* the component is frozen
*/
public void freezeComponent(final String coordinatorHandle)
throws gov.cca.CCAException {
logger.finest("called");
// call the freezeComponent of the services object in a separate thread
new Thread() {
public void run() {
try {
((MobileServices) services).freezeComponent(coordinatorHandle);
} catch (Exception e) {
logger.severe("Exception caught while freezing component", e);
}
}
}.start();
}
/**
* Resumes execution of a component that has been frozen
*/
public void unfreezeComponent()
throws gov.cca.CCAException {
logger.finest("called");
// call the corresponding method inside the services object
((MobileServices) services).unfreezeComponent();
}
//-----------------------------------------------------------------//
// Methods to support checkpointing & migration on provides side //
//-----------------------------------------------------------------//
/**
* A request from the Application Coordinator to store the state of
* this component into the Persistent Storage Service during migration
* @param individualStorageServiceURL the URL of the individual storage service
*/
public String storeIndividualComponentState(String individualStorageServiceURL)
throws gov.cca.CCAException {
logger.finest("called");
// get the state of the component
String xmlState = getComponentState();
// send the state of the component to the Storage Service
IndividualStorageService ss = (IndividualStorageService)
URLToReference.createReference(individualStorageServiceURL,
IndividualStorageService.class.getName());
return ss.storeState(xmlState);
}
/**
* Request to append component state to a distributed checkpoint
* @param individualStorageServiceURL the URL of the individual storage service
* @param coordinatorHandle the GSH for the coordinator to callback after
* the component is checkpointed
*/
public void appendStateToCheckpoint(final String individualStorageServiceURL,
final String coordinatorHandle)
throws gov.cca.CCAException {
logger.finest("called");
// append the checkpoint in another thread
new Thread() {
public void run() {
String storageID = null;
try {
// get the state of the component
String xmlState = getComponentState();
// send the state of the component to the Storage Service
IndividualStorageService ss = (IndividualStorageService)
URLToReference.createReference(individualStorageServiceURL,
IndividualStorageService.class.getName());
storageID = ss.storeState(xmlState);
} catch (Exception e) {
logger.severe("Exception while creating/storing checkpoint", e);
try {
// send an exception message to the coordinator
AppCoordinatorCallback coord = (AppCoordinatorCallback)
HandleResolver.resolveHandle(coordinatorHandle,
AppCoordinatorCallback.class.getName());
coord.componentCheckpointed(getInstanceName(),
individualStorageServiceURL,
storageID,
AppCoordinatorCallback.EXCEPTION);
} catch (Exception ex) {
logger.severe("Can't send notification to AppCoordinator", ex);
}
}
// send a checkpoint completed message to the coordinator
try {
AppCoordinatorCallback coord = (AppCoordinatorCallback)
HandleResolver.resolveHandle(coordinatorHandle,
AppCoordinatorCallback.class.getName());
coord.componentCheckpointed(getInstanceName(),
individualStorageServiceURL,
storageID,
AppCoordinatorCallback.CHECKPOINTED);
} catch (Exception e) {
logger.severe("Can't send notification to AppCoordinator", e);
}
}
}.start();
}
/**
* Retrieves the state of the component and associated framework from serialized XML
* form during migration and checkpointing
* @param storageServiceURL the URL of the storage service
* @param storageID the storageID to use to locate the component state
*/
public void loadComponentState(String individualStorageServiceURL,
String storageID)
throws gov.cca.CCAException {
logger.finest("called");
// retrieve the component state from the storage service
IndividualStorageService ss = (IndividualStorageService)
URLToReference.createReference(individualStorageServiceURL,
IndividualStorageService.class.getName());
String xmlState = ss.retrieveState(storageID);
// set the state of the component
setComponentState(xmlState);
}
/**
* Resumes execution of a component that has been restarted
*/
public void resumeExecution()
throws gov.cca.CCAException {
logger.finest("called");
((MobileServices) services).getComponent().resumeExecution();
}
/**
* Returns the state of the component after it is frozen
*/
private String getComponentState()
throws gov.cca.CCAException {
logger.finest("called");
try {
// initialize the buffer
StringBuffer xmlBuffer = new StringBuffer();
xmlBuffer.append("<componentState>");
// retrieve the state of the services object
String sInfo = ((MobileServices) services).getState();
xmlBuffer.append(sInfo);
// append the Service Data Elements
xmlBuffer.append("<serviceData>");
ServiceDataManagerInterface sdmi = getServiceDataManager();
QName[] sdeNames = sdmi.enumerateServiceDataNames();
for (int i = 0; i < sdeNames.length; i++) {
ServiceDataElement[] sde =
sdmi.getServiceDataByName(sdeNames[i]);
for (int j = 0; j < sde.length; j++) {
String nextSDE = sde[j].getSDE().toString();
StringWriter sw = new StringWriter();
Util.writeXMLEscapedString(sw, nextSDE);
xmlBuffer.append("<serviceDataElement>" +
sw.toString() +
"</serviceDataElement>");
}
}
xmlBuffer.append("</serviceData>");
// retrieve the state of the Component
xmlBuffer.append("<localState>");
String localState =
((MobileServices) services).getComponent().generateComponentState();
if (localState != null) {
StringWriter sw = new StringWriter();
Util.writeXMLEscapedString(sw, localState);
xmlBuffer.append(sw.toString());
}
xmlBuffer.append("</localState>");
// return the state of the component
xmlBuffer.append("</componentState>");
logger.finest("Size of checkpoint: " + xmlBuffer.length());
return xmlBuffer.toString();
} catch (Exception e) {
logger.severe("Exception caught while storing state", e);
throw new NonstandardException("Exception caught while storing state", e);
}
}
/**
* Loads the state of the component and associated framework from serialized XML form
* @param xmlState the state of the component in XML form
*/
private void setComponentState(String xmlState)
throws gov.cca.CCAException {
logger.finest("called");
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser pp = factory.newPullParser();
pp.setInput(new StringReader(xmlState));
pp.next();
XmlPullNode stateTree = factory.newPullNode(pp);
while(true) {
// get the next child and check if we are done
XmlPullNode nextChild = (XmlPullNode) stateTree.readNextChild();
if (nextChild == null)
break;
// check the type of the child node, and act appropriately
if (nextChild.getLocalName().equals("servicesInfo")) {
// set the state of the services object
((MobileServices) services).setState(XmlUtil.xmlNode2String(nextChild));
} else if (nextChild.getLocalName().equals("localState")) {
// set the state of the component and ports
Object localState = nextChild.readNextChild();
if (localState != null) {
StringWriter sw = new StringWriter();
Util.readXMLEscapedString(sw, (String) localState);
((MobileServices) services).getComponent().
setComponentState(services, sw.toString());
} else {
((MobileServices) services).getComponent().
setComponentState(services, null);
}
} else if (nextChild.getLocalName().equals("serviceData")) {
// set the state of the Service Data
ServiceDataManagerInterface sdm = getServiceDataManager();
ServiceDataElementFactory sdeFactory = ServiceDataElementFactory.getDefault();
while (true) {
XmlPullNode sdeNode = (XmlPullNode) nextChild.readNextChild();
if (sdeNode == null)
break;
// get the value of SDE as a String
String sdeString = (String) sdeNode.readNextChild();
// create an SDE from the current entry
StringWriter sw = new StringWriter();
Util.readXMLEscapedString(sw, sdeString);
ServiceDataElement nextSDE =
sdeFactory.newServiceDataElement(sw.toString());
QName sdeQName = nextSDE.getQName();
// make sure the SDE can be added
ServiceDataTypeMetadata sdtm = sdm.getTypeManager().getRegisteredType(sdeQName);
// 1. maxoccurs
ServiceDataElement[] sdeList = sdm.getServiceDataByName(sdeQName);
if(sdtm.getMaxOccurs() > 0 && sdeList.length >= sdtm.getMaxOccurs()) {
continue;
}
// 2. mutability
if(sdtm.getMutable() == sdtm.STATIC || sdtm.getMutable() == sdtm.CONSTANT){
continue;
}
// 3. nillability
if(!sdtm.isNillable() && nextSDE.isContentNil()) {
continue;
}
// add the SDE
sdm.addServiceData(nextSDE);
}
}
}
} catch (Exception e) {
logger.severe("Exception caught while setting component state", e);
throw new NonstandardException("Exception while setting component state", e);
}
}
}