All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.weaver.tools.cache.WeavedClassCache Maven / Gradle / Ivy

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2012 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *   John Kew (vmware)         	initial implementation
 *   Lyor Goldstein (vmware)	add support for weaved class being re-defined
 *******************************************************************************/

package org.aspectj.weaver.tools.cache;

import java.util.LinkedList;
import java.util.List;

import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.weaver.tools.GeneratedClassHandler;

/**
 * Manages a cache of weaved and generated classes similar to Eclipse Equinox,
 * except designed to operate across multiple restarts of the JVM and with one
 * cache per classloader; allowing URLClassLoaders with the same set of URI
 * paths to share the same cache (with the default configuration).
 * 

* To enable the default configuration two system properties must be set: *

*
 *    "-Daj.weaving.cache.enabled=true"
 *    "-Daj.weaving.cache.dir=/some/directory"
 * 
*

* The class cache is often something that application developers or * containers would like to manage, so there are a few interfaces for overriding the * default behavior and performing other management functions. *

*

* {@link CacheBacking}
* Provides an interface for implementing a custom backing store * for the cache; The default implementation in {@link DefaultFileCacheBacking} * provides a naive file-backed cache. An alternate implementation may ignore * caching until signaled explicitly by the application, or only cache files * for a specific duration. This class delegates the locking and synchronization * requirements to the CacheBacking implementation. *

*

* {@link CacheKeyResolver}
* Provides methods for creating keys from classes to be cached and for * creating the "scope" of the cache itself for a given classloader and aspect * list. The default implementation is provided by {@link DefaultCacheKeyResolver} * but an alternate implementation may want to associate a cache with a particular * application running underneath a container. *

*

* This naive cache does not normally invalidate *any* classes; the interfaces above * must be used to implement more intelligent behavior. Cache invalidation * problems may occur in at least three scenarios: *

*
    *
  1. New aspects are added dynamically somewhere in the classloader hierarchy; affecting * other classes elsewhere.
  2. *
  3. Use of declare parent in aspects to change the type hierarchy; if the cache * has not invalidated the right classes in the type hierarchy aspectj may not * be reconstruct the class incorrectly.
  4. *
  5. Similarly to (2), the addition of fields or methods on classes which have * already been weaved and cached could have inter-type conflicts.
  6. *
*/ public class WeavedClassCache { public static final String WEAVED_CLASS_CACHE_ENABLED = "aj.weaving.cache.enabled"; public static final String CACHE_IMPL = SimpleCacheFactory.CACHE_IMPL; private static CacheFactory DEFAULT_FACTORY = new DefaultCacheFactory(); public static final byte[] ZERO_BYTES = new byte[0]; private final IMessageHandler messageHandler; private final GeneratedCachedClassHandler cachingClassHandler; private final CacheBacking backing; private final CacheStatistics stats; private final CacheKeyResolver resolver; private final String name; private static final List cacheRegistry = new LinkedList<>(); protected WeavedClassCache(GeneratedClassHandler existingClassHandler, IMessageHandler messageHandler, String name, CacheBacking backing, CacheKeyResolver resolver) { this.resolver = resolver; this.name = name; this.backing = backing; this.messageHandler = messageHandler; // wrap the existing class handler with a caching version cachingClassHandler = new GeneratedCachedClassHandler(this, existingClassHandler); this.stats = new CacheStatistics(); synchronized (cacheRegistry) { cacheRegistry.add(this); } } /** * Creates a new cache using the resolver and backing returned by the DefaultCacheFactory. * * @param loader classloader for this cache * @param aspects list of aspects used by the WeavingAdapter * @param existingClassHandler the existing GeneratedClassHandler used by the weaver * @param messageHandler the existing messageHandler used by the weaver * @return */ public static WeavedClassCache createCache(ClassLoader loader, List aspects, GeneratedClassHandler existingClassHandler, IMessageHandler messageHandler) { CacheKeyResolver resolver = DEFAULT_FACTORY.createResolver(); String name = resolver.createClassLoaderScope(loader, aspects); if (name == null) { return null; } CacheBacking backing = DEFAULT_FACTORY.createBacking(name); if (backing != null) { return new WeavedClassCache(existingClassHandler, messageHandler, name, backing, resolver); } return null; } public String getName() { return name; } /** * The Cache and be extended in two ways, through a specialized CacheKeyResolver and * a specialized CacheBacking. The default factory used to create these classes can * be set with this method. Since each weaver will create a cache, this method must be * called before the weaver is first initialized. * * @param factory */ public static void setDefaultCacheFactory(CacheFactory factory) { DEFAULT_FACTORY = factory; } /** * Created a key for a generated class * * @param className ClassName, e.g. "com.foo.Bar" * @return the cache key, or null if no caching should be performed */ public CachedClassReference createGeneratedCacheKey(String className) { return resolver.generatedKey(className); } /** * Create a key for a normal weaved class * * @param className ClassName, e.g. "com.foo.Bar" * @param originalBytes Original byte array of the class * @return a cache key, or null if no caching should be performed */ public CachedClassReference createCacheKey(String className, byte[] originalBytes) { return resolver.weavedKey(className, originalBytes); } /** * Returns a generated class handler which wraps the handler this cache was initialized * with; this handler should be used to make sure that generated classes are added * to the cache */ public GeneratedClassHandler getCachingClassHandler() { return cachingClassHandler; } /** * Has caching been enabled through the System property, * WEAVED_CLASS_CACHE_ENABLED * * @return true if caching is enabled */ public static boolean isEnabled() { String enabled = System.getProperty(WEAVED_CLASS_CACHE_ENABLED); String impl = System.getProperty(CACHE_IMPL); return (enabled != null && (impl == null || !SimpleCache.IMPL_NAME.equalsIgnoreCase(impl) ) ); } /** * Put a class in the cache * * @param ref reference to the entry, as created through createCacheKey * @param classBytes pre-weaving class bytes * @param weavedBytes bytes to cache */ public void put(CachedClassReference ref, byte[] classBytes, byte[] weavedBytes) { CachedClassEntry.EntryType type = CachedClassEntry.EntryType.WEAVED; if (ref.getKey().matches(resolver.getGeneratedRegex())) { type = CachedClassEntry.EntryType.GENERATED; } backing.put(new CachedClassEntry(ref, weavedBytes, type), classBytes); stats.put(); } /** * Get a cache value * * @param ref reference to the cache entry, created through createCacheKey * @param classBytes Pre-weaving class bytes - required to ensure that * cached aspects refer to an unchanged original class * @return the CacheEntry, or null if no entry exists in the cache */ public CachedClassEntry get(CachedClassReference ref, byte[] classBytes) { CachedClassEntry entry = backing.get(ref, classBytes); if (entry == null) { stats.miss(); } else { stats.hit(); if (entry.isGenerated()) stats.generated(); if (entry.isWeaved()) stats.weaved(); if (entry.isIgnored()) stats.ignored(); } return entry; } /** * Put a cache entry to indicate that the class should not be * weaved; the original bytes of the class should be used. * * @param ref The cache reference * @param classBytes The un-weaved class bytes */ public void ignore(CachedClassReference ref, byte[] classBytes) { stats.putIgnored(); backing.put(new CachedClassEntry(ref, ZERO_BYTES, CachedClassEntry.EntryType.IGNORED), classBytes); } /** * Invalidate a cache entry * * @param ref */ public void remove(CachedClassReference ref) { backing.remove(ref); } /** * Clear the entire cache */ public void clear() { backing.clear(); } /** * Get the statistics associated with this cache, or * null if statistics have not been enabled. * * @return */ public CacheStatistics getStats() { return stats; } /** * Return a list of all WeavedClassCaches which have been initialized * * @return */ public static List getCaches() { synchronized (cacheRegistry) { return new LinkedList<>(cacheRegistry); } } protected void error(String message, Throwable th) { messageHandler.handleMessage(new Message(message, IMessage.ERROR, th, null)); } protected void error(String message) { MessageUtil.error(messageHandler, message); } protected void info(String message) { MessageUtil.info(message); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy