Package org.eclipse.osgi.internal.composite

Source Code of org.eclipse.osgi.internal.composite.CompositeHelper

/*******************************************************************************
* Copyright (c) 2008, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.composite;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.jar.*;
import org.eclipse.osgi.internal.baseadaptor.BaseStorageHook;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.*;
import org.osgi.service.permissionadmin.PermissionAdmin;
import org.osgi.service.permissionadmin.PermissionInfo;

public class CompositeHelper {
  private static final PermissionInfo[] COMPOSITE_PERMISSIONS = new PermissionInfo[] {new PermissionInfo(PackagePermission.class.getName(), "*", PackagePermission.EXPORT), new PermissionInfo(ServicePermission.class.getName(), "*", ServicePermission.REGISTER + ',' + ServicePermission.GET)}; //$NON-NLS-1$ //$NON-NLS-2$
  private static final String COMPOSITE_POLICY = "org.eclipse.osgi.composite"; //$NON-NLS-1$
  private static String ELEMENT_SEPARATOR = "; "; //$NON-NLS-1$
  private static final Object EQUALS_QUOTE = "=\""; //$NON-NLS-1$
  private static final String[] INVALID_COMPOSITE_HEADERS = new String[] {Constants.DYNAMICIMPORT_PACKAGE, Constants.FRAGMENT_HOST, Constants.REQUIRE_BUNDLE, Constants.BUNDLE_NATIVECODE, Constants.BUNDLE_CLASSPATH, Constants.BUNDLE_ACTIVATOR, Constants.BUNDLE_LOCALIZATION, Constants.BUNDLE_ACTIVATIONPOLICY};

  private static Manifest getCompositeManifest(Map compositeManifest) {
    Manifest manifest = new Manifest();
    Attributes attributes = manifest.getMainAttributes();
    attributes.putValue("Manifest-Version", "1.0"); //$NON-NLS-1$//$NON-NLS-2$
    // get the common headers Bundle-ManifestVersion, Bundle-SymbolicName and Bundle-Version
    // get the manifest version from the map
    String manifestVersion = (String) compositeManifest.remove(Constants.BUNDLE_MANIFESTVERSION);
    // here we assume the validation got the correct version for us
    attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, manifestVersion);
    // Ignore the Equinox composite bundle header
    compositeManifest.remove(BaseStorageHook.COMPOSITE_HEADER);
    attributes.putValue(BaseStorageHook.COMPOSITE_HEADER, BaseStorageHook.COMPOSITE_BUNDLE);
    for (Iterator entries = compositeManifest.entrySet().iterator(); entries.hasNext();) {
      Map.Entry entry = (Entry) entries.next();
      if (entry.getKey() instanceof String && entry.getValue() instanceof String)
        attributes.putValue((String) entry.getKey(), (String) entry.getValue());
    }
    return manifest;
  }

  private static Manifest getSurrogateManifest(Dictionary compositeManifest, BundleDescription compositeDesc, ExportPackageDescription[] matchingExports) {
    Manifest manifest = new Manifest();
    Attributes attributes = manifest.getMainAttributes();
    attributes.putValue("Manifest-Version", "1.0"); //$NON-NLS-1$//$NON-NLS-2$
    // Ignore the manifest version from the map
    // always use bundle manifest version 2
    attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, "2"); //$NON-NLS-1$
    // Ignore the Equinox composite bundle header
    attributes.putValue(BaseStorageHook.COMPOSITE_HEADER, BaseStorageHook.SURROGATE_BUNDLE);

    if (compositeDesc != null && matchingExports != null) {
      // convert the exports from the composite into imports
      addImports(attributes, compositeDesc, matchingExports);

      // convert the matchingExports from the composite into exports
      addExports(attributes, compositeDesc, matchingExports);
    }

    // add the rest
    for (Enumeration keys = compositeManifest.keys(); keys.hasMoreElements();) {
      Object header = keys.nextElement();
      if (Constants.BUNDLE_MANIFESTVERSION.equals(header) || BaseStorageHook.COMPOSITE_HEADER.equals(header) || Constants.IMPORT_PACKAGE.equals(header) || Constants.EXPORT_PACKAGE.equals(header))
        continue;
      if (header instanceof String && compositeManifest.get(header) instanceof String)
        attributes.putValue((String) header, (String) compositeManifest.get(header));
    }
    return manifest;
  }

  static InputStream getCompositeInput(Map frameworkConfig, Map compositeManifest) throws IOException {
    // use an in memory stream to store the content
    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
    // the composite bundles only consist of a manifest describing the packages they import and export
    // and a framework config properties file
    Manifest manifest = CompositeHelper.getCompositeManifest(compositeManifest);
    JarOutputStream jarOut = new JarOutputStream(bytesOut, manifest);
    try {
      // store the framework config
      Properties fwProps = new Properties();
      if (frameworkConfig != null)
        fwProps.putAll(frameworkConfig);
      JarEntry entry = new JarEntry(CompositeImpl.COMPOSITE_CONFIGURATION);
      jarOut.putNextEntry(entry);
      fwProps.store(jarOut, null);
      jarOut.closeEntry();
      jarOut.flush();
    } finally {
      try {
        jarOut.close();
      } catch (IOException e) {
        // nothing
      }
    }
    return new ByteArrayInputStream(bytesOut.toByteArray());
  }

  static InputStream getSurrogateInput(Dictionary compositeManifest, BundleDescription compositeDesc, ExportPackageDescription[] matchingExports) throws IOException {
    // use an in memory stream to store the content
    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
    Manifest manifest = CompositeHelper.getSurrogateManifest(compositeManifest, compositeDesc, matchingExports);
    JarOutputStream jarOut = new JarOutputStream(bytesOut, manifest);
    jarOut.flush();
    jarOut.close();
    return new ByteArrayInputStream(bytesOut.toByteArray());
  }

  private static void addImports(Attributes attrigutes, BundleDescription compositeDesc, ExportPackageDescription[] matchingExports) {
    ExportPackageDescription[] exports = compositeDesc.getExportPackages();
    List systemExports = getSystemExports(matchingExports);
    if (exports.length == 0 && systemExports.size() == 0)
      return;
    StringBuffer importStatement = new StringBuffer();
    Collection importedNames = new ArrayList(exports.length);
    int i = 0;
    for (; i < exports.length; i++) {
      if (i != 0)
        importStatement.append(',');
      importedNames.add(exports[i].getName());
      getImportFrom(exports[i], importStatement);
    }
    for (Iterator iSystemExports = systemExports.iterator(); iSystemExports.hasNext();) {
      ExportPackageDescription systemExport = (ExportPackageDescription) iSystemExports.next();
      if (!importedNames.contains(systemExport.getName())) {
        if (i != 0)
          importStatement.append(',');
        i++;
        importStatement.append(systemExport.getName()).append(ELEMENT_SEPARATOR).append(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE).append('=').append(Constants.SYSTEM_BUNDLE_SYMBOLICNAME);
      }
    }
    attrigutes.putValue(Constants.IMPORT_PACKAGE, importStatement.toString());
  }

  private static List getSystemExports(ExportPackageDescription[] matchingExports) {
    ArrayList list = null;
    for (int i = 0; i < matchingExports.length; i++) {
      if (matchingExports[i].getExporter().getBundleId() != 0)
        continue;
      if (list == null)
        list = new ArrayList();
      list.add(matchingExports[i]);
    }
    return list == null ? Collections.EMPTY_LIST : list;
  }

  private static void getImportFrom(ExportPackageDescription export, StringBuffer importStatement) {
    importStatement.append(export.getName()).append(ELEMENT_SEPARATOR);
    Version version = export.getVersion();
    importStatement.append(Constants.VERSION_ATTRIBUTE).append(EQUALS_QUOTE).append('[').append(version).append(',').append(new Version(version.getMajor(), version.getMinor(), version.getMicro() + 1)).append(')').append('\"');
    addMap(importStatement, export.getAttributes(), "="); //$NON-NLS-1$
  }

  private static void addExports(Attributes attributes, BundleDescription compositeDesc, ExportPackageDescription[] matchingExports) {
    if (matchingExports.length == 0)
      return;
    StringBuffer exportStatement = new StringBuffer();
    for (int i = 0; i < matchingExports.length; i++) {
      if (matchingExports[i].getExporter() == compositeDesc) {
        // the matching export from outside is the composite bundle itself
        // this must be one of our own substitutable exports, it must be ignored (bug 345640)
        continue;
      }
      if (exportStatement.length() > 0)
        exportStatement.append(',');
      getExportFrom(matchingExports[i], exportStatement);
    }
    if (exportStatement.length() > 0)
      attributes.putValue(Constants.EXPORT_PACKAGE, exportStatement.toString());
  }

  private static void getExportFrom(ExportPackageDescription export, StringBuffer exportStatement) {
    exportStatement.append(export.getName()).append(ELEMENT_SEPARATOR);
    exportStatement.append(Constants.VERSION_ATTRIBUTE).append(EQUALS_QUOTE).append(export.getVersion()).append('\"');
    addMap(exportStatement, export.getDirectives(), ":="); //$NON-NLS-1$
    addMap(exportStatement, export.getAttributes(), "="); //$NON-NLS-1$
  }

  private static void addMap(StringBuffer manifest, Map values, String assignment) {
    if (values == null)
      return; // nothing to add
    for (Iterator iEntries = values.entrySet().iterator(); iEntries.hasNext();) {
      manifest.append(ELEMENT_SEPARATOR);
      Map.Entry entry = (Entry) iEntries.next();
      manifest.append(entry.getKey()).append(assignment).append('\"');
      Object value = entry.getValue();
      if (value instanceof String[]) {
        String[] strings = (String[]) value;
        for (int i = 0; i < strings.length; i++) {
          if (i != 0)
            manifest.append(',');
          manifest.append(strings[i]);
        }
      } else {
        manifest.append(value);
      }
      manifest.append('\"');
    }
  }

  static void setCompositePermissions(String bundleLocation, BundleContext systemContext) {
    ServiceReference ref = systemContext.getServiceReference(PermissionAdmin.class.getName());
    PermissionAdmin permAdmin = (PermissionAdmin) (ref == null ? null : systemContext.getService(ref));
    if (permAdmin == null)
      throw new RuntimeException("No Permission Admin service is available"); //$NON-NLS-1$
    try {
      permAdmin.setPermissions(bundleLocation, COMPOSITE_PERMISSIONS);
    } finally {
      systemContext.ungetService(ref);
    }
  }

  static void setDisabled(boolean disable, Bundle bundle, BundleContext systemContext) {
    ServiceReference ref = systemContext.getServiceReference(PlatformAdmin.class.getName());
    PlatformAdmin pa = (PlatformAdmin) (ref == null ? null : systemContext.getService(ref));
    if (pa == null)
      throw new RuntimeException("No Platform Admin service is available."); //$NON-NLS-1$
    try {
      State state = pa.getState(false);
      BundleDescription desc = state.getBundle(bundle.getBundleId());
      setDisabled(disable, desc);
    } finally {
      systemContext.ungetService(ref);
    }
  }

  static void setDisabled(boolean disable, BundleDescription bundle) {
    State state = bundle.getContainingState();
    if (disable) {
      state.addDisabledInfo(new DisabledInfo(COMPOSITE_POLICY, "Composite companion bundle is not resolved.", bundle)); //$NON-NLS-1$
    } else {
      DisabledInfo toRemove = state.getDisabledInfo(bundle, COMPOSITE_POLICY);
      if (toRemove != null)
        state.removeDisabledInfo(toRemove);
    }
  }

  static void validateCompositeManifest(Map compositeManifest) throws BundleException {
    if (compositeManifest == null)
      throw new BundleException("The composite manifest cannot be null.", BundleException.MANIFEST_ERROR); //$NON-NLS-1$
    // check for symbolic name
    if (compositeManifest.get(Constants.BUNDLE_SYMBOLICNAME) == null)
      throw new BundleException("The composite manifest must contain a Bundle-SymbolicName header.", BundleException.MANIFEST_ERROR); //$NON-NLS-1$
    // check for invalid manifests headers
    for (int i = 0; i < INVALID_COMPOSITE_HEADERS.length; i++)
      if (compositeManifest.get(INVALID_COMPOSITE_HEADERS[i]) != null)
        throw new BundleException("The composite manifest must not contain the header " + INVALID_COMPOSITE_HEADERS[i], BundleException.MANIFEST_ERROR); //$NON-NLS-1$
    // validate manifest version
    String manifestVersion = (String) compositeManifest.get(Constants.BUNDLE_MANIFESTVERSION);
    if (manifestVersion == null) {
      compositeManifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); //$NON-NLS-1$
    } else {
      try {
        Integer parsed = Integer.valueOf(manifestVersion);
        if (parsed.intValue() > 2 || parsed.intValue() < 2)
          throw new BundleException("Invalid Bundle-ManifestVersion: " + manifestVersion); //$NON-NLS-1$
      } catch (NumberFormatException e) {
        throw new BundleException("Invalid Bundle-ManifestVersion: " + manifestVersion); //$NON-NLS-1$
      }
    }
  }
}
TOP

Related Classes of org.eclipse.osgi.internal.composite.CompositeHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.