001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                    preferences.setValue(
238                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
239                            oldPluginPackagesIgnored.concat(StringPool.NEW_LINE).concat(
240                                    pluginPackagesIgnored));
241    
242                    preferences.store();
243    
244                    PluginPackageUtil.refreshUpdatesAvailableCache();
245            }
246    
247            protected void localDeploy(ActionRequest actionRequest) throws Exception {
248                    UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
249                            actionRequest);
250    
251                    String fileName = null;
252    
253                    String deploymentContext = ParamUtil.getString(
254                            actionRequest, "deploymentContext");
255    
256                    if (Validator.isNotNull(deploymentContext)) {
257                            fileName =
258                                    BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
259                    }
260                    else {
261                            fileName = GetterUtil.getString(uploadRequest.getFileName("file"));
262    
263                            int pos = fileName.lastIndexOf(CharPool.PERIOD);
264    
265                            if (pos != -1) {
266                                    deploymentContext = fileName.substring(0, pos);
267                            }
268                    }
269    
270                    File file = uploadRequest.getFile("file");
271    
272                    byte[] bytes = FileUtil.getBytes(file);
273    
274                    if ((bytes == null) || (bytes.length == 0)) {
275                            SessionErrors.add(actionRequest, UploadException.class.getName());
276    
277                            return;
278                    }
279    
280                    try {
281                            PluginPackageUtil.registerPluginPackageInstallation(
282                                    deploymentContext);
283    
284                            String source = file.toString();
285    
286                            String deployDir = PrefsPropsUtil.getString(
287                                    PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
288                                    PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
289    
290                            String destination = deployDir + StringPool.SLASH + fileName;
291    
292                            FileUtil.copyFile(source, destination);
293    
294                            SessionMessages.add(actionRequest, "pluginUploaded");
295                    }
296                    finally {
297                            PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
298                    }
299            }
300    
301            protected void reloadRepositories(ActionRequest actionRequest)
302                    throws Exception {
303    
304                    RepositoryReport repositoryReport =
305                            PluginPackageUtil.reloadRepositories();
306    
307                    SessionMessages.add(
308                            actionRequest, WebKeys.PLUGIN_REPOSITORY_REPORT, repositoryReport);
309            }
310    
311            protected void remoteDeploy(ActionRequest actionRequest) throws Exception {
312                    try {
313                            String url = ParamUtil.getString(actionRequest, "url");
314    
315                            URL urlObj = new URL(url);
316    
317                            String host = urlObj.getHost();
318    
319                            if (host.endsWith(".sf.net") || host.endsWith(".sourceforge.net")) {
320                                    remoteDeploySourceForge(urlObj.getPath(), actionRequest);
321                            }
322                            else {
323                                    remoteDeploy(url, urlObj, actionRequest, true);
324                            }
325                    }
326                    catch (MalformedURLException murle) {
327                            SessionErrors.add(actionRequest, "invalidUrl", murle);
328                    }
329            }
330    
331            protected int remoteDeploy(
332                            String url, URL urlObj, ActionRequest actionRequest,
333                            boolean failOnError)
334                    throws Exception {
335    
336                    int responseCode = HttpServletResponse.SC_OK;
337    
338                    GetMethod getMethod = null;
339    
340                    String deploymentContext = ParamUtil.getString(
341                            actionRequest, "deploymentContext");
342    
343                    try {
344                            HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
345    
346                            HostConfiguration hostConfig = httpImpl.getHostConfig(url);
347    
348                            HttpClient client = httpImpl.getClient(hostConfig);
349    
350                            getMethod = new GetMethod(url);
351    
352                            String fileName = null;
353    
354                            if (Validator.isNotNull(deploymentContext)) {
355                                    fileName =
356                                            BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
357                            }
358                            else {
359                                    fileName = url.substring(url.lastIndexOf(CharPool.SLASH) + 1);
360    
361                                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
362    
363                                    if (pos != -1) {
364                                            deploymentContext = fileName.substring(0, pos);
365                                    }
366                            }
367    
368                            PluginPackageUtil.registerPluginPackageInstallation(
369                                    deploymentContext);
370    
371                            responseCode = client.executeMethod(hostConfig, getMethod);
372    
373                            if (responseCode != HttpServletResponse.SC_OK) {
374                                    if (failOnError) {
375                                            SessionErrors.add(
376                                                    actionRequest, "errorConnectingToUrl",
377                                                    new Object[] {String.valueOf(responseCode)});
378                                    }
379    
380                                    return responseCode;
381                            }
382    
383                            long contentLength = getMethod.getResponseContentLength();
384    
385                            String progressId = ParamUtil.getString(
386                                    actionRequest, Constants.PROGRESS_ID);
387    
388                            ProgressInputStream pis = new ProgressInputStream(
389                                    actionRequest, getMethod.getResponseBodyAsStream(),
390                                    contentLength, progressId);
391    
392                            String deployDir = PrefsPropsUtil.getString(
393                                    PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
394                                    PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
395    
396                            String tmpFilePath =
397                                    deployDir + StringPool.SLASH + _DOWNLOAD_DIR +
398                                            StringPool.SLASH + fileName;
399    
400                            File tmpFile = new File(tmpFilePath);
401    
402                            if (!tmpFile.getParentFile().exists()) {
403                                    tmpFile.getParentFile().mkdirs();
404                            }
405    
406                            FileOutputStream fos = new FileOutputStream(tmpFile);
407    
408                            try {
409                                    pis.readAll(fos);
410    
411                                    if (_log.isInfoEnabled()) {
412                                            _log.info(
413                                                    "Downloaded plugin from " + urlObj + " has " +
414                                                            pis.getTotalRead() + " bytes");
415                                    }
416                            }
417                            finally {
418                                    pis.clearProgress();
419                            }
420    
421                            getMethod.releaseConnection();
422    
423                            if (pis.getTotalRead() > 0) {
424                                    String destination = deployDir + StringPool.SLASH + fileName;
425    
426                                    File destinationFile = new File(destination);
427    
428                                    boolean moved = FileUtil.move(tmpFile, destinationFile);
429    
430                                    if (!moved) {
431                                            FileUtil.copyFile(tmpFile, destinationFile);
432                                            FileUtil.delete(tmpFile);
433                                    }
434    
435                                    SessionMessages.add(actionRequest, "pluginDownloaded");
436                            }
437                            else {
438                                    if (failOnError) {
439                                            SessionErrors.add(
440                                                    actionRequest, UploadException.class.getName());
441                                    }
442    
443                                    responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
444                            }
445                    }
446                    catch (MalformedURLException murle) {
447                            SessionErrors.add(actionRequest, "invalidUrl", murle);
448                    }
449                    catch (IOException ioe) {
450                            SessionErrors.add(actionRequest, "errorConnectingToUrl", ioe);
451                    }
452                    finally {
453                            if (getMethod != null) {
454                                    getMethod.releaseConnection();
455                            }
456    
457                            PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
458                    }
459    
460                    return responseCode;
461            }
462    
463            protected void remoteDeploySourceForge(
464                            String path, ActionRequest actionRequest)
465                    throws Exception {
466    
467                    String[] sourceForgeMirrors = getSourceForgeMirrors();
468    
469                    for (int i = 0; i < sourceForgeMirrors.length; i++) {
470                            try {
471                                    String url = sourceForgeMirrors[i] + path;
472    
473                                    if (_log.isDebugEnabled()) {
474                                            _log.debug("Downloading from SourceForge mirror " + url);
475                                    }
476    
477                                    URL urlObj = new URL(url);
478    
479                                    boolean failOnError = false;
480    
481                                    if ((i + 1) == sourceForgeMirrors.length) {
482                                            failOnError = true;
483                                    }
484    
485                                    int responseCode = remoteDeploy(
486                                            url, urlObj, actionRequest, failOnError);
487    
488                                    if (responseCode == HttpServletResponse.SC_OK) {
489                                            return;
490                                    }
491                            }
492                            catch (MalformedURLException murle) {
493                                    SessionErrors.add(actionRequest, "invalidUrl", murle);
494                            }
495                    }
496            }
497    
498            protected void unignorePackages(ActionRequest actionRequest)
499                    throws Exception {
500    
501                    String[] pluginPackagesUnignored = StringUtil.split(
502                            ParamUtil.getString(actionRequest, "pluginPackagesUnignored"),
503                            StringPool.NEW_LINE);
504    
505                    String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
506                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
507                            StringPool.NEW_LINE,
508                            PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
509    
510                    StringBundler sb = new StringBundler();
511    
512                    for (int i = 0; i < pluginPackagesIgnored.length; i++) {
513                            String packageId = pluginPackagesIgnored[i];
514    
515                            if (!ArrayUtil.contains(pluginPackagesUnignored, packageId)) {
516                                    sb.append(packageId);
517                                    sb.append(StringPool.NEW_LINE);
518                            }
519                    }
520    
521                    PortletPreferences preferences = PrefsPropsUtil.getPreferences();
522    
523                    preferences.setValue(
524                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED, sb.toString());
525    
526                    preferences.store();
527    
528                    PluginPackageUtil.refreshUpdatesAvailableCache();
529            }
530    
531            protected void uninstall(ActionRequest actionRequest) throws Exception {
532                    String appServerType = ServerDetector.getServerId();
533    
534                    String deploymentContext = ParamUtil.getString(
535                            actionRequest, "deploymentContext");
536    
537                    if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
538                            deploymentContext += ".war";
539                    }
540    
541                    File deployDir = new File(
542                            DeployUtil.getAutoDeployDestDir() + "/" + deploymentContext);
543    
544                    DeployUtil.undeploy(appServerType, deployDir);
545            }
546    
547            private static final String _DOWNLOAD_DIR = "download";
548    
549            private static Log _log = LogFactoryUtil.getLog(InstallPluginAction.class);
550    
551    }