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