/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.marketplace.store.web.internal.portlet; import com.liferay.marketplace.model.App; import com.liferay.marketplace.service.AppLocalService; import com.liferay.marketplace.service.AppService; import com.liferay.marketplace.store.web.constants.MarketplaceConstants; import com.liferay.marketplace.store.web.constants.MarketplaceStorePortletKeys; import com.liferay.marketplace.store.web.constants.MarketplaceStoreWebKeys; import com.liferay.marketplace.store.web.internal.configuration.MarketplaceStoreWebConfigurationValues; import com.liferay.marketplace.store.web.internal.oauth.util.OAuthManager; import com.liferay.marketplace.store.web.internal.util.MarketplaceLicenseUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.json.JSONArray; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.patcher.PatcherUtil; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.ReleaseInfo; import com.liferay.portal.kernel.util.ServerDetector; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.Portlet; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.WindowState; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.scribe.model.OAuthRequest; import org.scribe.model.Response; import org.scribe.model.Token; import org.scribe.model.Verb; /** * @author Ryan Park * @author Joan Kim */ @Component( immediate = true, property = { "com.liferay.portlet.css-class-wrapper=marketplace-portlet", "com.liferay.portlet.display-category=category.hidden", "com.liferay.portlet.header-portlet-css=/css/main.css", "com.liferay.portlet.header-portlet-javascript=/js/main.js", "com.liferay.portlet.icon=/icons/store.png", "com.liferay.portlet.preferences-owned-by-group=false", "com.liferay.portlet.private-request-attributes=false", "com.liferay.portlet.private-session-attributes=false", "com.liferay.portlet.render-weight=50", "com.liferay.portlet.use-default-template=true", "javax.portlet.description=", "javax.portlet.display-name=Store", "javax.portlet.init-param.add-process-action-success-action=false", "javax.portlet.init-param.template-path=/", "javax.portlet.init-param.view-template=/view.jsp", "javax.portlet.name=" + MarketplaceStorePortletKeys.MARKETPLACE_STORE, "javax.portlet.resource-bundle=content.Language", "javax.portlet.security-role-ref=administrator,guest,power-user,user", "javax.portlet.supports.mime-type=text/html" }, service = {Portlet.class} ) public class MarketplaceStorePortlet extends RemoteMVCPortlet { public void downloadApp( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long appPackageId = ParamUtil.getLong(actionRequest, "appPackageId"); boolean unlicensed = ParamUtil.getBoolean(actionRequest, "unlicensed"); File file = null; try { file = FileUtil.createTempFile(); downloadApp( actionRequest, actionResponse, appPackageId, unlicensed, file); App app = _appService.updateApp(file); JSONObject jsonObject = getAppJSONObject(app.getRemoteAppId()); jsonObject.put("cmd", "downloadApp"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } finally { if (file != null) { file.delete(); } } } public void getApp( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long remoteAppId = ParamUtil.getLong(actionRequest, "appId"); JSONObject jsonObject = getAppJSONObject(remoteAppId); jsonObject.put("cmd", "getApp"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } public void getInstalledApps( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("apps", getInstalledAppsJSONArray()); jsonObject.put("cmd", "getInstalledApps"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } public void getPrepackagedApps( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); OAuthRequest oAuthRequest = new OAuthRequest( Verb.POST, getServerPortletURL()); setBaseRequestParameters(actionRequest, actionResponse, oAuthRequest); addOAuthParameter(oAuthRequest, "p_p_lifecycle", "1"); addOAuthParameter( oAuthRequest, "p_p_state", WindowState.NORMAL.toString()); String serverNamespace = getServerNamespace(); addOAuthParameter( oAuthRequest, serverNamespace.concat("compatibility"), String.valueOf(ReleaseInfo.getBuildNumber())); addOAuthParameter( oAuthRequest, serverNamespace.concat("javax.portlet.action"), "getPrepackagedApps"); Map<String, String> prepackagedApps = _appLocalService.getPrepackagedApps(); JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); Set<String> keys = prepackagedApps.keySet(); for (String key : keys) { jsonObject.put(key, prepackagedApps.get(key)); } addOAuthParameter( oAuthRequest, serverNamespace.concat("prepackagedApps"), jsonObject.toString()); Response response = getResponse(themeDisplay.getUser(), oAuthRequest); JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject( response.getBody()); writeJSON(actionRequest, actionResponse, responseJSONObject); } public void installApp( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long remoteAppId = ParamUtil.getLong(actionRequest, "appId"); _appService.installApp(remoteAppId); JSONObject jsonObject = getAppJSONObject(remoteAppId); jsonObject.put("cmd", "installApp"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { try { super.render(renderRequest, renderResponse); } catch (PortletException pe) { include("/error.jsp", renderRequest, renderResponse); } } public void uninstallApp( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long remoteAppId = ParamUtil.getLong(actionRequest, "appId"); _appService.uninstallApp(remoteAppId); JSONObject jsonObject = getAppJSONObject(remoteAppId); jsonObject.put("cmd", "uninstallApp"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } public void updateApp( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long appPackageId = ParamUtil.getLong(actionRequest, "appPackageId"); boolean unlicensed = ParamUtil.getBoolean(actionRequest, "unlicensed"); String orderUuid = ParamUtil.getString(actionRequest, "orderUuid"); String productEntryName = ParamUtil.getString( actionRequest, "productEntryName"); File file = null; try { file = FileUtil.createTempFile(); downloadApp( actionRequest, actionResponse, appPackageId, unlicensed, file); App app = _appService.updateApp(file); if (Validator.isNull(orderUuid) && Validator.isNotNull(productEntryName)) { orderUuid = MarketplaceLicenseUtil.getOrder(productEntryName); } if (Validator.isNotNull(orderUuid)) { MarketplaceLicenseUtil.registerOrder( orderUuid, productEntryName); } _appService.installApp(app.getRemoteAppId()); JSONObject jsonObject = getAppJSONObject(app.getRemoteAppId()); jsonObject.put("cmd", "updateApp"); jsonObject.put("message", "success"); writeJSON(actionRequest, actionResponse, jsonObject); } finally { if (file != null) { file.delete(); } } } public void updateAppLicense( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { String orderUuid = ParamUtil.getString(actionRequest, "orderUuid"); String productEntryName = ParamUtil.getString( actionRequest, "productEntryName"); JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("cmd", "updateAppLicense"); if (Validator.isNull(orderUuid) && Validator.isNotNull(productEntryName)) { orderUuid = MarketplaceLicenseUtil.getOrder(productEntryName); } if (Validator.isNotNull(orderUuid)) { MarketplaceLicenseUtil.registerOrder(orderUuid, productEntryName); jsonObject.put("message", "success"); } else { jsonObject.put("message", "failed"); } writeJSON(actionRequest, actionResponse, jsonObject); } public void updateApps( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("cmd", "updateApps"); jsonObject.put("message", "success"); if (_reentrantLock.tryLock()) { try { long[] appPackageIds = ParamUtil.getLongValues( actionRequest, "appPackageIds"); JSONArray jsonArray = JSONFactoryUtil.createJSONArray(); for (long appPackageId : appPackageIds) { File file = null; try { file = FileUtil.createTempFile(); downloadApp( actionRequest, actionResponse, appPackageId, false, file); App app = _appService.updateApp(file); _appService.installApp(app.getRemoteAppId()); jsonArray.put(getAppJSONObject(app)); } catch (Exception e) { jsonObject.put("message", "failed"); } finally { if (file != null) { file.delete(); } } } jsonObject.put("updatedApps", jsonArray); } finally { _reentrantLock.unlock(); } } else { jsonObject.put("message", "failed"); } writeJSON(actionRequest, actionResponse, jsonObject); } @Override protected void doDispatch( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { try { ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(WebKeys.THEME_DISPLAY); Token accessToken = oAuthManager.getAccessToken( themeDisplay.getUser()); if (accessToken == null) { include("/login.jsp", renderRequest, renderResponse); return; } } catch (PortalException pe) { throw new PortletException(pe); } renderRequest.setAttribute( MarketplaceStoreWebKeys.OAUTH_AUTHORIZED, Boolean.TRUE); super.doDispatch(renderRequest, renderResponse); } protected void downloadApp( PortletRequest portletRequest, PortletResponse portletResponse, long appPackageId, boolean unlicensed, File file) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute( WebKeys.THEME_DISPLAY); OAuthRequest oAuthRequest = new OAuthRequest( Verb.GET, getServerPortletURL()); setBaseRequestParameters(portletRequest, portletResponse, oAuthRequest); String serverNamespace = getServerNamespace(); addOAuthParameter( oAuthRequest, serverNamespace.concat("appPackageId"), String.valueOf(appPackageId)); addOAuthParameter(oAuthRequest, "p_p_lifecycle", "2"); if (unlicensed) { addOAuthParameter( oAuthRequest, "p_p_resource_id", "serveUnlicensedApp"); } else { addOAuthParameter(oAuthRequest, "p_p_resource_id", "serveApp"); } Response response = getResponse(themeDisplay.getUser(), oAuthRequest); FileUtil.write(file, response.getStream()); } protected JSONObject getAppJSONObject(App app) throws Exception { JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("appId", app.getRemoteAppId()); jsonObject.put("downloaded", app.isDownloaded()); jsonObject.put("installed", app.isInstalled()); jsonObject.put("version", app.getVersion()); return jsonObject; } protected JSONObject getAppJSONObject(long remoteAppId) throws Exception { App app = _appLocalService.fetchRemoteApp(remoteAppId); if (app != null) { return getAppJSONObject(app); } JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("appId", remoteAppId); jsonObject.put("downloaded", false); jsonObject.put("installed", false); jsonObject.put("version", StringPool.BLANK); return jsonObject; } @Override protected String getClientPortletId() { return MarketplaceStorePortletKeys.MARKETPLACE_STORE; } protected JSONArray getInstalledAppsJSONArray() throws Exception { JSONArray jsonArray = JSONFactoryUtil.createJSONArray(); List<App> apps = _appLocalService.getInstalledApps(); for (App app : apps) { if (app.getRemoteAppId() > 0) { jsonArray.put(getAppJSONObject(app)); } } return jsonArray; } @Override protected String getServerPortletId() { return MarketplaceStoreWebConfigurationValues.MARKETPLACE_PORTLET_ID; } @Override protected String getServerPortletURL() { return MarketplaceStoreWebConfigurationValues.MARKETPLACE_URL + "/osb-portlet/mp_server"; } @Override protected void processPortletParameterMap( PortletRequest portletRequest, PortletResponse portletResponse, Map<String, String[]> parameterMap) { parameterMap.put( "clientBuild", new String[] {String.valueOf(MarketplaceConstants.CLIENT_BUILD)}); if (!parameterMap.containsKey("compatibility")) { parameterMap.put( "compatibility", new String[] {String.valueOf(ReleaseInfo.getBuildNumber())}); } parameterMap.put("installedPatches", PatcherUtil.getInstalledPatches()); parameterMap.put( "supportsHotDeploy", new String[] { String.valueOf(ServerDetector.isSupportsHotDeploy()) }); } @Reference(unbind = "-") protected void setAppLocalService(AppLocalService appLocalService) { _appLocalService = appLocalService; } @Reference(unbind = "-") protected void setAppService(AppService appService) { _appService = appService; } @Override @Reference(unbind = "-") protected void setOAuthManager(OAuthManager oAuthManager) { super.setOAuthManager(oAuthManager); } private AppLocalService _appLocalService; private AppService _appService; private final ReentrantLock _reentrantLock = new ReentrantLock(); }