Package at.bestsolution.efxclipse.runtime.osgi.patch

Source Code of at.bestsolution.efxclipse.runtime.osgi.patch.PFBundleFile

/*******************************************************************************
* Copyright (c) 2008 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 at.bestsolution.efxclipse.runtime.osgi.patch;

import java.io.File;
import java.io.IOException;
import java.util.*;
import org.eclipse.osgi.baseadaptor.BaseData;
import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry;
import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile;
import org.eclipse.osgi.framework.internal.core.AbstractBundle;
import org.eclipse.osgi.internal.baseadaptor.DevClassPathHelper;
import org.osgi.framework.Bundle;
import org.osgi.service.packageadmin.PackageAdmin;

/**
* A bundle file that wraps the content of another bundle file.
* A list of bundle files is used to patch the content of the
* wrapped bundle file.  The list of patches is searched
* before the wrapped bundle file.  This allows the
* content of the patches to override (or patch) the
* content of the wrapped bundle file.
*/
public class PFBundleFile extends BundleFile {
  /**
   * The wrapped bundle file that is being patched
   */
  private final BundleFile wrapped;
  /**
   * The BaseData for the wrapped bundle file
   */
  private final BaseData patchedData;
  /**
   * The adaptor hook
   */
  private final PFAdaptorHook pfAdaptorHook;
  /**
   * Indicates that the list of patches is current and ready to use
   */
  private boolean processed = false;
  /**
   * The list of patch bundle files that are associated with this bundle file.
   */
  private BundleFile[] patches;

  public PFBundleFile(BundleFile wrapped, BaseData patchedData, PFAdaptorHook pfAdaptorHook) {
    // use the base file from the wrapped bundle file
    super(wrapped.getBaseFile());
    this.wrapped = wrapped;
    this.patchedData = patchedData;
    this.pfAdaptorHook = pfAdaptorHook;
  }

  public void close() throws IOException {
    wrapped.close();
  }

  public boolean containsDir(String dir) {
    return wrapped.containsDir(dir);
  }

  public BundleEntry getEntry(String path) {
    // see if there are any patches available
    BundleFile[] patchFiles = getPatches();
    if (patchFiles == null) // none available just use the wrapped content
      return wrapped.getEntry(path);
    if ("META-INF/MANIFEST.MF".equals(path)) //$NON-NLS-1$
      return wrapped.getEntry(path); // don't patch manifest
    for (int i = 0; i < patchFiles.length; i++) {
      BundleEntry entry = patchFiles[i].getEntry(path);
      if (entry != null) { // found patched content; return it
        if (PFConfigurator.DEBUG)
          System.out.println("Found patch for \"" + path + "\" in \"" + patchFiles[i] + "\""); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
        return entry;
      }
    }
    // no patched content found for the path; use the wrapped content
    return wrapped.getEntry(path);
  }

  public Enumeration getEntryPaths(String path) {
    // we simply call the wrapped bundle file here because
    // we do not want to return more entries than what the original content has
    return wrapped.getEntryPaths(path);
  }

  public File getFile(String path, boolean nativeCode) {
    // see if there are any patches available
    BundleFile[] patchFiles = getPatches();
    if (patchFiles == null) // none available just use the wrapped content
      return wrapped.getFile(path, nativeCode);
    for (int i = 0; i < patchFiles.length; i++) {
      File file = patchFiles[i].getFile(path, nativeCode);
      if (file != null) // found patched content; return it
        return file;
    }
    // no patched content found for the path; use the wrapped content
    return wrapped.getFile(path, nativeCode);
  }

  public void open() throws IOException {
    wrapped.open();
  }

  private synchronized BundleFile[] getPatches() {
    if (processed) // the patches list is current; return it
      return patches;
    Bundle bundle = patchedData.getBundle();
    if (bundle == null)
      // BundleFile objects are created before the Bundle object
      return null; // we don't know yet
    // bundle is not resolved; we can only patch after the bundle is resolved
    if (((Bundle.INSTALLED | Bundle.UNINSTALLED) & bundle.getState()) != 0)
      return null; // we can only patch if resolved;
    // bundle is resolved; now check package admin for patch fragments
    PackageAdmin pa = pfAdaptorHook.getPackageAdmin();
    if (pa == null)
      return null; // we cannot know without PA
    // collect a list of bundles we need to listen for UNRESOLVED/UNINSTALLED events
    Collection bundlesToListen = new ArrayList();
    try {
      if ((pa.getBundleType(bundle) & PackageAdmin.BUNDLE_TYPE_FRAGMENT) == 0)
        bundlesToListen.add(bundle); // Always listen to the host bundle
      else
        return null; // we don't patch fragments; no need to listen
      Bundle[] fragments = pa.getFragments(bundle);
      if (fragments == null)
        return null; // no fragments
      // search the fragments for patch fragments
      ArrayList patchList = new ArrayList(fragments.length);
      for (int i = 0; i < fragments.length; i++) {
        AbstractBundle fragment = (AbstractBundle) fragments[i];
        BaseData fragmentData = (BaseData) fragment.getBundleData();
        // The PFStorageHook knows if this is a patch fragment
        PFStorageHook storageHook = (PFStorageHook) fragmentData.getStorageHook(PFStorageHook.KEY);
        if (storageHook.isPatchFragment()) {
          if (PFConfigurator.DEBUG)
            System.out.println("Found patch fragment: " + fragmentData.toString()); //$NON-NLS-1$
          patchList.add(fragmentData.getBundleFile());
          // need to listen to this fragment
          bundlesToListen.add(fragment);
          // add in dev classpaths
          if (DevClassPathHelper.inDevelopmentMode()) {
            String[] devPath = DevClassPathHelper.getDevClassPath(fragmentData.getSymbolicName());
            if (devPath != null) {
              for (int j = 0; j < devPath.length; j++) {
                File devFile = fragmentData.getBundleFile().getFile(devPath[i], false);
                patchList.add(pfAdaptorHook.createDevClasspathBundleFile(devFile, fragmentData));
              }
            }
          }
        }
        patches = (BundleFile[]) patchList.toArray(new BundleFile[patchList.size()]);
      }
    } finally {
      // tell the listener about the list to listen
      pfAdaptorHook.listenToPatches(bundlesToListen, this);
      // mark the patches as processed
      processed = true;
    }
    return patches;
  }

  synchronized void resetPatches() {
    // reset the patches list so it will be re-computed.
    processed = false;
    patches = null;
  }

  public String toString() {
    return patchedData.toString();
  }
}
TOP

Related Classes of at.bestsolution.efxclipse.runtime.osgi.patch.PFBundleFile

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.