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.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.StreamUtil;
021    
022    import java.io.File;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    
027    import java.net.URL;
028    import java.net.URLClassLoader;
029    
030    import java.security.ProtectionDomain;
031    
032    import java.util.Arrays;
033    
034    import org.aspectj.bridge.AbortException;
035    
036    /**
037     * @author Shuyang Zhou
038     */
039    public class WeavingClassLoader extends URLClassLoader {
040    
041            public WeavingClassLoader(
042                    URL[] urls, Class<?>[] aspectClasses, File dumpDir) {
043    
044                    super(urls, null);
045    
046                    _dumpDir = dumpDir;
047    
048                    _urlWeavingAdaptor = new URLWeavingAdaptor(urls, aspectClasses);
049            }
050    
051            @Override
052            protected Class<?> findClass(String name) throws ClassNotFoundException {
053                    String resourcePath = name.replace('.', '/') + ".class";
054    
055                    InputStream inputStream = getResourceAsStream(resourcePath);
056    
057                    byte[] data = null;
058    
059                    try {
060                            if (inputStream == null) {
061    
062                                    // It may be a generated inner class
063    
064                                    data = _urlWeavingAdaptor.removeGeneratedClassDate(name);
065                            }
066                            else {
067                                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
068                                            new UnsyncByteArrayOutputStream();
069    
070                                    StreamUtil.transfer(
071                                            inputStream, unsyncByteArrayOutputStream, true);
072    
073                                    data = unsyncByteArrayOutputStream.toByteArray();
074                            }
075    
076                            if (data == null) {
077                                    throw new ClassNotFoundException(name);
078                            }
079    
080                            byte[] oldData = data;
081    
082                            try {
083                                    data = _urlWeavingAdaptor.weaveClass(name, data, false);
084                            }
085                            catch (AbortException ae) {
086                                    if (_log.isWarnEnabled()) {
087                                            _log.warn("Abort weaving class " + name, ae);
088                                    }
089                            }
090    
091                            if (Arrays.equals(oldData, data)) {
092                                    return _generateClass(name, data);
093                            }
094    
095                            if (_dumpDir != null) {
096                                    File dumpFile = new File(_dumpDir, resourcePath);
097    
098                                    File dumpDir = dumpFile.getParentFile();
099    
100                                    dumpDir.mkdirs();
101    
102                                    FileOutputStream fileOutputStream = new FileOutputStream(
103                                            dumpFile);
104    
105                                    fileOutputStream.write(data);
106    
107                                    fileOutputStream.close();
108    
109                                    if (_log.isInfoEnabled()) {
110                                            _log.info(
111                                                    "Woven class " + name + " result in " +
112                                                            dumpFile.getCanonicalPath());
113                                    }
114                            }
115                            else {
116                                    if (_log.isInfoEnabled()) {
117                                            _log.info("Woven class " + name);
118                                    }
119                            }
120    
121                            return _generateClass(name, data);
122                    }
123                    catch (IOException ioe) {
124                            throw new ClassNotFoundException(name, ioe);
125                    }
126            }
127    
128            private Class<?> _generateClass(String name, byte[] data) {
129                    Class<?> clazz = defineClass(
130                            name, data, 0, data.length, (ProtectionDomain)null);
131    
132                    String packageName = null;
133    
134                    int index = name.lastIndexOf('.');
135    
136                    if (index != -1) {
137                            packageName = name.substring(0, index);
138                    }
139    
140                    if (packageName != null) {
141                            Package pkg = getPackage(packageName);
142    
143                            if (pkg == null) {
144                                    definePackage(
145                                            packageName, null, null, null, null, null, null, null);
146                            }
147                    }
148    
149                    return clazz;
150            }
151    
152            private static Log _log = LogFactoryUtil.getLog(WeavingClassLoader.class);
153    
154            private File _dumpDir;
155            private URLWeavingAdaptor _urlWeavingAdaptor;
156    
157    }