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:
019: /**
020: * Handles ILF node edit directives recorded in the PLF.
021: *
022: * @version $Revision: 36299 $ $Date: 2005-11-11 14:05:08 -0700 (Fri, 11 Nov 2005) $
023: * @since uPortal 2.5
024: */
025: public class EditManager {
026: public static final String RCS_ID = "@(#) $Header$";
027:
028: private static RDBMDistributedLayoutStore dls = null;
029: private static final Log LOG = LogFactory.getLog(EditManager.class);
030:
031: /**
032: * Hands back the single instance of RDBMDistributedLayoutStore. There is
033: * already a method
034: * for aquiring a single instance of the configured layout store so we
035: * delegate over there so that all references refer to the same instance.
036: * This method is solely for convenience so that we don't have to keep
037: * calling UserLayoutStoreFactory and casting the resulting class.
038: */
039: private static RDBMDistributedLayoutStore getDLS() {
040: if (dls == null) {
041: IUserLayoutStore uls = null;
042: uls = UserLayoutStoreFactory.getUserLayoutStoreImpl();
043: dls = (RDBMDistributedLayoutStore) uls;
044: }
045: return dls;
046: }
047:
048: /**
049: Get the edit set if any stored in the passed in node. If not found and
050: if the create flag is true then create a new edit set and add it as a
051: child to the passed in node. Then return it.
052: */
053: private static Element getEditSet(Element node, Document plf,
054: IPerson person, boolean create) throws PortalException {
055: Node child = node.getFirstChild();
056:
057: while (child != null) {
058: if (child.getNodeName().equals(Constants.ELM_EDIT_SET))
059: return (Element) child;
060: child = child.getNextSibling();
061: }
062:
063: if (create == false)
064: return null;
065:
066: String ID = null;
067:
068: try {
069: ID = getDLS().getNextStructDirectiveId(person);
070: } catch (Exception e) {
071: throw new PortalException("Exception encountered while "
072: + "generating new edit set node "
073: + "Id for userId=" + person.getID(), e);
074: }
075: Element editSet = plf.createElement(Constants.ELM_EDIT_SET);
076: editSet
077: .setAttribute(Constants.ATT_TYPE,
078: Constants.ELM_EDIT_SET);
079: editSet.setAttribute(Constants.ATT_ID, ID);
080: node.appendChild(editSet);
081: return editSet;
082: }
083:
084: /**
085: Create and append an edit directive to the edit set if not there.
086: This only records that the attribute was changed
087: and the value in the plf copy node should be used, if
088: allowed, during the merge at login time.
089: */
090: static void addEditDirective(Element plfNode, String attributeName,
091: IPerson person) throws PortalException {
092: addDirective(plfNode, attributeName, Constants.ELM_EDIT, person);
093: }
094:
095: /**
096: Create and append a user preferences edit directive to the edit set if
097: not there. This only records that the attribute was changed. The value
098: will be in the user preferences object for the user.
099: */
100: public static void addPrefsDirective(Element plfNode,
101: String attributeName, IPerson person)
102: throws PortalException {
103: addDirective(plfNode, attributeName, Constants.ELM_PREF, person);
104: }
105:
106: /**
107: Create and append an edit directive to the edit set if not there.
108: */
109: private static void addDirective(Element plfNode,
110: String attributeName, String type, IPerson person)
111: throws PortalException {
112: Document plf = (Document) person.getAttribute(Constants.PLF);
113: Element editSet = getEditSet(plfNode, plf, person, true);
114:
115: // see if attributes has already been marked as being edited
116: Element child = (Element) editSet.getFirstChild();
117: Element edit = null;
118:
119: while (child != null && edit == null) {
120: if (child.getNodeName().equals(type)
121: && child.getAttribute(Constants.ATT_NAME).equals(
122: attributeName))
123: edit = child;
124: child = (Element) child.getNextSibling();
125: }
126: if (edit == null) // if not found then newly mark as edited
127: {
128: String ID = null;
129:
130: try {
131: ID = getDLS().getNextStructDirectiveId(person);
132: } catch (Exception e) {
133: throw new PortalException(
134: "Exception encountered while "
135: + "generating new edit node "
136: + "Id for userId=" + person.getID(), e);
137: }
138: edit = plf.createElement(type);
139: edit.setAttribute(Constants.ATT_TYPE, type);
140: edit.setAttribute(Constants.ATT_ID, ID);
141: edit.setAttribute(Constants.ATT_NAME, attributeName);
142: editSet.appendChild(edit);
143: }
144: }
145:
146: /**
147: Evaluate whether attribute changes exist in the ilfChild and if so
148: apply them. Returns true if some changes existed. If changes existed
149: but matched those in the original node then they are not applicable,
150: are removed from the editSet, and false is returned.
151: */
152: public static boolean applyEditSet(Element plfChild,
153: Element original) {
154: // first get edit set if it exists
155: Element editSet = null;
156: try {
157: editSet = getEditSet(plfChild, null, null, false);
158: } catch (Exception e) {
159: // should never occur unless problem during create in getEditSet
160: // and we are telling it not to create.
161: return false;
162: }
163:
164: if (editSet == null || editSet.getChildNodes().getLength() == 0)
165: return false;
166:
167: if (original.getAttribute(Constants.ATT_EDIT_ALLOWED).equals(
168: "false")) {
169: // can't change anymore so discard changes
170: plfChild.removeChild(editSet);
171: return false;
172: }
173:
174: Document ilf = original.getOwnerDocument();
175: boolean attributeChanged = false;
176: Element edit = (Element) editSet.getFirstChild();
177:
178: while (edit != null) {
179: String attribName = edit.getAttribute(Constants.ATT_NAME);
180: Attr attr = plfChild.getAttributeNode(attribName);
181:
182: // preferences are only updated at preference storage time so
183: // if a preference change exists in the edit set assume it is
184: // still valid so that the node being edited will persist in
185: // the PLF.
186: if (edit.getNodeName().equals(Constants.ELM_PREF))
187: attributeChanged = true;
188: else if (attr == null) {
189: // attribute removed. See if needs removing in original.
190: attr = original.getAttributeNode(attribName);
191: if (attr == null) // edit irrelevant,
192: editSet.removeChild(edit);
193: else {
194: // edit differs, apply to original
195: original.removeAttribute(attribName);
196: attributeChanged = true;
197: }
198: } else {
199: // attribute there, see if original is also there
200: Attr origAttr = original.getAttributeNode(attribName);
201: if (origAttr == null) {
202: // original attribute isn't defined so need to add
203: origAttr = (Attr) ilf.importNode(attr, true);
204: original.setAttributeNode(origAttr);
205: attributeChanged = true;
206: } else {
207: // original attrib found, see if different
208: if (attr.getValue().equals(origAttr.getValue())) {
209: // they are the same, edit irrelevant
210: editSet.removeChild(edit);
211: } else {
212: // edit differs, apply to original
213: origAttr.setValue(attr.getValue());
214: attributeChanged = true;
215: }
216: }
217: }
218: edit = (Element) edit.getNextSibling();
219: }
220: return attributeChanged;
221: }
222:
223: /**
224: * Searches for a dlm:pref command which indicates that a user preference
225: * was change and if found removes it from the user's PLF.
226: */
227: public static void removePreferenceDirective(IPerson person,
228: String elementId, String attributeName) {
229: removeDirective(elementId, attributeName, Constants.ELM_PREF,
230: person);
231: }
232:
233: /**
234: * Searches for a dlm:edit command which indicates that a node attribute was
235: * reset to the value in the fragment and if found removes it from the
236: * user's PLF.
237: */
238: public static void removeEditDirective(String elementId,
239: String attributeName, IPerson person) {
240: removeDirective(elementId, attributeName, Constants.ELM_EDIT,
241: person);
242: }
243:
244: /**
245: * Searches for a command of the passed-in type and if found removes it from
246: * the user's PLF.
247: */
248: private static void removeDirective(String elementId,
249: String attributeName, String type, IPerson person) {
250: Document plf = (Document) person.getAttribute(Constants.PLF);
251: Element node = plf.getElementById(elementId);
252: if (node == null)
253: return;
254:
255: Element editSet = null;
256:
257: try {
258: editSet = getEditSet(node, plf, person, false);
259: } catch (Exception e) {
260: /*
261: * we should never get here since we are calling getEditSet passing
262: * create=false meaning that the only portion of that method that
263: * tosses an exception will not be reached with this call. But if a
264: * runtime exception somehow occurs we will log it so that we don't
265: * lose the information.
266: */
267: LOG.error(e, e);
268: return;
269: }
270:
271: // if no edit set then the edit can't be there either
272: if (editSet == null)
273: return;
274:
275: Node child = editSet.getFirstChild();
276:
277: while (child != null) {
278: if (child.getNodeName().equals(type)) {
279: Attr attr = ((Element) child)
280: .getAttributeNode(Constants.ATT_NAME);
281: if (attr != null
282: && attr.getValue().equals(attributeName)) {
283: // we found it, remove it
284: editSet.removeChild(child);
285: break;
286: }
287: }
288: child = child.getNextSibling();
289: }
290: // if that was the last on in the edit set then delete it
291: if (editSet.getFirstChild() == null)
292: node.removeChild(editSet);
293: }
294: }
|