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.util;
016    
017    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterRequest;
019    import com.liferay.portal.kernel.cluster.FutureClusterResponses;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.FileUtil;
023    import com.liferay.portal.kernel.util.HttpUtil;
024    import com.liferay.portal.kernel.util.MethodHandler;
025    import com.liferay.portal.kernel.util.MethodKey;
026    import com.liferay.portal.kernel.util.ProgressStatusConstants;
027    import com.liferay.portal.kernel.util.ProgressTracker;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.model.CompanyConstants;
030    import com.liferay.portal.spring.context.PortalContextLoaderLifecycleThreadLocal;
031    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
032    
033    import java.io.File;
034    import java.io.InputStream;
035    
036    import java.lang.reflect.Method;
037    
038    import java.net.URI;
039    import java.net.URL;
040    import java.net.URLClassLoader;
041    
042    import java.util.concurrent.TimeUnit;
043    
044    /**
045     * @author Alexander Chow
046     */
047    public class JarUtil {
048    
049            public static void downloadAndInstallJar(
050                            boolean globalClassPath, String url, String name,
051                            ProgressTracker progressTracker)
052                    throws Exception {
053    
054                    setProgressStatus(progressTracker, ProgressStatusConstants.DOWNLOADING);
055    
056                    if (_log.isInfoEnabled()) {
057                            _log.info("Downloading " + url);
058                    }
059    
060                    byte[] bytes = HttpUtil.URLtoByteArray(url);
061    
062                    setProgressStatus(progressTracker, ProgressStatusConstants.COPYING);
063    
064                    if (PropsValues.CLUSTER_LINK_ENABLED &&
065                            !PortalContextLoaderLifecycleThreadLocal.isInitializing()) {
066    
067                            try {
068                                    DLStoreUtil.deleteFile(
069                                            _REPOSITORY, _REPOSITORY, _FILE_PATH + name);
070                            }
071                            catch (Exception e) {
072                            }
073    
074                            DLStoreUtil.addFile(
075                                    _REPOSITORY, _REPOSITORY, _FILE_PATH + name, bytes);
076    
077                            try {
078                                    ClusterRequest clusterRequest =
079                                            ClusterRequest.createMulticastRequest(
080                                                    new MethodHandler(
081                                                            _installJarKey, globalClassPath, name));
082    
083                                    FutureClusterResponses futureClusterResponses =
084                                            ClusterExecutorUtil.execute(clusterRequest);
085    
086                                    futureClusterResponses.get(30, TimeUnit.SECONDS);
087                            }
088                            finally {
089                                    try {
090                                            DLStoreUtil.deleteFile(
091                                                    _REPOSITORY, _REPOSITORY, _FILE_PATH + name);
092                                    }
093                                    catch (Exception e) {
094                                    }
095                            }
096                    }
097                    else {
098                            setProgressStatus(progressTracker, ProgressStatusConstants.COPYING);
099    
100                            installJar(bytes, globalClassPath, name);
101                    }
102            }
103    
104            public static void installJar(boolean globalClassPath, String name)
105                    throws Exception {
106    
107                    installJar(null, globalClassPath, name);
108            }
109    
110            protected static void addJarFileToClassLoader(File file) throws Exception {
111                    Class<?> clazz = URLClassLoader.class;
112    
113                    Method method = clazz.getDeclaredMethod(
114                            "addURL", new Class<?>[] {URL.class});
115    
116                    method.setAccessible(true);
117    
118                    URI uri = file.toURI();
119    
120                    Object[] arguments = new Object[] {uri.toURL()};
121    
122                    method.invoke(ClassLoader.getSystemClassLoader(), arguments);
123    
124                    Thread currentThread = Thread.currentThread();
125    
126                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
127    
128                    if (contextClassLoader instanceof URLClassLoader) {
129                            method.invoke(contextClassLoader, arguments);
130                    }
131            }
132    
133            protected static void installJar(
134                            byte[] bytes, boolean globalClassPath, String name)
135                    throws Exception {
136    
137                    String libPath = PropsValues.LIFERAY_LIB_PORTAL_DIR;
138    
139                    if (globalClassPath) {
140                            libPath = PropsValues.LIFERAY_LIB_GLOBAL_DIR;
141                    }
142    
143                    File file = new File(libPath + StringPool.SLASH + name);
144    
145                    InputStream is = null;
146    
147                    try {
148                            if (_log.isInfoEnabled()) {
149                                    _log.info("Writing " + file);
150                            }
151    
152                            if (bytes != null) {
153                                    FileUtil.write(file, bytes);
154                            }
155                            else {
156                                    is = DLStoreUtil.getFileAsStream(
157                                            _REPOSITORY, _REPOSITORY, _FILE_PATH + name);
158    
159                                    FileUtil.write(file, is);
160                            }
161                    }
162                    finally {
163                            if (is != null) {
164                                    is.close();
165                            }
166                    }
167    
168                    addJarFileToClassLoader(file);
169            }
170    
171            protected static void setProgressStatus(
172                    ProgressTracker progressTracker, int status) {
173    
174                    if (progressTracker == null) {
175                            return;
176                    }
177    
178                    progressTracker.setStatus(status);
179            }
180    
181            private static final String _FILE_PATH = "jar_temp/";
182    
183            private static final long _REPOSITORY = CompanyConstants.SYSTEM;
184    
185            private static final Log _log = LogFactoryUtil.getLog(JarUtil.class);
186    
187            private static final MethodKey _installJarKey = new MethodKey(
188                    JarUtil.class, "installJar", boolean.class, String.class);
189    
190    }