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