| /******************************************************************************* |
| * Copyright (c) 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.defaultadaptor; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.*; |
| import org.eclipse.osgi.framework.adaptor.*; |
| import org.eclipse.osgi.framework.adaptor.core.AbstractFrameworkAdaptor; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.eclipse.osgi.framework.internal.core.Constants; |
| import org.eclipse.osgi.framework.util.Headers; |
| import org.eclipse.osgi.internal.resolver.StateManager; |
| import org.eclipse.osgi.service.resolver.*; |
| import org.eclipse.osgi.service.resolver.BundleDescription; |
| import org.eclipse.osgi.service.resolver.State; |
| import org.osgi.framework.*; |
| |
| /** |
| * //TODO Add comment here |
| */ |
| public class DefaultAdaptor extends AbstractFrameworkAdaptor |
| { |
| |
| protected static final String METADATA_ADAPTOR_NEXTID = "METADATA_ADAPTOR_NEXTID"; |
| protected static final String METADATA_ADAPTOR_IBSL = "METADATA_ADAPTOR_IBSL"; |
| |
| /** directory containing installed bundles */ |
| protected File bundleRootDir; |
| |
| /** String containing bundle dir */ |
| protected String bundledir = null; |
| |
| /** name of a bundles data directory */ |
| protected String dataDirName = "data"; |
| |
| protected boolean reset = false; |
| |
| /** The MetaData for the default adaptor */ |
| protected MetaData metadata; |
| |
| /** Dictionary containing permission data */ |
| protected PermissionStorage permissionStore; |
| |
| /** next available bundle id */ |
| protected long nextId = 1; |
| |
| /** Development ClassPath entries */ |
| protected String[] devCP; |
| |
| /** Name of the Adaptor manifest file */ |
| protected final String ADAPTOR_MANIFEST = "/META-INF/ADAPTOR.MF"; |
| |
| /** This adaptor's manifest file */ |
| protected Headers manifest=null; |
| |
| protected AdaptorElementFactory elementFactory = null; |
| |
| /** The State Manager */ |
| protected StateManager stateManager; |
| |
| /** |
| * Constructor for DefaultAdaptor. This constructor parses the arguments passed |
| * and remembers them for later when initialize is called. |
| * <p>No blank spaces should be used in the arguments to the DefaultAdaptor. |
| * The options that DefaultAdaptor recognizes and handles are: |
| * <ul> |
| * <li><b>bundledir=<i>directory name</i></b>If a directory name is specified, the adaptor should initialize |
| * to store bundles in that directory. This arg should be enclosed in "" if it contains the ":" |
| * character (example "bundledir=c:\mydir"). |
| * <li><b>reset</b>Resets the bundle storage by deleting the bundledir |
| * </ul> |
| * Any other arguments are ignored. |
| * |
| * @param An array of strings containing arguments. |
| * This object cannot be used until initialize is called. |
| * |
| */ |
| public DefaultAdaptor(String[] args) |
| { |
| if (args != null) |
| { |
| for (int i = 0; i < args.length; i++) |
| { |
| String arg = args[i]; |
| if (arg.equalsIgnoreCase("reset")) |
| { |
| reset = true; |
| } |
| else if (arg.indexOf("=") != -1) |
| { |
| StringTokenizer tok = new StringTokenizer(args[i], "="); |
| if (tok.countTokens() == 2) |
| { |
| String key = tok.nextToken(); |
| if (key.equalsIgnoreCase("bundledir")) |
| { |
| // save file name for initializeStorage to use |
| bundledir = tok.nextToken(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public void initialize(EventPublisher eventPublisher) |
| { |
| super.initialize(eventPublisher); |
| getBundleDir(); |
| readAdaptorManifest(); |
| stateManager = createStateManager(); |
| } |
| |
| /** |
| * Creates the StateManager for the adaptor |
| * @return the StateManager. |
| */ |
| protected StateManager createStateManager(){ |
| stateManager = new StateManager(bundleRootDir); |
| State systemState = stateManager.getSystemState(); |
| if (systemState != null) |
| return stateManager; |
| systemState = stateManager.createSystemState(); |
| Vector installedBundles = getInstalledBundles(); |
| if (installedBundles == null) |
| return stateManager; |
| StateObjectFactory factory = stateManager.getFactory(); |
| for (Iterator iter = installedBundles.iterator(); iter.hasNext(); ) { |
| BundleData toAdd = (BundleData) iter.next(); |
| try { |
| Dictionary manifest = toAdd.getManifest(); |
| BundleDescription newDescription = factory.createBundleDescription(manifest, toAdd.getLocation(),toAdd.getBundleID()); |
| systemState.addBundle(newDescription); |
| } catch (BundleException be) { |
| // just ignore bundle datas with invalid manifests |
| } |
| } |
| // we need the state resolved |
| systemState.resolve(); |
| return stateManager; |
| } |
| |
| /** |
| * Get the directory to store the bundles in. Bundledir can be set in 3 different ways. |
| * Priority is: |
| * 1 - OSGI Launcher command line -adaptor argument |
| * 2 - System property org.eclipse.osgi.framework.defaultadaptor.bundledir - could be specified with -D when launching |
| * 3 - osgi.properties - org.eclipse.osgi.framework.defaultadaptor.bundledir property |
| * |
| * Bundledir will be stored back to adaptor properties which |
| * the framework will copy into the System properties. |
| */ |
| protected void getBundleDir() |
| { |
| /* if bundledir was not set by the constructor from the -adaptor cmd line arg */ |
| if (bundledir == null) |
| { |
| /* check the system properties */ |
| bundledir = System.getProperty("org.eclipse.osgi.framework.defaultadaptor.bundledir"); |
| |
| if (bundledir == null) |
| { |
| /* check the osgi.properties file, but default to "bundles" */ |
| bundledir = properties.getProperty("org.eclipse.osgi.framework.defaultadaptor.bundledir", "bundles"); |
| } |
| } |
| |
| /* store bundledir back into adaptor properties for others to see */ |
| properties.put("org.eclipse.osgi.framework.defaultadaptor.bundledir", bundledir); |
| |
| bundleRootDir = new File(bundledir); |
| } |
| |
| /** |
| * Reads and initializes the adaptor BundleManifest object. The |
| * BundleManifest is used by the getExportPackages() and getExportServices() |
| * methods of the adpator. |
| */ |
| protected void readAdaptorManifest() { |
| InputStream in = getClass().getResourceAsStream(ADAPTOR_MANIFEST); |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if (in == null) { |
| Debug.println("Unable to find adaptor bundle manifest " + ADAPTOR_MANIFEST); |
| } |
| } |
| try { |
| manifest = Headers.parseManifest(in); |
| } catch (BundleException e) { |
| Debug.println("Unable to read adaptor bundle manifest " + ADAPTOR_MANIFEST); |
| } |
| } |
| |
| /** |
| * Initialize the persistent storage. |
| * |
| * <p>This method initializes the bundle persistent storage |
| * area. |
| * If a dir was specified in the -adaptor command line option, then it |
| * is used. If not, |
| * if the property |
| * <i>org.eclipse.osgi.framework.defaultadaptor.bundledir</i> is specifed, its value |
| * will be used as the name of the bundle directory |
| * instead of <tt>./bundles</tt>. |
| * If reset was specified on the -adaptor command line option, |
| * then the storage will be cleared. |
| * |
| * @throws IOException If an error occurs initializing the storage. |
| */ |
| public void initializeStorage() throws IOException |
| { |
| boolean makedir = false; |
| if (bundleRootDir.exists()) |
| { |
| if (reset) |
| { |
| makedir = true; |
| if (!rm(bundleRootDir)) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Could not remove directory: " + bundleRootDir.getPath()); |
| } |
| } |
| } |
| else |
| { |
| if (!bundleRootDir.isDirectory()) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Exists but not a directory: " + bundleRootDir.getPath()); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); |
| } |
| } |
| } |
| else |
| { |
| makedir = true; |
| } |
| if (makedir) |
| { |
| if (!bundleRootDir.mkdirs()) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to create directory: " + bundleRootDir.getPath()); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); |
| } |
| } |
| |
| metadata = new MetaData(getMetaDataFile(), "Framework metadata"); |
| metadata.load(); |
| nextId = metadata.getLong(METADATA_ADAPTOR_NEXTID, 1); |
| initialBundleStartLevel = metadata.getInt(METADATA_ADAPTOR_IBSL,1); |
| } |
| |
| protected File getMetaDataFile(){ |
| return new File(bundleRootDir, ".framework"); |
| } |
| |
| /** |
| * This method cleans up storage in the specified directory and |
| * any subdirectories. |
| * |
| * @param directory The directory to clean. |
| * @param depth The remaining depth. When depth is zero, this |
| * method will not recurse any deeper |
| * @see #compactStorage |
| */ |
| private void compact(File directory) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("compact(" + directory.getPath() + ")"); |
| } |
| |
| String list[] = directory.list(); |
| |
| if (list != null) |
| { |
| int len = list.length; |
| |
| for (int i = 0; i < len; i++) |
| { |
| if (dataDirName.equals(list[i])) |
| { |
| continue; /* do not examine the bundles data dir. */ |
| } |
| |
| File target = new File(directory, list[i]); |
| |
| /* if the file is a directory */ |
| if (target.isDirectory()) |
| { |
| File delete = new File(target, ".delete"); |
| |
| /* and the directory is marked for delete */ |
| if (delete.exists()) |
| { |
| /* if rm fails to delete the directory * |
| * and .delete was removed |
| */ |
| if (!rm(target) && !delete.exists()) |
| { |
| try |
| { |
| /* recreate .delete */ |
| FileOutputStream out = new FileOutputStream(delete); |
| out.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); |
| } |
| } |
| } |
| } |
| else |
| { |
| compact(target); /* descend into directory */ |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Clean up the persistent storage. |
| * |
| * <p>Cleans up any deferred deletions in persistent storage. |
| * |
| */ |
| public void compactStorage() |
| { |
| compact(bundleRootDir); |
| } |
| |
| /** |
| * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getInstalledBundles() |
| */ |
| public Vector getInstalledBundles() |
| { |
| String list[] = bundleRootDir.list(); |
| |
| if (list == null) { |
| return null; |
| } |
| int len = list.length; |
| |
| Vector bundleDatas = new Vector(len << 1, 10); |
| |
| /* create bundle objects for all installed bundles. */ |
| for (int i = 0; i < len; i++) |
| { |
| try |
| { |
| DefaultBundleData data; |
| |
| try |
| { |
| data = (DefaultBundleData)getElementFactory().getBundleData(this); |
| data.initializeExistingBundle(list[i]); |
| } |
| catch (NumberFormatException e) |
| { |
| continue; /* the directory is not a bundle id */ |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("BundleData created: " + data); |
| } |
| |
| bundleDatas.addElement(data); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to open Bundle[" + list[i] + "]: " + e.getMessage()); |
| Debug.printStackTrace(e); |
| } |
| } |
| } |
| |
| return (bundleDatas); |
| } |
| |
| /** |
| * Prepare to install a bundle from a URLConnection. |
| * <p>To complete the install, |
| * begin and then commit |
| * must be called on the returned <code>BundleOperation</code> object. |
| * If either of these methods throw a BundleException |
| * or some other error occurs, |
| * then undo must be called on the <code>BundleOperation</code> object |
| * to undo the change to persistent storage. |
| * |
| * @param location Bundle location. |
| * @param source URLConnection from which the bundle may be read. |
| * Any InputStreams returned from the source |
| * (URLConnections.getInputStream) must be closed by the |
| * <code>BundleOperation</code> object. |
| * @return BundleOperation object to be used to complete the install. |
| */ |
| public BundleOperation installBundle(final String location, final URLConnection source) |
| { |
| return (new BundleOperation() |
| { |
| private DefaultBundleData data; |
| |
| /** |
| * Begin the operation on the bundle (install, update, uninstall). |
| * |
| * @return BundleData object for the target bundle. |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException |
| { |
| long id; |
| |
| try |
| { |
| /* |
| * Open InputStream first to trigger prereq installs, if any, |
| * before allocating bundle id. |
| */ |
| InputStream in = source.getInputStream(); |
| |
| try |
| { |
| try |
| { |
| id = getNextBundleId(); |
| metadata.save(); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); |
| } |
| |
| if (in instanceof ReferenceInputStream) |
| { |
| URL reference = ((ReferenceInputStream) in).getReference(); |
| |
| if (!"file".equals(reference.getProtocol())) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString("ADAPTOR_URL_CREATE_EXCEPTION", reference)); |
| } |
| |
| data = (DefaultBundleData)getElementFactory().getBundleData(DefaultAdaptor.this); |
| data.initializeReferencedBundle(id, location, reference.getPath()); |
| } |
| else |
| { |
| data = (DefaultBundleData)getElementFactory().getBundleData(DefaultAdaptor.this); |
| data.initializeNewBundle(id, location, in); |
| } |
| } |
| finally |
| { |
| try |
| { |
| in.close(); |
| } |
| catch (IOException e) |
| { |
| } |
| } |
| } |
| catch (IOException ioe) |
| { |
| throw new BundleException(AdaptorMsg.formatter.getString("BUNDLE_READ_EXCEPTION"), ioe); |
| } |
| |
| return (data); |
| } |
| |
| public void undo() |
| { |
| if (data != null) |
| { |
| try |
| { |
| data.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to close " + data + ": " + e.getMessage()); |
| } |
| } |
| } |
| |
| if (data != null) |
| { |
| File bundleDir = data.getBundleDir(); |
| |
| if (!rm(bundleDir)) |
| { |
| /* mark this bundle to be deleted to ensure it is fully cleaned up |
| * on next restart. |
| */ |
| File delete = new File(bundleDir, ".delete"); |
| |
| if (!delete.exists()) |
| { |
| try |
| { |
| /* create .delete */ |
| FileOutputStream out = new FileOutputStream(delete); |
| out.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public void commit(boolean postpone) throws BundleException |
| { |
| try |
| { |
| data.save(); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); |
| } |
| BundleDescription bundleDescription = stateManager.getFactory().createBundleDescription(data.getManifest(), data.getLocation(),data.getBundleID()); |
| stateManager.getSystemState().addBundle(bundleDescription); |
| } |
| |
| }); |
| } |
| |
| /** |
| * Prepare to update a bundle from a URLConnection. |
| * <p>To complete the update, |
| * modify and then commit |
| * will be called on the returned BundleStorage object. |
| * If either of these methods throw a BundleException |
| * or some other error occurs, |
| * then undo will be called on the BundleStorage object |
| * to undo the change to persistent storage. |
| * |
| * @param bundle Bundle to update. |
| * @param source URLConnection from which the bundle may be read. |
| * @return BundleOperation object to be used to complete the update. |
| */ |
| |
| public BundleOperation updateBundle( |
| final org.eclipse.osgi.framework.adaptor.BundleData bundledata, |
| final URLConnection source) |
| { |
| return (new BundleOperation() |
| { |
| private DefaultBundleData data; |
| private DefaultBundleData newData; |
| |
| /** |
| * Perform the change to persistent storage. |
| * |
| * @return Bundle object for the target bundle. |
| */ |
| public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException |
| { |
| this.data = (DefaultBundleData) bundledata; |
| try |
| { |
| InputStream in = source.getInputStream(); |
| try |
| { |
| if (in instanceof ReferenceInputStream) |
| { |
| URL reference = ((ReferenceInputStream) in).getReference(); |
| |
| if (!"file".equals(reference.getProtocol())) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString("ADAPTOR_URL_CREATE_EXCEPTION", reference)); |
| } |
| |
| // check to make sure we are not just trying to update to the same |
| // directory reference. This would be a no-op. |
| String path = reference.getPath(); |
| if (path.equals(data.getName())){ |
| throw new BundleException( |
| AdaptorMsg.formatter.getString("ADAPTOR_SAME_REF_UPDATE",reference)); |
| } |
| |
| try |
| { |
| newData = data.nextGeneration(reference.getPath()); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), |
| e); |
| } |
| |
| File bundleGenerationDir = newData.getGenerationDir(); |
| |
| if (!bundleGenerationDir.exists()) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString( |
| "ADAPTOR_DIRECTORY_CREATE_EXCEPTION", |
| bundleGenerationDir.getPath())); |
| } |
| |
| newData.bundleFile = BundleFile.createBundleFile(newData.file, newData); |
| } |
| else |
| { |
| try |
| { |
| newData = data.nextGeneration(); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), |
| e); |
| } |
| |
| File bundleGenerationDir = newData.getGenerationDir(); |
| |
| if (!bundleGenerationDir.exists()) |
| { |
| throw new BundleException( |
| AdaptorMsg.formatter.getString( |
| "ADAPTOR_DIRECTORY_CREATE_EXCEPTION", |
| bundleGenerationDir.getPath())); |
| } |
| |
| File file = newData.getBundleFile(); |
| |
| readFile(in, file); |
| newData.bundleFile = BundleFile.createBundleFile(file, newData); |
| } |
| } |
| finally |
| { |
| try |
| { |
| in.close(); |
| } |
| catch (IOException ee) |
| { |
| } |
| } |
| newData.loadFromManifest(); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException(AdaptorMsg.formatter.getString("BUNDLE_READ_EXCEPTION"), e); |
| } |
| |
| return (newData); |
| } |
| /** |
| * Commit the change to persistent storage. |
| * |
| * @param postpone If true, the bundle's persistent |
| * storage cannot be immediately reclaimed. |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| |
| public void commit(boolean postpone) throws BundleException |
| { |
| try |
| { |
| newData.save(); |
| } |
| catch (IOException e) |
| { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); |
| } |
| long bundleId = newData.getBundleID(); |
| State systemState = stateManager.getSystemState(); |
| systemState.removeBundle(bundleId); |
| BundleDescription newDescription = stateManager.getFactory().createBundleDescription(newData.getManifest(), newData.getLocation(),bundleId); |
| systemState.addBundle(newDescription); |
| |
| File originalGenerationDir = data.getGenerationDir(); |
| |
| if (postpone || !rm(originalGenerationDir)) |
| { |
| /* mark this bundle to be deleted to ensure it is fully cleaned up |
| * on next restart. |
| */ |
| |
| File delete = new File(originalGenerationDir, ".delete"); |
| |
| if (!delete.exists()) |
| { |
| try |
| { |
| /* create .delete */ |
| FileOutputStream out = new FileOutputStream(delete); |
| out.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); |
| } |
| |
| eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Undo the change to persistent storage. |
| * |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| public void undo() throws BundleException |
| { |
| /*if (bundleFile != null) |
| { |
| bundleFile.close(); |
| } */ |
| |
| if (newData != null) |
| { |
| File nextGenerationDir = newData.getGenerationDir(); |
| |
| if (!rm(nextGenerationDir)) /* delete downloaded bundle */ |
| { |
| /* mark this bundle to be deleted to ensure it is fully cleaned up |
| * on next restart. |
| */ |
| |
| File delete = new File(nextGenerationDir, ".delete"); |
| |
| if (!delete.exists()) |
| { |
| try |
| { |
| /* create .delete */ |
| FileOutputStream out = new FileOutputStream(delete); |
| out.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); |
| } |
| } |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Prepare to uninstall a bundle. |
| * <p>To complete the uninstall, |
| * modify and then commit |
| * will be called on the returned BundleStorage object. |
| * If either of these methods throw a BundleException |
| * or some other error occurs, |
| * then undo will be called on the BundleStorage object |
| * to undo the change to persistent storage. |
| * |
| * @param bundle BundleData to uninstall. |
| * @return BundleOperation object to be used to complete the uninstall. |
| */ |
| public BundleOperation uninstallBundle(final org.eclipse.osgi.framework.adaptor.BundleData bundledata) |
| { |
| return (new BundleOperation() |
| { |
| private DefaultBundleData data; |
| |
| /** |
| * Perform the change to persistent storage. |
| * |
| * @return Bundle object for the target bundle. |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException |
| { |
| this.data = (DefaultBundleData) bundledata; |
| return (bundledata); |
| } |
| /** |
| * Commit the change to persistent storage. |
| * |
| * @param postpone If true, the bundle's persistent |
| * storage cannot be immediately reclaimed. |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| public void commit(boolean postpone) throws BundleException |
| { |
| File bundleDir = data.getBundleDir(); |
| |
| if (postpone || !rm(bundleDir)) |
| { |
| /* mark this bundle to be deleted to ensure it is fully cleaned up |
| * on next restart. |
| */ |
| |
| File delete = new File(bundleDir, ".delete"); |
| |
| if (!delete.exists()) |
| { |
| try |
| { |
| /* create .delete */ |
| FileOutputStream out = new FileOutputStream(delete); |
| out.close(); |
| } |
| catch (IOException e) |
| { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); |
| } |
| } |
| } |
| } |
| |
| stateManager.getSystemState().removeBundle(data.getBundleID()); |
| } |
| /** |
| * Undo the change to persistent storage. |
| * |
| * @throws BundleException If a failure occured modifiying peristent storage. |
| */ |
| public void undo() throws BundleException |
| { |
| } |
| }); |
| } |
| |
| /** |
| * Returns the PermissionStorage object which will be used to |
| * to manage the permission data. |
| * |
| * <p>The PermissionStorage object will store permission data |
| * in the "permdata" subdirectory of the bundle storage directory |
| * assigned by <tt>initializeStorage</tt>. |
| * |
| * @return The PermissionStorage object for the DefaultAdaptor. |
| */ |
| public org.eclipse.osgi.framework.adaptor.PermissionStorage getPermissionStorage() throws IOException |
| { |
| if (permissionStore == null) |
| { |
| synchronized (this) |
| { |
| if (permissionStore == null) |
| { |
| permissionStore = new PermissionStorage(this); |
| } |
| } |
| } |
| |
| return permissionStore; |
| } |
| |
| public void frameworkStart(BundleContext context) throws BundleException{ |
| super.frameworkStart(context); |
| |
| // Check the osgi.dev property to see if dev classpath entries have been defined. |
| String osgiDev = context.getProperty("osgi.dev"); |
| if (osgiDev != null) { |
| // Add each dev classpath entry |
| Vector devClassPath = new Vector(6); |
| StringTokenizer st = new StringTokenizer(osgiDev,","); |
| while (st.hasMoreTokens()) { |
| String tok = st.nextToken(); |
| if (!tok.equals("")) { |
| devClassPath.addElement(tok); |
| } |
| } |
| devCP = new String[devClassPath.size()]; |
| devClassPath.toArray(devCP); |
| } |
| |
| State state = stateManager.getSystemState(); |
| BundleDescription systemBundle = state.getBundle(0); |
| if (systemBundle == null || !systemBundle.isResolved()) |
| // this would be a bug in the framework |
| throw new IllegalStateException(); |
| } |
| |
| public void frameworkStop(BundleContext context) throws BundleException { |
| try { |
| stateManager.shutdown(); |
| } catch (IOException e) { |
| throw new BundleException(null, e); |
| } |
| super.frameworkStop(context); |
| } |
| /** |
| * Register a service object. |
| * |
| */ |
| protected ServiceRegistration register(String name, Object service, Bundle bundle) |
| { |
| Hashtable properties = new Hashtable(7); |
| |
| Dictionary headers = bundle.getHeaders(); |
| |
| properties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR)); |
| |
| properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE)); |
| |
| properties.put(Constants.SERVICE_PID, bundle.getBundleId() + "." + service.getClass().getName()); |
| |
| return context.registerService(name, service, properties); |
| } |
| |
| /** |
| * This function performs the equivalent of "rm -r" on a file or directory. |
| * |
| * @param file file or directory to delete |
| * @return false is the specified files still exists, true otherwise. |
| */ |
| protected boolean rm(File file) |
| { |
| if (file.exists()) |
| { |
| if (file.isDirectory()) |
| { |
| String list[] = file.list(); |
| int len = list.length; |
| for (int i = 0; i < len; i++) |
| { |
| // we are doing a lot of garbage collecting here |
| rm(new File(file, list[i])); |
| } |
| |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| if (file.isDirectory()) |
| { |
| Debug.println("rmdir " + file.getPath()); |
| } |
| else |
| { |
| Debug.println("rm " + file.getPath()); |
| } |
| } |
| |
| boolean success = file.delete(); |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| if (!success) |
| { |
| Debug.println(" rm failed!!"); |
| } |
| } |
| |
| return (success); |
| } |
| else |
| { |
| return (true); |
| } |
| } |
| |
| public void setInitialBundleStartLevel(int value) { |
| super.setInitialBundleStartLevel(value); |
| metadata.setInt(METADATA_ADAPTOR_IBSL,value); |
| try { |
| metadata.save(); |
| } catch (IOException e) { |
| eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e); |
| } |
| } |
| |
| /** |
| * Map a location string into a bundle name. |
| * This methods treats the location string as a URL. |
| * |
| * @param location bundle location string. |
| * @return bundle name. |
| */ |
| public String mapLocationToName(String location) |
| { |
| int end = location.indexOf('?', 0); /* "?" query */ |
| |
| if (end == -1) |
| { |
| end = location.indexOf('#', 0); /* "#" fragment */ |
| |
| if (end == -1) |
| { |
| end = location.length(); |
| } |
| } |
| |
| int begin = location.replace('\\', '/').lastIndexOf('/', end); |
| int colon = location.lastIndexOf(':', end); |
| |
| if (colon > begin) |
| { |
| begin = colon; |
| } |
| |
| return (location.substring(begin + 1, end)); |
| } |
| |
| /** |
| * Return the next valid, unused bundle id. |
| * |
| * @return Next valid, unused bundle id. |
| * @throws IOException If there are no more unused bundle ids. |
| */ |
| protected synchronized long getNextBundleId() throws IOException |
| { |
| while (nextId < Long.MAX_VALUE) |
| { |
| long id = nextId; |
| |
| nextId++; |
| metadata.setLong(METADATA_ADAPTOR_NEXTID, nextId); |
| |
| File bundleDir = new File(bundleRootDir, String.valueOf(id)); |
| if (bundleDir.exists()) |
| { |
| continue; |
| } |
| |
| return (id); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); |
| } |
| |
| /** |
| * Read a file from an InputStream and write it to the file system. |
| * |
| * @param is InputStream from which to read. |
| * @param file output file to create. |
| * @exception IOException |
| */ |
| public static void readFile(InputStream in, File file) throws IOException |
| { |
| FileOutputStream fos = null; |
| try |
| { |
| fos = new FileOutputStream(file); |
| |
| byte buffer[] = new byte[1024]; |
| int count; |
| while ((count = in.read(buffer, 0, buffer.length)) > 0) |
| { |
| fos.write(buffer, 0, count); |
| } |
| |
| fos.close(); |
| fos = null; |
| |
| in.close(); |
| in = null; |
| } |
| catch (IOException e) |
| { |
| // close open streams |
| if (fos != null) |
| { |
| try |
| { |
| fos.close(); |
| } |
| catch (IOException ee) |
| { |
| } |
| } |
| |
| if (in != null) |
| { |
| try |
| { |
| in.close(); |
| } |
| catch (IOException ee) |
| { |
| } |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) |
| { |
| Debug.println("Unable to read file"); |
| Debug.printStackTrace(e); |
| } |
| |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportPackages() |
| */ |
| public String getExportPackages() { |
| if (manifest == null) |
| return null; |
| return (String)manifest.get(Constants.EXPORT_PACKAGE); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportServices() |
| */ |
| public String getExportServices() { |
| if (manifest == null) |
| return null; |
| return (String)manifest.get(Constants.EXPORT_SERVICE); |
| } |
| |
| public AdaptorElementFactory getElementFactory() { |
| if (elementFactory == null) |
| elementFactory = new AdaptorElementFactory(); |
| return elementFactory; |
| } |
| |
| public IBundleStats getBundleStats(){ |
| return null; |
| } |
| |
| // TODO need to clean this up. get state, statemanger, platform admin etc all need to be harmonized |
| public State getState() { |
| return stateManager.getSystemState(); |
| } |
| public StateManager getStateManager() { |
| return stateManager; |
| } |
| public PlatformAdmin getPlatformAdmin() { |
| return PlatformAdmin.getInstance(); |
| } |
| } |