001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.aspectj;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
018    import com.liferay.portal.kernel.util.StreamUtil;
019    
020    import java.io.ByteArrayInputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    
024    import java.net.URL;
025    
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    import org.aspectj.apache.bcel.classfile.ClassParser;
030    import org.aspectj.apache.bcel.classfile.JavaClass;
031    import org.aspectj.weaver.CrosscuttingMembersSet;
032    import org.aspectj.weaver.ResolvedType;
033    import org.aspectj.weaver.bcel.BcelObjectType;
034    import org.aspectj.weaver.tools.GeneratedClassHandler;
035    import org.aspectj.weaver.tools.WeavingAdaptor;
036    
037    /**
038     * @author Shuyang Zhou
039     */
040    public class URLWeavingAdaptor extends WeavingAdaptor {
041    
042            public URLWeavingAdaptor(URL[] urls, Class<?>[] aspectClasses) {
043                    super(null, urls, new URL[0]);
044    
045                    generatedClassHandler = new RecordGeneratedClassHandler();
046    
047                    for (Class<?> aspectClass : aspectClasses) {
048                            _addAspectClass(aspectClass);
049                    }
050    
051                    weaver.prepareForWeave();
052            }
053    
054            public byte[] removeGeneratedClassDate(String name) {
055                    return _generatedClasses.remove(name);
056            }
057    
058            private void _addAspectClass(Class<?> aspectClass) {
059                    Class<?> currentClass = aspectClass;
060    
061                    while (true) {
062                            Class<?>[] interfaceClasses = currentClass.getInterfaces();
063    
064                            for (Class<?> interfaceClass : interfaceClasses) {
065                                    JavaClass javaClass = _classToJavaClass(interfaceClass);
066    
067                                    if (javaClass != null) {
068                                            bcelWorld.addSourceObjectType(javaClass, false);
069                                    }
070                            }
071    
072                            currentClass = currentClass.getSuperclass();
073    
074                            if (currentClass != null) {
075                                    JavaClass javaClass = _classToJavaClass(currentClass);
076    
077                                    if (javaClass != null) {
078                                            bcelWorld.addSourceObjectType(javaClass, false);
079                                    }
080                            }
081                            else {
082                                    break;
083                            }
084                    }
085    
086                    JavaClass javaClass = _classToJavaClass(aspectClass);
087    
088                    BcelObjectType bcelObjectType = bcelWorld.addSourceObjectType(
089                            javaClass, false);
090    
091                    ResolvedType resolvedType = bcelObjectType.getResolvedTypeX();
092    
093                    if (resolvedType.isAspect()) {
094                            CrosscuttingMembersSet crosscuttingMembersSet =
095                                    bcelWorld.getCrosscuttingMembersSet();
096    
097                            crosscuttingMembersSet.addOrReplaceAspect(resolvedType);
098                    }
099                    else {
100                            throw new IllegalArgumentException(
101                                    "Class object " + aspectClass + " is not an aspect");
102                    }
103            }
104    
105            private JavaClass _classToJavaClass(Class<?> aspectClass) {
106                    ClassLoader aspectClassLoader = aspectClass.getClassLoader();
107    
108                    if (aspectClassLoader == null) {
109                            aspectClassLoader = ClassLoader.getSystemClassLoader();
110                    }
111    
112                    String resourcePath = aspectClass.getName();
113    
114                    resourcePath = resourcePath.replace('.', '/') + ".class";
115    
116                    ByteArrayInputStream byteArrayInputStream = null;
117    
118                    InputStream inputStream = aspectClassLoader.getResourceAsStream(
119                            resourcePath);
120    
121                    if (inputStream instanceof ByteArrayInputStream) {
122                            byteArrayInputStream = (ByteArrayInputStream)inputStream;
123                    }
124                    else {
125                            try {
126                                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
127                                            new UnsyncByteArrayOutputStream();
128    
129                                    StreamUtil.transfer(
130                                            inputStream, unsyncByteArrayOutputStream, true);
131    
132                                    byte[] classData =
133                                            unsyncByteArrayOutputStream.unsafeGetByteArray();
134    
135                                    byteArrayInputStream = new ByteArrayInputStream(
136                                            classData, 0, unsyncByteArrayOutputStream.size());
137                            }
138                            catch (IOException ioe) {
139                                    throw new RuntimeException("Unable to reload class data", ioe);
140                            }
141                    }
142    
143                    ClassParser classParser = new ClassParser(
144                            byteArrayInputStream, aspectClass.getSimpleName() + ".class");
145    
146                    try {
147                            return classParser.parse();
148                    }
149                    catch (Exception e) {
150                            throw new RuntimeException("Unable to parse class data", e);
151                    }
152            }
153    
154            private Map<String, byte[]> _generatedClasses =
155                    new HashMap<String, byte[]>();
156    
157            private class RecordGeneratedClassHandler implements GeneratedClassHandler {
158    
159                    @Override
160                    public void acceptClass(String name, byte[] bytes) {
161                            _generatedClasses.put(name, bytes);
162                    }
163    
164            }
165    
166    }