001: /* Copyright 2005 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.layout.dlm;
007:
008: import org.apache.commons.logging.Log;
009: import org.apache.commons.logging.LogFactory;
010: import org.jasig.portal.PortalException;
011: import org.jasig.portal.layout.IUserLayoutStore;
012: import org.jasig.portal.layout.UserLayoutStoreFactory;
013: import org.jasig.portal.security.IPerson;
014: import org.w3c.dom.Attr;
015: import org.w3c.dom.Document;
016: import org.w3c.dom.Element;
017: import org.w3c.dom.Node;
018: import org.w3c.dom.NodeList;
019:
020: /**
021: * Looks for, applies against the ilf, and updates accordingly within the plf
022: * the set of parameter edits made against channels incorporated from fragments.
023: *
024: * @version $Revision: 36476 $ $Date: 2006-02-07 15:05:10 -0700 (Tue, 07 Feb 2006) $
025: * @since uPortal 2.6
026: */
027: public class ParameterEditManager {
028: public static final String RCS_ID = "@(#) $Header$";
029: private static final Log LOG = LogFactory
030: .getLog(ParameterEditManager.class);
031:
032: private static RDBMDistributedLayoutStore dls = null;
033:
034: /**
035: * Hands back the single instance of RDBMDistributedLayoutStore. There is
036: * already a method for aquiring a single instance of the configured layout
037: * store so we delegate over there so that all references refer to the same
038: * instance. This method is solely for convenience so that we don't have to
039: * keep calling UserLayoutStoreFactory and casting the resulting class.
040: */
041: private static RDBMDistributedLayoutStore getDLS() {
042: if (dls == null) {
043: IUserLayoutStore uls = null;
044: uls = UserLayoutStoreFactory.getUserLayoutStoreImpl();
045: dls = (RDBMDistributedLayoutStore) uls;
046: }
047: return dls;
048: }
049:
050: /**
051: Get the parm edit set if any from the plf and process each edit command
052: removing any that fail from the set so that the set is self cleaning.
053: * @throws Exception
054: */
055: static void applyAndUpdateParmEditSet(Document plf, Document ilf,
056: IntegrationResult result) {
057:
058: Element pSet = null;
059: try {
060: pSet = getParmEditSet(plf, null, false);
061: } catch (Exception e) {
062: LOG.error("Exception occurred while getting user's DLM "
063: + "paramter-edit-set.", e);
064: }
065:
066: if (pSet == null)
067: return;
068:
069: NodeList edits = pSet.getChildNodes();
070:
071: for (int i = edits.getLength() - 1; i >= 0; i--) {
072: if (applyEdit((Element) edits.item(i), ilf) == false) {
073: pSet.removeChild(edits.item(i));
074: result.changedPLF = true;
075: } else {
076: result.changedILF = true;
077: }
078: }
079:
080: if (pSet.getChildNodes().getLength() == 0) {
081: plf.getDocumentElement().removeChild(pSet);
082: result.changedPLF = true;
083: }
084: }
085:
086: /**
087: * Attempt to apply a single channel parameter edit command and return true
088: * if it succeeds or false otherwise. If the edit is disallowed or the
089: * target element no longer exists in the document the edit command fails
090: * and returns false.
091: * @throws Exception
092: */
093: private static boolean applyEdit(Element edit, Document ilf) {
094: String nodeID = edit.getAttribute(Constants.ATT_TARGET);
095:
096: Element channel = ilf.getElementById(nodeID);
097:
098: if (channel == null)
099: return false;
100:
101: // now get the name of the parameter to be edited and find that element
102: String parmName = edit.getAttribute(Constants.ATT_NAME);
103: String parmValue = edit.getAttribute(Constants.ATT_USER_VALUE);
104: NodeList ilfParms = channel.getChildNodes();
105: Element targetParm = null;
106:
107: for (int i = 0; i < ilfParms.getLength(); i++) {
108: Element ilfParm = (Element) ilfParms.item(i);
109: if (ilfParm.getAttribute(Constants.ATT_NAME).equals(
110: parmName)) {
111: targetParm = ilfParm;
112: break;
113: }
114: }
115: if (targetParm == null) // parameter not found so we are free to set
116: {
117: Element parameter = ilf.createElement("parameter");
118: parameter.setAttribute("name", parmName);
119: parameter.setAttribute("value", parmValue);
120: parameter.setAttribute("override", "yes");
121: channel.appendChild(parameter);
122: return true;
123: }
124: /* TODO Add support for fragments to set dlm:editAllowed attribute for
125: * channel parameters. (2005.11.04 mboyd)
126: *
127: * In the commented code below, the check for editAllowed will never be
128: * seen on a parameter element in the
129: * current database schema approach used by DLM. This is because
130: * parameters are second class citizens of the layout structure. They
131: * are not found in the up_layout_struct table but only in the
132: * up_layout_param table. DLM functionality like dlm:editAllowed,
133: * dlm:moveAllowed, dlm:deleteAllowed, and dlm:addChildAllowed were
134: * implemented without schema changes by adding these as parameters to
135: * structural elements and upon loading any parameter that begins with
136: * 'dlm:' is placed as an attribute on the containing structural
137: * element. So any channel parameter entry with dlm:editAllowed has that
138: * value placed as an attribute on the containing channel not on the
139: * parameter that was meant to have it.
140: *
141: * The only solution would be to add special dlm:parm children below
142: * channels that would get the editAllowed value and then when creating
143: * the DOM don't create those as child elements but use them to set the
144: * attribute on the corresponding parameter by having the name of the
145: * dlm:parm element be the name of the parameter to which it is to be
146: * related.
147: *
148: * The result of this lack of functionality is that fragments can't
149: * mark any channel parameters as dlm:editAllowed='false' thereby
150: * further restricting which channel parameters can be edited beyond
151: * what the channel definition specifies during publishing.
152: */
153: //Attr editAllowed = targetParm.getAttributeNode( Constants.ATT_EDIT_ALLOWED );
154: //if ( editAllowed != null && editAllowed.getNodeValue().equals("false"))
155: // return false;
156: // target parm found. See if channel definition will still allow changes.
157: Attr override = targetParm
158: .getAttributeNode(Constants.ATT_OVERRIDE);
159: if (override != null
160: && !override.getNodeValue().equals(
161: Constants.CAN_OVERRIDE))
162: return false;
163:
164: // now see if the change is still needed
165: if (targetParm.getAttribute(Constants.ATT_VALUE).equals(
166: parmValue))
167: return false; // user's edit same as fragment or chan def
168:
169: targetParm.setAttribute("value", parmValue);
170: return true;
171: }
172:
173: /**
174: * Get the parameter edits set if any stored in the root of the document or
175: * create it if passed-in create flag is true.
176: */
177: private static Element getParmEditSet(Document plf, IPerson person,
178: boolean create) throws PortalException {
179: Node root = plf.getDocumentElement();
180: Node child = root.getFirstChild();
181:
182: while (child != null) {
183: if (child.getNodeName().equals(Constants.ELM_PARM_SET))
184: return (Element) child;
185: child = child.getNextSibling();
186: }
187:
188: if (create == false)
189: return null;
190:
191: String ID = null;
192:
193: try {
194: ID = getDLS().getNextStructDirectiveId(person);
195: } catch (Exception e) {
196: throw new PortalException("Exception encountered while "
197: + "generating new parameter edit set node "
198: + "Id for userId=" + person.getID(), e);
199: }
200: Element parmSet = plf.createElement(Constants.ELM_PARM_SET);
201: parmSet
202: .setAttribute(Constants.ATT_TYPE,
203: Constants.ELM_PARM_SET);
204: parmSet.setAttribute(Constants.ATT_ID, ID);
205: parmSet.setIdAttribute(Constants.ATT_ID, true);
206: root.appendChild(parmSet);
207: return parmSet;
208: }
209:
210: /**
211: * Create and append a parameter edit directive to parameter edits set for
212: * applying a user specified value to a named parameter of the incorporated
213: * channel represented by the passed-in target id. If one already exists
214: * for that node and that name then the value of the existing edit is
215: * changed to the passed-in value.
216: */
217: public static synchronized void addParmEditDirective(
218: Element compViewChannelNode, String targetId, String name,
219: String value, IPerson person) throws PortalException {
220: Document plf = (Document) person.getAttribute(Constants.PLF);
221: Element parmSet = getParmEditSet(plf, person, true);
222: NodeList edits = parmSet.getChildNodes();
223: Element existingEdit = null;
224:
225: for (int i = 0; i < edits.getLength(); i++) {
226: Element edit = (Element) edits.item(i);
227: if (edit.getAttribute(Constants.ATT_TARGET)
228: .equals(targetId)
229: && edit.getAttribute(Constants.ATT_NAME).equals(
230: name)) {
231: existingEdit = edit;
232: break;
233: }
234: }
235: if (existingEdit == null) // existing one not found, create a new one
236: {
237: addParmEditDirective(targetId, name, value, person, plf,
238: parmSet);
239: return;
240: }
241: existingEdit.setAttribute(Constants.ATT_USER_VALUE, value);
242: }
243:
244: /**
245: This method does the actual work of adding a newly created parameter
246: edit and adding it to the parameter edits set.
247: */
248: private static void addParmEditDirective(String targetID,
249: String name, String value, IPerson person, Document plf,
250: Element parmSet) throws PortalException {
251:
252: String ID = null;
253:
254: try {
255: ID = getDLS().getNextStructDirectiveId(person);
256: } catch (Exception e) {
257: throw new PortalException("Exception encountered while "
258: + "generating new parameter edit node "
259: + "Id for userId=" + person.getID(), e);
260: }
261: Element parm = plf.createElement(Constants.ELM_PARM_EDIT);
262: parm.setAttribute(Constants.ATT_TYPE, Constants.ELM_PARM_EDIT);
263: parm.setAttribute(Constants.ATT_ID, ID);
264: parm.setIdAttribute(Constants.ATT_ID, true);
265: parm.setAttributeNS(Constants.NS_URI, Constants.ATT_TARGET,
266: targetID);
267: parm.setAttribute(Constants.ATT_NAME, name);
268: parm.setAttribute(Constants.ATT_USER_VALUE, value);
269: parmSet.appendChild(parm);
270: }
271:
272: /**
273: * Remove a parameter edit directive from the parameter edits set for
274: * applying user specified values to a named parameter of an incorporated
275: * channel represented by the passed-in target id. If one doesn't exists
276: * for that node and that name then this call returns without any effects.
277: */
278: public static void removeParmEditDirective(String targetId,
279: String name, IPerson person) throws PortalException {
280: Document plf = (Document) person.getAttribute(Constants.PLF);
281: Element parmSet = getParmEditSet(plf, person, false);
282:
283: if (parmSet == null)
284: return; // no set so no edit to remove
285:
286: NodeList edits = parmSet.getChildNodes();
287:
288: for (int i = 0; i < edits.getLength(); i++) {
289: Element edit = (Element) edits.item(i);
290: if (edit.getAttribute(Constants.ATT_TARGET)
291: .equals(targetId)
292: && edit.getAttribute(Constants.ATT_NAME).equals(
293: name)) {
294: parmSet.removeChild(edit);
295: break;
296: }
297: }
298: if (parmSet.getChildNodes().getLength() == 0) // no more edits, remove
299: {
300: Node parent = parmSet.getParentNode();
301: parent.removeChild(parmSet);
302: }
303: }
304: }
|