/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/
/*
* ***************************************************************
* The LEAP libraries, when combined with certain JADE platform components,
* provide a run-time environment for enabling FIPA agents to execute on
* lightweight devices running Java. LEAP and JADE teams have jointly
* designed the API for ease of integration and hence to take advantage
* of these dual developments and extensions so that users only see
* one development platform and a
* single homogeneous set of APIs. Enabling deployment to a wide range of
* devices whilst still having access to the full development
* environment and functionalities that JADE provides.
* Copyright (C) 2001 Telecom Italia LAB S.p.A.
*
* GNU Lesser General Public License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* **************************************************************
*/
package jade.imtp.leap;
import jade.core.*;
import jade.lang.acl.ACLMessage;
import jade.mtp.TransportAddress;
import jade.util.leap.*;
import jade.imtp.leap.JICP.JICPProtocol;
import jade.imtp.leap.JICP.Connection;
import jade.util.Logger;
import java.io.IOException;
/**
* @author Giovanni Caire - Telecom Italia Lab
*/
public class LEAPIMTPManager implements IMTPManager {
/**
* Profile keys for LEAP-IMTP specific parameters
*/
static final String MAIN_URL = "main-url";
public static final String CHANGE_PORT_IF_BUSY = "jade_imtp_leap_LEAPIMTPManager_changeportifbusy";
private static final String ICPS = "icps";
private static final String ROUTER_URL = "router-url";
/**
* Local pointer to the singleton command dispatcher in this JVM
*/
private CommandDispatcher theDispatcher = null;
/**
* The Profile holding the configuration for this IMTPManager
*/
private Profile theProfile = null;
private String masterPMAddr;
private String localAddr;
private NodeLEAP localNode;
Logger logger = Logger.getMyLogger(getClass().getName());
/**
* Default constructor used to dynamically instantiate a new
* LEAPIMTPManager object
*/
public LEAPIMTPManager() {
}
// ////////////////////////////////
// IMTPManager Interface
// ////////////////////////////////
/**
* Initialize the support for intra-platform communication
*/
public void initialize(Profile p) throws IMTPException {
theProfile = p;
// Get the CommandDispatcher for the local platform
String platformName = p.getParameter(Profile.PLATFORM_ID, null);
theDispatcher = CommandDispatcher.getDispatcher(platformName);
// Add to the CommandDispatcher the ICPs specified in the Profile
try {
// Set defaults if not explicitly set.
setDefaults();
List l = theProfile.getSpecifiers(ICPS);
Iterator it = l.iterator();
while (it.hasNext()) {
Specifier s = (Specifier) it.next();
try {
ICP peer = (ICP) Class.forName(s.getClassName()).newInstance();
String id = (s.getArgs() != null ? (String) (s.getArgs()[0]) : null);
theDispatcher.addICP(peer, id, theProfile);
}
catch (Exception e) {
if(logger.isLoggable(Logger.SEVERE))
logger.log(Logger.SEVERE,"Error adding ICP. "+e);
}
}
// Initialize the local node
localNode = new NodeLEAP("No-Name", theProfile.getBooleanProperty(Profile.MAIN, true), theDispatcher);
Skeleton skel = new NodeSkel(localNode);
theDispatcher.registerSkeleton(skel, localNode);
}
catch (ProfileException pe) {
// Just print a warning
if(logger.isLoggable(Logger.SEVERE))
logger.log(Logger.SEVERE,"Profile error. "+pe.getMessage());
}
// Now check that some ICP is active. Note that, as a CommandDispatcher
// can serve multiple IMTPManagers, some ICPs could be already active.
List URLs = theDispatcher.getLocalURLs();
if (URLs.size() == 0) {
throw new IMTPException("No ICP active");
}
else {
localAddr = (String) URLs.get(0);
Iterator it = URLs.iterator();
StringBuffer sb = new StringBuffer("Listening for intra-platform commands on address:\n");
while (it.hasNext()) {
sb.append("- "+(String) it.next()+"\n");
}
logger.log(Logger.INFO,sb.toString());
}
// Be sure the mainURL uses the host address. Note that this must
// be done after ICP installation
adjustMainURL();
// If this is a backup main get the address of the master PlatformManager
if (theProfile.isBackupMain()) {
// This node hosts a real PlatformManager that is NOT the master PlatformManager
// --> MAIN_URL points to the master PlatformManager
masterPMAddr = theProfile.getParameter(MAIN_URL, null);
}
// Finally, if a URL for the default router is specified in the
// Profile, set it in the CommandDispatcher
theDispatcher.setRouterAddress(theProfile.getParameter(ROUTER_URL, null));
}
private void adjustMainURL() {
//#MIDP_EXCLUDE_BEGIN
try {
String mainURL = theProfile.getParameter(MAIN_URL, null);
TransportAddress ta = theDispatcher.stringToAddr(mainURL);
java.net.InetAddress ad = java.net.InetAddress.getByName(ta.getHost());
TransportProtocol tp = theDispatcher.getProtocol(ta.getProto());
String hostAddr = ad.getHostAddress();
if (hostAddr.equals("127.0.0.1")) {
hostAddr = ad.getHostName();
}
ta = tp.buildAddress(hostAddr, ta.getPort(), ta.getFile(), ta.getAnchor());
// DEBUG
//System.out.println("MAIN URL set to "+tp.addrToString(ta));
theProfile.setParameter(MAIN_URL, tp.addrToString(ta));
}
catch (Exception e) {
// Ignore it
}
//#MIDP_EXCLUDE_END
}
public Node getLocalNode() throws IMTPException {
return localNode;
}
//#MIDP_EXCLUDE_BEGIN
public void exportPlatformManager(PlatformManager mgr) throws IMTPException {
Skeleton skel = new PlatformManagerSkel(mgr, this);
mgr.setLocalAddress(localAddr);
theDispatcher.registerSkeleton(skel, mgr);
// Attach to the original Platform manager, if any
if (masterPMAddr != null) {
PlatformManager masterPM = theDispatcher.getPlatformManagerStub(masterPMAddr);
try {
((PlatformManagerImpl) mgr).setPlatformName(masterPM.getPlatformName());
logger.log(Logger.INFO, "Connecting to master Main Container at address "+masterPMAddr);
mgr.addReplica(masterPMAddr, true); // Do as if it was a propagated info
masterPM.addReplica(localAddr, false);
}
catch (ServiceException se) {
throw new IMTPException("Cannot attach to the original PlatformManager.", se);
}
catch (IMTPException imtpe) {
Throwable t = imtpe.getNested();
if ((t != null) && (t instanceof UnreachableException)) {
// The master main container does not exist. Become the leader
logger.log(Logger.INFO,"No master Main Container found at address "+masterPMAddr+". Take the leadership");
masterPMAddr = null;
theProfile.setParameter(Profile.LOCAL_SERVICE_MANAGER, "false");
}
else {
throw imtpe;
}
}
}
}
public void unexportPlatformManager(PlatformManager pm) throws IMTPException {
theDispatcher.deregisterSkeleton(pm);
}
//#MIDP_EXCLUDE_END
public PlatformManager getPlatformManagerProxy() throws IMTPException {
return theDispatcher.getPlatformManagerProxy(theProfile);
}
public PlatformManager getPlatformManagerProxy(String addr) throws IMTPException {
return theDispatcher.getPlatformManagerStub(addr);
}
public void reconnected(PlatformManager pm) {
theDispatcher.setPlatformManagerProxy(pm);
}
// FIXME: this is not IMTP-dependent --> Should be moved elsewhere
public Service.Slice createSliceProxy(String serviceName, Class itf, Node where) throws IMTPException {
try {
Class proxyClass = Class.forName(serviceName + "Proxy");
Service.Slice proxy = (Service.Slice) proxyClass.newInstance();
if (proxy instanceof SliceProxy) {
((SliceProxy) proxy).setNode(where);
}
//#DOTNET_EXCLUDE_BEGIN
else if (proxy instanceof Service.SliceProxy) {
((Service.SliceProxy) proxy).setNode(where);
}
//#DOTNET_EXCLUDE_END
else {
throw new IMTPException("Class "+proxyClass.getName()+" is not a slice proxy.");
}
return proxy;
}
catch(Exception e) {
throw new IMTPException("Error creating a slice proxy", e);
}
}
/**
* Release all resources of this LEAPIMTPManager
*/
public void shutDown() {
try {
if (localNode != null) {
localNode.exit();
theDispatcher.deregisterSkeleton(localNode);
}
}
catch (IMTPException imtpe) {
// Should never happen since this is a local call
imtpe.printStackTrace();
}
}
/**
*/
public List getLocalAddresses() {
return theDispatcher.getLocalTAs();
}
// /////////////////////////
// PRIVATE METHODS
// /////////////////////////
/**
In the Profile ICPS can be specified as follows.
1) If there is only one ICP -->
icps = <icp-class-name>
<param-key> = <param-value>
.......
2) In general (typically used when there are 2 or more ICPs)
icps = <icp1-class-name>(<icp1-id>);<icp2-class-name>(<icp2-id>)...
<icp1-id>-<param-key> = <param-value>
.......
<icp2-id>-<param-key> = <param-value>
.......
If there is no ICP indication set it as follows.
a) Peripheral container / J2SE or PJAVA
- There is at least 1 ICP already active --> Nothing
- There are no ICPs already active --> JICPPeer
b) Peripheral container / MIDP --> Throws a ProfileException
c) Main container / J2SE or PJAVA --> JICPPeer
*/
private void setDefaults() throws ProfileException {
// - MAIN URL (Useful for peripheral containers and backup main. Ignored otherwise
String mainURL = theProfile.getParameter(MAIN_URL, null);
if (mainURL == null) {
String mainHost = getMainHost();
if (mainHost != null) {
String mainProto = theProfile.getParameter(Profile.MAIN_PROTO, "jicp");
String mainPort = theProfile.getParameter(Profile.MAIN_PORT, null);
mainPort = (mainPort != null) ? (":" + mainPort) : (":" + JICPProtocol.DEFAULT_PORT);
mainURL = new String(mainProto + "://" + mainHost + mainPort);
theProfile.setParameter(MAIN_URL, mainURL);
}
}
if (!theProfile.getBooleanProperty(Profile.MAIN, true)) {
// ICPS for a "Peripheral Container"
if (theProfile.getParameter(ICPS, null) == null) {
String jvm = theProfile.getParameter(Profile.JVM, null);
if (Profile.MIDP.equals(jvm)) {
// Should never happen
throw new ProfileException("Stand-alone execution mode not supported in MIDP");
}
else {
// Set default ICPS for J2SE and PJAVA
if (theDispatcher.getLocalURLs().size() == 0) {
theProfile.setParameter(ICPS, "jade.imtp.leap.JICP.JICPPeer");
}
}
}
}
else {
// ICPS for a Main Container
if (theProfile.getParameter(ICPS, null) == null) {
theProfile.setParameter(ICPS, "jade.imtp.leap.JICP.JICPPeer");
}
}
}
/**
*/
private String getMainHost() {
String host = theProfile.getParameter(Profile.MAIN_HOST, null);
//#MIDP_EXCLUDE_BEGIN
if (host == null) {
host = Profile.getDefaultNetworkName();
}
//#MIDP_EXCLUDE_END
return host;
}
public TransportAddress stringToAddr(String addr) throws IMTPException {
try {
return theDispatcher.stringToAddr(addr);
}
catch (DispatcherException de) {
throw new IMTPException(de.getMessage());
}
}
}