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