View | Details | Raw Unified | Return to bug 386341 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/aspectj/weaver/loadtime/Aj.java (-2 / +30 lines)
Lines 17-22 Link Here
17
import java.util.Collections;
17
import java.util.Collections;
18
import java.util.HashMap;
18
import java.util.HashMap;
19
import java.util.Iterator;
19
import java.util.Iterator;
20
import java.util.LinkedHashMap;
20
import java.util.Map;
21
import java.util.Map;
21
import java.util.Set;
22
import java.util.Set;
22
23
Lines 25-30 Link Here
25
import org.aspectj.weaver.tools.Trace;
26
import org.aspectj.weaver.tools.Trace;
26
import org.aspectj.weaver.tools.TraceFactory;
27
import org.aspectj.weaver.tools.TraceFactory;
27
import org.aspectj.weaver.tools.WeavingAdaptor;
28
import org.aspectj.weaver.tools.WeavingAdaptor;
29
import org.aspectj.weaver.tools.cache.SimpleCache;
30
import org.aspectj.weaver.tools.cache.SimpleCacheFactory;
28
31
29
/**
32
/**
30
 * Adapter between the generic class pre processor interface and the AspectJ weaver Load time weaving consistency relies on
33
 * Adapter between the generic class pre processor interface and the AspectJ weaver Load time weaving consistency relies on
Lines 35-40 Link Here
35
public class Aj implements ClassPreProcessor {
38
public class Aj implements ClassPreProcessor {
36
39
37
	private IWeavingContext weavingContext;
40
	private IWeavingContext weavingContext;
41
	public static SimpleCache laCache=SimpleCacheFactory.createSimpleCache();
38
42
39
	/**
43
	/**
40
	 * References are added to this queue when their associated classloader is removed, and once on here that indicates that we
44
	 * References are added to this queue when their associated classloader is removed, and once on here that indicates that we
Lines 88-93 Link Here
88
92
89
		try {
93
		try {
90
			synchronized (loader) {
94
			synchronized (loader) {
95
				
96
				
97
				
98
				byte[] cacheBytes= laCache.getAndInitialize(className, bytes,loader,protectionDomain);
99
				if (cacheBytes!=null){
100
						return cacheBytes;
101
				}
102
				
103
				
91
				WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext);
104
				WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext);
92
				if (weavingAdaptor == null) {
105
				if (weavingAdaptor == null) {
93
					if (trace.isTraceEnabled())
106
					if (trace.isTraceEnabled())
Lines 100-105 Link Here
100
					Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true);
113
					Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true);
101
					if (trace.isTraceEnabled())
114
					if (trace.isTraceEnabled())
102
						trace.exit("preProcess", newBytes);
115
						trace.exit("preProcess", newBytes);
116
					laCache.put(className, bytes, newBytes);
103
					return newBytes;
117
					return newBytes;
104
				} finally {
118
				} finally {
105
					weavingAdaptor.setActiveProtectionDomain(null);
119
					weavingAdaptor.setActiveProtectionDomain(null);
Lines 247-267 Link Here
247
261
248
			synchronized (weavingAdaptors) {
262
			synchronized (weavingAdaptors) {
249
				checkQ();
263
				checkQ();
250
				adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey);
264
                if(loader.equals(myClassLoader)){
265
                    adaptor = myClassLoaderAdpator;
266
                }
267
                else{
268
                	adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey);
269
                }
251
				if (adaptor == null) {
270
				if (adaptor == null) {
252
					// create it and put it back in the weavingAdaptors map but avoid any kind of instantiation
271
					// create it and put it back in the weavingAdaptors map but avoid any kind of instantiation
253
					// within the synchronized block
272
					// within the synchronized block
254
					ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor();
273
					ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor();
255
					adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor);
274
					adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor);
256
					weavingAdaptors.put(adaptorKey, adaptor);
275
					  if(myClassLoaderAdpator == null){
276
	                        myClassLoaderAdpator = adaptor;
277
					  }
278
	                    else{
279
	                    	weavingAdaptors.put(adaptorKey, adaptor);
280
	                    }
257
				}
281
				}
258
			}
282
			}
259
			// perform the initialization
283
			// perform the initialization
260
			return adaptor.getWeavingAdaptor(loader, weavingContext);
284
			return adaptor.getWeavingAdaptor(loader, weavingContext);
285
		
261
286
262
		}
287
		}
288
		private static final ClassLoader myClassLoader = WeavingAdaptor.class.getClassLoader();
289
		private static ExplicitlyInitializedClassLoaderWeavingAdaptor myClassLoaderAdpator;
263
	}
290
	}
264
291
292
265
	static class ExplicitlyInitializedClassLoaderWeavingAdaptor {
293
	static class ExplicitlyInitializedClassLoaderWeavingAdaptor {
266
		private final ClassLoaderWeavingAdaptor weavingAdaptor;
294
		private final ClassLoaderWeavingAdaptor weavingAdaptor;
267
		private boolean isInitialized;
295
		private boolean isInitialized;
(-)src/org/aspectj/weaver/tools/cache/SimpleCache.java (+365 lines)
Line 0 Link Here
1
package org.aspectj.weaver.tools.cache;
2
3
import java.io.ByteArrayOutputStream;
4
import java.io.File;
5
import java.io.FileInputStream;
6
import java.io.FileNotFoundException;
7
import java.io.FileOutputStream;
8
import java.io.IOException;
9
import java.io.ObjectInputStream;
10
import java.io.ObjectOutputStream;
11
import java.lang.reflect.InvocationTargetException;
12
import java.lang.reflect.Method;
13
import java.security.ProtectionDomain;
14
import java.util.Arrays;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.Map;
18
import java.util.zip.CRC32;
19
20
import org.aspectj.weaver.Dump;
21
import org.aspectj.weaver.tools.Trace;
22
import org.aspectj.weaver.tools.TraceFactory;
23
24
25
public class SimpleCache {
26
27
	private static final String SAME_BYTES_STRING = "IDEM";
28
	private static final byte[] SAME_BYTES = SAME_BYTES_STRING.getBytes();
29
30
	private Map<String, byte[]> cacheMap;
31
	private boolean enabled = false;
32
33
	// cache for generated classes
34
	private Map<String, byte[]> generatedCache;
35
	private static final String GENERATED_CACHE_SUBFOLDER = "panenka.cache";
36
	private static final String GENERATED_CACHE_SEPARATOR = ";";
37
	
38
	public static final String IMPL_NAME = "shared";
39
40
	protected SimpleCache(String folder, boolean enabled) {
41
		this.enabled = enabled;
42
43
		cacheMap = Collections.synchronizedMap(StoreableCachingMap.init(folder));
44
45
		if (enabled) {
46
			String generatedCachePath = folder + File.separator + GENERATED_CACHE_SUBFOLDER;
47
			File f = new File (generatedCachePath);
48
			if (!f.exists()){
49
				f.mkdir();
50
			}
51
			generatedCache = Collections.synchronizedMap(StoreableCachingMap.init(generatedCachePath,0));
52
		}
53
	}
54
55
	public byte[] getAndInitialize(String classname, byte[] bytes,
56
			ClassLoader loader, ProtectionDomain protectionDomain) {
57
		if (!enabled) {
58
			return null;
59
		}
60
		byte[] res = get(classname, bytes);
61
62
		if (Arrays.equals(SAME_BYTES, res)) {
63
			return bytes;
64
		} else {
65
			if (res != null) {
66
				initializeClass(classname, res, loader, protectionDomain);
67
			}
68
			return res;
69
		}
70
71
	}
72
73
	private byte[] get(String classname, byte bytes[]) {
74
		String key = generateKey(classname, bytes);
75
76
		byte[] res = cacheMap.get(key);
77
		return res;
78
	}
79
80
	public void put(String classname, byte[] origbytes, byte[] wovenbytes) {
81
		if (!enabled) {
82
			return;
83
		}
84
85
		String key = generateKey(classname, origbytes);
86
87
		if (Arrays.equals(origbytes, wovenbytes)) {
88
			cacheMap.put(key, SAME_BYTES);
89
			return;
90
		}
91
		cacheMap.put(key, wovenbytes);
92
	}
93
94
	private String generateKey(String classname, byte[] bytes) {
95
		CRC32 checksum = new CRC32();
96
		checksum.update(bytes);
97
		long crc = checksum.getValue();
98
		classname = classname.replace("/", ".");
99
		return new String(classname + "-" + crc);
100
101
	}
102
103
	private static class StoreableCachingMap extends HashMap {
104
		private String folder;
105
		private static final String CACHENAMEIDX = "cache.idx";
106
		
107
		private long lastStored = System.currentTimeMillis();
108
		private static int DEF_STORING_TIMER = 60000; //ms
109
		private int storingTimer;
110
		
111
		private transient Trace trace;
112
		private void initTrace(){
113
			trace = TraceFactory.getTraceFactory().getTrace(StoreableCachingMap.class);
114
		}
115
		
116
//		private StoreableCachingMap(String folder) {
117
//			this.folder = folder;
118
//			initTrace();
119
//		}
120
		
121
		private StoreableCachingMap(String folder, int storingTimer){
122
			this.folder = folder;
123
			initTrace();
124
			this.storingTimer = storingTimer;
125
		}
126
		
127
		public static StoreableCachingMap init(String folder) {
128
			return init(folder,DEF_STORING_TIMER);
129
			
130
		}
131
		
132
		public static StoreableCachingMap init(String folder, int storingTimer) {
133
			File file = new File(folder + File.separator + CACHENAMEIDX);
134
			if (file.exists()) {
135
				try {
136
					ObjectInputStream in = new ObjectInputStream(
137
							new FileInputStream(file));
138
					// Deserialize the object
139
					StoreableCachingMap sm = (StoreableCachingMap) in.readObject();
140
					sm.initTrace();
141
					in.close();
142
					return sm;
143
				} catch (Exception e) {
144
					Trace trace = TraceFactory.getTraceFactory().getTrace(StoreableCachingMap.class);
145
					trace.error("Error reading Storable Cache", e);
146
				}
147
			}
148
149
			return new StoreableCachingMap(folder,storingTimer);
150
151
		}
152
153
		@Override
154
		public Object get(Object obj) {
155
			try {
156
				if (super.containsKey(obj)) {
157
					String path = (String) super.get(obj);
158
					if (path.equals(SAME_BYTES_STRING)) {
159
						return SAME_BYTES;
160
					}
161
					return readFromPath(path);
162
				} else {
163
					return null;
164
				}
165
			} catch (IOException e) {
166
				trace.error("Error reading key:"+obj.toString(),e);
167
				Dump.dumpWithException(e);
168
			}
169
			return null;
170
		}
171
172
		@Override
173
		public Object put(Object key, Object value) {
174
			try {
175
				String path = null;
176
				byte[] valueBytes = (byte[]) value;
177
				
178
				if (Arrays.equals(valueBytes, SAME_BYTES)) {
179
					path = SAME_BYTES_STRING;
180
				} else {
181
					path = writeToPath((String) key, valueBytes);
182
				}
183
				Object result = super.put(key, path);
184
				storeMap();
185
				return result;
186
			} catch (IOException e) {
187
				trace.error("Error inserting in cache: key:"+key.toString() + "; value:"+value.toString(), e);
188
				Dump.dumpWithException(e);
189
			}
190
			return null;
191
		}
192
		
193
		
194
195
		public void storeMap() {
196
			long now = System.currentTimeMillis();
197
			if ((now - lastStored ) < storingTimer){
198
				return;
199
			}
200
			File file = new File(folder + File.separator + CACHENAMEIDX);;
201
			try {
202
				ObjectOutputStream out = new ObjectOutputStream(
203
						new FileOutputStream(file));
204
				// Deserialize the object
205
				out.writeObject(this);
206
				out.close();
207
				lastStored = now;
208
			} catch (Exception e) {
209
				trace.error("Error storing cache; cache file:"+file.getAbsolutePath(), e);
210
				Dump.dumpWithException(e);
211
			}
212
		}
213
214
		private byte[] readFromPath(String fullPath) throws IOException {
215
			FileInputStream is = null ;
216
			try{
217
				is = new FileInputStream(fullPath);
218
			}
219
			catch (FileNotFoundException e){
220
				//may be caused by a generated class that has been stored in generated cache but not saved at cache folder
221
				System.out.println("FileNotFoundExceptions: The aspectj cache is corrupt. Please clean it and reboot the server. Cache path:"+this.folder );
222
				e.printStackTrace();
223
				return null;
224
			}
225
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
226
227
			int nRead;
228
			byte[] data = new byte[16384];
229
230
			while ((nRead = is.read(data, 0, data.length)) != -1) {
231
				buffer.write(data, 0, nRead);
232
			}
233
234
			buffer.flush();
235
			is.close();
236
			return buffer.toByteArray();
237
238
		}
239
240
		private String writeToPath(String key, byte[] bytes) throws IOException {
241
			String fullPath = folder + File.separator + key;
242
			FileOutputStream fos = new FileOutputStream(fullPath);
243
			fos.write(bytes);
244
			fos.flush();
245
			fos.close();
246
			return fullPath;
247
		}
248
249
	}
250
251
	private void initializeClass(String className, byte[] bytes,
252
			ClassLoader loader, ProtectionDomain protectionDomain) {
253
		String[] generatedClassesNames = getGeneratedClassesNames(className,bytes);
254
255
		if (generatedClassesNames == null) {
256
			return;
257
		}
258
		for (String generatedClassName : generatedClassesNames) {
259
260
			byte[] generatedBytes = get(generatedClassName, bytes);
261
			
262
			if (protectionDomain == null) {
263
				defineClass(loader, generatedClassName, generatedBytes);
264
			} else {
265
				defineClass(loader, generatedClassName, generatedBytes,
266
						protectionDomain);
267
			}
268
269
		}
270
271
	}
272
273
	private String[] getGeneratedClassesNames(String className, byte[] bytes) {
274
		String key = generateKey(className, bytes);
275
276
		byte[] readBytes = generatedCache.get(key);
277
		if (readBytes == null) {
278
			return null;
279
		}
280
		String readString = new String(readBytes);
281
		return readString.split(GENERATED_CACHE_SEPARATOR);
282
	}
283
284
	public void addGeneratedClassesNames(String parentClassName, byte[] parentBytes, String generatedClassName) {
285
		if (!enabled) {
286
			return;
287
		}
288
		String key = generateKey(parentClassName, parentBytes);
289
290
		byte[] storedBytes = generatedCache.get(key);
291
		if (storedBytes == null) {
292
			generatedCache.put(key, generatedClassName.getBytes());
293
		} else {
294
			String storedClasses = new String(storedBytes);
295
			storedClasses += GENERATED_CACHE_SEPARATOR + generatedClassName;
296
			generatedCache.put(key, storedClasses.getBytes());
297
		}
298
	}
299
300
	private Method defineClassMethod = null;
301
	private Method defineClassWithProtectionDomainMethod = null;
302
303
	private void defineClass(ClassLoader loader, String name, byte[] bytes) {
304
305
		Object clazz = null;
306
307
		try {
308
			if (defineClassMethod == null) {
309
				defineClassMethod = ClassLoader.class.getDeclaredMethod(
310
						"defineClass", new Class[] { String.class,
311
								bytes.getClass(), int.class, int.class });
312
			}
313
			defineClassMethod.setAccessible(true);
314
			clazz = defineClassMethod.invoke(loader, new Object[] { name,
315
					bytes, new Integer(0), new Integer(bytes.length) });
316
		} catch (InvocationTargetException e) {
317
			if (e.getTargetException() instanceof LinkageError) {
318
				e.printStackTrace();
319
			} else {
320
				System.out.println("define generated class failed"
321
						+ e.getTargetException());
322
			}
323
		} catch (Exception e) {
324
			e.printStackTrace();
325
			Dump.dumpWithException(e);
326
		}
327
	}
328
329
	private void defineClass(ClassLoader loader, String name, byte[] bytes,
330
			ProtectionDomain protectionDomain) {
331
332
		Object clazz = null;
333
334
		try {
335
			// System.out.println(">> Defining with protection domain " + name +
336
			// " pd=" + protectionDomain);
337
			if (defineClassWithProtectionDomainMethod == null) {
338
				defineClassWithProtectionDomainMethod = ClassLoader.class
339
						.getDeclaredMethod("defineClass", new Class[] {
340
								String.class, bytes.getClass(), int.class,
341
								int.class, ProtectionDomain.class });
342
			}
343
			defineClassWithProtectionDomainMethod.setAccessible(true);
344
			clazz = defineClassWithProtectionDomainMethod.invoke(loader,
345
					new Object[] { name, bytes, Integer.valueOf(0),
346
							new Integer(bytes.length), protectionDomain });
347
		} catch (InvocationTargetException e) {
348
			if (e.getTargetException() instanceof LinkageError) {
349
				e.printStackTrace();
350
				// is already defined (happens for X$ajcMightHaveAspect
351
				// interfaces since aspects are reweaved)
352
				// TODO maw I don't think this is OK and
353
			} else {
354
				e.printStackTrace();
355
			}
356
		}catch (NullPointerException e) {
357
			System.out.println("NullPointerException loading class:"+name+".  Probabily caused by a corruput cache. Please clean it and reboot the server");
358
		} catch (Exception e) {
359
			e.printStackTrace();
360
			Dump.dumpWithException(e);
361
		}
362
363
	}
364
365
}
(-)src/org/aspectj/weaver/tools/cache/WeavedClassCache.java (-1 / +4 lines)
Lines 67-72 Link Here
67
 */
