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 report = PluginPackageUtil.reloadRepositories();
317 
318         SessionMessages.add(
319             actionRequest, WebKeys.PLUGIN_REPOSITORY_REPORT, report);
320     }
321 
322     protected void remoteDeploy(ActionRequest actionRequest) throws Exception {
323         try {
324             String url = ParamUtil.getString(actionRequest, "url");
325 
326             URL urlObj = new URL(url);
327 
328             String host = urlObj.getHost();
329 
330             if (host.endsWith(".sf.net") || host.endsWith(".sourceforge.net")) {
331                 remoteDeploySourceForge(urlObj.getPath(), actionRequest);
332             }
333             else {
334                 remoteDeploy(url, urlObj, actionRequest, true);
335             }
336         }
337         catch (MalformedURLException murle) {
338             SessionErrors.add(actionRequest, "invalidUrl", murle);
339         }
340     }
341 
342     protected int remoteDeploy(
343             String url, URL urlObj, ActionRequest actionRequest,
344             boolean failOnError)
345         throws Exception {
346 
347         int responseCode = HttpServletResponse.SC_OK;
348 
349         GetMethod getMethod = null;
350 
351         String deploymentContext = ParamUtil.getString(
352             actionRequest, "deploymentContext");
353 
354         try {
355             HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
356 
357             HostConfiguration hostConfig = httpImpl.getHostConfig(url);
358 
359             HttpClient client = httpImpl.getClient(hostConfig);
360 
361             getMethod = new GetMethod(url);
362 
363             String fileName = null;
364 
365             if (Validator.isNotNull(deploymentContext)) {
366                 fileName =
367                     BaseDeployer.DEPLOY_TO_PREFIX + deploymentContext + ".war";
368             }
369             else {
370                 fileName = url.substring(url.lastIndexOf(StringPool.SLASH) + 1);
371 
372                 int pos = fileName.lastIndexOf(StringPool.PERIOD);
373 
374                 if (pos != -1) {
375                     deploymentContext = fileName.substring(0, pos);
376                 }
377             }
378 
379             PluginPackageUtil.registerPluginPackageInstallation(
380                 deploymentContext);
381 
382             responseCode = client.executeMethod(hostConfig, getMethod);
383 
384             if (responseCode != HttpServletResponse.SC_OK) {
385                 if (failOnError) {
386                     SessionErrors.add(
387                         actionRequest, "errorConnectingToUrl",
388                         new Object[] {String.valueOf(responseCode)});
389                 }
390 
391                 return responseCode;
392             }
393 
394             long contentLength = getMethod.getResponseContentLength();
395 
396             String progressId = ParamUtil.getString(
397                 actionRequest, Constants.PROGRESS_ID);
398 
399             ProgressInputStream pis = new ProgressInputStream(
400                 actionRequest, getMethod.getResponseBodyAsStream(),
401                 contentLength, progressId);
402 
403             String deployDir = PrefsPropsUtil.getString(
404                 PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
405                 PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
406 
407             String tmpFilePath =
408                 deployDir + StringPool.SLASH + _DOWNLOAD_DIR +
409                     StringPool.SLASH + fileName;
410 
411             File tmpFile = new File(tmpFilePath);
412 
413             if (!tmpFile.getParentFile().exists()) {
414                 tmpFile.getParentFile().mkdirs();
415             }
416 
417             FileOutputStream fos = new FileOutputStream(tmpFile);
418 
419             try {
420                 pis.readAll(fos);
421 
422                 if (_log.isInfoEnabled()) {
423                     _log.info(
424                         "Downloaded plugin from " + urlObj + " has " +
425                             pis.getTotalRead() + " bytes");
426                 }
427             }
428             finally {
429                 pis.clearProgress();
430             }
431 
432             getMethod.releaseConnection();
433 
434             if (pis.getTotalRead() > 0) {
435                 String destination = deployDir + StringPool.SLASH + fileName;
436 
437                 File destinationFile = new File(destination);
438 
439                 boolean moved = FileUtil.move(tmpFile, destinationFile);
440 
441                 if (!moved) {
442                     FileUtil.copyFile(tmpFile, destinationFile);
443                     FileUtil.delete(tmpFile);
444                 }
445 
446                 SessionMessages.add(actionRequest, "pluginDownloaded");
447             }
448             else {
449                 if (failOnError) {
450                     SessionErrors.add(
451                         actionRequest, UploadException.class.getName());
452                 }
453 
454                 responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
455             }
456         }
457         catch (MalformedURLException murle) {
458             SessionErrors.add(actionRequest, "invalidUrl", murle);
459         }
460         catch (IOException ioe) {
461             SessionErrors.add(actionRequest, "errorConnectingToUrl", ioe);
462         }
463         finally {
464             if (getMethod != null) {
465                 getMethod.releaseConnection();
466             }
467 
468             PluginPackageUtil.endPluginPackageInstallation(deploymentContext);
469         }
470 
471         return responseCode;
472     }
473 
474     protected void remoteDeploySourceForge(
475             String path, ActionRequest actionRequest)
476         throws Exception {
477 
478         String[] sourceForgeMirrors = getSourceForgeMirrors();
479 
480         for (int i = 0; i < sourceForgeMirrors.length; i++) {
481             try {
482                 String url = sourceForgeMirrors[i] + path;
483 
484                 if (_log.isDebugEnabled()) {
485                     _log.debug("Downloading from SourceForge mirror " + url);
486                 }
487 
488                 URL urlObj = new URL(url);
489 
490                 boolean failOnError = false;
491 
492                 if ((i + 1) == sourceForgeMirrors.length) {
493                     failOnError = true;
494                 }
495 
496                 int responseCode = remoteDeploy(
497                     url, urlObj, actionRequest, failOnError);
498 
499                 if (responseCode == HttpServletResponse.SC_OK) {
500                     return;
501                 }
502             }
503             catch (MalformedURLException murle) {
504                 SessionErrors.add(actionRequest, "invalidUrl", murle);
505             }
506         }
507     }
508 
509     protected void unignorePackages(ActionRequest actionRequest)
510         throws Exception {
511 
512         String[] pluginPackagesUnignored = StringUtil.split(
513             ParamUtil.getString(actionRequest, "pluginPackagesUnignored"),
514             StringPool.NEW_LINE);
515 
516         String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
517             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
518             StringPool.NEW_LINE,
519             PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
520 
521         StringBuilder sb = new StringBuilder();
522 
523         for (int i = 0; i < pluginPackagesIgnored.length; i++) {
524             String packageId = pluginPackagesIgnored[i];
525 
526             if (!ArrayUtil.contains(pluginPackagesUnignored, packageId)) {
527                 sb.append(packageId);
528                 sb.append(StringPool.NEW_LINE);
529             }
530         }
531 
532         PortletPreferences preferences = PrefsPropsUtil.getPreferences();
533 
534         preferences.setValue(
535             PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED, sb.toString());
536 
537         preferences.store();
538 
539         PluginPackageUtil.refreshUpdatesAvailableCache();
540     }
541 
542     protected void uninstall(ActionRequest actionRequest) throws Exception {
543         String appServerType = ServerDetector.getServerId();
544 
545         String deploymentContext = ParamUtil.getString(
546             actionRequest, "deploymentContext");
547 
548         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
549             deploymentContext += ".war";
550         }
551 
552         File deployDir = new File(
553             DeployUtil.getAutoDeployDestDir() + "/" + deploymentContext);
554 
555         DeployUtil.undeploy(appServerType, deployDir);
556     }
557 
558     private static final String _DOWNLOAD_DIR = "download";
559 
560     private static Log _log = LogFactoryUtil.getLog(InstallPluginAction.class);
561 
562 }