/******************************************************************************* * Copyright (c) 2006, 2013 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: * 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; } }