blob: 631dffe6ecd8db3fa8b00944392a4f82f66fa481 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2013 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* David Knibb initial implementation
* Matthew Webster Eclipse 3.2 changes
* Martin Lippert minor changes and bugfixes
* Martin Lippert caching of generated classes
*******************************************************************************/
package org.eclipse.equinox.weaving.adaptors;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.equinox.service.weaving.CacheEntry;
import org.eclipse.equinox.service.weaving.ICachingService;
import org.eclipse.equinox.service.weaving.IWeavingService;
import org.eclipse.equinox.weaving.hooks.WeavingBundleFile;
import org.eclipse.osgi.container.ModuleRevision;
import org.eclipse.osgi.internal.loader.ModuleClassLoader;
import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.eclipse.osgi.storage.bundlefile.BundleFile;
import org.osgi.framework.Bundle;
import org.osgi.framework.wiring.BundleRevision;
public class WeavingAdaptor implements IWeavingAdaptor {
private static class ThreadLocalSet extends ThreadLocal<Set<Object>> {
public boolean contains(final Object obj) {
final Set<Object> set = get();
return set.contains(obj);
}
@Override
protected Set<Object> initialValue() {
return new HashSet<Object>();
}
public void put(final Object obj) {
final Set<Object> set = get();
if (set.contains(obj)) {
throw new RuntimeException(obj.toString());
}
set.add(obj);
}
public void remove(final Object obj) {
final Set<?> set = get();
if (!set.contains(obj)) {
throw new RuntimeException(obj.toString());
}
set.remove(obj);
}
}
private static ThreadLocalSet identifyRecursionSet = new ThreadLocalSet();
private Bundle bundle;
private ICachingService cachingService;
private final WeavingAdaptorFactory factory;
private final Generation generation;
private boolean initialized = false;
private final ModuleClassLoader moduleLoader;
private final String symbolicName;
private IWeavingService weavingService;
public WeavingAdaptor(final Generation generation,
final WeavingAdaptorFactory serviceFactory,
final IWeavingService weavingService,
final ICachingService cachingService,
final ModuleClassLoader classLoader) {
this.generation = generation;
this.factory = serviceFactory;
this.symbolicName = generation.getRevision().getSymbolicName();
this.moduleLoader = classLoader;
if (Debug.DEBUG_GENERAL)
Debug.println("- WeavingAdaptor.WeavingAdaptor() bundle=" //$NON-NLS-1$
+ symbolicName);
}
@Override
public CacheEntry findClass(final String name, final URL sourceFileURL) {
if (Debug.DEBUG_CACHE)
Debug.println("> WeavingAdaptor.findClass() bundle=" + symbolicName //$NON-NLS-1$
+ ", url=" + sourceFileURL + ", name=" + name); //$NON-NLS-1$ //$NON-NLS-2$
CacheEntry cacheEntry = null;
initialize();
if (cachingService != null) {
cacheEntry = cachingService
.findStoredClass("", sourceFileURL, name); //$NON-NLS-1$
}
if (Debug.DEBUG_CACHE)
Debug.println("< WeavingAdaptor.findClass() cacheEntry=" //$NON-NLS-1$
+ cacheEntry);
return cacheEntry;
}
@Override
public void initialize() {
synchronized (this) {
if (initialized) return;
this.bundle = generation.getRevision().getBundle();
if (!identifyRecursionSet.contains(this)) {
identifyRecursionSet.put(this);
if (Debug.DEBUG_GENERAL)
Debug.println("> WeavingAdaptor.initialize() bundle=" //$NON-NLS-1$
+ symbolicName + ", moduleLoader=" + moduleLoader); //$NON-NLS-1$
if (symbolicName != null && symbolicName.startsWith("org.aspectj")) { //$NON-NLS-1$
if (Debug.DEBUG_GENERAL)
Debug.println("- WeavingAdaptor.initialize() symbolicName=" //$NON-NLS-1$
+ symbolicName + ", moduleLoader=" //$NON-NLS-1$
+ moduleLoader);
} else if (moduleLoader != null) {
weavingService = factory.getWeavingService(moduleLoader);
cachingService = factory.getCachingService(moduleLoader,
bundle, weavingService);
} else if ((generation.getRevision().getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
final Bundle host = factory.getHost(bundle);
if (Debug.DEBUG_GENERAL)
Debug.println("- WeavingAdaptor.initialize() symbolicName=" //$NON-NLS-1$
+ symbolicName + ", host=" + host); //$NON-NLS-1$
final Generation hostGeneration = (Generation) ((ModuleRevision) host
.adapt(BundleRevision.class)).getRevisionInfo();
final BundleFile bundleFile = hostGeneration
.getBundleFile();
if (bundleFile instanceof WeavingBundleFile) {
final WeavingBundleFile hostFile = (WeavingBundleFile) bundleFile;
final WeavingAdaptor hostAdaptor = (WeavingAdaptor) hostFile
.getAdaptor();
weavingService = hostAdaptor.weavingService;
cachingService = factory.getCachingService(
hostAdaptor.moduleLoader, bundle,
weavingService);
}
} else {
if (Debug.DEBUG_GENERAL)
Debug.println("W WeavingAdaptor.initialize() symbolicName=" //$NON-NLS-1$
+ symbolicName + ", baseLoader=" + moduleLoader); //$NON-NLS-1$
}
initialized = true;
identifyRecursionSet.remove(this);
}
if (Debug.DEBUG_GENERAL)
Debug.println("< WeavingAdaptor.initialize() weavingService=" //$NON-NLS-1$
+ (weavingService != null) + ", cachingService=" //$NON-NLS-1$
+ (cachingService != null));
}
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public boolean storeClass(final String name, final URL sourceFileURL,
final Class<?> clazz, final byte[] classbytes) {
if (Debug.DEBUG_CACHE)
Debug.println("> WeavingAdaptor.storeClass() bundle=" //$NON-NLS-1$
+ symbolicName + ", url=" + sourceFileURL //$NON-NLS-1$
+ ", name=" //$NON-NLS-1$
+ name + ", clazz=" + clazz); //$NON-NLS-1$
boolean stored = false;
initialize();
if (cachingService != null) {
//have we generated a closure?
if (weavingService != null
&& weavingService.generatedClassesExistFor(moduleLoader,
name)) {
//If so we need to ask the cache if its capable of handling generated closures
if (cachingService.canCacheGeneratedClasses()) {
final Map<String, byte[]> generatedClasses = weavingService
.getGeneratedClassesFor(name);
stored = cachingService.storeClassAndGeneratedClasses("", //$NON-NLS-1$
sourceFileURL, clazz, classbytes, generatedClasses);
} else {
weavingService.flushGeneratedClasses(moduleLoader);
if (Debug.DEBUG_CACHE)
Debug.println("- WeavingAdaptor.storeClass() generatedClassesExistFor=true"); //$NON-NLS-1$
}
} else {
stored = cachingService.storeClass("", sourceFileURL, clazz, //$NON-NLS-1$
classbytes);
if (!stored) {
if (Debug.DEBUG_CACHE)
Debug.println("E WeavingAdaptor.storeClass() bundle=" //$NON-NLS-1$
+ symbolicName + ", name=" + name); //$NON-NLS-1$
}
}
}
if (Debug.DEBUG_CACHE)
Debug.println("< WeavingAdaptor.storeClass() stored=" + stored); //$NON-NLS-1$
return stored;
}
@Override
public String toString() {
return "WeavingAdaptor[" + symbolicName + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public byte[] weaveClass(final String name, final byte[] bytes) {
if (Debug.DEBUG_WEAVE)
Debug.println("> WeavingAdaptor.weaveClass() bundle=" //$NON-NLS-1$
+ symbolicName + ", name=" + name + ", bytes=" //$NON-NLS-1$ //$NON-NLS-2$
+ bytes.length);
byte[] newBytes = null;
initialize();
if (/* shouldWeave(bytes) && */weavingService != null) {
try {
newBytes = weavingService.preProcess(name, bytes, moduleLoader);
} catch (final IOException ex) {
throw new ClassFormatError(ex.toString());
}
}
if (Debug.DEBUG_WEAVE)
Debug.println("< WeavingAdaptor.weaveClass() newBytes=" + newBytes); //$NON-NLS-1$
return newBytes;
}
}