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.deploy.hot;
016    
017    import aQute.bnd.annotation.ProviderType;
018    
019    import com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener;
020    import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
021    import com.liferay.portal.kernel.deploy.hot.HotDeployException;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.servlet.WebDirDetector;
025    import com.liferay.portal.kernel.util.FileUtil;
026    import com.liferay.portal.kernel.util.HttpUtil;
027    import com.liferay.portal.kernel.util.PortalUtil;
028    import com.liferay.portal.kernel.util.StreamUtil;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.SystemProperties;
032    import com.liferay.portal.tools.WebXMLBuilder;
033    import com.liferay.portal.util.ExtRegistry;
034    import com.liferay.taglib.FileAvailabilityUtil;
035    import com.liferay.util.ant.CopyTask;
036    
037    import java.io.File;
038    import java.io.FileOutputStream;
039    import java.io.IOException;
040    import java.io.InputStream;
041    
042    import java.nio.file.Files;
043    import java.nio.file.Path;
044    import java.nio.file.Paths;
045    
046    import java.util.Map;
047    import java.util.Set;
048    
049    import javax.servlet.ServletContext;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     */
054    @ProviderType
055    public class ExtHotDeployListener extends BaseHotDeployListener {
056    
057            @Override
058            public void invokeDeploy(HotDeployEvent hotDeployEvent)
059                    throws HotDeployException {
060    
061                    try {
062                            doInvokeDeploy(hotDeployEvent);
063                    }
064                    catch (Throwable t) {
065                            throwHotDeployException(
066                                    hotDeployEvent, "Error registering extension environment for ",
067                                    t);
068                    }
069            }
070    
071            @Override
072            public void invokeUndeploy(HotDeployEvent hotDeployEvent)
073                    throws HotDeployException {
074    
075                    try {
076                            doInvokeUndeploy(hotDeployEvent);
077                    }
078                    catch (Throwable t) {
079                            throwHotDeployException(
080                                    hotDeployEvent,
081                                    "Error unregistering extension environment for ", t);
082                    }
083            }
084    
085            protected void copyJar(
086                            ServletContext servletContext, String dir, String jarName)
087                    throws Exception {
088    
089                    String servletContextName = servletContext.getServletContextName();
090    
091                    String jarFullName = "/WEB-INF/" + jarName + "/" + jarName + ".jar";
092    
093                    InputStream is = servletContext.getResourceAsStream(jarFullName);
094    
095                    if (is == null) {
096                            throw new HotDeployException(jarFullName + " does not exist");
097                    }
098    
099                    String newJarFullName =
100                            dir + "ext-" + servletContextName + jarName.substring(3) + ".jar";
101    
102                    StreamUtil.transfer(is, new FileOutputStream(new File(newJarFullName)));
103            }
104    
105            protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
106                    throws Exception {
107    
108                    ServletContext servletContext = hotDeployEvent.getServletContext();
109    
110                    String servletContextName = servletContext.getServletContextName();
111    
112                    if (_log.isDebugEnabled()) {
113                            _log.debug("Invoking deploy for " + servletContextName);
114                    }
115    
116                    String xml = HttpUtil.URLtoString(
117                            servletContext.getResource(
118                                    "/WEB-INF/ext-" + servletContextName + ".xml"));
119    
120                    if (xml == null) {
121                            return;
122                    }
123    
124                    if (_log.isInfoEnabled()) {
125                            _log.info(
126                                    "Registering extension environment for " + servletContextName);
127                    }
128    
129                    if (ExtRegistry.isRegistered(servletContextName)) {
130                            if (_log.isInfoEnabled()) {
131                                    _log.info(
132                                            "Extension environment for " + servletContextName +
133                                                    " has been applied.");
134                            }
135    
136                            return;
137                    }
138    
139                    Map<String, Set<String>> conflicts = ExtRegistry.getConflicts(
140                            servletContext);
141    
142                    if (!conflicts.isEmpty()) {
143                            StringBundler sb = new StringBundler();
144    
145                            sb.append("Extension environment for ");
146                            sb.append(servletContextName);
147                            sb.append(" cannot be applied because of detected conflicts:");
148    
149                            for (Map.Entry<String, Set<String>> entry : conflicts.entrySet()) {
150                                    String conflictServletContextName = entry.getKey();
151                                    Set<String> conflictFiles = entry.getValue();
152    
153                                    sb.append("\n\t");
154                                    sb.append(conflictServletContextName);
155                                    sb.append(":");
156    
157                                    for (String conflictFile : conflictFiles) {
158                                            sb.append("\n\t\t");
159                                            sb.append(conflictFile);
160                                    }
161                            }
162    
163                            _log.error(sb.toString());
164    
165                            return;
166                    }
167    
168                    installExt(servletContext, hotDeployEvent.getContextClassLoader());
169    
170                    FileAvailabilityUtil.clearAvailabilities();
171    
172                    if (_log.isInfoEnabled()) {
173                            _log.info(
174                                    "Extension environment for " + servletContextName +
175                                            " has been applied. You must reboot the server and " +
176                                                    "redeploy all other plugins.");
177                    }
178            }
179    
180            protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
181                    throws Exception {
182    
183                    ServletContext servletContext = hotDeployEvent.getServletContext();
184    
185                    String servletContextName = servletContext.getServletContextName();
186    
187                    if (_log.isDebugEnabled()) {
188                            _log.debug("Invoking undeploy for " + servletContextName);
189                    }
190    
191                    String xml = HttpUtil.URLtoString(
192                            servletContext.getResource(
193                                    "/WEB-INF/ext-" + servletContextName + ".xml"));
194    
195                    if (xml == null) {
196                            return;
197                    }
198    
199                    if (_log.isInfoEnabled()) {
200                            _log.info(
201                                    "Extension environment for " + servletContextName +
202                                            " will not be undeployed");
203                    }
204            }
205    
206            @Deprecated
207            protected void installExt(ServletContext servletContext) throws Exception {
208                    installExt(servletContext, servletContext.getClassLoader());
209            }
210    
211            protected void installExt(
212                            ServletContext servletContext, ClassLoader portletClassLoader)
213                    throws Exception {
214    
215                    String servletContextName = servletContext.getServletContextName();
216    
217                    String globalLibDir = PortalUtil.getGlobalLibDir();
218                    String portalWebDir = PortalUtil.getPortalWebDir();
219                    String portalLibDir = PortalUtil.getPortalLibDir();
220                    String pluginWebDir = WebDirDetector.getRootDir(portletClassLoader);
221    
222                    copyJar(servletContext, globalLibDir, "ext-service");
223                    copyJar(servletContext, portalLibDir, "ext-impl");
224                    copyJar(servletContext, portalLibDir, "ext-util-bridges");
225                    copyJar(servletContext, portalLibDir, "ext-util-java");
226                    copyJar(servletContext, portalLibDir, "ext-util-taglib");
227    
228                    mergeWebXml(portalWebDir, pluginWebDir);
229    
230                    CopyTask.copyDirectory(
231                            pluginWebDir + "WEB-INF/ext-web/docroot", portalWebDir,
232                            StringPool.BLANK, "**/WEB-INF/web.xml", true, false);
233    
234                    FileUtil.copyFile(
235                            pluginWebDir + "WEB-INF/ext-" + servletContextName + ".xml",
236                            portalWebDir + "WEB-INF/ext-" + servletContextName + ".xml");
237    
238                    ExtRegistry.registerExt(servletContext);
239            }
240    
241            protected void mergeWebXml(String portalWebDir, String pluginWebDir)
242                    throws IOException {
243    
244                    if (!FileUtil.exists(
245                                    pluginWebDir + "WEB-INF/ext-web/docroot/WEB-INF/web.xml")) {
246    
247                            return;
248                    }
249    
250                    Path tempDirPath = Files.createTempDirectory(
251                            Paths.get(SystemProperties.get(SystemProperties.TMP_DIR)), null);
252    
253                    File tempDir = tempDirPath.toFile();
254    
255                    WebXMLBuilder.main(
256                            new String[] {
257                                    portalWebDir + "WEB-INF/web.xml",
258                                    pluginWebDir + "WEB-INF/ext-web/docroot/WEB-INF/web.xml",
259                                    tempDir.getAbsolutePath() + "/web.xml"
260                            });
261    
262                    File portalWebXml = new File(portalWebDir + "WEB-INF/web.xml");
263                    File tmpWebXml = new File(tempDir + "/web.xml");
264    
265                    tmpWebXml.setLastModified(portalWebXml.lastModified());
266    
267                    CopyTask.copyFile(
268                            tmpWebXml, new File(portalWebDir + "WEB-INF"), true, true);
269    
270                    FileUtil.deltree(tempDir);
271            }
272    
273            private static final Log _log = LogFactoryUtil.getLog(
274                    ExtHotDeployListener.class);
275    
276    }