67
 */
68
public class WeavedClassCache {
68
public class WeavedClassCache {
69
	public static final String WEAVED_CLASS_CACHE_ENABLED = "aj.weaving.cache.enabled";
69
	public static final String WEAVED_CLASS_CACHE_ENABLED = "aj.weaving.cache.enabled";
70
	public static final String CACHE_IMPL = SimpleCacheFactory.CACHE_IMPL;
70
	private static CacheFactory DEFAULT_FACTORY = new DefaultCacheFactory();
71
	private static CacheFactory DEFAULT_FACTORY = new DefaultCacheFactory();
71
	public static final byte[] ZERO_BYTES = new byte[0];
72
	public static final byte[] ZERO_BYTES = new byte[0];
72
	private final IMessageHandler messageHandler;
73
	private final IMessageHandler messageHandler;
Lines 171-177 Link Here
171
	 * @return true if caching is enabled
172
	 * @return true if caching is enabled
172
	 */
173
	 */
173
	public static boolean isEnabled() {
174
	public static boolean isEnabled() {
174
		return System.getProperty(WEAVED_CLASS_CACHE_ENABLED) != null;
175
		String enabled = System.getProperty(WEAVED_CLASS_CACHE_ENABLED);
176
		String impl = System.getProperty(CACHE_IMPL);
177
		return (enabled != null && (impl == null || !SimpleCache.IMPL_NAME.equalsIgnoreCase(impl) ) );
175
	}
178
	}
176
179
177
	/**
180
	/**
(-)src/org/aspectj/weaver/tools/cache/SimpleCacheFactory.java (+72 lines)
Line 0 Link Here
1
package org.aspectj.weaver.tools.cache;
2
3
import java.io.File;
4
5
import org.aspectj.weaver.Dump;
6
7
public class SimpleCacheFactory {
8
	
9
	public static final String CACHE_ENABLED_PROPERTY = "aj.weaving.cache.enabled";
10
	public static final String CACHE_DIR = "aj.weaving.cache.dir";
11
	public static final String CACHE_IMPL = "aj.weaving.cache.impl";
12
	
13
	public static final String PATH_DEFAULT="/tmp/panenka";
14
	public static final boolean BYDEFAULT= false;	
15
		
16
		
17
	public static String path = PATH_DEFAULT;
18
	public static Boolean enable = false;
19
	private static SimpleCache lacache=null;
20
	
21
	public static synchronized SimpleCache createSimpleCache(){
22
		if (lacache==null){
23
		 	
24
			try {
25
				String property = System.getProperty(CACHE_ENABLED_PROPERTY);
26
				if (property == null ){
27
					enable = BYDEFAULT;
28
				}
29
				else if (property.equalsIgnoreCase("true")){
30
					
31
						String impl = System.getProperty(CACHE_IMPL);
32
						if (SimpleCache.IMPL_NAME.equals(impl)){
33
							enable = true;
34
						}
35
						else{
36
							enable = BYDEFAULT;
37
						}
38
				}
39
				else{
40
					enable = BYDEFAULT;
41
				}
42
				
43
			} catch (Throwable t) {
44
				enable=BYDEFAULT;
45
				System.err.println("Error creating cache");
46
				t.printStackTrace();
47
				Dump.dumpWithException(t);
48
			}
49
50
			try {
51
				path = System.getProperty(CACHE_DIR);
52
				if (path == null){
53
					path = PATH_DEFAULT;
54
				}
55
				
56
			} catch (Throwable t) {
57
				path=PATH_DEFAULT;
58
				t.printStackTrace();
59
				Dump.dumpWithException(t);
60
			}
61
			File f = new File(path);
62
			if (!f.exists()){
63
				f.mkdir();
64
			}
65
			lacache= new SimpleCache(path, enable);
66
		}
67
		return lacache;
68
		
69
	} 
70
	
71
72
}
(-)src/org/aspectj/weaver/tools/WeavingAdaptor.java (+9 lines)
Lines 46-51 Link Here
46
import org.aspectj.weaver.bcel.UnwovenClassFile;
46
import org.aspectj.weaver.bcel.UnwovenClassFile;
47
import org.aspectj.weaver.tools.cache.CachedClassEntry;
47
import org.aspectj.weaver.tools.cache.CachedClassEntry;
48
import org.aspectj.weaver.tools.cache.CachedClassReference;
48
import org.aspectj.weaver.tools.cache.CachedClassReference;
49
import org.aspectj.weaver.tools.cache.SimpleCache;
50
import org.aspectj.weaver.tools.cache.SimpleCacheFactory;
49
import org.aspectj.weaver.tools.cache.WeavedClassCache;
51
import org.aspectj.weaver.tools.cache.WeavedClassCache;
50
52
51
// OPTIMIZE add guards for all the debug/info/etc
53
// OPTIMIZE add guards for all the debug/info/etc
Lines 881-886 Link Here
881
					} else {
883
					} else {
882
						// Classes generated by weaver e.g. around closure advice
884
						// Classes generated by weaver e.g. around closure advice
883
						String className = result.getClassName();
885
						String className = result.getClassName();
886
						
887
						SimpleCache lacache=SimpleCacheFactory.createSimpleCache();
888
						  
889
						lacache.put(result.getClassName(), wovenClass.getBytes(), result.getBytes());
890
						lacache.addGeneratedClassesNames(wovenClass.getClassName(), wovenClass.getBytes(), result.getClassName());
891
						
892
						
884
						generatedClasses.put(className, result);
893
						generatedClasses.put(className, result);
885
						generatedClasses.put(wovenClass.getClassName(), result);
894
						generatedClasses.put(wovenClass.getClassName(), result);
886
						generatedClassHandler.acceptClass(className, result.getBytes());
895
						generatedClassHandler.acceptClass(className, result.getBytes());

Return to bug 386341