001    /**
002     * Copyright (c) 2000-present 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 URLWeavingAdapter extends WeavingAdaptor {
041    
042            public URLWeavingAdapter(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(inputStream, unsyncByteArrayOutputStream);
130    
131                                    byte[] classData =
132                                            unsyncByteArrayOutputStream.unsafeGetByteArray();
133    
134                                    byteArrayInputStream = new ByteArrayInputStream(
135                                            classData, 0, unsyncByteArrayOutputStream.size());
136                            }
137                            catch (IOException ioe) {
138                                    throw new RuntimeException("Unable to reload class data", ioe);
139                            }
140                    }
141    
142                    ClassParser classParser = new ClassParser(
143                            byteArrayInputStream, aspectClass.getSimpleName() + ".class");
144    
145                    try {
146                            return classParser.parse();
147                    }
148                    catch (Exception e) {
149                            throw new RuntimeException("Unable to parse class data", e);
150                    }
151            }
152    
153            private final Map<String, byte[]> _generatedClasses = new HashMap<>();
154    
155            private class RecordGeneratedClassHandler implements GeneratedClassHandler {
156    
157                    @Override
158                    public void acceptClass(
159                            String name, byte[] originalBytes, byte[] weavedBytes) {
160    
161                            _generatedClasses.put(name, weavedBytes);
162                    }
163    
164            }
165    
166    }