001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.portlet.plugininstaller.action;
022:
023: import com.liferay.portal.events.GlobalStartupAction;
024: import com.liferay.portal.kernel.deploy.auto.AutoDeployDir;
025: import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil;
026: import com.liferay.portal.kernel.security.permission.PermissionChecker;
027: import com.liferay.portal.kernel.util.ArrayUtil;
028: import com.liferay.portal.kernel.util.Constants;
029: import com.liferay.portal.kernel.util.GetterUtil;
030: import com.liferay.portal.kernel.util.ParamUtil;
031: import com.liferay.portal.kernel.util.StringMaker;
032: import com.liferay.portal.kernel.util.StringPool;
033: import com.liferay.portal.kernel.util.StringUtil;
034: import com.liferay.portal.kernel.util.Validator;
035: import com.liferay.portal.plugin.PluginPackageUtil;
036: import com.liferay.portal.plugin.RepositoryReport;
037: import com.liferay.portal.security.auth.PrincipalException;
038: import com.liferay.portal.struts.PortletAction;
039: import com.liferay.portal.theme.ThemeDisplay;
040: import com.liferay.portal.tools.BaseDeployer;
041: import com.liferay.portal.util.PortalUtil;
042: import com.liferay.portal.util.PrefsPropsUtil;
043: import com.liferay.portal.util.PropsUtil;
044: import com.liferay.portal.util.PropsValues;
045: import com.liferay.portal.util.WebKeys;
046: import com.liferay.util.FileUtil;
047: import com.liferay.util.Http;
048: import com.liferay.util.servlet.ProgressInputStream;
049: import com.liferay.util.servlet.SessionErrors;
050: import com.liferay.util.servlet.SessionMessages;
051: import com.liferay.util.servlet.UploadException;
052: import com.liferay.util.servlet.UploadPortletRequest;
053:
054: import java.io.File;
055: import java.io.FileOutputStream;
056: import java.io.IOException;
057:
058: import java.net.MalformedURLException;
059: import java.net.URL;
060:
061: import java.util.List;
062:
063: import javax.portlet.ActionRequest;
064: import javax.portlet.ActionResponse;
065: import javax.portlet.PortletConfig;
066: import javax.portlet.PortletPreferences;
067:
068: import javax.servlet.http.HttpServletResponse;
069:
070: import org.apache.commons.httpclient.HostConfiguration;
071: import org.apache.commons.httpclient.HttpClient;
072: import org.apache.commons.httpclient.methods.GetMethod;
073: import org.apache.commons.logging.Log;
074: import org.apache.commons.logging.LogFactory;
075: import org.apache.struts.action.ActionForm;
076: import org.apache.struts.action.ActionMapping;
077:
078: /**
079: * <a href="InstallPluginAction.java.html"><b><i>View Source</i></b></a>
080: *
081: * @author Jorge Ferrer
082: * @author Brian Wing Shun Chan
083: * @author Minhchau Dang
084: *
085: */
086: public class InstallPluginAction extends PortletAction {
087:
088: public void processAction(ActionMapping mapping, ActionForm form,
089: PortletConfig config, ActionRequest req, ActionResponse res)
090: throws Exception {
091:
092: ThemeDisplay themeDisplay = (ThemeDisplay) req
093: .getAttribute(WebKeys.THEME_DISPLAY);
094:
095: PermissionChecker permissionChecker = themeDisplay
096: .getPermissionChecker();
097:
098: if (!permissionChecker.isOmniadmin()) {
099: SessionErrors.add(req, PrincipalException.class.getName());
100:
101: setForward(req, "portlet.plugin_installer.error");
102:
103: return;
104: }
105:
106: String cmd = ParamUtil.getString(req, Constants.CMD);
107:
108: if (cmd.equals("deployConfiguration")) {
109: deployConfiguration(req);
110: } else if (cmd.equals("ignorePackages")) {
111: ignorePackages(req);
112: } else if (cmd.equals("localDeploy")) {
113: localDeploy(req);
114: } else if (cmd.equals("reloadRepositories")) {
115: reloadRepositories(req);
116: } else if (cmd.equals("remoteDeploy")) {
117: remoteDeploy(req);
118: } else if (cmd.equals("unignorePackages")) {
119: unignorePackages(req);
120: }
121:
122: sendRedirect(req, res);
123: }
124:
125: protected void deployConfiguration(ActionRequest req)
126: throws Exception {
127: boolean enabled = ParamUtil.getBoolean(req, "enabled");
128: String deployDir = ParamUtil.getString(req, "deployDir");
129: String destDir = ParamUtil.getString(req, "destDir");
130: long interval = ParamUtil.getLong(req, "interval");
131: int blacklistThreshold = ParamUtil.getInteger(req,
132: "blacklistThreshold");
133: boolean unpackWar = ParamUtil.getBoolean(req, "unpackWar");
134: boolean customPortletXml = ParamUtil.getBoolean(req,
135: "customPortletXml");
136: String jbossPrefix = ParamUtil.getString(req, "jbossPrefix");
137: String tomcatConfDir = ParamUtil
138: .getString(req, "tomcatConfDir");
139: String tomcatLibDir = ParamUtil.getString(req, "tomcatLibDir");
140: String pluginRepositoriesTrusted = ParamUtil.getString(req,
141: "pluginRepositoriesTrusted");
142: String pluginRepositoriesUntrusted = ParamUtil.getString(req,
143: "pluginRepositoriesUntrusted");
144: boolean pluginNotificationsEnabled = ParamUtil.getBoolean(req,
145: "pluginNotificationsEnabled");
146: String pluginPackagesIgnored = ParamUtil.getString(req,
147: "pluginPackagesIgnored");
148:
149: PortletPreferences prefs = PrefsPropsUtil.getPreferences();
150:
151: prefs.setValue(PropsUtil.AUTO_DEPLOY_ENABLED, String
152: .valueOf(enabled));
153: prefs.setValue(PropsUtil.AUTO_DEPLOY_DEPLOY_DIR, deployDir);
154: prefs.setValue(PropsUtil.AUTO_DEPLOY_DEST_DIR, destDir);
155: prefs.setValue(PropsUtil.AUTO_DEPLOY_INTERVAL, String
156: .valueOf(interval));
157: prefs.setValue(PropsUtil.AUTO_DEPLOY_BLACKLIST_THRESHOLD,
158: String.valueOf(blacklistThreshold));
159: prefs.setValue(PropsUtil.AUTO_DEPLOY_UNPACK_WAR, String
160: .valueOf(unpackWar));
161: prefs.setValue(PropsUtil.AUTO_DEPLOY_CUSTOM_PORTLET_XML, String
162: .valueOf(customPortletXml));
163: prefs.setValue(PropsUtil.AUTO_DEPLOY_JBOSS_PREFIX, jbossPrefix);
164: prefs.setValue(PropsUtil.AUTO_DEPLOY_TOMCAT_CONF_DIR,
165: tomcatConfDir);
166: prefs.setValue(PropsUtil.AUTO_DEPLOY_TOMCAT_LIB_DIR,
167: tomcatLibDir);
168: prefs.setValue(PropsUtil.PLUGIN_REPOSITORIES_TRUSTED,
169: pluginRepositoriesTrusted);
170: prefs.setValue(PropsUtil.PLUGIN_REPOSITORIES_UNTRUSTED,
171: pluginRepositoriesUntrusted);
172: prefs.setValue(PropsUtil.PLUGIN_NOTIFICATIONS_ENABLED, String
173: .valueOf(pluginNotificationsEnabled));
174: prefs.setValue(PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
175: pluginPackagesIgnored);
176:
177: prefs.store();
178:
179: reloadRepositories(req);
180:
181: if (_log.isInfoEnabled()) {
182: _log.info("Unregistering auto deploy directories");
183: }
184:
185: AutoDeployUtil.unregisterDir("defaultAutoDeployDir");
186:
187: if (enabled) {
188: if (_log.isInfoEnabled()) {
189: _log.info("Registering auto deploy directories");
190: }
191:
192: List autoDeployListeners = GlobalStartupAction
193: .getAutoDeployListeners();
194:
195: AutoDeployDir autoDeployDir = new AutoDeployDir(
196: "defaultAutoDeployDir", new File(deployDir),
197: new File(destDir), interval, blacklistThreshold,
198: autoDeployListeners);
199:
200: AutoDeployUtil.registerDir(autoDeployDir);
201: } else {
202: if (_log.isInfoEnabled()) {
203: _log.info("Not registering auto deploy directories");
204: }
205: }
206: }
207:
208: protected String[] getSourceForgeMirrors() {
209: return PropsUtil.getArray(PropsUtil.SOURCE_FORGE_MIRRORS);
210: }
211:
212: protected void ignorePackages(ActionRequest req) throws Exception {
213: String pluginPackagesIgnored = ParamUtil.getString(req,
214: "pluginPackagesIgnored");
215:
216: String oldPluginPackagesIgnored = PrefsPropsUtil
217: .getString(PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
218:
219: StringMaker sm = new StringMaker();
220:
221: sm.append(oldPluginPackagesIgnored);
222: sm.append(StringPool.NEW_LINE);
223: sm.append(pluginPackagesIgnored);
224:
225: PortletPreferences prefs = PrefsPropsUtil.getPreferences();
226:
227: prefs.setValue(PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
228: sm.toString());
229:
230: prefs.store();
231:
232: PluginPackageUtil.refreshUpdatesAvailableCache();
233: }
234:
235: protected void localDeploy(ActionRequest req) throws Exception {
236: UploadPortletRequest uploadReq = PortalUtil
237: .getUploadPortletRequest(req);
238:
239: String fileName = null;
240:
241: String deploymentContext = ParamUtil.getString(req,
242: "deploymentContext");
243:
244: if (Validator.isNotNull(deploymentContext)) {
245: fileName = BaseDeployer.DEPLOY_TO_PREFIX
246: + deploymentContext + ".war";
247: } else {
248: fileName = GetterUtil.getString(uploadReq
249: .getFileName("file"));
250:
251: int pos = fileName.lastIndexOf(StringPool.PERIOD);
252:
253: if (pos != -1) {
254: deploymentContext = fileName.substring(0, pos);
255: }
256: }
257:
258: File file = uploadReq.getFile("file");
259:
260: byte[] bytes = FileUtil.getBytes(file);
261:
262: if ((bytes == null) || (bytes.length == 0)) {
263: SessionErrors.add(req, UploadException.class.getName());
264:
265: return;
266: }
267:
268: try {
269: PluginPackageUtil
270: .registerPluginPackageInstallation(deploymentContext);
271:
272: String source = file.toString();
273:
274: String deployDir = PrefsPropsUtil.getString(
275: PropsUtil.AUTO_DEPLOY_DEPLOY_DIR,
276: PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
277:
278: String destination = deployDir + StringPool.SLASH
279: + fileName;
280:
281: FileUtil.copyFile(source, destination);
282:
283: SessionMessages.add(req, "pluginUploaded");
284: } finally {
285: PluginPackageUtil
286: .endPluginPackageInstallation(deploymentContext);
287: }
288: }
289:
290: protected void reloadRepositories(ActionRequest req)
291: throws Exception {
292: RepositoryReport report = PluginPackageUtil
293: .reloadRepositories();
294:
295: SessionMessages.add(req, WebKeys.PLUGIN_REPOSITORY_REPORT,
296: report);
297: }
298:
299: protected void remoteDeploy(ActionRequest req) throws Exception {
300: try {
301: String url = ParamUtil.getString(req, "url");
302:
303: URL urlObj = new URL(url);
304:
305: String host = urlObj.getHost();
306:
307: if (host.endsWith(".sf.net")
308: || host.endsWith(".sourceforge.net")) {
309: remoteDeploySourceForge(urlObj.getPath(), req);
310: } else {
311: remoteDeploy(url, urlObj, req, true);
312: }
313: } catch (MalformedURLException murle) {
314: SessionErrors.add(req, "invalidUrl", murle);
315: }
316: }
317:
318: protected int remoteDeploy(String url, URL urlObj,
319: ActionRequest req, boolean failOnError) throws Exception {
320:
321: int responseCode = HttpServletResponse.SC_OK;
322:
323: GetMethod getMethod = null;
324:
325: String deploymentContext = ParamUtil.getString(req,
326: "deploymentContext");
327:
328: try {
329: HostConfiguration hostConfig = Http.getHostConfig(url);
330:
331: HttpClient client = Http.getClient(hostConfig);
332:
333: getMethod = new GetMethod(url);
334:
335: String fileName = null;
336:
337: if (Validator.isNotNull(deploymentContext)) {
338: fileName = BaseDeployer.DEPLOY_TO_PREFIX
339: + deploymentContext + ".war";
340: } else {
341: fileName = url.substring(url
342: .lastIndexOf(StringPool.SLASH) + 1);
343:
344: int pos = fileName.lastIndexOf(StringPool.PERIOD);
345:
346: if (pos != -1) {
347: deploymentContext = fileName.substring(0, pos);
348: }
349: }
350:
351: PluginPackageUtil
352: .registerPluginPackageInstallation(deploymentContext);
353:
354: responseCode = client.executeMethod(hostConfig, getMethod);
355:
356: if (responseCode != HttpServletResponse.SC_OK) {
357: if (failOnError) {
358: SessionErrors
359: .add(req, "errorConnectingToUrl",
360: new Object[] { String
361: .valueOf(responseCode) });
362: }
363:
364: return responseCode;
365: }
366:
367: long contentLength = getMethod.getResponseContentLength();
368:
369: String progressId = ParamUtil.getString(req,
370: Constants.PROGRESS_ID);
371:
372: ProgressInputStream pis = new ProgressInputStream(req,
373: getMethod.getResponseBodyAsStream(), contentLength,
374: progressId);
375:
376: String deployDir = PrefsPropsUtil.getString(
377: PropsUtil.AUTO_DEPLOY_DEPLOY_DIR,
378: PropsValues.AUTO_DEPLOY_DEPLOY_DIR);
379:
380: String tmpFilePath = deployDir + StringPool.SLASH
381: + _DOWNLOAD_DIR + StringPool.SLASH + fileName;
382:
383: File tmpFile = new File(tmpFilePath);
384:
385: if (!tmpFile.getParentFile().exists()) {
386: tmpFile.getParentFile().mkdirs();
387: }
388:
389: FileOutputStream fos = new FileOutputStream(tmpFile);
390:
391: try {
392: pis.readAll(fos);
393:
394: if (_log.isInfoEnabled()) {
395: _log.info("Downloaded plugin from " + urlObj
396: + " has " + pis.getTotalRead() + " bytes");
397: }
398: } finally {
399: pis.clearProgress();
400: }
401:
402: getMethod.releaseConnection();
403:
404: if (pis.getTotalRead() > 0) {
405: String destination = deployDir + StringPool.SLASH
406: + fileName;
407:
408: File destinationFile = new File(destination);
409:
410: boolean moved = FileUtil.move(tmpFile, destinationFile);
411:
412: if (!moved) {
413: FileUtil.copyFile(tmpFile, destinationFile);
414: FileUtil.delete(tmpFile);
415: }
416:
417: SessionMessages.add(req, "pluginDownloaded");
418: } else {
419: if (failOnError) {
420: SessionErrors.add(req, UploadException.class
421: .getName());
422: }
423:
424: responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
425: }
426: } catch (MalformedURLException murle) {
427: SessionErrors.add(req, "invalidUrl", murle);
428: } catch (IOException ioe) {
429: SessionErrors.add(req, "errorConnectingToUrl", ioe);
430: } finally {
431: if (getMethod != null) {
432: getMethod.releaseConnection();
433: }
434:
435: PluginPackageUtil
436: .endPluginPackageInstallation(deploymentContext);
437: }
438:
439: return responseCode;
440: }
441:
442: protected void remoteDeploySourceForge(String path,
443: ActionRequest req) throws Exception {
444:
445: String[] sourceForgeMirrors = getSourceForgeMirrors();
446:
447: for (int i = 0; i < sourceForgeMirrors.length; i++) {
448: try {
449: String url = sourceForgeMirrors[i] + path;
450:
451: if (_log.isDebugEnabled()) {
452: _log.debug("Downloading from SourceForge mirror "
453: + url);
454: }
455:
456: URL urlObj = new URL(url);
457:
458: boolean failOnError = false;
459:
460: if ((i + 1) == sourceForgeMirrors.length) {
461: failOnError = true;
462: }
463:
464: int responseCode = remoteDeploy(url, urlObj, req,
465: failOnError);
466:
467: if (responseCode == HttpServletResponse.SC_OK) {
468: return;
469: }
470: } catch (MalformedURLException murle) {
471: SessionErrors.add(req, "invalidUrl", murle);
472: }
473: }
474: }
475:
476: protected void unignorePackages(ActionRequest req) throws Exception {
477: String[] pluginPackagesUnignored = StringUtil.split(ParamUtil
478: .getString(req, "pluginPackagesUnignored"),
479: StringPool.NEW_LINE);
480:
481: String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
482: PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
483: StringPool.NEW_LINE,
484: PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
485:
486: StringMaker sm = new StringMaker();
487:
488: for (int i = 0; i < pluginPackagesIgnored.length; i++) {
489: String packageId = pluginPackagesIgnored[i];
490:
491: if (!ArrayUtil.contains(pluginPackagesUnignored, packageId)) {
492: sm.append(packageId);
493: sm.append(StringPool.NEW_LINE);
494: }
495: }
496:
497: PortletPreferences prefs = PrefsPropsUtil.getPreferences();
498:
499: prefs.setValue(PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
500: sm.toString());
501:
502: prefs.store();
503:
504: PluginPackageUtil.refreshUpdatesAvailableCache();
505: }
506:
507: private static final String _DOWNLOAD_DIR = "download";
508:
509: private static Log _log = LogFactory
510: .getLog(InstallPluginAction.class);
511:
512: }
|