/tags/release/7010/aipo/core/src/main/java/com/aimluck/eip/modules/actions/portlets/ALCustomizeAction.java

http://aipo.googlecode.com/ · Java · 601 lines · 410 code · 56 blank · 135 comment · 111 complexity · b0e3cdf151f3e5344e1c35a3bd1a2387 MD5 · raw file

  1. /*
  2. * Aipo is a groupware program developed by Aimluck,Inc.
  3. * Copyright (C) 2004-2011 Aimluck,Inc.
  4. * http://www.aipo.com
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.aimluck.eip.modules.actions.portlets;
  20. // Jetspeed Stuff
  21. import java.util.ArrayList;
  22. import java.util.Collections;
  23. import java.util.Comparator;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.Map;
  27. import org.apache.jetspeed.modules.actions.portlets.VelocityPortletAction;
  28. import org.apache.jetspeed.om.BaseSecurityReference;
  29. import org.apache.jetspeed.om.SecurityReference;
  30. import org.apache.jetspeed.om.profile.Entry;
  31. import org.apache.jetspeed.om.profile.Profile;
  32. import org.apache.jetspeed.om.profile.Skin;
  33. import org.apache.jetspeed.om.profile.psml.PsmlSkin;
  34. import org.apache.jetspeed.om.registry.Parameter;
  35. import org.apache.jetspeed.om.registry.PortletEntry;
  36. import org.apache.jetspeed.om.registry.base.BaseParameter;
  37. import org.apache.jetspeed.om.security.JetspeedUser;
  38. import org.apache.jetspeed.portal.Portlet;
  39. import org.apache.jetspeed.portal.PortletConfig;
  40. import org.apache.jetspeed.portal.PortletException;
  41. import org.apache.jetspeed.portal.PortletInstance;
  42. import org.apache.jetspeed.portal.PortletSkin;
  43. import org.apache.jetspeed.portal.portlets.VelocityPortlet;
  44. import org.apache.jetspeed.services.JetspeedSecurity;
  45. import org.apache.jetspeed.services.PortalToolkit;
  46. import org.apache.jetspeed.services.Registry;
  47. import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
  48. import org.apache.jetspeed.services.logging.JetspeedLogger;
  49. import org.apache.jetspeed.services.persistence.PersistenceManager;
  50. import org.apache.jetspeed.services.rundata.JetspeedRunData;
  51. import org.apache.jetspeed.services.security.PortalResource;
  52. import org.apache.jetspeed.services.statemanager.SessionState;
  53. import org.apache.jetspeed.util.MetaData;
  54. import org.apache.turbine.modules.ActionLoader;
  55. import org.apache.turbine.util.RunData;
  56. import org.apache.velocity.context.Context;
  57. import com.aimluck.commons.field.ALStringField;
  58. import com.aimluck.commons.utils.ALStringUtil;
  59. import com.aimluck.eip.common.ALApplication;
  60. import com.aimluck.eip.services.social.ALApplicationService;
  61. import com.aimluck.eip.services.social.gadgets.ALUserPref;
  62. import com.aimluck.eip.services.social.model.ALApplicationGetRequest;
  63. import com.aimluck.eip.util.ALCommonUtils;
  64. /**
  65. * This action implements the default portlet behavior customizer
  66. *
  67. * <p>
  68. * Don't call it from the URL, the Portlet and the Action are automatically
  69. * associated through the registry PortletName
  70. *
  71. * @author <a href="mailto:raphael@apache.org">Rapha?l Luta</a>
  72. */
  73. public class ALCustomizeAction extends VelocityPortletAction {
  74. public static final String PARAM_NAMESPACE = "_param_";
  75. /**
  76. * Static initialization of the logger for this class
  77. */
  78. private static final JetspeedLogger logger = JetspeedLogFactoryService
  79. .getLogger(ALCustomizeAction.class.getName());
  80. /**
  81. * Subclasses must override this method to provide default behavior for the
  82. * portlet action
  83. *
  84. * <table>
  85. * <tr>
  86. * <th>Context</th>
  87. * <th>Description</th>
  88. * </tr>
  89. * <!-- --------- ------------------------- -->
  90. * <tr>
  91. * <td>action</td>
  92. * <td>Action to use</td>
  93. * </tr>
  94. * <tr>
  95. * <td>current_skin</td>
  96. * <td>Current skin for this portlet INSTANCE</td>
  97. * </tr>
  98. * <tr>
  99. * <td>params</td>
  100. * <td>List of configurable parameters from the REGISTRY entry.</td>
  101. * </tr>
  102. * <tr>
  103. * <td>portlet</td>
  104. * <td>Portlet, not the Portlet Instance!</td>
  105. * </tr>
  106. * <tr>
  107. * <td>skins</td>
  108. * <td>List of skins</td>
  109. * </tr>
  110. * <tr>
  111. * <td>security</td>
  112. * <td>List of security ref</td>
  113. * </tr>
  114. * <tr>
  115. * <td>security_ref</td>
  116. * <td>Current securityRef for this portlet INSTANCE</td>
  117. * </tr>
  118. * </table>
  119. */
  120. @Override
  121. protected void buildNormalContext(VelocityPortlet portlet, Context context,
  122. RunData rundata) {
  123. // generic context stuff
  124. context
  125. .put("skins", ALCustomizeSetAction.buildList(rundata, Registry.SKIN));
  126. context.put("securitys", ALCustomizeSetAction.buildList(
  127. rundata,
  128. Registry.SECURITY));
  129. // we should first retrieve the portlet to customize
  130. Portlet p = ((JetspeedRunData) rundata).getCustomized();
  131. context.put("action", "portlets.ALCustomizeAction");
  132. PortletInstance instance = PersistenceManager.getInstance(p, rundata);
  133. context.put("portlet_instance", PersistenceManager.getInstance(p, rundata));
  134. if (p == null) {
  135. return;
  136. }
  137. // retrieve the portlet parameters
  138. PortletEntry entry =
  139. (PortletEntry) Registry.getEntry(Registry.PORTLET, p.getName());
  140. // save the entry in the session
  141. List<Parameter> params = new ArrayList<Parameter>();
  142. Iterator<?> i = entry.getParameterNames();
  143. while (i.hasNext()) {
  144. String name = (String) i.next();
  145. Parameter param = entry.getParameter(name);
  146. // filter some "system" and hidden parameters
  147. if ((!param.isHidden()) && (name.charAt(0) != '_')) {
  148. // check the user role
  149. if (JetspeedSecurity.checkPermission(
  150. (JetspeedUser) rundata.getUser(),
  151. new PortalResource(entry, param),
  152. JetspeedSecurity.PERMISSION_CUSTOMIZE)) {
  153. // Implementation of clone() is missing so we have do it "by hand"
  154. Parameter clone = new BaseParameter();
  155. clone.setName(param.getName());
  156. clone.setTitle(param.getTitle());
  157. clone.setDescription(param.getDescription());
  158. clone.setType(param.getType());
  159. String value;
  160. if (instance.getAttribute(name, null) != null) {
  161. value = instance.getAttribute(name);
  162. } else if (p.getPortletConfig().getInitParameter(name) != null) {
  163. value = p.getPortletConfig().getInitParameter(name);
  164. } else {
  165. value = param.getValue();
  166. }
  167. clone.setValue(ALStringUtil.sanitizing(value));
  168. params.add(clone);
  169. }
  170. }
  171. }
  172. PortletConfig pc = p.getPortletConfig();
  173. if ("GadgetsTemplate".equals(pc.getName())) {
  174. String appId = pc.getInitParameter("aid");
  175. ALApplication app =
  176. ALApplicationService.get(new ALApplicationGetRequest()
  177. .withAppId(appId)
  178. .withIsFetchXml(true));
  179. List<List<Map.Entry<String, String>>> enumsList =
  180. new ArrayList<List<Map.Entry<String, String>>>();
  181. List<ALUserPref> userPrefs = app.getUserPrefs();
  182. Collections.sort(userPrefs, new Comparator<ALUserPref>() {
  183. @Override
  184. public int compare(ALUserPref a, ALUserPref b) {
  185. ALUserPref p1 = a;
  186. ALUserPref p2 = b;
  187. return (p1.getName()).compareTo(p2.getName());
  188. }
  189. });
  190. for (ALUserPref userPref : userPrefs) {
  191. String name = "pref-" + userPref.getName();
  192. Parameter clone = new BaseParameter();
  193. clone.setName(name);
  194. clone.setTitle(userPref.getDisplayName());
  195. clone.setDescription(null);
  196. boolean hidden = false;
  197. boolean list = false;
  198. switch (userPref.getType()) {
  199. case ENUM:
  200. List<Map.Entry<String, String>> enums = userPref.getEnums();
  201. enumsList.add(enums);
  202. clone.setType("enum");
  203. break;
  204. case LIST:
  205. clone.setType("list");
  206. list = true;
  207. break;
  208. case BOOL:
  209. clone.setType("boolean");
  210. break;
  211. case HIDDEN:
  212. clone.setType("hidden");
  213. hidden = true;
  214. default:
  215. clone.setType(null);
  216. }
  217. String value;
  218. if (instance.getAttribute(name, null) != null) {
  219. value = instance.getAttribute(name);
  220. } else if (p.getPortletConfig().getInitParameter(name) != null) {
  221. value = p.getPortletConfig().getInitParameter(name);
  222. } else {
  223. value = userPref.getDefault();
  224. if (list) {
  225. value = value.replace("|", ",");
  226. }
  227. }
  228. clone.setValue(ALStringUtil.sanitizing(value));
  229. if (!hidden) {
  230. params.add(clone);
  231. }
  232. }
  233. context.put("enums", enumsList);
  234. } else {
  235. // ??? ?XREG ???????????????????????
  236. // ?????????????????????????
  237. Collections.sort(params, new Comparator<Parameter>() {
  238. @Override
  239. public int compare(Parameter a, Parameter b) {
  240. Parameter p1 = a;
  241. Parameter p2 = b;
  242. return (p1.getName()).compareTo(p2.getName());
  243. }
  244. });
  245. }
  246. // get the customization state for this page
  247. SessionState customizationState =
  248. ((JetspeedRunData) rundata).getPageSessionState();
  249. customizationState.setAttribute("customize-parameters", params);
  250. // populate the customizer context
  251. context.put("parameters", params);
  252. context.put("portlet", p);
  253. context.put("customizer", portlet);
  254. // 2007.04.04 update
  255. context.put("utils", new ALCommonUtils());
  256. if (p.getPortletConfig().getSecurityRef() != null) {
  257. context.put("security_ref", p
  258. .getPortletConfig()
  259. .getSecurityRef()
  260. .getParent());
  261. }
  262. if (p.getPortletConfig().getSkin() != null) {
  263. context.put("current_skin", p
  264. .getPortletConfig()
  265. .getPortletSkin()
  266. .getName());
  267. }
  268. Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
  269. String currentTitle =
  270. profile.getDocument().getEntryById(p.getID()).getTitle();
  271. if (currentTitle == null && p.getPortletConfig().getMetainfo() != null) {
  272. currentTitle = p.getPortletConfig().getMetainfo().getTitle();
  273. }
  274. context.put("current_title", new ALStringField(currentTitle));
  275. }
  276. /** Clean up the customization state */
  277. public void doCancel(RunData rundata, Context context) {
  278. ((JetspeedRunData) rundata).setCustomized(null);
  279. if (((JetspeedRunData) rundata).getCustomized() == null) {
  280. try {
  281. ActionLoader.getInstance().exec(rundata, "controls.EndCustomize");
  282. } catch (Exception e) {
  283. logger.error("Unable to load action controls.EndCustomize ", e);
  284. }
  285. }
  286. }
  287. /**
  288. * Resets the portlet settings to default
  289. *
  290. * @param rundata
  291. * @param context
  292. */
  293. public void doDefault(RunData rundata, Context context) {
  294. // we should first retrieve the portlet to customize and its parameters
  295. // definition
  296. Portlet p = ((JetspeedRunData) rundata).getCustomized();
  297. // Update paramaters
  298. try {
  299. // ??? ????????????????????????
  300. // ?????XREG????????????????
  301. Portlet portlet = ((JetspeedRunData) rundata).getCustomized();
  302. String defTitle = portlet.getPortletConfig().getMetainfo().getTitle();
  303. Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
  304. Entry entry = profile.getDocument().getEntryById(p.getID());
  305. PortletConfig pc = p.getPortletConfig();
  306. MetaData md = pc.getMetainfo();
  307. if (md == null) {
  308. md = new MetaData();
  309. pc.setMetainfo(md);
  310. }
  311. boolean isGadgets = false;
  312. String appId = null;
  313. String url = null;
  314. String moduleId = null;
  315. if ("GadgetsTemplate".equals(pc.getName())) {
  316. appId = pc.getInitParameter("aid");
  317. url = pc.getInitParameter("url");
  318. moduleId = pc.getInitParameter("mid");
  319. ALApplication app =
  320. ALApplicationService.get(new ALApplicationGetRequest()
  321. .withAppId(appId));
  322. isGadgets = true;
  323. ALStringField title = app.getTitle();
  324. defTitle = title.getValue();
  325. }
  326. md.setTitle(defTitle);
  327. entry.setTitle(defTitle);
  328. PortletInstance instance = PersistenceManager.getInstance(p, rundata);
  329. instance.removeAllAttributes();
  330. if (isGadgets) {
  331. instance.setAttribute("aid", appId);
  332. instance.setAttribute("url", url);
  333. instance.setAttribute("mid", moduleId);
  334. }
  335. // add by Haruo Kaneko
  336. profile.store();
  337. p.init();
  338. // FIXME: this hack is due to the corrupted lifecycle of the portlet in
  339. // the
  340. // current API when caching is activated
  341. try {
  342. org.apache.jetspeed.util.PortletSessionState.setPortletConfigChanged(
  343. p,
  344. rundata);
  345. p.init();
  346. } catch (PortletException e) {
  347. logger.error("Customizer failed to reinitialize the portlet "
  348. + p.getName(), e);
  349. }
  350. // we're done, make sure clean up the
  351. // session
  352. doCancel(rundata, context);
  353. } catch (Exception e) {
  354. logger.error("Exception", e);
  355. }
  356. }
  357. /** Updates the customized portlet entry */
  358. public void doUpdate(RunData rundata, Context context) {
  359. // get the customization state for this page
  360. SessionState customizationState =
  361. ((JetspeedRunData) rundata).getPageSessionState();
  362. // we should first retrieve the portlet to customize and its parameters
  363. // definition
  364. Portlet p = ((JetspeedRunData) rundata).getCustomized();
  365. List<?> params =
  366. (List<?>) customizationState.getAttribute("customize-parameters");
  367. String newSecurityParent =
  368. rundata.getParameters().getString("_security_ref");
  369. String newSkinName = rundata.getParameters().getString("_skin");
  370. String newTitle = rundata.getParameters().getString("current_title");
  371. boolean changeRequested =
  372. ((params != null) || (newSkinName != null) || (newSecurityParent != null) || (newTitle != null));
  373. boolean madePsChange = false;
  374. boolean madePcChange = false;
  375. if ((p == null) || (changeRequested == false)) {
  376. doCancel(rundata, context);
  377. return;
  378. }
  379. PortletConfig pc = p.getPortletConfig();
  380. Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
  381. Entry entry = profile.getDocument().getEntryById(p.getID());
  382. // Only update the security ref if the parent changed
  383. if ((newSecurityParent != null)) {
  384. boolean securityChanged = false;
  385. SecurityReference currentSecurityRef = pc.getSecurityRef();
  386. if (currentSecurityRef != null) {
  387. securityChanged =
  388. (newSecurityParent.equals(currentSecurityRef.getParent()) == false);
  389. } else {
  390. securityChanged = (newSecurityParent.trim().length() > 0);
  391. }
  392. if (securityChanged == true) {
  393. SecurityReference securityRef = null;
  394. if ((newSecurityParent.trim().length() > 0)) {
  395. securityRef = new BaseSecurityReference();
  396. securityRef.setParent(newSecurityParent);
  397. }
  398. // Note: setting the portlet's config may not be a good idea -
  399. // it might be used as the Portlet for other PSMLDocument Entries that
  400. // have a different idea of security - and the caching of Portlets does
  401. // NOT include security -ggolden.
  402. pc.setSecurityRef(securityRef);
  403. entry.setSecurityRef(securityRef);
  404. madePcChange = true;
  405. }
  406. }
  407. // Only update the skin if the name changed
  408. if (newSkinName != null) {
  409. boolean skinChanged = false;
  410. String currentSkinName = null;
  411. if (pc.getSkin() != null) {
  412. currentSkinName = pc.getPortletSkin().getName();
  413. }
  414. if (currentSkinName != null) {
  415. skinChanged = (newSkinName.equals(currentSkinName) == false);
  416. } else {
  417. skinChanged = (newSkinName.trim().length() > 0);
  418. }
  419. if (skinChanged == true) {
  420. PortletSkin skin = null;
  421. if ((newSkinName.trim().length() > 0)) {
  422. skin = PortalToolkit.getSkin(newSkinName);
  423. if (skin != null) {
  424. // Note: setting the portlet's config may not be a good idea -
  425. // it might be used as the Portlet for other PSMLDocument Entries
  426. // that
  427. // have a different idea of skin - and the caching of Portlets does
  428. // NOT include skin -ggolden.
  429. pc.setPortletSkin(skin);
  430. Skin psmlSkin = entry.getSkin();
  431. if (psmlSkin == null) {
  432. entry.setSkin(new PsmlSkin());
  433. }
  434. entry.getSkin().setName(newSkinName);
  435. } else {
  436. logger.warn("Unable to update skin for portlet entry "
  437. + entry.getId()
  438. + " because skin does not exist.");
  439. }
  440. } else {
  441. // Note: setting the portlet's config may not be a good idea -
  442. // it might be used as the Portlet for other PSMLDocument Entries that
  443. // have a different idea of skin - and the caching of Portlets does
  444. // NOT include skin -ggolden.
  445. pc.setPortletSkin(null);
  446. entry.setSkin(null);
  447. }
  448. madePcChange = true;
  449. }
  450. }
  451. // Only update the title if the title changed
  452. if (newTitle != null) {
  453. boolean titleChanged = false;
  454. String currentTitle = entry.getTitle();
  455. MetaData md = pc.getMetainfo();
  456. if (currentTitle == null && md != null && md.getTitle() != null) {
  457. currentTitle = md.getTitle();
  458. }
  459. if (currentTitle != null) {
  460. titleChanged = (newTitle.equals(currentTitle) == false);
  461. } else {
  462. titleChanged = (newTitle.trim().length() > 0);
  463. }
  464. if (titleChanged == true) {
  465. if ((newTitle.trim().length() > 0)) {
  466. // Note: setting the portlet's config may not be a good idea -
  467. // it might be used as the Portlet for other PSMLDocument Entries that
  468. // have a different idea of title - and the caching of Portlets does
  469. // NOT include title -ggolden.
  470. if (md == null) {
  471. md = new MetaData();
  472. pc.setMetainfo(md);
  473. }
  474. md.setTitle(newTitle);
  475. entry.setTitle(newTitle);
  476. madePcChange = true;
  477. }
  478. }
  479. }
  480. // Update paramaters
  481. try {
  482. PortletInstance instance = PersistenceManager.getInstance(p, rundata);
  483. PortletEntry regEntry =
  484. (PortletEntry) Registry.getEntry(Registry.PORTLET, p.getName());
  485. Iterator<?> i = params.iterator();
  486. while (i.hasNext()) {
  487. Parameter param = (Parameter) i.next();
  488. String name = param.getName();
  489. String newValue = null;
  490. String[] testArray = rundata.getParameters().getStrings(name);
  491. if (testArray != null && testArray.length > 1) {
  492. newValue =
  493. org.apache.jetspeed.util.StringUtils.arrayToString(testArray, ",");
  494. } else {
  495. newValue = rundata.getParameters().getString(name);
  496. if (newValue == null) {
  497. newValue = "";
  498. }
  499. }
  500. String regValue =
  501. name.startsWith("pref-") ? "" : regEntry
  502. .getParameter(name)
  503. .getValue();
  504. String psmlValue = instance.getAttribute(name);
  505. // New value for this parameter exists
  506. if (newValue != null) {
  507. if (!regValue.equals(newValue) || !psmlValue.equals(newValue)) {
  508. instance.setAttribute(name, newValue);
  509. psmlValue = newValue;
  510. }
  511. madePsChange = true;
  512. }
  513. // Remove duplicate parameters from psml
  514. if (psmlValue != null && psmlValue.equals(regValue)) {
  515. instance.removeAttribute(name);
  516. madePsChange = true;
  517. }
  518. }
  519. // save all the changes
  520. if ((madePsChange == true) || (madePcChange == true)) {
  521. try {
  522. // JetspeedRunData jdata = (JetspeedRunData) rundata;
  523. profile.store();
  524. // FIXME: this hack is due to the corrupted lifecycle of the portlet
  525. // in the
  526. // current API when caching is activated
  527. p.init();
  528. org.apache.jetspeed.util.PortletSessionState.setPortletConfigChanged(
  529. p,
  530. rundata);
  531. } catch (PortletException e) {
  532. logger.error("Customizer failed to reinitialize the portlet "
  533. + p.getName(), e);
  534. } catch (Exception e) {
  535. logger.error("Unable to save profile ", e);
  536. }
  537. }
  538. // we're done, make sure clean up the
  539. // session
  540. doCancel(rundata, context);
  541. } catch (Exception e) {
  542. logger.error("Exception", e);
  543. }
  544. }
  545. }