| /******************************************************************************* |
| * Copyright (c) 2003, 2004 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.*; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.eclipse.osgi.framework.internal.core.Constants; |
| import org.eclipse.osgi.framework.log.FrameworkLog; |
| import org.eclipse.osgi.internal.resolver.StateManager; |
| import org.eclipse.osgi.service.resolver.*; |
| import org.osgi.framework.*; |
| |
| /** |
| * //TODO Add comment here |
| */ |
| public class DefaultAdaptor extends AbstractFrameworkAdaptor { |
| |
| public static final String METADATA_ADAPTOR_NEXTID = "METADATA_ADAPTOR_NEXTID"; //$NON-NLS-1$ |
| public static final String METADATA_ADAPTOR_IBSL = "METADATA_ADAPTOR_IBSL"; //$NON-NLS-1$ |
| public static final String DATA_DIR_NAME = "data"; //$NON-NLS-1$ |
| public static final String BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$ |
| |
| protected AdaptorElementFactory elementFactory; |
| |
| /** directory containing installed bundles */ |
| protected File bundleStoreRootDir; |
| |
| /** directory containing data directories for installed bundles */ |
| protected File dataRootDir; |
| |
| /** String containing bundle store root dir */ |
| protected String bundleStore = null; |
| |
| protected boolean reset = false; |
| |
| /** The MetaData for the default adaptor */ |
| protected MetaData fwMetadata; |
| |
| /** Dictionary containing permission data */ |
| protected DefaultPermissionStorage permissionStore; |
| |
| /** next available bundle id */ |
| protected long nextId = 1; |
| |
| /** The State Manager */ |
| protected StateManager stateManager; |
| |
| /** The FrameworkLog for the adaptor */ |
| protected FrameworkLog frameworkLog; |
| |
| /** |
| * 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 |
| bundleStore = tok.nextToken(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public void initialize(EventPublisher eventPublisher) { |
| super.initialize(eventPublisher); |
| initBundleStoreRootDir(); |
| |
| // need to create the FrameworkLog very early |
| frameworkLog = createFrameworkLog(); |
| stateManager = createStateManager(); |
| } |
| |
| /** |
| * Creates the StateManager for the adaptor |
| * @return the StateManager. |
| */ |
| protected StateManager createStateManager() { |
| File stateLocation = new File(getBundleStoreRootDir(), ".state"); |
| stateManager = new StateManager(stateLocation); |
| 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; |
| } |
| |
| /** |
| * |
| * |
| */ |
| protected FrameworkLog createFrameworkLog() { |
| return new DefaultLog(); |
| } |
| |
| /** |
| * Init 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 initBundleStoreRootDir() { |
| /* if bundleStore was not set by the constructor from the -adaptor cmd line arg */ |
| if (bundleStore == null) { |
| /* check the system properties */ |
| bundleStore = System.getProperty(BUNDLE_STORE); |
| |
| if (bundleStore == null) { |
| /* check the osgi.properties file, but default to "bundles" */ |
| bundleStore = properties.getProperty(BUNDLE_STORE, "bundles"); |
| } |
| } |
| |
| bundleStoreRootDir = new File(bundleStore); |
| /* store bundleStore back into adaptor properties for others to see */ |
| properties.put(BUNDLE_STORE, bundleStoreRootDir.getAbsolutePath()); |
| |
| } |
| |
| protected void initDataRootDir() { |
| dataRootDir = getBundleStoreRootDir(); |
| } |
| |
| public File getBundleStoreRootDir() { |
| return bundleStoreRootDir; |
| } |
| |
| public File getDataRootDir() { |
| if (dataRootDir == null) |
| initDataRootDir(); |
| return dataRootDir; |
| } |
| |
| /** |
| * 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; |
| File bundleStore = getBundleStoreRootDir(); |
| if (bundleStore.exists()) { |
| if (reset) { |
| makedir = true; |
| if (!rm(bundleStore)) { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("Could not remove directory: " + bundleStore.getPath()); |
| } |
| } |
| } else { |
| if (!bundleStore.isDirectory()) { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("Exists but not a directory: " + bundleStore.getPath()); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); |
| } |
| } |
| } else { |
| makedir = true; |
| } |
| if (makedir) { |
| if (!bundleStore.mkdirs()) { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("Unable to create directory: " + bundleStore.getPath()); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); //$NON-NLS-1$ |
| } |
| } |
| |
| fwMetadata = new MetaData(getMetaDataFile(), "Framework metadata"); |
| fwMetadata.load(); |
| nextId = fwMetadata.getLong(METADATA_ADAPTOR_NEXTID, 1); |
| initialBundleStartLevel = fwMetadata.getInt(METADATA_ADAPTOR_IBSL, 1); |
| } |
| |
| protected File getMetaDataFile() { |
| return new File(getBundleStoreRootDir(), ".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 (DATA_DIR_NAME.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()) { //TODO Simplify the nesting. |
| 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(getBundleStoreRootDir()); |
| } |
| |
| /** |
| * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getInstalledBundles() |
| */ |
| public Vector getInstalledBundles() { |
| String list[] = getBundleStoreRootDir().list(); |
| |
| if (list == null) { |
| return null; |
| } |
| int len = list.length; |
| |
| Vector bundleDatas = new Vector(len << 1, 10); //TODO ArrayList? array? |
| |
| /* create bundle objects for all installed bundles. */ |
| for (int i = 0; i < len; i++) { |
| try { |
| DefaultBundleData data; |
| |
| long id = -1; |
| try { |
| id = Long.parseLong(list[i]); |
| } catch (NumberFormatException nfe) { |
| continue; |
| } |
| data = (DefaultBundleData) getElementFactory().createBundleData(this, id); |
| loadMetaDataFor(data); |
| data.initializeExistingBundle(); |
| |
| 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(); |
| URL sourceURL = source.getURL(); |
| String protocol = sourceURL == null ? null : sourceURL.getProtocol(); |
| try { |
| try { |
| id = getNextBundleId(); |
| fwMetadata.save(); |
| } catch (IOException e) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); //$NON-NLS-1$ |
| } |
| data = (DefaultBundleData) getElementFactory().createBundleData(DefaultAdaptor.this, id); |
| data.setLocation(location); |
| data.setStartLevel(getInitialBundleStartLevel()); |
| |
| 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)); //$NON-NLS-1$ |
| } |
| |
| data.setReference(true); |
| data.setFileName(reference.getPath()); |
| data.initializeNewBundle(); |
| } else { |
| File genDir = data.createGenerationDir(); |
| if (!genDir.exists()) { |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_DIRECTORY_CREATE_EXCEPTION", genDir.getPath())); //$NON-NLS-1$ |
| } |
| |
| String fileName = mapLocationToName(location); |
| File outFile = new File(genDir, fileName); |
| if ("file".equals(protocol)) { |
| File inFile = new File(source.getURL().getPath()); |
| if (inFile.isDirectory()) { |
| copyDir(inFile, outFile); |
| } else { |
| readFile(in, outFile); |
| } |
| } else { |
| readFile(in, outFile); |
| } |
| data.setReference(false); |
| data.setFileName(fileName); |
| data.initializeNewBundle(); |
| } |
| } 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.getBundleStoreDir(); |
| |
| 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(); |
| URL sourceURL = source.getURL(); |
| String protocol = sourceURL == null ? null : sourceURL.getProtocol(); |
| try { |
| if (in instanceof ReferenceInputStream) { |
| ReferenceInputStream refIn = (ReferenceInputStream) in; |
| URL reference = (refIn).getReference(); |
| if (!"file".equals(reference.getProtocol())) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_URL_CREATE_EXCEPTION", reference)); //$NON-NLS-1$ |
| } |
| // check to make sure we are not just trying to update to the same |
| // directory reference. This would be a no-op. |
| //TODO Unless the jars and manifest have been updated on disk |
| String path = reference.getPath(); |
| if (path.equals(data.getFileName())) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_SAME_REF_UPDATE", reference)); //$NON-NLS-1$ |
| } |
| try { |
| newData = data.nextGeneration(reference.getPath()); |
| } catch (IOException e) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); //$NON-NLS-1$ |
| } |
| File bundleGenerationDir = newData.createGenerationDir(); |
| if (!bundleGenerationDir.exists()) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_DIRECTORY_CREATE_EXCEPTION", bundleGenerationDir.getPath())); //$NON-NLS-1$ |
| } |
| newData.createBaseBundleFile(); |
| } else { |
| try { |
| newData = data.nextGeneration(null); |
| } catch (IOException e) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION"), e); //$NON-NLS-1$ |
| } |
| File bundleGenerationDir = newData.createGenerationDir(); |
| if (!bundleGenerationDir.exists()) { |
| throw new BundleException(AdaptorMsg.formatter.getString("ADAPTOR_DIRECTORY_CREATE_EXCEPTION", bundleGenerationDir.getPath())); //$NON-NLS-1$ |
| } |
| File outFile = newData.getBaseFile(); |
| if ("file".equals(protocol)) { |
| File inFile = new File(source.getURL().getPath()); |
| if (inFile.isDirectory()) { |
| copyDir(inFile, outFile); |
| } else { |
| readFile(in, outFile); |
| } |
| } else { |
| readFile(in, outFile); |
| } |
| newData.createBaseBundleFile(); |
| } |
| } finally { |
| try { |
| in.close(); |
| } catch (IOException ee) { |
| } |
| } |
| newData.loadFromManifest(); |
| } catch (IOException e) { |
| throw new BundleException(AdaptorMsg.formatter.getString("BUNDLE_READ_EXCEPTION"), e); //$NON-NLS-1$ |
| } |
| |
| 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); //$NON-NLS-1$ |
| } |
| 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.createGenerationDir(); |
| |
| 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.createGenerationDir(); |
| |
| 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.getBundleStoreDir(); |
| |
| 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 DefaultPermissionStorage(this); |
| } |
| } |
| } |
| |
| return permissionStore; |
| } |
| |
| public void frameworkStart(BundleContext context) throws BundleException { |
| super.frameworkStart(context); |
| |
| if (frameworkLog == null) { |
| frameworkLog = createFrameworkLog(); |
| } |
| |
| 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); |
| |
| frameworkLog.close(); |
| frameworkLog = null; |
| } |
| |
| /** |
| * 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); |
| fwMetadata.setInt(METADATA_ADAPTOR_IBSL, value); |
| try { |
| fwMetadata.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++; |
| fwMetadata.setLong(METADATA_ADAPTOR_NEXTID, nextId); |
| |
| File bundleDir = new File(getBundleStoreRootDir(), String.valueOf(id)); |
| if (bundleDir.exists()) { |
| continue; |
| } |
| |
| return (id); |
| } |
| |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); //$NON-NLS-1$ |
| } |
| |
| public AdaptorElementFactory getElementFactory() { |
| if (elementFactory == null) |
| elementFactory = new DefaultElementFactory(); |
| return elementFactory; |
| } |
| |
| public FrameworkLog getFrameworkLog() { |
| return frameworkLog; |
| } |
| |
| public State getState() { |
| return stateManager.getSystemState(); |
| } |
| |
| public PlatformAdmin getPlatformAdmin() { |
| return stateManager; |
| } |
| |
| public static final String METADATA_BUNDLE_GEN = "METADATA_BUNDLE_GEN"; |
| public static final String METADATA_BUNDLE_LOC = "METADATA_BUNDLE_LOC"; |
| public static final String METADATA_BUNDLE_REF = "METADATA_BUNDLE_REF"; |
| public static final String METADATA_BUNDLE_NAME = "METADATA_BUNDLE_NAME"; |
| public static final String METADATA_BUNDLE_NCP = "METADATA_BUNDLE_NCP"; |
| public static final String METADATA_BUNDLE_ABSL = "METADATA_BUNDLE_ABSL"; |
| public static final String METADATA_BUNDLE_STATUS = "METADATA_BUNDLE_STATUS"; |
| public static final String METADATA_BUNDLE_METADATA = "METADATA_BUNDLE_METADATA"; |
| |
| protected void loadMetaDataFor(DefaultBundleData data) throws IOException { |
| MetaData bundleMetaData = (new MetaData(new File(data.getBundleStoreDir(), ".bundle"), "Bundle metadata")); |
| bundleMetaData.load(); |
| |
| data.setLocation(bundleMetaData.get(METADATA_BUNDLE_LOC, null)); |
| data.setFileName(bundleMetaData.get(METADATA_BUNDLE_NAME, null)); |
| data.setGeneration(bundleMetaData.getInt(METADATA_BUNDLE_GEN, -1)); |
| data.setNativePaths(bundleMetaData.get(METADATA_BUNDLE_NCP, null)); |
| data.setStartLevel(bundleMetaData.getInt(METADATA_BUNDLE_ABSL, 1)); |
| data.setStatus(bundleMetaData.getInt(METADATA_BUNDLE_STATUS, 0)); |
| data.setReference(bundleMetaData.getBoolean(METADATA_BUNDLE_REF, false)); |
| |
| if (data.getGeneration() == -1 || data.getFileName() == null || data.getLocation() == null) { |
| throw new IOException(AdaptorMsg.formatter.getString("ADAPTOR_STORAGE_EXCEPTION")); |
| } |
| } |
| |
| public void saveMetaDataFor(DefaultBundleData data) throws IOException { |
| MetaData bundleMetadata = (new MetaData(new File(data.createBundleStoreDir(), ".bundle"), "Bundle metadata")); |
| bundleMetadata.load(); |
| |
| bundleMetadata.set(METADATA_BUNDLE_LOC, data.getLocation()); |
| bundleMetadata.set(METADATA_BUNDLE_NAME, data.getFileName()); |
| bundleMetadata.setInt(METADATA_BUNDLE_GEN, data.getGeneration()); |
| String nativePaths = data.getNativePathsString(); |
| if (nativePaths != null) { |
| bundleMetadata.set(METADATA_BUNDLE_NCP, nativePaths); |
| } |
| bundleMetadata.setInt(METADATA_BUNDLE_ABSL, data.getStartLevel()); |
| bundleMetadata.setInt(METADATA_BUNDLE_STATUS, data.getStatus()); |
| bundleMetadata.setBoolean(METADATA_BUNDLE_REF, data.isReference()); |
| |
| bundleMetadata.save(); |
| } |
| } |