package jadex.tools.daemon;
import jadex.bridge.ComponentIdentifier;
import jadex.bridge.IArgument;
import jadex.bridge.IComponentIdentifier;
import jadex.commons.ChangeEvent;
import jadex.commons.Future;
import jadex.commons.IFuture;
import jadex.commons.SUtil;
import jadex.commons.StreamCopy;
import jadex.commons.concurrent.DelegationResultListener;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.service.SServiceProvider;
import jadex.commons.service.library.ILibraryService;
import jadex.micro.IMicroExternalAccess;
import jadex.micro.MicroAgent;
import jadex.micro.MicroAgentMetaInfo;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.SwingUtilities;
/**
* Daemon agent provides functionalities for managing platforms.
*/
public class DaemonAgent extends MicroAgent
{
//-------- attributes --------
/** The started platforms. */
protected Map platforms;
/** The listeners. */
protected List listeners;
//-------- methods --------
/**
* Called once after agent creation.
*/
public void agentCreated()
{
platforms = Collections.synchronizedMap(new HashMap());
listeners = Collections.synchronizedList(new ArrayList());
addDirectService(new DaemonService(getExternalAccess()));
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
DaemonPanel.createGui((IMicroExternalAccess)getExternalAccess());
}
});
}
/**
* Start a platform using a configuration.
* @param args The arguments.
*/
public IFuture startPlatform(StartOptions opt)
{
final Future ret = new Future();
final StartOptions options = opt==null? new StartOptions(): opt;
// if(options.getMain()==null)
// {
// options.setMain("jadex.base.Starter");
// }
if(options.getClassPath()==null || options.getClassPath().length()==0)
{
SServiceProvider.getService(getServiceProvider(), ILibraryService.class)
.addResultListener(createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object source, Object result)
{
ILibraryService ls = (ILibraryService)result;
ls.getAllURLs().addResultListener(createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object source, Object result)
{
List urls = (List)result;
List res = new ArrayList();
for(int i=0; i<urls.size(); i++)
{
URL url = (URL)urls.get(i);
String name = SUtil.convertURLToString(url);
if(name!=null)
res.add(name);
else
System.out.println("Cannot convert url to file: "+url);
}
StringBuffer buf = new StringBuffer();
for(int i=0; i<res.size(); i++)
{
buf.append(res.get(i));
if(i+1<res.size())
buf.append(File.pathSeparator);
}
options.setClassPath(buf.toString());
doStartPlatform(options).addResultListener(new DelegationResultListener(ret));
}
}));
}
}));
}
else
{
doStartPlatform(options).addResultListener(createResultListener(new DelegationResultListener(ret)));
}
return ret;
}
/**
* Start a platform using a configuration.
* @param args The arguments.
* /
public IFuture startPlatform(StartOptions opt)
{
final Future ret = new Future();
// Start platform in the same VM.
Starter.createPlatform(args).addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
IExternalAccess platform = (IExternalAccess)result;
platforms.put(platform.getComponentIdentifier(), platform);
ret.setResult(result);
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
return ret;
}*/
/**
*
*/
public IFuture doStartPlatform(StartOptions options)
{
final Future ret = new Future();
// Start platform in another VM.
try
{
// Can be called in another directory
File newcurdir = new File(options.getStartDirectory());
newcurdir.mkdirs();
String cmd = options.getStartCommand();
System.out.println("Starting process: "+cmd);
final Process proc = Runtime.getRuntime().exec(options.getStartCommand(), null, newcurdir);
FilterOutputStream fos = new FilterOutputStream(System.out)
{
StringBuffer buf = new StringBuffer();
boolean fin = false;
public void write(byte[] b) throws IOException
{
if(!fin)
{
buf.append(new String(b));
for(int i=0; i<b.length; i++)
{
if(' '==b[i])
{
fin = true;
IComponentIdentifier cid = new ComponentIdentifier(buf.toString());
platforms.put(cid, proc);
notifyListeners(new ChangeEvent(null, IDaemonService.ADDED, cid));
ret.setResult(cid);
break;
}
}
}
super.write(b);
}
public void write(byte[] b, int off, int len) throws IOException
{
if(!fin)
{
for(int i=0; i<len; i++)
{
buf.append((char)b[i]);
if(' '==b[i])
{
fin = true;
IComponentIdentifier cid = new ComponentIdentifier(buf.toString());
platforms.put(cid, proc);
notifyListeners(new ChangeEvent(null, IDaemonService.ADDED, cid));
ret.setResult(cid);
break;
}
}
}
super.write(b, off, len);
}
public void write(int b) throws IOException
{
if(!fin)
{
buf.append((char)b);
if(' '==b)
{
fin = true;
IComponentIdentifier cid = new ComponentIdentifier(buf.toString());
platforms.put(cid, proc);
notifyListeners(new ChangeEvent(null, IDaemonService.ADDED, cid));
ret.setResult(cid);
}
}
super.write(b);
}
};
new Thread(new StreamCopy(proc.getInputStream(), fos)).start();
new Thread(new StreamCopy(proc.getErrorStream(), System.err)).start();
// boolean finished = false;
// while(!finished && !abort)
// {
// try
// {
// Thread.sleep(300);
// if(proc.exitValue()!=0)
// throw new RuntimeException("Java returned an error or could not be invoked.");
// finished = true;
// }
// catch(IllegalThreadStateException ie)
// {
// if(abort)
// proc.destroy();
// }
// }
/*Process proc = Runtime.getRuntime().exec(cmd+" "+cmdline);
new Thread(new StreamCopy(proc.getInputStream(), System.out)).start();
new Thread(new StreamCopy(proc.getErrorStream(), System.out)).start();
if(proc.waitFor()!=0)
// todo: does not work because process output stream is not read :-(
//if(Runtime.getRuntime().exec(cmd+" -classpath "+cp+cmdline).waitFor()!=0)
{
throw new RuntimeException("Javadoc returned an error or could not be invoked.");
}*/
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException("Could not start process. Reason: "+ex.getMessage());
}
return ret;
}
/**
* Shutdown a platform.
* @param cid The platform id.
*/
public IFuture shutdownPlatform(final IComponentIdentifier cid)
{
final Future ret = new Future();
Process proc = (Process)platforms.get(cid);
if(proc==null)
{
ret.setException(new RuntimeException("Platform not found: "+cid));
}
else
{
proc.destroy();
ret.setResult(null);
notifyListeners(new ChangeEvent(this, IDaemonService.REMOVED, cid));
}
return ret;
}
/**
* Shutdown a platform.
* @param cid The platform id.
* /
public IFuture shutdownPlatform(final IComponentIdentifier cid)
{
final Future ret = new Future();
IExternalAccess platform = (IExternalAccess)platforms.get(cid);
if(platform==null)
{
ret.setException(new RuntimeException("No platform found: "+cid));
}
else
{
SServiceProvider.getService(platform.getServiceProvider(), IComponentManagementService.class)
.addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
IComponentManagementService cms = (IComponentManagementService)result;
cms.destroyComponent(cid).addResultListener(new DelegationResultListener(ret));
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
}
return ret;
}*/
/**
* Get the component identifiers of all (managed) platforms.
* @return Collection of platform ids.
*/
public IFuture getPlatforms()
{
return new Future(platforms.keySet());
}
/**
* Add a change listener.
* @param listener The change listener.
*/
public void addChangeListener(IRemoteChangeListener listener)
{
listeners.add(listener);
}
/**
* Remove a change listener.
* @param listener The change listener.
*/
public void removeChangeListener(IRemoteChangeListener listener)
{
listeners.remove(listener);
}
/**
* Notify the listeners.
*/
protected void notifyListeners(ChangeEvent event)
{
IRemoteChangeListener[] alisteners;
synchronized(this)
{
alisteners = listeners.isEmpty()? null:
(IRemoteChangeListener[])listeners.toArray(new IRemoteChangeListener[0]);
}
if(alisteners!=null)
{
for(int i=0; i<alisteners.length; i++)
{
final IRemoteChangeListener lis = alisteners[i];
alisteners[i].changeOccurred(event).addResultListener(createResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
}
public void exceptionOccurred(Object source, Exception exception)
{
// System.out.println("Removing listener: "+lis);
removeChangeListener(lis);
}
}));
}
}
}
//-------- static methods --------
/**
* Get the meta information about the agent.
*/
public static MicroAgentMetaInfo getMetaInfo()
{
return new MicroAgentMetaInfo("This agent offers the daemon service.", null,
new IArgument[]{}//new Argument("infos", "Initial information records.", "InformationEntry[]")}
, null, null, SUtil.createHashMap(new String[]{"componentviewer.viewerclass"}, new Object[]{"jadex.tools.daemon.DaemonViewerPanel"}),
new Class[]{ILibraryService.class}, new Class[]{IDaemonService.class});
}
}