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