All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.base.service.library.LibraryService Maven / Gradle / Ivy

Go to download

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());		
	}
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy