Package org.eclipse.core.runtime.internal.adaptor

Source Code of org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter$TerminatingClassNotFoundException

/*******************************************************************************
* Copyright (c) 2006 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.core.runtime.internal.adaptor;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessController;
import java.util.*;
import org.eclipse.osgi.baseadaptor.*;
import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry;
import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook;
import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingStatsHook;
import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry;
import org.eclipse.osgi.baseadaptor.loader.ClasspathManager;
import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
import org.eclipse.osgi.framework.adaptor.StatusException;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.internal.core.*;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.StateHelper;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.startlevel.StartLevel;

public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, HookConfigurator {
  private static final boolean throwErrorOnFailedStart = "true".equals(FrameworkProperties.getProperty("osgi.compatibility.errorOnFailedStart", "true"))//$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
  private static final SecureAction secureAction = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction());
  private StartLevelImpl startLevelService;
  private ServiceReference slRef;
  private BaseAdaptor adaptor;
  // holds the current activation trigger class and the ClasspathManagers that need to be activated
  private ThreadLocal activationStack = new ThreadLocal();
  // used to store exceptions that occurred while activating a bundle
  // keyed by ClasspathManager->Exception
  // WeakHashMap is used to prevent pinning the ClasspathManager objects.
  private final Map errors = Collections.synchronizedMap(new WeakHashMap());

  public void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException {
    AbstractBundle bundle = (AbstractBundle) manager.getBaseData().getBundle();
    // If the bundle is active, uninstalled or stopping then the bundle has already
    // been initialized (though it may have been destroyed) so just return the class.
    if ((bundle.getState() & (Bundle.ACTIVE | Bundle.UNINSTALLED | Bundle.STOPPING)) != 0)
      return;
    EclipseStorageHook storageHook = (EclipseStorageHook) manager.getBaseData().getStorageHook(EclipseStorageHook.KEY);
    // The bundle is not active and does not require activation, just return the class
    if (!shouldActivateFor(name, manager.getBaseData(), storageHook, manager))
      return;
    ArrayList stack = (ArrayList) activationStack.get();
    if (stack == null) {
      stack = new ArrayList(6);
      activationStack.set(stack);
    }
    // the first element in the stack is the name of the trigger class,
    // each element after the trigger class is a classpath manager
    // that must be activated after the trigger class has been defined (see postFindLocalClass)
    int size = stack.size();
    if (size > 1) {
      for (int i = size -1; i >= 1; i--)
        if (manager == stack.get(i))
          // the manager is already on the stack in which case we are already in the process of loading the trigger class
          return;
    }
    Thread threadChangingState = bundle.getStateChanging();
    if (bundle.getState() == Bundle.STARTING && threadChangingState == Thread.currentThread())
      return; // this thread is starting the bundle already
    if (size == 0)
      stack.add(name);
    stack.add(manager);
  }

  public void postFindLocalClass(String name, Class clazz, ClasspathManager manager) throws ClassNotFoundException {
    ArrayList stack = (ArrayList) activationStack.get();
    if (stack == null)
      return;
    int size = stack.size();
    if (size <= 1 || stack.get(0) != name)
      return;
    // if we have a stack we must clear it even if (clazz == null)
    ClasspathManager[] managers = null;
    managers = new ClasspathManager[size - 1];
    for (int i = 1; i < size; i++)
      managers[i - 1] = (ClasspathManager) stack.get(i);
    stack.clear();
    if (clazz == null)
      return;
    for (int i = managers.length - 1; i >= 0; i--) {
      if (errors.get(managers[i]) != null) {
        if (throwErrorOnFailedStart)
          throw (TerminatingClassNotFoundException) errors.get(managers[i]);
        continue;
      }
      AbstractBundle bundle = (AbstractBundle) managers[i].getBaseData().getBundle();
      // The bundle must be started.
      // Note that another thread may already be starting this bundle;
      // In this case we will timeout after 5 seconds and record the BundleException
      try {
        // do not persist the start of this bundle
        secureAction.start(bundle, Bundle.START_TRANSIENT);
      } catch (BundleException e) {
        Throwable cause = e.getCause();
        if (cause != null && cause instanceof StatusException) {
          StatusException status = (StatusException) cause;
          if ((status.getStatusCode() & StatusException.CODE_ERROR) == 0) {
            if (status.getStatus() instanceof Thread) {
              String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CONCURRENT_STARTUP, new Object[] {Thread.currentThread(), name, status.getStatus(), bundle, new Integer(5000)});
              adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, message, 0, e, null));
            }     
            continue;
          }
        }
        String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_ACTIVATION, bundle.getSymbolicName(), Long.toString(bundle.getBundleId()));
        TerminatingClassNotFoundException error = new TerminatingClassNotFoundException(message, e);
        errors.put(managers[i], error);
        if (throwErrorOnFailedStart) {
          adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null));
          throw error;
        }
        adaptor.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(message, e));
      }
    }
  }

  public void preFindLocalResource(String name, ClasspathManager manager) {
    // do nothing
  }

  public void postFindLocalResource(String name, URL resource, ClasspathManager manager) {
    // do nothing
  }

  public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
    // do nothing
  }

  private boolean shouldActivateFor(String className, BaseData bundledata, EclipseStorageHook storageHook, ClasspathManager manager) throws ClassNotFoundException {
    if (!isLazyStartable(className, bundledata, storageHook))
      return false;
    // Don't activate non-starting bundles
    if (bundledata.getBundle().getState() == Bundle.RESOLVED) {
      if (throwErrorOnFailedStart) {
        TerminatingClassNotFoundException error = (TerminatingClassNotFoundException) errors.get(manager);
        if (error != null)
          throw error;
      }
      StartLevelImpl sl = startLevelService;
      return sl != null && ((sl.getStartLevel() == bundledata.getStartLevel() && sl.isSettingStartLevel()));
    }
    return true;
  }

  private boolean isLazyStartable(String className, BaseData bundledata, EclipseStorageHook storageHook) {
    if (storageHook == null)
      return false;
    boolean lazyStart = storageHook.isLazyStart();
    String[] excludes = storageHook.getLazyStartExcludes();
    String[] includes = storageHook.getLazyStartIncludes();
    // no exceptions, it is easy to figure it out
    if (excludes == null && includes == null)
      return lazyStart;
    // otherwise, we need to check if the package is in the exceptions list
    int dotPosition = className.lastIndexOf('.');
    // the class has no package name... no exceptions apply
    if (dotPosition == -1)
      return lazyStart;
    String packageName = className.substring(0, dotPosition);
    if (lazyStart)
      return ((includes == null || contains(includes, packageName)) && (excludes == null || !contains(excludes, packageName)));
    return (excludes != null && contains(excludes, packageName));
  }

  private boolean contains(String[] array, String element) {
    for (int i = 0; i < array.length; i++)
      if (array[i].equals(element))
        return true;
    return false;
  }

  public void addHooks(HookRegistry hookRegistry) {
    hookRegistry.addClassLoadingStatsHook(this);
    hookRegistry.addAdaptorHook(this);
  }

  public void addProperties(Properties properties) {
    // do nothing
  }

  public FrameworkLog createFrameworkLog() {
    // do nothing
    return null;
  }

  public void frameworkStart(BundleContext context) throws BundleException {
    slRef = context.getServiceReference(StartLevel.class.getName());
    if (slRef != null)
      startLevelService = (StartLevelImpl) context.getService(slRef);
  }

  public void frameworkStop(BundleContext context) throws BundleException {
    if (slRef != null) {
      context.ungetService(slRef);
      startLevelService = null;
    }
  }

  public void frameworkStopping(BundleContext context) {
    if (!Debug.DEBUG || !Debug.DEBUG_ENABLED)
      return;

    BundleDescription[] allBundles = adaptor.getState().getResolvedBundles();
    StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper();
    Object[][] cycles = stateHelper.sortBundles(allBundles);
    logCycles(cycles);
  }

  public void handleRuntimeError(Throwable error) {
    // do nothing

  }

  public void initialize(BaseAdaptor baseAdaptor) {
    this.adaptor = baseAdaptor;
  }

  public URLConnection mapLocationToURLConnection(String location) throws IOException {
    // do nothing
    return null;
  }

  public boolean matchDNChain(String pattern, String[] dnChain) {
    // do nothing
    return false;
  }

  private void logCycles(Object[][] cycles) {
    // log cycles
    if (cycles.length > 0) {
      StringBuffer cycleText = new StringBuffer("["); //$NON-NLS-1$     
      for (int i = 0; i < cycles.length; i++) {
        cycleText.append('[');
        for (int j = 0; j < cycles[i].length; j++) {
          cycleText.append(((BundleDescription) cycles[i][j]).getSymbolicName());
          cycleText.append(',');
        }
        cycleText.insert(cycleText.length() - 1, ']');
      }
      cycleText.setCharAt(cycleText.length() - 1, ']');
      String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_BUNDLESTOPPER_CYCLES_FOUND, cycleText);
      FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, message, 0, null, null);
      adaptor.getFrameworkLog().log(entry);
    }
  }

  private static class TerminatingClassNotFoundException extends ClassNotFoundException implements StatusException {
    private static final long serialVersionUID = -6730732895632169173L;
    private Object cause;
    public TerminatingClassNotFoundException(String message, Throwable cause) {
      super(message, cause);
      this.cause = cause;
    }

    public Object getStatus() {
      return cause;
    }

    public int getStatusCode() {
      return StatusException.CODE_ERROR;
    }
   
  }
}
TOP

Related Classes of org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter$TerminatingClassNotFoundException

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.