jadex.base.service.library.LibraryService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jadex-platform-base Show documentation
Show all versions of jadex-platform-base Show documentation
The Jadex platform base package contains
functionality useful for constructing platforms.
The newest version!
package jadex.base.service.library;
import jadex.bridge.IInputConnection;
import jadex.bridge.IInternalAccess;
import jadex.bridge.IResourceIdentifier;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.Excluded;
import jadex.bridge.service.annotation.Reference;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.annotation.ServiceComponent;
import jadex.bridge.service.annotation.ServiceShutdown;
import jadex.bridge.service.annotation.ServiceStart;
import jadex.bridge.service.types.library.IDependencyService;
import jadex.bridge.service.types.library.ILibraryService;
import jadex.bridge.service.types.library.ILibraryServiceListener;
import jadex.bridge.service.types.remote.ServiceOutputConnection;
import jadex.bridge.service.types.settings.ISettingsService;
import jadex.commons.IPropertiesProvider;
import jadex.commons.Properties;
import jadex.commons.SUtil;
import jadex.commons.Tuple2;
import jadex.commons.future.CollectionResultListener;
import jadex.commons.future.CounterResultListener;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.ExceptionDelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* Library service for loading classpath elements.
*/
@Service(ILibraryService.class)
public class LibraryService implements ILibraryService, IPropertiesProvider
{
//-------- constants --------
/**
* The (standard) Library service name.
*/
public static final String LIBRARY_SERVICE = "library_service";
//-------- attributes --------
/** The component. */
@ServiceComponent
protected IInternalAccess component;
/** LibraryService listeners. */
protected Set listeners;
/** The init urls. */
protected Object[] initurls;
/** The class loader futures for currently loading class loaders. */
protected Map> clfuts;
/** The map of managed resources (url (for local case) -> delegate loader). */
protected Map classloaders;
/** Rid support, for a rid all rids are saved that support it. */
protected Map> ridsupport;
/** The primary managed rids and the number of their support. */
protected Map managedrids;
/** The global class loader (cached for speed). */
// todo: remove!?
protected ClassLoader globalcl;
/** The base classloader. */
protected ClassLoader baseloader;
/** The non-managed urls (cached for speed). */
protected Set nonmanaged;
//-------- constructors --------
/**
* Creates a new LibraryService.
*/
public LibraryService()
{
this((ClassLoader)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)
{
this(urls, null);
}
/**
* Creates a new LibraryService.
* @param baseloader The base classloader that is parent of all subloaders.
*/
public LibraryService(ClassLoader baseloader)
{
this(null, baseloader, 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, ClassLoader baseloader)
{
this(urls, baseloader, 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, ClassLoader baseloader, Map properties)
{
this.classloaders = new HashMap();
this.clfuts = new HashMap>();
this.listeners = new LinkedHashSet();
this.ridsupport = new LinkedHashMap>();
this.managedrids = new LinkedHashMap();
this.initurls = urls!=null? urls.clone(): urls;
this.baseloader = baseloader!=null? baseloader: getClass().getClassLoader();
}
//-------- methods --------
/**
* Add a new resource identifier.
* @param rid The resource identifier.
* @return The possibly completed rid (may contain an additional local rid when global was given):
*/
public IFuture addResourceIdentifier(IResourceIdentifier rid, final boolean workspace)
{
// System.out.println("add "+rid);
final Future ret = new Future();
getDependencies(rid, workspace).addResultListener(new ExceptionDelegationResultListener
>>, IResourceIdentifier>(ret)
{
public void customResultAvailable(Tuple2>> result)
{
final IResourceIdentifier rid = result.getFirstEntity();
// System.out.println("add end "+rid);
getClassLoader(rid, null, rid, workspace).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
addManaged(rid);
ret.setResult(rid);
}
});
}
public void exceptionOccurred(Exception exception)
{
exception.printStackTrace();
super.exceptionOccurred(exception);
}
});
return ret;
}
/**
* Remove a resource identifier.
* @param url The resource identifier.
*/
public IFuture removeResourceIdentifier(final IResourceIdentifier rid)
{
// System.out.println("remove "+rid);
final Future ret = new Future();
// todo: workspace=true?
getClassLoader(rid, null, null, true).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
boolean removed = removeManaged(rid);
if(removed)
{
if(result!=null)
{
for(Iterator it=result.getAllResourceIdentifiers().iterator(); it.hasNext(); )
{
IResourceIdentifier dep = it.next();
removeSupport(dep, rid);
}
}
// Do not notify listeners with lock held!
ILibraryServiceListener[] lis = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
for(int i=0; i()
{
public void resultAvailable(Void result)
{
}
public void exceptionOccurred(Exception exception)
{
// todo: how to handle timeouts?! allow manual retry?
// exception.printStackTrace();
removeLibraryServiceListener(liscopy);
};
});
}
}
ret.setResult(null);
}
});
return ret;
}
/**
* Remove a resource identifier.
* @param url The resource identifier.
*/
public IFuture removeResourceIdentifierCompletely(final IResourceIdentifier rid)
{
// System.out.println("remove "+rid);
final Future ret = new Future();
// todo: workspace=true?
getClassLoader(rid, null, null, true).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
removeManagedCompletely(rid);
if(result!=null)
{
for(Iterator it=result.getAllResourceIdentifiers().iterator(); it.hasNext(); )
{
IResourceIdentifier dep = it.next();
removeSupport(dep, rid);
}
}
// Do not notify listeners with lock held!
ILibraryServiceListener[] lis = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
for(int i=0; i()
{
public void resultAvailable(Void result)
{
}
public void exceptionOccurred(Exception exception)
{
// todo: how to handle timeouts?! allow manual retry?
// exception.printStackTrace();
removeLibraryServiceListener(liscopy);
};
});
}
ret.setResult(null);
}
});
return ret;
}
/**
* Get all managed (directly added i.e. top-level) resource identifiers.
* @return The list of resource identifiers.
*/
public IFuture> getManagedResourceIdentifiers()
{
return new Future>(new ArrayList(managedrids.keySet()));
}
/**
* Get all resource identifiers (also indirectly managed.
*/
public IFuture> getIndirectResourceIdentifiers()
{
List ret = new ArrayList();
for(Iterator it=classloaders.values().iterator(); it.hasNext(); )
{
IResourceIdentifier rid = it.next().getResourceIdentifier();
if(!managedrids.containsKey(rid))
{
ret.add(rid);
}
}
return new Future>(ret);
}
/**
* Get all resource identifiers (does not include urls of parent loader).
* @return The list of resource identifiers.
*/
public IFuture> getAllResourceIdentifiers()
{
List ret = new ArrayList();
for(Iterator it=classloaders.values().iterator(); it.hasNext(); )
{
IResourceIdentifier rid = it.next().getResourceIdentifier();
ret.add(rid);
}
return new Future>(ret);
}
/**
* Add a new url.
* @param url The resource identifier.
*/
// public IFuture addURL(final URL url, final boolean workspace)
public IFuture addURL(final URL url)
{
final Future ret = new Future();
component.getServiceContainer().searchService(IDependencyService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IDependencyService drs)
{
drs.getResourceIdentifier(url).addResultListener(
new DelegationResultListener(ret)
{
public void customResultAvailable(final IResourceIdentifier rid)
{
// todo: should be true?
addResourceIdentifier(rid, true).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IResourceIdentifier result)
{
ret.setResult(rid);
}
});
}
});
}
});
return ret;
}
/**
* Remove a new url.
* @param url The resource identifier.
*/
public IFuture removeURL(final URL url)
{
final Future ret = new Future();
component.getServiceContainer().searchService(IDependencyService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IDependencyService drs)
{
drs.getResourceIdentifier(url).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IResourceIdentifier result)
{
removeResourceIdentifier(result).addResultListener(new DelegationResultListener(ret));
}
});
}
});
return ret;
}
/**
* Remove a new url.
* @param url The resource identifier.
*/
public IFuture removeURLCompletely(final URL url)
{
final Future ret = new Future();
component.getServiceContainer().searchService(IDependencyService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IDependencyService drs)
{
drs.getResourceIdentifier(url).addResultListener(
new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IResourceIdentifier result)
{
removeResourceIdentifierCompletely(result).addResultListener(new DelegationResultListener(ret));
}
});
}
});
return ret;
}
/**
* Get other contained (but not directly managed) urls from parent classloaders.
* @return The list of urls.
*/
public IFuture> getNonManagedURLs()
{
return new Future>(new ArrayList(getInternalNonManagedURLs()));
}
/**
* Get other contained (but not directly managed) urls from parent classloaders.
* @return The set of urls.
*/
protected Set getInternalNonManagedURLs()
{
if(nonmanaged==null)
{
nonmanaged = new LinkedHashSet();
collectClasspathURLs(baseloader, nonmanaged);
}
return nonmanaged;
}
/**
* Get all urls (managed, indirect and non-managed from parent loader).
* @return The list of urls.
*/
public IFuture> getAllURLs()
{
final Future> ret = new Future>();
getAllResourceIdentifiers().addResultListener(new ExceptionDelegationResultListener, List>(ret)
{
public void customResultAvailable(List result)
{
final List res = new ArrayList();
for(int i=0; i getClassLoader(IResourceIdentifier rid)
{
return getClassLoader(rid, true);
}
/**
* Returns the current ClassLoader.
* @param rid The resource identifier (null for current global loader).
* @return the current ClassLoader
*/
@Excluded()
public IFuture getClassLoader(IResourceIdentifier rid, boolean workspace)
{
final Future ret = new Future();
if(rid==null)
{
if(globalcl==null)
{
DelegationURLClassLoader[] delegates = (DelegationURLClassLoader[])classloaders.values().toArray(new DelegationURLClassLoader[classloaders.size()]);
globalcl = new DelegationURLClassLoader(baseloader, delegates);
}
ret.setResult(globalcl);
}
else if(isLocal(rid) && getInternalNonManagedURLs().contains(rid.getLocalIdentifier().getUrl()))
{
ret.setResult(baseloader);
}
else
{
// Resolve global rid or local rid from same platform.
if(rid.getGlobalIdentifier()!=null || isLocal(rid))
{
getClassLoader(rid, null, null, workspace).addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
ret.setResult(result);
}
});
}
else
{
ret.setResult(null);
}
}
return ret;
}
/**
* Get the resource identifier for an url.
* @return The resource identifier.
*/
public IFuture getResourceIdentifier(final URL url)
{
final Future ret = new Future();
component.getServiceContainer().searchService(IDependencyService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(IDependencyService drs)
{
drs.getResourceIdentifier(url).addResultListener(new DelegationResultListener(ret));
}
});
return ret;
}
//-------- listener methods --------
/**
* Add an Library Service listener.
* The listener is registered for changes in the loaded library states.
* @param listener The listener to be added.
*/
public IFuture addLibraryServiceListener(ILibraryServiceListener listener)
{
if(listener==null)
throw new IllegalArgumentException();
listeners.add(listener);
return IFuture.DONE;
}
/**
* Remove an Library Service listener.
* @param listener The listener to be removed.
*/
public IFuture removeLibraryServiceListener(ILibraryServiceListener listener)
{
listeners.remove(listener);
return IFuture.DONE;
}
//-------- internal methods --------
/**
* Get or create a classloader for a rid.
*/
protected IFuture getClassLoader(final IResourceIdentifier rid,
Map> alldeps, final IResourceIdentifier support, final boolean workspace)
{
final Future ret;
if(isLocal(rid) && getInternalNonManagedURLs().contains(rid.getLocalIdentifier().getUrl()))
{
ret = new Future((DelegationURLClassLoader)null);
}
else if(clfuts.containsKey(rid))
{
ret = clfuts.get(rid);
}
else
{
// final URL url = rid.getLocalIdentifier().getSecondEntity();
ret = new Future();
DelegationURLClassLoader cl = (DelegationURLClassLoader)classloaders.get(rid);
if(cl!=null)
{
addSupport(rid, support);
ret.setResult(cl);
}
else
{
clfuts.put(rid, ret);
// if(rid.getGlobalIdentifier()==null)
// System.out.println("getClassLoader(): "+rid);
if(alldeps==null)
{
// System.out.println("getdeps in getcl: "+rid);
getDependencies(rid, workspace).addResultListener(
new ExceptionDelegationResultListener>>, DelegationURLClassLoader>(ret)
{
public void customResultAvailable(Tuple2>> deps)
{
createClassLoader(rid, deps.getSecondEntity(), support, workspace).addResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
clfuts.remove(rid);
super.customResultAvailable(result);
}
public void exceptionOccurred(Exception exception)
{
clfuts.remove(rid);
super.exceptionOccurred(exception);
}
});
}
public void exceptionOccurred(Exception exception)
{
clfuts.remove(rid);
super.exceptionOccurred(exception);
}
});
}
else
{
createClassLoader(rid, alldeps, support, workspace).addResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(DelegationURLClassLoader result)
{
clfuts.remove(rid);
super.customResultAvailable(result);
}
public void exceptionOccurred(Exception exception)
{
clfuts.remove(rid);
super.exceptionOccurred(exception);
}
});
}
}
}
return ret;
}
/**
* Create a new classloader.
*/
protected IFuture createClassLoader(final IResourceIdentifier rid, Map> alldeps, final IResourceIdentifier support, final boolean workspace)
{
// Class loaders shouldn't be created for local URLs, which are already available in base class loader.
assert rid.getLocalIdentifier()==null || !isLocal(rid) || !getInternalNonManagedURLs().contains(rid.getLocalIdentifier().getUrl());
final Future ret = new Future();
// final URL url = rid.getLocalIdentifier().getSecondEntity();
final List deps = alldeps.get(rid);
CollectionResultListener lis = new CollectionResultListener
(deps.size(), true, new ExceptionDelegationResultListener, DelegationURLClassLoader>(ret)
{
public void customResultAvailable(Collection result)
{
// Strip null values of provided dependencies from results.
for(Iterator it=result.iterator(); it.hasNext(); )
{
if(it.next()==null)
it.remove();
}
DelegationURLClassLoader[] delegates = (DelegationURLClassLoader[])result.toArray(new DelegationURLClassLoader[result.size()]);
DelegationURLClassLoader cl = new DelegationURLClassLoader(rid, baseloader, delegates);
classloaders.put(rid, cl);
// System.out.println("createClassLoader() put: "+rid);
globalcl = null;
addSupport(rid, support);
ret.setResult(cl);
ILibraryServiceListener[] lis = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
for(int i=0; i()
{
public void resultAvailable(Void result)
{
}
public void exceptionOccurred(Exception exception)
{
// todo: how to handle timeouts?! allow manual retry?
// exception.printStackTrace();
removeLibraryServiceListener(liscopy);
};
});
}
}
});
for(int i=0; i(platcid, mydep), null);
getClassLoader(mydep, alldeps, support, workspace).addResultListener(lis);
}
return ret;
}
/**
* Get the dependent urls.
*/
protected IFuture>>>
getDependencies(final IResourceIdentifier rid, final boolean workspace)
{
final Future>>> ret = new Future>>>();
component.getServiceContainer().searchService(IDependencyService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener>>>(ret)
{
public void customResultAvailable(IDependencyService drs)
{
drs.loadDependencies(rid, workspace).addResultListener(new DelegationResultListener>>>(ret));
}
});
return ret;
}
// /**
// * Add a path.
// * @param path The path.
// */
// protected void addPath(String path)
// {
// addURL(SUtil.toURL(path));
// }
/**
* Add support for a rid.
*/
protected void addSupport(IResourceIdentifier rid, IResourceIdentifier support)
{
if(rid!=null && support!=null)
{
Set mysup = ridsupport.get(rid);
if(mysup==null)
{
mysup = new HashSet();
ridsupport.put(rid, mysup);
}
mysup.add(support);
}
}
/**
* Remove support for a rid.
*/
protected void removeSupport(IResourceIdentifier rid, IResourceIdentifier support)
{
if(rid!=null && support!=null)
{
Set mysup = ridsupport.get(rid);
if(mysup!=null)
{
mysup.remove(support);
if(mysup.size()==0)
ridsupport.remove(rid);
}
else
{
throw new RuntimeException("No support found: "+ridsupport);
}
}
}
/**
* Add primary management entry for a rid.
*/
protected void addManaged(IResourceIdentifier rid)
{
if(rid!=null)
{
Integer num = managedrids.get(rid);
if(num==null)
{
managedrids.put(rid, 1);
}
else
{
managedrids.put(rid, new Integer(num.intValue()+1));
}
}
}
/**
* Remove primary management for a rid.
* @return True, if entry has to be removed.
*/
protected boolean removeManaged(IResourceIdentifier rid)
{
boolean ret = false;
if(rid!=null)
{
Integer num = managedrids.get(rid);
if(num!=null)
{
int now = num.intValue()-1;
if(now==0)
{
managedrids.remove(rid);
ret = true;
}
else
{
managedrids.put(rid, managedrids.put(rid, new Integer(num.intValue()-1)));
}
}
}
return ret;
}
/**
* Remove primary management for a rid.
*/
protected void removeManagedCompletely(IResourceIdentifier rid)
{
if(rid!=null)
{
managedrids.remove(rid);
}
}
/**
* Get the jar for a rid.
* @param rid The rid.
* @return The jar.
*/
public IFuture getJar(IResourceIdentifier rid)
{
final Future ret = new Future();
boolean fin = false;
// Has rid a local file desc on this platform?
if(isLocal(rid))
{
URL url = rid.getLocalIdentifier().getUrl();
File f = new File(url.getFile());
if(url.getFile().endsWith(".jar") && f.exists())
{
try
{
FileInputStream fis = new FileInputStream(f);
ServiceOutputConnection soc = new ServiceOutputConnection();
ret.setResult(soc.getInputConnection());
soc.writeFromInputStream(fis, component.getExternalAccess());
fin = true;
}
catch(IOException e)
{
}
}
}
if(!fin)
ret.setException(new RuntimeException("Could not find resource: "+rid));
// if(!fin && rid.getGlobalIdentifier()!=null)
// {
// // todo: get local location from dependency service?
// }
return ret;
}
//-------- methods --------
// /**
// * Add a new url.
// * @param url The url.
// */
// public void addURL(final URL url)
// {
//// System.out.println("add "+url);
// ILibraryServiceListener[] tmp = null;
//
// synchronized(this)
// {
// Integer refcount = (Integer)urlrefcount.get(url);
// if(refcount != null)
// {
// urlrefcount.put(url, new Integer(refcount.intValue() + 1));
// }
// else
// {
// urlrefcount.put(url, new Integer(1));
// tmp = (ILibraryServiceListener[])listeners.toArray(new ILibraryServiceListener[listeners.size()]);
// }
// }
//
// if(tmp != null)
// {
// final ILibraryServiceListener[] lis = tmp;
//
// getClassLoader(url).addResultListener(new DefaultResultListener()
// {
// public void resultAvailable(DelegationURLClassLoader result)
// {
// // Do not notify listeners with lock held!
//
// for(int i=0; i()
// {
// public void resultAvailable(DelegationURLClassLoader result)
// {
//// updateGlobalClassLoader();
//
// for(int i=0; i> getURLs()
// {
// return new Future>(new ArrayList(libcl.getAllURLs()));
// }
//
// /**
// * 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(libcl.getAllURLs());
// ret.addAll(SUtil.getClasspathURLs(libcl));
// ret.addAll(SUtil.getClasspathURLs(null));
// return new Future>(ret);
// }
//
// /**
// * Returns the current ClassLoader
// * @return the current ClassLoader
// */
// public ClassLoader getClassLoader()
// {
// return libcl;
// }
// /**
// * Load a class given a class identifier.
// * @param clid The class identifier.
// * @return The class for the identifier.
// */
// public IFuture loadClass(final IClassIdentifier clid)
// {
// final Future ret = new Future();
// IResourceIdentifier rid = clid.getResourceIdentifier();
// getClassLoader(rid).addResultListener(component.createResultListener(new ExceptionDelegationResultListener(ret)
// {
// public void customResultAvailable(ClassLoader cl)
// {
// try
// {
// ret.setResult(cl.loadClass(clid.getClassname()));
// }
// catch(Exception e)
// {
// ret.setException(e);
// }
// }
// }));
// return ret;
// }
/**
* Start the service.
*/
@ServiceStart
public IFuture startService()
{
final Future urlsdone = new Future();
if(initurls!=null)
{
CounterResultListener lis = new CounterResultListener(
initurls.length, new DelegationResultListener(urlsdone));
for(int i=0; i ret = new Future();
urlsdone.addResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Void result)
{
component.getServiceContainer().searchService(ISettingsService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(ISettingsService settings)
{
settings.registerPropertiesProvider(LIBRARY_SERVICE, LibraryService.this)
.addResultListener(new DelegationResultListener(ret));
}
public void exceptionOccurred(Exception exception)
{
// No settings service: ignore
ret.setResult(null);
}
});
}
});
return ret;
}
/**
* Shutdown the service.
* Releases all cached resources and shuts down the library service.
* @param listener The listener.
*/
@ServiceShutdown
public IFuture shutdownService()
{
// System.out.println("shut");
final Future saved = new Future();
component.getServiceContainer().searchService(ISettingsService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(new ExceptionDelegationResultListener(saved)
{
public void customResultAvailable(ISettingsService settings)
{
settings.deregisterPropertiesProvider(LIBRARY_SERVICE)
.addResultListener(new DelegationResultListener(saved));
}
public void exceptionOccurred(Exception exception)
{
// No settings service: ignore
saved.setResult(null);
}
});
final Future ret = new Future();
saved.addResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Void result)
{
synchronized(this)
{
// libcl = null;
listeners.clear();
ret.setResult(null);
}
}
});
return ret;
}
/**
* 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;
// boolean jar = false;
// if(url instanceof String)
// {
// String string = (String) url;
// if(string.startsWith("file:") || string.startsWith("jar:file:"))
// {
// try
// {
// string = URLDecoder.decode(string, "UTF-8");
// }
// catch(UnsupportedEncodingException e)
// {
// e.printStackTrace();
// }
// }
//
// jar = string.startsWith("jar:file:");
// url = jar ? new File(string.substring(9))
// : string.startsWith("file:") ? new File(string.substring(5)) : null;
//
//
// if(url==null)
// {
// 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
// {
// String abs = ((File)url).getAbsolutePath();
// String rel = SUtil.convertPathToRelative(abs);
// ret = abs.equals(rel) ? new File(abs).toURI().toURL()
// : new File(System.getProperty("user.dir"), rel).toURI().toURL();
// if(jar)
// {
// if(ret.toString().endsWith("!"))
// ret = new URL("jar:"+ret.toString()+"/"); // Add missing slash in jar url.
// else
// ret = new URL("jar:"+ret.toString());
// }
// }
// 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(List result)
// {
//// List urls = (List)result;
// List tmp = new ArrayList();
// // todo: hack!!!
//
// for(Iterator it=result.iterator(); it.hasNext(); )
// {
// 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(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(List result)
// {
//// List urls = (List)result;
// List tmp = new ArrayList();
// // todo: hack!!!
//
// for(Iterator it=result.iterator(); it.hasNext(); )
// {
// 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(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 getClassDefinition(String name)
// {
// Future ret = new Future();
//
// Class clazz = SReflect.findClass0(name, null, libcl);
// if(clazz!=null)
// {
// try
// {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(bos);
// oos.writeObject(clazz);
// oos.close();
// bos.close();
// byte[] data = bos.toByteArray();
// ret.setResult(data);
// }
// catch(Exception e)
// {
// ret.setResult(null);
// }
// }
// else
// {
// ret.setResult(null);
// }
//
// return ret;
// }
//-------- IPropertiesProvider interface --------
/**
* Update from given properties.
*/
public IFuture setProperties(Properties props)
{
// // Do not remove existing urls?
// // todo: treat arguments and
// // Remove existing urls
//// libcl = new DelegationURLClassLoader(ClassLoader.getSystemClassLoader(), initurls);
//
// // todo: fix me / does not work getClassLoader is async
// if(initurls!=null)
// {
// for(int i=0; i getProperties()
{
// String[] entries;
// if(libcl != null)
// {
// synchronized(this)
// {
// List urls = new ArrayList(libcl.getAllURLs());
// entries = new String[urls.size()];
// for(int i=0; i(props);
return new Future(new Properties());
}
// /**
// * Update the global class loader.
// *
// * hack: should be removed
// */
// public void updateGlobalClassLoader()
// {
// DelegationURLClassLoader[] delegates = (DelegationURLClassLoader[])classloaders.values().toArray(new DelegationURLClassLoader[classloaders.size()]);
//
/* if_not[android] */
// this.libcl = new DelegationURLClassLoader(ClassLoader.getSystemClassLoader(), delegates);
/* else[android]
// this.libcl = new DelegationClassLoader(LibraryService.class.getClassLoader(), urls);
// end[android]*/
//
// System.out.println("update global: "+delegates.length);
// }
// /**
// *
// */
// protected IFuture createResourceIdentifier(URL url)
// {
// Tuple2 lid = new Tuple2(cid, url);
// String gid = mh.getArtifactDescription(url);
// ResourceIdentifier rid = new ResourceIdentifier(lid, gid);
// return new Future(rid);
// }
/**
* Collect all URLs belonging to a class loader.
*/
protected void collectClasspathURLs(ClassLoader classloader, Set set)
{
assert classloader!=null;
if(classloader.getParent()!=null)
{
collectClasspathURLs(classloader.getParent(), set);
}
if(classloader instanceof URLClassLoader)
{
URL[] urls = ((URLClassLoader)classloader).getURLs();
for(int i = 0; i < urls.length; i++)
{
set.add(urls[i]);
collectManifestURLs(urls[i], set);
}
}
}
/**
* Collect all URLs as specified in a manifest.
*/
protected void collectManifestURLs(URL url, Set set)
{
File file = SUtil.urlToFile(url.toString());
if(file!=null && file.exists() && !file.isDirectory()) // Todo: load manifest also from directories!?
{
try
{
JarFile jarfile = new JarFile(file);
Manifest manifest = jarfile.getManifest();
if(manifest!=null)
{
String classpath = manifest.getMainAttributes().getValue(new Attributes.Name("Class-Path"));
if(classpath!=null)
{
StringTokenizer tok = new StringTokenizer(classpath, " ");
while(tok.hasMoreElements())
{
String path = tok.nextToken();
File urlfile;
// Search in directory of original jar (todo: also search in local dir!?)
urlfile = new File(file.getParentFile(), path);
// Try as absolute path
if(!urlfile.exists())
{
urlfile = new File(path);
}
// Try as url
if(!urlfile.exists())
{
urlfile = SUtil.urlToFile(path);
}
if(urlfile!=null && urlfile.exists())
{
try
{
URL depurl = urlfile.toURI().toURL();
set.add(depurl);
collectManifestURLs(depurl, set);
}
catch (Exception e)
{
component.getLogger().warning("Error collecting manifest URLs for "+urlfile+": "+e);
}
}
else
{
component.getLogger().warning("Jar not found: "+file+", "+path);
}
}
}
}
}
catch(Exception e)
{
component.getLogger().warning("Error collecting manifest URLs for "+url+": "+e);
}
}
}
/**
* Test if a rid is local to this platform.
*/
protected boolean isLocal(IResourceIdentifier rid)
{
return rid.getLocalIdentifier()!=null && rid.getLocalIdentifier().getComponentIdentifier().equals(component.getComponentIdentifier().getRoot());
}
}