/* * Aipo is a groupware program developed by TOWN, Inc. * Copyright (C) 2004-2015 TOWN, Inc. * http://www.aipo.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.aimluck.eip.modules.actions.portlets; // Jetspeed Stuff import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.jetspeed.modules.actions.portlets.VelocityPortletAction; import org.apache.jetspeed.om.BaseSecurityReference; import org.apache.jetspeed.om.SecurityReference; import org.apache.jetspeed.om.profile.Entry; import org.apache.jetspeed.om.profile.Profile; import org.apache.jetspeed.om.profile.Skin; import org.apache.jetspeed.om.profile.psml.PsmlSkin; import org.apache.jetspeed.om.registry.Parameter; import org.apache.jetspeed.om.registry.PortletEntry; import org.apache.jetspeed.om.registry.base.BaseParameter; import org.apache.jetspeed.om.security.JetspeedUser; import org.apache.jetspeed.portal.Portlet; import org.apache.jetspeed.portal.PortletConfig; import org.apache.jetspeed.portal.PortletException; import org.apache.jetspeed.portal.PortletInstance; import org.apache.jetspeed.portal.PortletSkin; import org.apache.jetspeed.portal.portlets.VelocityPortlet; import org.apache.jetspeed.services.JetspeedSecurity; import org.apache.jetspeed.services.PortalToolkit; import org.apache.jetspeed.services.Registry; import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.jetspeed.services.persistence.PersistenceManager; import org.apache.jetspeed.services.rundata.JetspeedRunData; import org.apache.jetspeed.services.security.PortalResource; import org.apache.jetspeed.services.statemanager.SessionState; import org.apache.jetspeed.util.MetaData; import org.apache.turbine.modules.ActionLoader; import org.apache.turbine.util.RunData; import org.apache.velocity.context.Context; import com.aimluck.commons.field.ALStringField; import com.aimluck.commons.utils.ALStringUtil; import com.aimluck.eip.common.ALApplication; import com.aimluck.eip.services.social.ALApplicationService; import com.aimluck.eip.services.social.gadgets.ALUserPref; import com.aimluck.eip.services.social.model.ALApplicationGetRequest; import com.aimluck.eip.util.ALCommonUtils; /** * This action implements the default portlet behavior customizer * * <p> * Don't call it from the URL, the Portlet and the Action are automatically * associated through the registry PortletName * * @author <a href="mailto:raphael@apache.org">Rapha�l Luta</a> */ public class ALCustomizeAction extends VelocityPortletAction { public static final String PARAM_NAMESPACE = "_param_"; /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService .getLogger(ALCustomizeAction.class.getName()); /** * Subclasses must override this method to provide default behavior for the * portlet action * * <table> * <tr> * <th>Context</th> * <th>Description</th> * </tr> * <!-- --------- ------------------------- --> * <tr> * <td>action</td> * <td>Action to use</td> * </tr> * <tr> * <td>current_skin</td> * <td>Current skin for this portlet INSTANCE</td> * </tr> * <tr> * <td>params</td> * <td>List of configurable parameters from the REGISTRY entry.</td> * </tr> * <tr> * <td>portlet</td> * <td>Portlet, not the Portlet Instance!</td> * </tr> * <tr> * <td>skins</td> * <td>List of skins</td> * </tr> * <tr> * <td>security</td> * <td>List of security ref</td> * </tr> * <tr> * <td>security_ref</td> * <td>Current securityRef for this portlet INSTANCE</td> * </tr> * </table> */ @Override protected void buildNormalContext(VelocityPortlet portlet, Context context, RunData rundata) { // generic context stuff context .put("skins", ALCustomizeSetAction.buildList(rundata, Registry.SKIN)); context.put("securitys", ALCustomizeSetAction.buildList( rundata, Registry.SECURITY)); // we should first retrieve the portlet to customize Portlet p = ((JetspeedRunData) rundata).getCustomized(); context.put("action", "portlets.ALCustomizeAction"); PortletInstance instance = PersistenceManager.getInstance(p, rundata); context.put("portlet_instance", PersistenceManager.getInstance(p, rundata)); if (p == null) { return; } // retrieve the portlet parameters PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, p.getName()); // save the entry in the session List<Parameter> params = new ArrayList<Parameter>(); Iterator<?> i = entry.getParameterNames(); while (i.hasNext()) { String name = (String) i.next(); Parameter param = entry.getParameter(name); // filter some "system" and hidden parameters if ((!param.isHidden()) && (name.charAt(0) != '_')) { // check the user role if (JetspeedSecurity.checkPermission( (JetspeedUser) rundata.getUser(), new PortalResource(entry, param), JetspeedSecurity.PERMISSION_CUSTOMIZE)) { // Implementation of clone() is missing so we have do it "by hand" Parameter clone = new BaseParameter(); clone.setName(param.getName()); clone.setTitle(param.getTitle()); clone.setDescription(param.getDescription()); clone.setType(param.getType()); String value; if (instance.getAttribute(name, null) != null) { value = instance.getAttribute(name); } else if (p.getPortletConfig().getInitParameter(name) != null) { value = p.getPortletConfig().getInitParameter(name); } else { value = param.getValue(); } clone.setValue(ALStringUtil.sanitizing(value)); params.add(clone); } } } PortletConfig pc = p.getPortletConfig(); if ("GadgetsTemplate".equals(pc.getName())) { String appId = pc.getInitParameter("aid"); ALApplication app = ALApplicationService.get(new ALApplicationGetRequest() .withAppId(appId) .withIsFetchXml(true)); List<List<Map.Entry<String, String>>> enumsList = new ArrayList<List<Map.Entry<String, String>>>(); List<ALUserPref> userPrefs = app.getUserPrefs(); Collections.sort(userPrefs, new Comparator<ALUserPref>() { @Override public int compare(ALUserPref a, ALUserPref b) { ALUserPref p1 = a; ALUserPref p2 = b; return (p1.getName()).compareTo(p2.getName()); } }); for (ALUserPref userPref : userPrefs) { String name = "pref-" + userPref.getName(); Parameter clone = new BaseParameter(); clone.setName(name); clone.setTitle(userPref.getDisplayName()); clone.setDescription(null); boolean hidden = false; boolean list = false; switch (userPref.getType()) { case ENUM: List<Map.Entry<String, String>> enums = userPref.getEnums(); enumsList.add(enums); clone.setType("enum"); break; case LIST: clone.setType("list"); list = true; break; case BOOL: clone.setType("boolean"); break; case HIDDEN: clone.setType("hidden"); hidden = true; break; default: clone.setType(null); } String value; if (instance.getAttribute(name, null) != null) { value = instance.getAttribute(name); } else if (p.getPortletConfig().getInitParameter(name) != null) { value = p.getPortletConfig().getInitParameter(name); } else { value = userPref.getDefault(); if (list) { value = value.replace("|", ","); } } clone.setValue(ALStringUtil.sanitizing(value)); if (!hidden) { params.add(clone); } } context.put("enums", enumsList); } else { // 理由等 :XREG からパラメータを読み込む際に順不同になっていた // 対処方法:パラメータ名でソートするように変更した。 Collections.sort(params, new Comparator<Parameter>() { @Override public int compare(Parameter a, Parameter b) { Parameter p1 = a; Parameter p2 = b; return (p1.getName()).compareTo(p2.getName()); } }); } // get the customization state for this page SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState(); customizationState.setAttribute("customize-parameters", params); // populate the customizer context context.put("parameters", params); context.put("portlet", p); context.put("customizer", portlet); // 2007.04.04 update context.put("utils", new ALCommonUtils()); if (p.getPortletConfig().getSecurityRef() != null) { context.put("security_ref", p .getPortletConfig() .getSecurityRef() .getParent()); } if (p.getPortletConfig().getSkin() != null) { context.put("current_skin", p .getPortletConfig() .getPortletSkin() .getName()); } Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile(); String currentTitle = profile.getDocument().getEntryById(p.getID()).getTitle(); if (currentTitle == null && p.getPortletConfig().getMetainfo() != null) { currentTitle = p.getPortletConfig().getMetainfo().getTitle(); } context.put("current_title", new ALStringField(currentTitle)); } /** Clean up the customization state */ public void doCancel(RunData rundata, Context context) { ((JetspeedRunData) rundata).setCustomized(null); if (((JetspeedRunData) rundata).getCustomized() == null) { try { ActionLoader.getInstance().exec(rundata, "controls.EndCustomize"); } catch (Exception e) { logger.error("Unable to load action controls.EndCustomize ", e); } } } /** * Resets the portlet settings to default * * @param rundata * @param context */ public void doDefault(RunData rundata, Context context) { // we should first retrieve the portlet to customize and its parameters // definition Portlet p = ((JetspeedRunData) rundata).getCustomized(); // Update paramaters try { // 理由等 :デフォルトに戻す際に、ポートレット名も元に戻す // 対処方法:XREGからタイトルを取り出し、値を設定 Portlet portlet = ((JetspeedRunData) rundata).getCustomized(); String defTitle = portlet.getPortletConfig().getMetainfo().getTitle(); Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile(); Entry entry = profile.getDocument().getEntryById(p.getID()); PortletConfig pc = p.getPortletConfig(); MetaData md = pc.getMetainfo(); if (md == null) { md = new MetaData(); pc.setMetainfo(md); } boolean isGadgets = false; String appId = null; String url = null; String moduleId = null; if ("GadgetsTemplate".equals(pc.getName())) { appId = pc.getInitParameter("aid"); url = pc.getInitParameter("url"); moduleId = pc.getInitParameter("mid"); ALApplication app = ALApplicationService.get(new ALApplicationGetRequest() .withAppId(appId)); isGadgets = true; ALStringField title = app.getTitle(); defTitle = title.getValue(); } md.setTitle(defTitle); entry.setTitle(defTitle); PortletInstance instance = PersistenceManager.getInstance(p, rundata); instance.removeAllAttributes(); if (isGadgets) { instance.setAttribute("aid", appId); instance.setAttribute("url", url); instance.setAttribute("mid", moduleId); } // add by Haruo Kaneko profile.store(); p.init(); // FIXME: this hack is due to the corrupted lifecycle of the portlet in // the // current API when caching is activated try { org.apache.jetspeed.util.PortletSessionState.setPortletConfigChanged( p, rundata); p.init(); } catch (PortletException e) { logger.error("Customizer failed to reinitialize the portlet " + p.getName(), e); } // we're done, make sure clean up the // session doCancel(rundata, context); } catch (Exception e) { logger.error("ALCustomizeAction.doDefault", e); } } /** Updates the customized portlet entry */ public void doUpdate(RunData rundata, Context context) { // get the customization state for this page SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState(); // we should first retrieve the portlet to customize and its parameters // definition Portlet p = ((JetspeedRunData) rundata).getCustomized(); List<?> params = (List<?>) customizationState.getAttribute("customize-parameters"); String newSecurityParent = rundata.getParameters().getString("_security_ref"); String newSkinName = rundata.getParameters().getString("_skin"); String newTitle = rundata.getParameters().getString("current_title"); boolean changeRequested = ((params != null) || (newSkinName != null) || (newSecurityParent != null) || (newTitle != null)); boolean madePsChange = false; boolean madePcChange = false; if ((p == null) || (changeRequested == false)) { doCancel(rundata, context); return; } PortletConfig pc = p.getPortletConfig(); Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile(); Entry entry = profile.getDocument().getEntryById(p.getID()); // Only update the security ref if the parent changed if ((newSecurityParent != null)) { boolean securityChanged = false; SecurityReference currentSecurityRef = pc.getSecurityRef(); if (currentSecurityRef != null) { securityChanged = (newSecurityParent.equals(currentSecurityRef.getParent()) == false); } else { securityChanged = (newSecurityParent.trim().length() > 0); } if (securityChanged == true) { SecurityReference securityRef = null; if ((newSecurityParent.trim().length() > 0)) { securityRef = new BaseSecurityReference(); securityRef.setParent(newSecurityParent); } // Note: setting the portlet's config may not be a good idea - // it might be used as the Portlet for other PSMLDocument Entries that // have a different idea of security - and the caching of Portlets does // NOT include security -ggolden. pc.setSecurityRef(securityRef); entry.setSecurityRef(securityRef); madePcChange = true; } } // Only update the skin if the name changed if (newSkinName != null) { boolean skinChanged = false; String currentSkinName = null; if (pc.getSkin() != null) { currentSkinName = pc.getPortletSkin().getName(); } if (currentSkinName != null) { skinChanged = (newSkinName.equals(currentSkinName) == false); } else { skinChanged = (newSkinName.trim().length() > 0); } if (skinChanged == true) { PortletSkin skin = null; if ((newSkinName.trim().length() > 0)) { skin = PortalToolkit.getSkin(newSkinName); if (skin != null) { // Note: setting the portlet's config may not be a good idea - // it might be used as the Portlet for other PSMLDocument Entries // that // have a different idea of skin - and the caching of Portlets does // NOT include skin -ggolden. pc.setPortletSkin(skin); Skin psmlSkin = entry.getSkin(); if (psmlSkin == null) { entry.setSkin(new PsmlSkin()); } entry.getSkin().setName(newSkinName); } else { logger.warn("Unable to update skin for portlet entry " + entry.getId() + " because skin does not exist."); } } else { // Note: setting the portlet's config may not be a good idea - // it might be used as the Portlet for other PSMLDocument Entries that // have a different idea of skin - and the caching of Portlets does // NOT include skin -ggolden. pc.setPortletSkin(null); entry.setSkin(null); } madePcChange = true; } } // Only update the title if the title changed if (newTitle != null) { boolean titleChanged = false; String currentTitle = entry.getTitle(); MetaData md = pc.getMetainfo(); if (currentTitle == null && md != null && md.getTitle() != null) { currentTitle = md.getTitle(); } if (currentTitle != null) { titleChanged = (newTitle.equals(currentTitle) == false); } else { titleChanged = (newTitle.trim().length() > 0); } if (titleChanged == true) { if ((newTitle.trim().length() > 0)) { // Note: setting the portlet's config may not be a good idea - // it might be used as the Portlet for other PSMLDocument Entries that // have a different idea of title - and the caching of Portlets does // NOT include title -ggolden. if (md == null) { md = new MetaData(); pc.setMetainfo(md); } md.setTitle(newTitle); entry.setTitle(newTitle); madePcChange = true; } } } // Update paramaters try { PortletInstance instance = PersistenceManager.getInstance(p, rundata); PortletEntry regEntry = (PortletEntry) Registry.getEntry(Registry.PORTLET, p.getName()); Iterator<?> i = params.iterator(); while (i.hasNext()) { Parameter param = (Parameter) i.next(); String name = param.getName(); String newValue = null; String[] testArray = rundata.getParameters().getStrings(name); if (testArray != null && testArray.length > 1) { newValue = org.apache.jetspeed.util.StringUtils.arrayToString(testArray, ","); } else { newValue = rundata.getParameters().getString(name); if (newValue == null) { newValue = ""; } } String regValue = name.startsWith("pref-") ? "" : regEntry .getParameter(name) .getValue(); String psmlValue = instance.getAttribute(name); // New value for this parameter exists if (newValue != null) { if (!regValue.equals(newValue) || !psmlValue.equals(newValue)) { instance.setAttribute(name, newValue); psmlValue = newValue; } madePsChange = true; } // Remove duplicate parameters from psml if (psmlValue != null && psmlValue.equals(regValue)) { instance.removeAttribute(name); madePsChange = true; } } // save all the changes if ((madePsChange == true) || (madePcChange == true)) { try { // JetspeedRunData jdata = (JetspeedRunData) rundata; profile.store(); // FIXME: this hack is due to the corrupted lifecycle of the portlet // in the // current API when caching is activated p.init(); org.apache.jetspeed.util.PortletSessionState.setPortletConfigChanged( p, rundata); } catch (PortletException e) { logger.error("Customizer failed to reinitialize the portlet " + p.getName(), e); } catch (Exception e) { logger.error("Unable to save profile ", e); } } // we're done, make sure clean up the // session doCancel(rundata, context); } catch (Exception e) { logger.error("ALCustomizeAction.doUpdate", e); } } }