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.portlet.plugininstaller.action;
016    
017    import com.liferay.portal.deploy.DeployUtil;
018    import com.liferay.portal.events.GlobalStartupAction;
019    import com.liferay.portal.kernel.deploy.auto.AutoDeployDir;
020    import com.liferay.portal.kernel.deploy.auto.AutoDeployListener;
021    import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.servlet.SessionErrors;
025    import com.liferay.portal.kernel.servlet.SessionMessages;
026    import com.liferay.portal.kernel.upload.UploadException;
027    import com.liferay.portal.kernel.upload.UploadPortletRequest;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.CharPool;
030    import com.liferay.portal.kernel.util.Constants;
031    import com.liferay.portal.kernel.util.FileUtil;
032    import com.liferay.portal.kernel.util.GetterUtil;
033    import com.liferay.portal.kernel.util.HttpUtil;
034    import com.liferay.portal.kernel.util.ParamUtil;
035    import com.liferay.portal.kernel.util.PropsKeys;
036    import com.liferay.portal.kernel.util.ServerDetector;
037    import com.liferay.portal.kernel.util.StringBundler;
038    import com.liferay.portal.kernel.util.StringPool;
039    import com.liferay.portal.kernel.util.StringUtil;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.plugin.PluginPackageUtil;
042    import com.liferay.portal.plugin.RepositoryReport;
043    import com.liferay.portal.security.auth.PrincipalException;
044    import com.liferay.portal.security.lang.DoPrivilegedBean;
045    import com.liferay.portal.security.permission.PermissionChecker;
046    import com.liferay.portal.struts.PortletAction;
047    import com.liferay.portal.theme.ThemeDisplay;
048    import com.liferay.portal.tools.deploy.BaseDeployer;
049    import com.liferay.portal.upload.ProgressInputStream;
050    import com.liferay.portal.util.HttpImpl;
051    import com.liferay.portal.util.PortalUtil;
052    import com.liferay.portal.util.PrefsPropsUtil;
053    import com.liferay.portal.util.PropsUtil;
054    import com.liferay.portal.util.PropsValues;
055    import com.liferay.portal.util.WebKeys;
056    
057    import java.io.File;
058    import java.io.FileOutputStream;
059    import java.io.IOException;
060    
061    import java.net.MalformedURLException;
062    import java.net.URL;
063    
064    import java.util.List;
065    
066    import javax.portlet.ActionRequest;
067    import javax.portlet.ActionResponse;
068    import javax.portlet.PortletConfig;
069    import javax.portlet.PortletPreferences;
070    
071    import javax.servlet.http.HttpServletResponse;
072    
073    import org.apache.commons.httpclient.HostConfiguration;
074    import org.apache.commons.httpclient.HttpClient;
075    import org.apache.commons.httpclient.methods.GetMethod;
076    import org.apache.struts.action.ActionForm;
077    import org.apache.struts.action.ActionMapping;
078    
079    /**
080     * @author Jorge Ferrer
081     * @author Brian Wing Shun Chan
082     * @author Minhchau Dang
083     */
084    public class InstallPluginAction extends PortletAction {
085    
086            @Override
087            public void processAction(
088                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
089                            ActionRequest actionRequest, ActionResponse actionResponse)
090                    throws Exception {
091    
092                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
093                            WebKeys.THEME_DISPLAY);
094    
095                    PermissionChecker permissionChecker =
096                            themeDisplay.getPermissionChecker();
097    
098                    if (!permissionChecker.isOmniadmin()) {
099                            SessionErrors.add(
100                                    actionRequest, PrincipalException.class.getName());
101    
102                            setForward(actionRequest, "portlet.plugin_installer.error");
103    
104                            return;
105                    }
106    
107                    String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
108    
109                    if (cmd.equals("deployConfiguration")) {
110                            deployConfiguration(actionRequest);
111                    }
112                    else if (cmd.equals("ignorePackages")) {
113                            ignorePackages(actionRequest);
114                    }
115                    else if (cmd.equals("localDeploy")) {
116                            localDeploy(actionRequest);
117                    }
118                    else if (cmd.equals("reloadRepositories")) {
119                            reloadRepositories(actionRequest);
120                    }
121                    else if (cmd.equals("remoteDeploy")) {
122                            remoteDeploy(actionRequest);
123                    }
124                    else if (cmd.equals("unignorePackages")) {
125                            unignorePackages(actionRequest);
126                    }
127                    else if (cmd.equals("uninstall")) {
128                            uninstall(actionRequest);
129                    }
130    
131                    sendRedirect(actionRequest, actionResponse);
132            }
133    
134            protected void deployConfiguration(ActionRequest actionRequest)
135                    throws Exception {
136    
137                    boolean enabled = ParamUtil.getBoolean(actionRequest, "enabled");
138                    String deployDir = ParamUtil.getString(actionRequest, "deployDir");
139                    String destDir = ParamUtil.getString(actionRequest, "destDir");
140                    long interval = ParamUtil.getLong(actionRequest, "interval");
141                    boolean unpackWar = ParamUtil.getBoolean(actionRequest, "unpackWar");
142                    boolean customPortletXml = ParamUtil.getBoolean(
143                            actionRequest, "customPortletXml");
144                    String jbossPrefix = ParamUtil.getString(actionRequest, "jbossPrefix");
145                    String tomcatConfDir = ParamUtil.getString(
146                            actionRequest, "tomcatConfDir");
147                    String tomcatLibDir = ParamUtil.getString(
148                            actionRequest, "tomcatLibDir");
149                    String pluginRepositoriesTrusted = ParamUtil.getString(
150                            actionRequest, "pluginRepositoriesTrusted");
151                    String pluginRepositoriesUntrusted = ParamUtil.getString(
152                            actionRequest, "pluginRepositoriesUntrusted");
153                    boolean pluginNotificationsEnabled = ParamUtil.getBoolean(
154                            actionRequest, "pluginNotificationsEnabled");
155                    String pluginPackagesIgnored = ParamUtil.getString(
156                            actionRequest, "pluginPackagesIgnored");
157    
158                    PortletPreferences preferences = PrefsPropsUtil.getPreferences();
159    
160                    preferences.setValue(
161                            PropsKeys.AUTO_DEPLOY_ENABLED, String.valueOf(enabled));
162                    preferences.setValue(PropsKeys.AUTO_DEPLOY_DEPLOY_DIR, deployDir);
163                    preferences.setValue(PropsKeys.AUTO_DEPLOY_DEST_DIR, destDir);
164                    preferences.setValue(
165                            PropsKeys.AUTO_DEPLOY_INTERVAL, String.valueOf(interval));
166                    preferences.setValue(
167                            PropsKeys.AUTO_DEPLOY_UNPACK_WAR, String.valueOf(unpackWar));
168                    preferences.setValue(
169                            PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
170                            String.valueOf(customPortletXml));
171                    preferences.setValue(PropsKeys.AUTO_DEPLOY_JBOSS_PREFIX, jbossPrefix);
172                    preferences.setValue(
173                            PropsKeys.AUTO_DEPLOY_TOMCAT_CONF_DIR, tomcatConfDir);
174                    preferences.setValue(
175                            PropsKeys.AUTO_DEPLOY_TOMCAT_LIB_DIR, tomcatLibDir);
176                    preferences.setValue(
177                            PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, pluginRepositoriesTrusted);
178                    preferences.setValue(
179                            PropsKeys.PLUGIN_REPOSITORIES_UNTRUSTED,
180                            pluginRepositoriesUntrusted);
181                    preferences.setValue(
182                            PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
183                            String.valueOf(pluginNotificationsEnabled));
184                    preferences.setValue(
185                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
186                            pluginPackagesIgnored);
187    
188                    preferences.store();
189    
190                    reloadRepositories(actionRequest);
191    
192                    if (_log.isInfoEnabled()) {
193                            _log.info("Unregistering auto deploy directories");
194                    }
195    
196                    AutoDeployUtil.unregisterDir("defaultAutoDeployDir");
197    
198                    if (enabled) {
199                            if (_log.isInfoEnabled()) {
200                                    _log.info("Registering auto deploy directories");
201                            }
202    
203                            List<AutoDeployListener> autoDeployListeners =
204                                    GlobalStartupAction.getAutoDeployListeners();
205    
206                            AutoDeployDir autoDeployDir = new AutoDeployDir(
207                                    "defaultAutoDeployDir", new File(deployDir), new File(destDir),
208                                    interval, autoDeployListeners);
209    
210                            AutoDeployUtil.registerDir(autoDeployDir);
211                    }
212                    else {
213                            if (_log.isInfoEnabled()) {
214                                    _log.info("Not registering auto deploy directories");
215                            }
216                    }
217            }
218    
219            protected String[] getSourceForgeMirrors() {
220                    return PropsUtil.getArray(PropsKeys.SOURCE_FORGE_MIRRORS);
221            }
222    
223            protected void ignorePackages(ActionRequest actionRequest)
224                    throws Exception {
225    
226                    String pluginPackagesIgnored = ParamUtil.getString(
227                            actionRequest, "pluginPackagesIgnored");
228    
229                    String oldPluginPackagesIgnored = PrefsPropsUtil.getString(
230                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
231    
232                    PortletPreferences preferences = PrefsPropsUtil.getPreferences();
233    
234                    if (Validator.isNotNull(oldPluginPackagesIgnored)) {
235                            preferences.setValue(
236                                    PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
237                                    oldPluginPackagesIgnored.concat(StringPool.NEW_LINE).concat(
238                                            pluginPackagesIgnored));
239                    }
240                    else {
241                            preferences.setValue(
242                                    PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
243                                    pluginPackagesIgnored);
244                    }
245    
246                    preferences.store();
247    
248                    PluginPackageUtil.refreshUpdatesAvailableCache();
249            }
250    
251            protected void localDeploy(ActionRequest actionRequest) throws Exception {
252                    UploadPortletRequest uploadPortletRequest =
253                            PortalUtil.getUploadPortletRequest(actionRequest);
254    
255                    String fileName = null;
256    
257                    String deploymentContext = ParamUtil.getString(
258                            actionRequest, "deploymentContext");
259    
260                    if (Validator.isNotNull(deploymentContext)) {
261                            fileName =
262                                    BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
263                    }
264                    else {
265                            fileName = GetterUtil.getString(
266                                    uploadPortletRequest.getFileName("file"));
267    
268                            int pos = fileName.lastIndexOf(CharPool.PERIOD);
269    
270                            if (pos != -1) {
271                                    deploymentContext = fileName.substring(0, pos);
272                            }
273                    }
274    
275                    File file = uploadPortletRequest.getFile("file");
276    
277                    byte[] bytes = FileUtil.getBytes(file);
278    
279                    if ((bytes == null) || (bytes.length == 0)) {
280                            SessionErrors.add(actionRequest, UploadException.class.getName());
281    
282                            return;
283                    }
284    
285                    try {
286                            PluginPackageUtil.registerPluginPackageInstallation(
287                                    deploymentContext);
288    
289                            String source = file.toString();
290    
291                            String deployDir = PrefsPropsUtil.getString(
292                                    PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
293                                    PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
294    
295                            String destination = deployDir + StringPool.SLASH + fileName;
296    
297                            FileUtil.copyFile(source, destination);
298    
299                            SessionMessages.add(actionRequest, "pluginUploaded");
300                    }
301                    finally {
302                            PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
303                    }
304            }
305    
306            protected void reloadRepositories(ActionRequest actionRequest)
307                    throws Exception {
308    
309                    RepositoryReport repositoryReport =
310                            PluginPackageUtil.reloadRepositories();
311    
312                    SessionMessages.add(
313                            actionRequest, WebKeys.PLUGIN_REPOSITORY_REPORT, repositoryReport);
314            }
315    
316            protected void remoteDeploy(ActionRequest actionRequest) throws Exception {
317                    try {
318                            String url = ParamUtil.getString(actionRequest, "url");
319    
320                            URL urlObj = new URL(url);
321    
322                            String host = urlObj.getHost();
323    
324                            if (host.endsWith(".sf.net") || host.endsWith(".sourceforge.net")) {
325                                    remoteDeploySourceForge(urlObj.getPath(), actionRequest);
326                            }
327                            else {
328                                    remoteDeploy(url, urlObj, actionRequest, true);
329                            }
330                    }
331                    catch (MalformedURLException murle) {
332                            SessionErrors.add(actionRequest, "invalidUrl", murle);
333                    }
334            }
335    
336            protected int remoteDeploy(
337                            String url, URL urlObj, ActionRequest actionRequest,
338                            boolean failOnError)
339                    throws Exception {
340    
341                    int responseCode = HttpServletResponse.SC_OK;
342    
343                    GetMethod getMethod = null;
344    
345                    String deploymentContext = ParamUtil.getString(
346                            actionRequest, "deploymentContext");
347    
348                    try {
349                            HttpImpl httpImpl = null;
350    
351                            Object httpObject = HttpUtil.getHttp();
352    
353                            if (httpObject instanceof DoPrivilegedBean) {
354                                    DoPrivilegedBean doPrivilegedBean =
355                                            (DoPrivilegedBean)httpObject;
356    
357                                    httpImpl = (HttpImpl)doPrivilegedBean.getActualBean();
358                            }
359                            else {
360                                    httpImpl = (HttpImpl)httpObject;
361                            }
362    
363                            HostConfiguration hostConfiguration = httpImpl.getHostConfiguration(
364                                    url);
365    
366                            HttpClient httpClient = httpImpl.getClient(hostConfiguration);
367    
368                            getMethod = new GetMethod(url);
369    
370                            String fileName = null;
371    
372                            if (Validator.isNotNull(deploymentContext)) {
373                                    fileName =
374                                            BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
375                            }
376                            else {
377                                    fileName = url.substring(url.lastIndexOf(CharPool.SLASH) + 1);
378    
379                                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
380    
381                                    if (pos != -1) {
382                                            deploymentContext = fileName.substring(0, pos);
383                                    }
384                            }
385    
386                            PluginPackageUtil.registerPluginPackageInstallation(
387                                    deploymentContext);
388    
389                            responseCode = httpClient.executeMethod(
390                                    hostConfiguration, getMethod);
391    
392                            if (responseCode != HttpServletResponse.SC_OK) {
393                                    if (failOnError) {
394                                            SessionErrors.add(
395                                                    actionRequest, "errorConnectingToUrl",
396                                                    new Object[] {String.valueOf(responseCode)});
397                                    }
398    
399                                    return responseCode;
400                            }
401    
402                            long contentLength = getMethod.getResponseContentLength();
403    
404                            String progressId = ParamUtil.getString(
405                                    actionRequest, Constants.PROGRESS_ID);
406    
407                            ProgressInputStream pis = new ProgressInputStream(
408                                    actionRequest, getMethod.getResponseBodyAsStream(),
409                                    contentLength, progressId);
410    
411                            String deployDir = PrefsPropsUtil.getString(
412                                    PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
413                                    PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
414    
415                            String tmpFilePath =
416                                    deployDir + StringPool.SLASH + _DOWNLOAD_DIR +
417                                            StringPool.SLASH + fileName;
418    
419                            File tmpFile = new File(tmpFilePath);
420    
421                            if (!tmpFile.getParentFile().exists()) {
422                                    tmpFile.getParentFile().mkdirs();
423                            }
424    
425                            FileOutputStream fos = new FileOutputStream(tmpFile);
426    
427                            try {
428                                    pis.readAll(fos);
429    
430                                    if (_log.isInfoEnabled()) {
431                                            _log.info(
432                                                    "Downloaded plugin from " + urlObj + " has " +
433                                                            pis.getTotalRead() + " bytes");
434                                    }
435                            }
436                            finally {
437                                    pis.clearProgress();
438                            }
439    
440                            getMethod.releaseConnection();
441    
442                            if (pis.getTotalRead() > 0) {
443                                    String destination = deployDir + StringPool.SLASH + fileName;
444    
445                                    File destinationFile = new File(destination);
446    
447                                    boolean moved = FileUtil.move(tmpFile, destinationFile);
448    
449                                    if (!moved) {
450                                            FileUtil.copyFile(tmpFile, destinationFile);
451                                            FileUtil.delete(tmpFile);
452                                    }
453    
454                                    SessionMessages.add(actionRequest, "pluginDownloaded");
455                            }
456                            else {
457                                    if (failOnError) {
458                                            SessionErrors.add(
459                                                    actionRequest, UploadException.class.getName());
460                                    }
461    
462                                    responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
463                            }
464                    }
465                    catch (MalformedURLException murle) {
466                            SessionErrors.add(actionRequest, "invalidUrl", murle);
467                    }
468                    catch (IOException ioe) {
469                            SessionErrors.add(actionRequest, "errorConnectingToUrl", ioe);
470                    }
471                    finally {
472                            if (getMethod != null) {
473                                    getMethod.releaseConnection();
474                            }
475    
476                            PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
477                    }
478    
479                    return responseCode;
480            }
481    
482            protected void remoteDeploySourceForge(
483                            String path, ActionRequest actionRequest)
484                    throws Exception {
485    
486                    String[] sourceForgeMirrors = getSourceForgeMirrors();
487    
488                    for (int i = 0; i < sourceForgeMirrors.length; i++) {
489                            try {
490                                    String url = sourceForgeMirrors[i] + path;
491    
492                                    if (_log.isDebugEnabled()) {
493                                            _log.debug("Downloading from SourceForge mirror " + url);
494                                    }
495    
496                                    URL urlObj = new URL(url);
497    
498                                    boolean failOnError = false;
499    
500                                    if ((i + 1) == sourceForgeMirrors.length) {
501                                            failOnError = true;
502                                    }
503    
504                                    int responseCode = remoteDeploy(
505                                            url, urlObj, actionRequest, failOnError);
506    
507                                    if (responseCode == HttpServletResponse.SC_OK) {
508                                            return;
509                                    }
510                            }
511                            catch (MalformedURLException murle) {
512                                    SessionErrors.add(actionRequest, "invalidUrl", murle);
513                            }
514                    }
515            }
516    
517            protected void unignorePackages(ActionRequest actionRequest)
518                    throws Exception {
519    
520                    String[] pluginPackagesUnignored = StringUtil.splitLines(
521                            ParamUtil.getString(actionRequest, "pluginPackagesUnignored"));
522    
523                    String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
524                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
525                            StringPool.NEW_LINE,
526                            PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
527    
528                    StringBundler sb = new StringBundler();
529    
530                    for (int i = 0; i < pluginPackagesIgnored.length; i++) {
531                            String packageId = pluginPackagesIgnored[i];
532    
533                            if (!ArrayUtil.contains(pluginPackagesUnignored, packageId)) {
534                                    sb.append(packageId);
535                                    sb.append(StringPool.NEW_LINE);
536                            }
537                    }
538    
539                    PortletPreferences preferences = PrefsPropsUtil.getPreferences();
540    
541                    preferences.setValue(
542                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED, sb.toString());
543    
544                    preferences.store();
545    
546                    PluginPackageUtil.refreshUpdatesAvailableCache();
547            }
548    
549            protected void uninstall(ActionRequest actionRequest) throws Exception {
550                    String appServerType = ServerDetector.getServerId();
551    
552                    String deploymentContext = ParamUtil.getString(
553                            actionRequest, "deploymentContext");
554    
555                    File deployDir = new File(
556                            DeployUtil.getAutoDeployDestDir(), deploymentContext);
557    
558                    DeployUtil.undeploy(appServerType, deployDir);
559    
560                    SessionMessages.add(actionRequest, "triggeredPortletUndeploy");
561            }
562    
563            private static final String _DOWNLOAD_DIR = "download";
564    
565            private static Log _log = LogFactoryUtil.getLog(InstallPluginAction.class);
566    
567    }