1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portlet.plugininstaller.action;
16  
17  import com.liferay.portal.deploy.DeployUtil;
18  import com.liferay.portal.events.GlobalStartupAction;
19  import com.liferay.portal.kernel.deploy.auto.AutoDeployDir;
20  import com.liferay.portal.kernel.deploy.auto.AutoDeployListener;
21  import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil;
22  import com.liferay.portal.kernel.log.Log;
23  import com.liferay.portal.kernel.log.LogFactoryUtil;
24  import com.liferay.portal.kernel.servlet.SessionErrors;
25  import com.liferay.portal.kernel.servlet.SessionMessages;
26  import com.liferay.portal.kernel.upload.UploadPortletRequest;
27  import com.liferay.portal.kernel.util.ArrayUtil;
28  import com.liferay.portal.kernel.util.CharPool;
29  import com.liferay.portal.kernel.util.Constants;
30  import com.liferay.portal.kernel.util.FileUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.ParamUtil;
34  import com.liferay.portal.kernel.util.PropsKeys;
35  import com.liferay.portal.kernel.util.ServerDetector;
36  import com.liferay.portal.kernel.util.StringBundler;
37  import com.liferay.portal.kernel.util.StringPool;
38  import com.liferay.portal.kernel.util.StringUtil;
39  import com.liferay.portal.kernel.util.Validator;
40  import com.liferay.portal.plugin.PluginPackageUtil;
41  import com.liferay.portal.plugin.RepositoryReport;
42  import com.liferay.portal.security.auth.PrincipalException;
43  import com.liferay.portal.security.permission.PermissionChecker;
44  import com.liferay.portal.struts.PortletAction;
45  import com.liferay.portal.theme.ThemeDisplay;
46  import com.liferay.portal.tools.deploy.BaseDeployer;
47  import com.liferay.portal.upload.ProgressInputStream;
48  import com.liferay.portal.util.HttpImpl;
49  import com.liferay.portal.util.PortalUtil;
50  import com.liferay.portal.util.PrefsPropsUtil;
51  import com.liferay.portal.util.PropsUtil;
52  import com.liferay.portal.util.PropsValues;
53  import com.liferay.portal.util.WebKeys;
54  import com.liferay.util.servlet.UploadException;
55  
56  import java.io.File;
57  import java.io.FileOutputStream;
58  import java.io.IOException;
59  
60  import java.net.MalformedURLException;
61  import java.net.URL;
62  
63  import java.util.List;
64  
65  import javax.portlet.ActionRequest;
66  import javax.portlet.ActionResponse;
67  import javax.portlet.PortletConfig;
68  import javax.portlet.PortletPreferences;
69  
70  import javax.servlet.http.HttpServletResponse;
71  
72  import org.apache.commons.httpclient.HostConfiguration;
73  import org.apache.commons.httpclient.HttpClient;
74  import org.apache.commons.httpclient.methods.GetMethod;
75  import org.apache.struts.action.ActionForm;
76  import org.apache.struts.action.ActionMapping;
77  
78  /**
79   * <a href="InstallPluginAction.java.html"><b><i>View Source</i></b></a>
80   *
81   * @author Jorge Ferrer
82   * @author Brian Wing Shun Chan
83   * @author Minhchau Dang
84   */
85  public class InstallPluginAction extends PortletAction {
86  
87      public void processAction(
88              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
89              ActionRequest actionRequest, ActionResponse actionResponse)
90          throws Exception {
91  
92          ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
93              WebKeys.THEME_DISPLAY);
94  
95          PermissionChecker permissionChecker =
96              themeDisplay.getPermissionChecker();
97  
98          if (!permissionChecker.isOmniadmin()) {
99              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         int blacklistThreshold = ParamUtil.getInteger(
142             actionRequest, "blacklistThreshold");
143         boolean unpackWar = ParamUtil.getBoolean(actionRequest, "unpackWar");
144         boolean customPortletXml = ParamUtil.getBoolean(
145             actionRequest, "customPortletXml");
146         String jbossPrefix = ParamUtil.getString(actionRequest, "jbossPrefix");
147         String tomcatConfDir = ParamUtil.getString(
148             actionRequest, "tomcatConfDir");
149         String tomcatLibDir = ParamUtil.getString(
150             actionRequest, "tomcatLibDir");
151         String pluginRepositoriesTrusted = ParamUtil.getString(
152             actionRequest, "pluginRepositoriesTrusted");
153         String pluginRepositoriesUntrusted = ParamUtil.getString(
154             actionRequest, "pluginRepositoriesUntrusted");
155         boolean pluginNotificationsEnabled = ParamUtil.getBoolean(
156             actionRequest, "pluginNotificationsEnabled");
157         String pluginPackagesIgnored = ParamUtil.getString(
158             actionRequest, "pluginPackagesIgnored");
159 
160         PortletPreferences preferences = PrefsPropsUtil.getPreferences();
161 
162         preferences.setValue(
163             PropsKeys.AUTO_DEPLOY_ENABLED, String.valueOf(enabled));
164         preferences.setValue(PropsKeys.AUTO_DEPLOY_DEPLOY_DIR, deployDir);
165         preferences.setValue(PropsKeys.AUTO_DEPLOY_DEST_DIR, destDir);
166         preferences.setValue(
167             PropsKeys.AUTO_DEPLOY_INTERVAL, String.valueOf(interval));
168         preferences.setValue(
169             PropsKeys.AUTO_DEPLOY_BLACKLIST_THRESHOLD,
170             String.valueOf(blacklistThreshold));
171         preferences.setValue(
172             PropsKeys.AUTO_DEPLOY_UNPACK_WAR, String.valueOf(unpackWar));
173         preferences.setValue(
174             PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
175             String.valueOf(customPortletXml));
176         preferences.setValue(PropsKeys.AUTO_DEPLOY_JBOSS_PREFIX, jbossPrefix);
177         preferences.setValue(
178             PropsKeys.AUTO_DEPLOY_TOMCAT_CONF_DIR, tomcatConfDir);
179         preferences.setValue(
180             PropsKeys.AUTO_DEPLOY_TOMCAT_LIB_DIR, tomcatLibDir);
181         preferences.setValue(
182             PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, pluginRepositoriesTrusted);
183         preferences.setValue(
184             PropsKeys.PLUGIN_REPOSITORIES_UNTRUSTED,
185             pluginRepositoriesUntrusted);
186         preferences.setValue(
187             PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
188             String.valueOf(pluginNotificationsEnabled));
189         preferences.setValue(
190             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
191             pluginPackagesIgnored);
192 
193         preferences.store();
194 
195         reloadRepositories(actionRequest);
196 
197         if (_log.isInfoEnabled()) {
198             _log.info("Unregistering auto deploy directories");
199         }
200 
201         AutoDeployUtil.unregisterDir("defaultAutoDeployDir");
202 
203         if (enabled) {
204             if (_log.isInfoEnabled()) {
205                 _log.info("Registering auto deploy directories");
206             }
207 
208             List<AutoDeployListener> autoDeployListeners =
209                 GlobalStartupAction.getAutoDeployListeners();
210 
211             AutoDeployDir autoDeployDir = new AutoDeployDir(
212                 "defaultAutoDeployDir", new File(deployDir), new File(destDir),
213                 interval, blacklistThreshold, autoDeployListeners);
214 
215             AutoDeployUtil.registerDir(autoDeployDir);
216         }
217         else {
218             if (_log.isInfoEnabled()) {
219                 _log.info("Not registering auto deploy directories");
220             }
221         }
222     }
223 
224     protected String[] getSourceForgeMirrors() {
225         return PropsUtil.getArray(PropsKeys.SOURCE_FORGE_MIRRORS);
226     }
227 
228     protected void ignorePackages(ActionRequest actionRequest)
229         throws Exception {
230 
231         String pluginPackagesIgnored = ParamUtil.getString(
232             actionRequest, "pluginPackagesIgnored");
233 
234         String oldPluginPackagesIgnored= PrefsPropsUtil.getString(
235             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
236 
237         PortletPreferences preferences = PrefsPropsUtil.getPreferences();
238 
239         preferences.setValue(
240             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
241             oldPluginPackagesIgnored.concat(StringPool.NEW_LINE).concat(
242                 pluginPackagesIgnored));
243 
244         preferences.store();
245 
246         PluginPackageUtil.refreshUpdatesAvailableCache();
247     }
248 
249     protected void localDeploy(ActionRequest actionRequest) throws Exception {
250         UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
251             actionRequest);
252 
253         String fileName = null;
254 
255         String deploymentContext = ParamUtil.getString(
256             actionRequest, "deploymentContext");
257 
258         if (Validator.isNotNull(deploymentContext)) {
259             fileName =
260                 BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
261         }
262         else {
263             fileName = GetterUtil.getString(uploadRequest.getFileName("file"));
264 
265             int pos = fileName.lastIndexOf(CharPool.PERIOD);
266 
267             if (pos != -1) {
268                 deploymentContext = fileName.substring(0, pos);
269             }
270         }
271 
272         File file = uploadRequest.getFile("file");
273 
274         byte[] bytes = FileUtil.getBytes(file);
275 
276         if ((bytes == null) || (bytes.length == 0)) {
277             SessionErrors.add(actionRequest, UploadException.class.getName());
278 
279             return;
280         }
281 
282         try {
283             PluginPackageUtil.registerPluginPackageInstallation(
284                 deploymentContext);
285 
286             String source = file.toString();
287 
288             String deployDir = PrefsPropsUtil.getString(
289                 PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
290                 PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
291 
292             String destination = deployDir + StringPool.SLASH + fileName;
293 
294             FileUtil.copyFile(source, destination);
295 
296             SessionMessages.add(actionRequest, "pluginUploaded");
297         }
298         finally {
299             PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
300         }
301     }
302 
303     protected void reloadRepositories(ActionRequest actionRequest)
304         throws Exception {
305 
306         RepositoryReport repositoryReport =
307             PluginPackageUtil.reloadRepositories();
308 
309         SessionMessages.add(
310             actionRequest, WebKeys.PLUGIN_REPOSITORY_REPORT, repositoryReport);
311     }
312 
313     protected void remoteDeploy(ActionRequest actionRequest) throws Exception {
314         try {
315             String url = ParamUtil.getString(actionRequest, "url");
316 
317             URL urlObj = new URL(url);
318 
319             String host = urlObj.getHost();
320 
321             if (host.endsWith(".sf.net") || host.endsWith(".sourceforge.net")) {
322                 remoteDeploySourceForge(urlObj.getPath(), actionRequest);
323             }
324             else {
325                 remoteDeploy(url, urlObj, actionRequest, true);
326             }
327         }
328         catch (MalformedURLException murle) {
329             SessionErrors.add(actionRequest, "invalidUrl", murle);
330         }
331     }
332 
333     protected int remoteDeploy(
334             String url, URL urlObj, ActionRequest actionRequest,
335             boolean failOnError)
336         throws Exception {
337 
338         int responseCode = HttpServletResponse.SC_OK;
339 
340         GetMethod getMethod = null;
341 
342         String deploymentContext = ParamUtil.getString(
343             actionRequest, "deploymentContext");
344 
345         try {
346             HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
347 
348             HostConfiguration hostConfig = httpImpl.getHostConfig(url);
349 
350             HttpClient client = httpImpl.getClient(hostConfig);
351 
352             getMethod = new GetMethod(url);
353 
354             String fileName = null;
355 
356             if (Validator.isNotNull(deploymentContext)) {
357                 fileName =
358                     BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
359             }
360             else {
361                 fileName = url.substring(url.lastIndexOf(CharPool.SLASH) + 1);
362 
363                 int pos = fileName.lastIndexOf(CharPool.PERIOD);
364 
365                 if (pos != -1) {
366                     deploymentContext = fileName.substring(0, pos);
367                 }
368             }
369 
370             PluginPackageUtil.registerPluginPackageInstallation(
371                 deploymentContext);
372 
373             responseCode = client.executeMethod(hostConfig, getMethod);
374 
375             if (responseCode != HttpServletResponse.SC_OK) {
376                 if (failOnError) {
377                     SessionErrors.add(
378                         actionRequest, "errorConnectingToUrl",
379                         new Object[] {String.valueOf(responseCode)});
380                 }
381 
382                 return responseCode;
383             }
384 
385             long contentLength = getMethod.getResponseContentLength();
386 
387             String progressId = ParamUtil.getString(
388                 actionRequest, Constants.PROGRESS_ID);
389 
390             ProgressInputStream pis = new ProgressInputStream(
391                 actionRequest, getMethod.getResponseBodyAsStream(),
392                 contentLength, progressId);
393 
394             String deployDir = PrefsPropsUtil.getString(
395                 PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
396                 PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
397 
398             String tmpFilePath =
399                 deployDir + StringPool.SLASH + _DOWNLOAD_DIR +
400                     StringPool.SLASH + fileName;
401 
402             File tmpFile = new File(tmpFilePath);
403 
404             if (!tmpFile.getParentFile().exists()) {
405                 tmpFile.getParentFile().mkdirs();
406             }
407 
408             FileOutputStream fos = new FileOutputStream(tmpFile);
409 
410             try {
411                 pis.readAll(fos);
412 
413                 if (_log.isInfoEnabled()) {
414                     _log.info(
415                         "Downloaded plugin from " + urlObj + " has " +
416                             pis.getTotalRead() + " bytes");
417                 }
418             }
419             finally {
420                 pis.clearProgress();
421             }
422 
423             getMethod.releaseConnection();
424 
425             if (pis.getTotalRead() > 0) {
426                 String destination = deployDir + StringPool.SLASH + fileName;
427 
428                 File destinationFile = new File(destination);
429 
430                 boolean moved = FileUtil.move(tmpFile, destinationFile);
431 
432                 if (!moved) {
433                     FileUtil.copyFile(tmpFile, destinationFile);
434                     FileUtil.delete(tmpFile);
435                 }
436 
437                 SessionMessages.add(actionRequest, "pluginDownloaded");
438             }
439             else {
440                 if (failOnError) {
441                     SessionErrors.add(
442                         actionRequest, UploadException.class.getName());
443                 }
444 
445                 responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
446             }
447         }
448         catch (MalformedURLException murle) {
449             SessionErrors.add(actionRequest, "invalidUrl", murle);
450         }
451         catch (IOException ioe) {
452             SessionErrors.add(actionRequest, "errorConnectingToUrl", ioe);
453         }
454         finally {
455             if (getMethod != null) {
456                 getMethod.releaseConnection();
457             }
458 
459             PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
460         }
461 
462         return responseCode;
463     }
464 
465     protected void remoteDeploySourceForge(
466             String path, ActionRequest actionRequest)
467         throws Exception {
468 
469         String[] sourceForgeMirrors = getSourceForgeMirrors();
470 
471         for (int i = 0; i < sourceForgeMirrors.length; i++) {
472             try {
473                 String url = sourceForgeMirrors[i] + path;
474 
475                 if (_log.isDebugEnabled()) {
476                     _log.debug("Downloading from SourceForge mirror " + url);
477                 }
478 
479                 URL urlObj = new URL(url);
480 
481                 boolean failOnError = false;
482 
483                 if ((i + 1) == sourceForgeMirrors.length) {
484                     failOnError = true;
485                 }
486 
487                 int responseCode = remoteDeploy(
488                     url, urlObj, actionRequest, failOnError);
489 
490                 if (responseCode == HttpServletResponse.SC_OK) {
491                     return;
492                 }
493             }
494             catch (MalformedURLException murle) {
495                 SessionErrors.add(actionRequest, "invalidUrl", murle);
496             }
497         }
498     }
499 
500     protected void unignorePackages(ActionRequest actionRequest)
501         throws Exception {
502 
503         String[] pluginPackagesUnignored = StringUtil.split(
504             ParamUtil.getString(actionRequest, "pluginPackagesUnignored"),
505             StringPool.NEW_LINE);
506 
507         String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
508             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
509             StringPool.NEW_LINE,
510             PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
511 
512         StringBundler sb = new StringBundler();
513 
514         for (int i = 0; i < pluginPackagesIgnored.length; i++) {
515             String packageId = pluginPackagesIgnored[i];
516 
517             if (!ArrayUtil.contains(pluginPackagesUnignored, packageId)) {
518                 sb.append(packageId);
519                 sb.append(StringPool.NEW_LINE);
520             }
521         }
522 
523         PortletPreferences preferences = PrefsPropsUtil.getPreferences();
524 
525         preferences.setValue(
526             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED, sb.toString());
527 
528         preferences.store();
529 
530         PluginPackageUtil.refreshUpdatesAvailableCache();
531     }
532 
533     protected void uninstall(ActionRequest actionRequest) throws Exception {
534         String appServerType = ServerDetector.getServerId();
535 
536         String deploymentContext = ParamUtil.getString(
537             actionRequest, "deploymentContext");
538 
539         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
540             deploymentContext += ".war";
541         }
542 
543         File deployDir = new File(
544             DeployUtil.getAutoDeployDestDir() + "/" + deploymentContext);
545 
546         DeployUtil.undeploy(appServerType, deployDir);
547     }
548 
549     private static final String _DOWNLOAD_DIR = "download";
550 
551     private static Log _log = LogFactoryUtil.getLog(InstallPluginAction.class);
552 
553 }