package jadex.commons.service.library;
import jadex.commons.Future;
import jadex.commons.IFuture;
import jadex.commons.SUtil;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.service.BasicService;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Library service for loading classpath elements.
*/
public class LibraryService extends BasicService implements ILibraryService
{
//-------- attributes --------
/** LibraryService listeners. */
private Set listeners;
/** The initial parent ClassLoader. */
private ClassLoader basecl;
/** The urls. */
private List urls;
/** Current ClassLoader. */
private ClassLoader libcl;
//-------- constructors --------
/**
* Creates a new LibraryService.
*/
public LibraryService(Object providerid)
{
this(null, providerid);
}
/**
* Creates a new LibraryService.
* @param urls Urls may be specified as java.net.URLs, java.io.Files or java.lang.Strings.
* Strings are interpreted as relative files (relative to current directory),
* absolute files or URLs (whatever can be found).
*/
public LibraryService(Object[] urls, Object providerid)
{
this(urls, providerid, null);
}
/**
* Creates a new LibraryService.
* @param urls Urls may be specified as java.net.URLs, java.io.Files or java.lang.Strings.
* Strings are interpreted as relative files (relative to current directory),
* absolute files or URLs (whatever can be found).
*/
public LibraryService(Object[] urls, Object providerid, Map properties)
{
// Hack!!! Should not reference gui???
super(providerid, ILibraryService.class, properties);
basecl = Thread.currentThread().getContextClassLoader();
libcl = basecl;
listeners = Collections.synchronizedSet(new HashSet());
synchronized(this)
{
this.urls = new ArrayList();
if(urls!=null)
{
for(int i=0; i<urls.length; i++)
{
addURL(toURL(urls[i]));
}
}
}
}
/**
* Add a path.
* @param path The path.
*/
public void addPath(String path)
{
addURL(toURL(path));
}
//-------- methods --------
/**
* Add a new url.
* @param url The url.
*/
public void addURL(URL url)
{
// System.out.println("add "+url);
ILibraryServiceListener[] lis;
synchronized(this)
{
urls.add(url);
libcl = new URLClassLoader((URL[])urls.toArray(new URL[urls.size()]), basecl);
lis = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
}
// Do not notify listeners with lock held!
for(int i=0; i<lis.length; i++)
{
final ILibraryServiceListener liscopy = lis[i];
lis[i].urlAdded(url).addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
}
public void exceptionOccurred(Object source, Exception exception)
{
exception.printStackTrace();
removeLibraryServiceListener(liscopy);
}
});
}
// fireURLAdded(url);
}
/**
* Remove a url.
* @param url The url.
*/
public void removeURL(URL url)
{
ILibraryServiceListener[] lis;
synchronized(this)
{
urls.remove(url);
libcl = new URLClassLoader((URL[])urls.toArray(new URL[urls.size()]), basecl);
lis = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
}
// Do not notify listeners with lock held!
for(int i=0; i<lis.length; i++)
{
final ILibraryServiceListener liscopy = lis[i];
lis[i].urlRemoved(url).addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
}
public void exceptionOccurred(Object source, Exception exception)
{
exception.printStackTrace();
removeLibraryServiceListener(liscopy);
}
});
}
// fireURLRemoved(url);
}
/**
* Get all managed entries as URLs.
* @return url The urls.
*/
public synchronized IFuture getURLs()
{
List ret = new ArrayList();
ret.addAll(urls);
return new Future(ret);
}
/**
* Get other contained (but not directly managed) URLs.
* @return The list of urls.
*/
public synchronized IFuture getNonManagedURLs()
{
return new Future(SUtil.getClasspathURLs(libcl));
}
/**
* Get all urls (managed and non-managed).
* @return The list of urls.
*/
public IFuture getAllURLs()
{
List ret = new ArrayList();
ret.addAll(urls);
ret.addAll(SUtil.getClasspathURLs(libcl));
return new Future(ret);
}
/**
* Returns the current ClassLoader
* @return the current ClassLoader
*/
public ClassLoader getClassLoader()
{
return libcl;
}
/**
* Start the service.
* /
public synchronized IFuture startService()
{
return super.startService();
}*/
/**
* Shutdown the service.
* Releases all cached resources and shuts down the library service.
* @param listener The listener.
*/
public synchronized IFuture shutdownService()
{
basecl = null;
libcl = null;
listeners.clear();
return super.shutdownService();
}
/**
* Add an Library Service listener.
* The listener is registered for changes in the loaded library states.
* @param listener The listener to be added.
*/
public void addLibraryServiceListener(ILibraryServiceListener listener)
{
listeners.add(listener);
}
/**
* Remove an Library Service listener.
* @param listener The listener to be removed.
*/
public void removeLibraryServiceListener(ILibraryServiceListener listener)
{
listeners.remove(listener);
}
/**
* Helper method for validating jar-files
* @param file the jar-file
* /
private boolean checkJar(File file)
{
try
{
JarFile jarFile = new JarFile(file);
}
catch(IOException e)
{
return false;
}
return true;
}*/
/**
* Fires the class-path-added event
* @param path the new class path
* /
protected synchronized void fireURLAdded(URL url)
{
// System.out.println("listeners: "+listeners);
for(Iterator it = listeners.iterator(); it.hasNext();)
{
ILibraryServiceListener listener = (ILibraryServiceListener)it.next();
listener.urlAdded(url);
}
}*/
/**
* Fires the class-path-removed event
* @param path the removed class path
* /
protected synchronized void fireURLRemoved(URL url)
{
for(Iterator it = listeners.iterator(); it.hasNext();)
{
ILibraryServiceListener listener = (ILibraryServiceListener)it.next();
listener.urlRemoved(url);
}
}*/
/**
* Convert a file/string/url.
*/
public static URL toURL(Object url)
{
URL ret = null;
if(url instanceof String)
{
String string = (String) url;
File file = new File(string);
if(file.exists())
{
url = file;
}
else
{
file = new File(System.getProperty("user.dir"), string);
if(file.exists())
{
url = file;
}
else
{
try
{
url = new URL(string);
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
}
}
if(url instanceof URL)
{
ret = (URL)url;
}
else if(url instanceof File)
{
try
{
ret = ((File)url).toURI().toURL();
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
return ret;
}
/**
* Get the non-managed classpath entries as strings.
* @return Classpath entries as a list of strings.
*/
public IFuture getURLStrings()
{
final Future ret = new Future();
getURLs().addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
List urls = (List)result;
// TODO Auto-generated method stub
List tmp = new ArrayList();
// todo: hack!!!
for(Iterator it=urls.iterator(); it.hasNext(); )
{
URL url = (URL)it.next();
tmp.add(url.toString());
// String file = url.getFile();
// File f = new File(file);
//
// // Hack!!! Above code doesnt handle relative url paths.
// if(!f.exists())
// {
// File newfile = new File(new File("."), file);
// if(newfile.exists())
// {
// f = newfile;
// }
// }
// ret.add(f.getAbsolutePath());
}
ret.setResult(tmp);
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
return ret;
}
/**
* Get the non-managed classpath entries.
* @return Classpath entries as a list of strings.
*/
public IFuture getNonManagedURLStrings()
{
final Future ret = new Future();
getNonManagedURLs().addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
List urls = (List)result;
List tmp = new ArrayList();
// todo: hack!!!
for(Iterator it=urls.iterator(); it.hasNext(); )
{
URL url = (URL)it.next();
tmp.add(url.toString());
// String file = url.getFile();
// File f = new File(file);
//
// // Hack!!! Above code doesnt handle relative url paths.
// if(!f.exists())
// {
// File newfile = new File(new File("."), file);
// if(newfile.exists())
// {
// f = newfile;
// }
// }
// ret.add(f.getAbsolutePath());
}
ret.setResult(tmp);
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
return ret;
// java.util.List ret = new ArrayList();
//
//// ILibraryService ls = (ILibraryService)getJCC().getServiceContainer().getService(ILibraryService.class);
// // todo: hack
//// ILibraryService ls = (ILibraryService)getJCC().getServiceContainer().getService(ILibraryService.class).get(new ThreadSuspendable());
// ClassLoader cl = ls.getClassLoader();
//
// List cps = SUtil.getClasspathURLs(cl!=null ? cl.getParent() : null); // todo: classpath?
// for(int i=0; i<cps.size(); i++)
// {
// URL url = (URL)cps.get(i);
// ret.add(url.toString());
//
//// String file = url.getFile();
//// File f = new File(file);
////
//// // Hack!!! Above code doesnt handle relative url paths.
//// if(!f.exists())
//// {
//// File newfile = new File(new File("."), file);
//// if(newfile.exists())
//// {
//// f = newfile;
//// }
//// }
//// ret.add(f.getAbsolutePath());
// }
//
// return ret;
}
}