001: /* Copyright 2003 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.alm;
007:
008: import java.util.Enumeration;
009: import java.util.HashSet;
010: import java.util.Hashtable;
011: import java.util.Iterator;
012: import java.util.Map;
013: import java.util.Set;
014: import java.util.Vector;
015:
016: import org.apache.commons.logging.Log;
017: import org.apache.commons.logging.LogFactory;
018: import org.jasig.portal.PortalException;
019: import org.jasig.portal.layout.LayoutEventListener;
020: import org.jasig.portal.layout.node.IUserLayoutFolderDescription;
021: import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
022: import org.jasig.portal.layout.restrictions.IUserLayoutRestriction;
023: import org.jasig.portal.layout.restrictions.alm.PriorityRestriction;
024: import org.jasig.portal.layout.restrictions.alm.RestrictionTypes;
025: import org.jasig.portal.utils.CommonUtils;
026: import org.jasig.portal.utils.GuidGenerator;
027: import org.w3c.dom.Document;
028: import org.w3c.dom.Element;
029: import org.w3c.dom.Node;
030: import org.xml.sax.ContentHandler;
031: import org.xml.sax.SAXException;
032: import org.xml.sax.helpers.AttributesImpl;
033:
034: /**
035: * The aggregated user layout implementation.
036: *
037: * Prior to uPortal 2.5, this class existed in the package org.jasig.portal.layout.
038: * It was moved to its present package to reflect that it is part of Aggregated
039: * Layouts.
040: *
041: * @author <a href="mailto:mvi@immagic.com">Michael Ivanov</a>
042: * @version $Revision: 42355 $
043: */
044: public class AggregatedLayout implements IAggregatedLayout {
045: private static final Log LOG = LogFactory
046: .getLog(AggregatedLayout.class);
047:
048: // The hashtable with the layout nodes
049: private Hashtable layout = null;
050:
051: // The layout ID value
052: private String layoutId;
053:
054: // The layout manager
055: private IAggregatedUserLayoutManager layoutManager = null;
056:
057: // GUID generator
058: private static GuidGenerator guid = null;
059: private String cacheKey = null;
060:
061: public AggregatedLayout(String layoutId,
062: IAggregatedUserLayoutManager layoutManager)
063: throws PortalException {
064: this (layoutId);
065: this .layoutManager = layoutManager;
066: }
067:
068: public AggregatedLayout(String layoutId) throws PortalException {
069: this .layoutId = layoutId;
070: if (guid == null)
071: guid = new GuidGenerator();
072: updateCacheKey();
073: }
074:
075: public void setLayoutManager(
076: IAggregatedUserLayoutManager layoutManager) {
077: this .layoutManager = layoutManager;
078: }
079:
080: public void setLayoutData(Hashtable layout) throws PortalException {
081: // check that layout isn't corrupt
082: for (Enumeration nodeIds = layout.keys(); nodeIds
083: .hasMoreElements();) {
084: String nodeId = nodeIds.nextElement().toString();
085: ALNode node = (ALNode) layout.get(nodeId);
086: // check for nodes that reference themselves
087: if (node != null
088: && (nodeId.equals(node.getNextNodeId())
089: || nodeId.equals(node.getPreviousNodeId()) || nodeId
090: .equals(node.getParentNodeId()))) {
091: throw new RuntimeException(
092: "corrupted layout detected, node: " + nodeId
093: + " " + "layout:" + layout);
094: }
095: }
096: this .layout = layout;
097: }
098:
099: public Hashtable getLayoutData() throws PortalException {
100: return layout;
101: }
102:
103: private void updateCacheKey() {
104: cacheKey = guid.getNewGuid();
105: }
106:
107: private void bindRestrictions(IALNodeDescription nodeDesc,
108: ContentHandler contentHandler) throws SAXException {
109: Hashtable restrictions = nodeDesc.getRestrictions();
110: if (restrictions != null) {
111: for (Enumeration e = restrictions.elements(); e
112: .hasMoreElements();) {
113: IUserLayoutRestriction restriction = (IUserLayoutRestriction) e
114: .nextElement();
115: AttributesImpl paramAttrs = new AttributesImpl();
116: paramAttrs.addAttribute("", "path", "path", "CDATA",
117: restriction.getRestrictionPath());
118: // we have to re-scale the priority restriction for the UI
119: if (restriction.getName().equals(
120: RestrictionTypes.PRIORITY_RESTRICTION)) {
121: PriorityRestriction priorRestriction = (PriorityRestriction) restriction;
122: paramAttrs
123: .addAttribute(
124: "",
125: "value",
126: "value",
127: "CDATA",
128: ((int) priorRestriction
129: .getMinValue() / IAggregatedUserLayoutManager.PRIORITY_COEFF)
130: + "-"
131: + ((int) priorRestriction
132: .getMaxValue() / IAggregatedUserLayoutManager.PRIORITY_COEFF));
133: } else
134: paramAttrs.addAttribute("", "value", "value",
135: "CDATA", restriction
136: .getRestrictionExpression());
137:
138: paramAttrs.addAttribute("", "type", "type", "CDATA",
139: restriction.getName());
140: contentHandler.startElement("", RESTRICTION,
141: RESTRICTION, paramAttrs);
142: contentHandler.endElement("", RESTRICTION, RESTRICTION);
143: }
144: }
145: }
146:
147: public ALNode getLayoutNode(String nodeId) {
148: if (nodeId != null) {
149: ALNode aln = (ALNode) layout.get(nodeId);
150: if (aln != null
151: && (nodeId.equals(aln.getNextNodeId())
152: || nodeId.equals(aln.getPreviousNodeId()) || nodeId
153: .equals(aln.getParentNodeId()))) {
154: throw new RuntimeException(
155: "corrupted layout detected, node: " + nodeId
156: + " " + "layout:" + layout);
157: }
158: return aln;
159: }
160: return null;
161: }
162:
163: public ALFolder getLayoutFolder(String folderId) {
164: if (folderId != null) {
165: ALFolder aln = (ALFolder) layout.get(folderId);
166: if (aln != null
167: && (folderId.equals(aln.getNextNodeId())
168: || folderId.equals(aln.getPreviousNodeId()) || folderId
169: .equals(aln.getParentNodeId()))) {
170: throw new RuntimeException(
171: "corrupted layout detected, node: " + folderId
172: + " " + "layout:" + layout);
173: }
174: return aln;
175: }
176: return null;
177: }
178:
179: public ALNode getLastSiblingNode(final String nodeIdArg) {
180: ALNode node = null;
181: for (String nextId = nodeIdArg; nextId != null;) {
182: node = getLayoutNode(nextId);
183: nextId = node.getNextNodeId();
184:
185: if (nodeIdArg.equals(nextId)) {
186: throw new RuntimeException(
187: "getLastSiblingNode of ["
188: + nodeIdArg
189: + "] encountered that same node ID in tracing the siblings of the node. "
190: + "This results in an unfortunate infinite loop. This layout is corrupted and needs to be deleted or manually fixed.");
191:
192: }
193: }
194: return node;
195: }
196:
197: public ALNode getFirstSiblingNode(final String nodeIdArg) {
198: ALNode node = null;
199: for (String prevId = nodeIdArg; prevId != null;) {
200: node = getLayoutNode(prevId);
201: prevId = node.getPreviousNodeId();
202:
203: if (nodeIdArg.equals(prevId)) {
204: throw new RuntimeException(
205: "getFirstSiblingNode of ["
206: + nodeIdArg
207: + "] encountered that same node ID in tracing the siblings of the node. "
208: + "This results in an unfortunate infinite loop. This layout is corrupted and needs to be deleted or manually fixed.");
209:
210: }
211: }
212: return node;
213: }
214:
215: /**
216: * Gets the tree depth for a given node
217: * @param nodeId a <code>String</code> node ID
218: * @return a depth value
219: * @exception PortalException if an error occurs
220: */
221: public int getDepth(String nodeId) throws PortalException {
222: int depth = 0;
223: for (String parentId = getParentId(nodeId); parentId != null; parentId = getParentId(parentId), depth++) {
224: // do nothing
225: }
226: return depth;
227: }
228:
229: private void createMarkingLeaf(ContentHandler contentHandler,
230: String leafName, String parentNodeId, String nextNodeId)
231: throws PortalException {
232: try {
233: AttributesImpl attributes = new AttributesImpl();
234: attributes.addAttribute("", "parentID", "parentID",
235: "CDATA", parentNodeId);
236: attributes.addAttribute("", "nextID", "nextID", "CDATA",
237: CommonUtils.nvl(nextNodeId));
238: contentHandler.startElement("", leafName, leafName,
239: attributes);
240: contentHandler.endElement("", leafName, leafName);
241: } catch (SAXException saxe) {
242: throw new PortalException(saxe);
243: }
244: }
245:
246: private void createMarkingLeaf(Document document, String leafName,
247: String parentNodeId, String nextNodeId, Node node)
248: throws PortalException {
249: try {
250: Element markingLeaf = document.createElement(leafName);
251: markingLeaf.setAttribute("parentID", parentNodeId);
252: markingLeaf.setAttribute("nextID", nextNodeId);
253: node.appendChild(markingLeaf);
254: } catch (Exception saxe) {
255: throw new PortalException(saxe);
256: }
257: }
258:
259: /**
260: * Build the DOM consistent of folders and channels using the internal representation
261: * @param domLayout a <code>Document</code> a user layout document.
262: * @param node a <code>Element</code> a node that will be used as a root for the tree construction
263: * @param nodeId a <code>String</code> a nodeId from the user layout internal representation
264: * @exception PortalException if an error occurs
265: */
266: private void appendDescendants(Document domLayout, Node node,
267: String nodeId) throws PortalException {
268: ALNode layoutNode = getLayoutNode(nodeId);
269: IALNodeDescription nodeDesc = (IALNodeDescription) layoutNode
270: .getNodeDescription();
271: Element newNode = domLayout
272: .createElement((layoutNode.getNodeType() == IUserLayoutNodeDescription.FOLDER) ? FOLDER
273: : CHANNEL);
274:
275: layoutNode.addNodeAttributes(newNode);
276:
277: String parentId = layoutNode.getParentNodeId();
278: String nextId = layoutNode.getNextNodeId();
279:
280: if (layoutManager != null && parentId != null
281: && layoutNode.getPreviousNodeId() == null) {
282: if (!nodeDesc.isHidden()
283: && !getLayoutNode(parentId).getNodeDescription()
284: .isHidden()) {
285: IALNodeDescription moveTargetsNodeDesc = layoutManager
286: .getNodeBeingMoved();
287: String moveTargetsNodeId = (moveTargetsNodeDesc != null) ? moveTargetsNodeDesc
288: .getId()
289: : null;
290: IALNodeDescription addTargetsNodeDesc = layoutManager
291: .getNodeBeingAdded();
292: if (addTargetsNodeDesc != null
293: && layoutManager.canAddNode(addTargetsNodeDesc,
294: parentId, nodeId))
295: createMarkingLeaf(domLayout, ADD_TARGET, parentId,
296: nodeId, node);
297:
298: if (moveTargetsNodeId != null
299: && layoutManager.canMoveNode(moveTargetsNodeId,
300: parentId, nodeId))
301: createMarkingLeaf(domLayout, MOVE_TARGET, parentId,
302: nodeId, node);
303: }
304: }
305:
306: // Appending a new node
307: node.appendChild(newNode);
308:
309: if (parentId != null) {
310:
311: boolean isNodeMarkable = false;
312: if (nextId != null
313: && !getLayoutNode(nextId).getNodeDescription()
314: .isHidden())
315: isNodeMarkable = true;
316: else if (nextId == null)
317: isNodeMarkable = true;
318:
319: if (layoutManager != null && isNodeMarkable) {
320: ALNode tempNode = getLayoutNode(parentId);
321: if (tempNode == null) {
322: throw new RuntimeException("getLayoutNode("
323: + parentId + ") returned null");
324: }
325: IUserLayoutNodeDescription desc = tempNode
326: .getNodeDescription();
327: if (desc == null) {
328: throw new RuntimeException(
329: "getNodeDescription() returned null. tempNode: "
330: + tempNode);
331: }
332: if (!desc.isHidden()) {
333: IALNodeDescription moveTargetsNodeDesc = layoutManager
334: .getNodeBeingMoved();
335: String moveTargetsNodeId = (moveTargetsNodeDesc != null) ? moveTargetsNodeDesc
336: .getId()
337: : null;
338: IALNodeDescription addTargetsNodeDesc = layoutManager
339: .getNodeBeingAdded();
340: if (addTargetsNodeDesc != null
341: && layoutManager.canAddNode(
342: addTargetsNodeDesc, parentId,
343: nextId)) {
344: createMarkingLeaf(domLayout, ADD_TARGET,
345: parentId, nextId, node);
346: }
347: if (moveTargetsNodeId != null
348: && !moveTargetsNodeId.equals(nextId)
349: && layoutManager
350: .canMoveNode(moveTargetsNodeId,
351: parentId, nextId)) {
352: createMarkingLeaf(domLayout, MOVE_TARGET,
353: parentId, nextId, node);
354: }
355: }
356: }
357:
358: }
359:
360: // Adding restrictions to the node
361: nodeDesc.addRestrictionChildren(newNode, domLayout);
362: if (layoutNode.getNodeType() == IUserLayoutNodeDescription.FOLDER) {
363: // Loop for all children
364: String firstChildId = ((ALFolder) layoutNode)
365: .getFirstChildNodeId();
366: for (String nextNodeId = firstChildId; nextNodeId != null;) {
367: // !!!!!!!!!!!
368: appendDescendants(domLayout, newNode, nextNodeId);
369: nextNodeId = getLayoutNode(nextNodeId).getNextNodeId();
370: }
371: } else if (layoutNode.getNodeType() == IUserLayoutNodeDescription.CHANNEL) {
372: ALChannelDescription channelDesc = (ALChannelDescription) nodeDesc;
373: // Adding channel parameters
374: channelDesc.addParameterChildren(newNode, domLayout);
375: }
376: }
377:
378: /**
379: * Returns a list of fragment Ids existing in the layout.
380: *
381: * @return a <code>Set</code> of <code>String</code> fragment Ids.
382: * @exception PortalException if an error occurs
383: */
384: public Set getFragmentIds() throws PortalException {
385: Set fragmentIds = new HashSet();
386: for (Enumeration nodes = layout.elements(); nodes
387: .hasMoreElements();) {
388: ALNode node = (ALNode) nodes.nextElement();
389: String fragmentId = node.getFragmentId();
390: if (fragmentId != null && !fragmentIds.contains(fragmentId))
391: fragmentIds.add(fragmentId);
392: }
393: return fragmentIds;
394: }
395:
396: /**
397: * Returns an fragment Id for a given node.
398: * Returns null if the node is not part of any fragments.
399: *
400: * @param nodeId a <code>String</code> value
401: * @return a <code>String</code> fragment Id
402: * @exception PortalException if an error occurs
403: */
404: public String getFragmentId(String nodeId) throws PortalException {
405: return getNode(nodeId).getFragmentId();
406: }
407:
408: /**
409: * Returns an fragment root Id for a given fragment.
410: *
411: * @param fragmentId a <code>String</code> value
412: * @return a <code>String</code> fragment root Id
413: * @exception PortalException if an error occurs
414: */
415: public String getFragmentRootId(String fragmentId)
416: throws PortalException {
417: ILayoutFragment fragment = layoutManager
418: .getFragment(fragmentId);
419: if (fragment != null && (fragment instanceof ALFragment)) {
420: ALFolder rootFolder = (ALFolder) ((ALFragment) fragment)
421: .getNode(fragment.getRootId());
422: return rootFolder.getFirstChildNodeId();
423: }
424: throw new PortalException("Check that the fragment with ID="
425: + fragmentId + " has " + ALFragment.class.getName()
426: + " type and is not NULL!");
427: }
428:
429: /**
430: * Writes user layout content (with appropriate markings) into
431: * a <code>ContentHandler</code>
432: *
433: * @param ch a <code>ContentHandler</code> value
434: * @exception PortalException if an error occurs
435: */
436: public void writeTo(ContentHandler ch) throws PortalException {
437: writeTo(getRootId(), ch);
438: }
439:
440: /**
441: * Writes subtree of a user layout (with appropriate markings) defined by a particular node into
442: * a <code>ContentHandler</code>
443: *
444: * @param nodeId a <code>String</code> a node determining a user layout subtree.
445: * @param contentHandler a <code>ContentHandler</code> value
446: * @exception PortalException if an error occurs
447: */
448: public void writeTo(String nodeId, ContentHandler contentHandler)
449: throws PortalException {
450:
451: IALFolderDescription folderDescription = null;
452: IALChannelDescription channelDescription = null;
453:
454: if (contentHandler != null && nodeId != null) {
455: try {
456:
457: ALNode node = getLayoutNode(nodeId);
458: AttributesImpl attributes = new AttributesImpl();
459:
460: // If we have a folder
461: if (node.getNodeType() == IUserLayoutNodeDescription.FOLDER) {
462:
463: // Start document if we have the root node
464: if (nodeId.equals(getRootId()))
465: contentHandler.startDocument();
466:
467: if (nodeId.equals(getRootId())) {
468: contentHandler.startElement("", LAYOUT, LAYOUT,
469: new AttributesImpl());
470: }
471:
472: ALFolder folder = (ALFolder) node;
473: folderDescription = (IALFolderDescription) node
474: .getNodeDescription();
475: attributes.addAttribute("", "ID", "ID", "ID",
476: nodeId);
477: attributes
478: .addAttribute(
479: "",
480: "type",
481: "type",
482: "CDATA",
483: IUserLayoutFolderDescription.folderTypeNames[folderDescription
484: .getFolderType()]);
485: attributes.addAttribute("", "hidden", "hidden",
486: "CDATA", CommonUtils
487: .boolToStr(folderDescription
488: .isHidden()));
489: attributes.addAttribute("", "unremovable",
490: "unremovable", "CDATA", CommonUtils
491: .boolToStr(folderDescription
492: .isUnremovable()));
493: attributes.addAttribute("", "immutable",
494: "immutable", "CDATA", CommonUtils
495: .boolToStr(folderDescription
496: .isImmutable()));
497: attributes.addAttribute("", "name", "name",
498: "CDATA", folderDescription.getName());
499: attributes.addAttribute("", "priority", "priority",
500: "CDATA", folder.getPriority() + "");
501:
502: // if the node has additional attributes, apply them
503: Map nodeAttributes = node.getAttributes();
504: for (Iterator attributeNameIter = nodeAttributes
505: .keySet().iterator(); attributeNameIter
506: .hasNext();) {
507: String attributeName = (String) attributeNameIter
508: .next();
509: String attributeValue = (String) nodeAttributes
510: .get(attributeName);
511: attributes.addAttribute("", attributeName,
512: attributeName, "CDATA", attributeValue);
513: }
514:
515: contentHandler.startElement("", FOLDER, FOLDER,
516: attributes);
517:
518: // Loop for all children
519: String firstChildId = folder.getFirstChildNodeId();
520: for (String nextNodeId = firstChildId; nextNodeId != null;) {
521:
522: // if necessary we add marking nodes
523: if (layoutManager != null) {
524: if (!node.getNodeDescription().isHidden()
525: && !getLayoutNode(nextNodeId)
526: .getNodeDescription()
527: .isHidden()) {
528: IALNodeDescription nodeDesc = layoutManager
529: .getNodeBeingMoved();
530: String moveTargetsNodeId = (nodeDesc != null) ? nodeDesc
531: .getId()
532: : null;
533: IALNodeDescription addTargetsNodeDesc = layoutManager
534: .getNodeBeingAdded();
535: if (addTargetsNodeDesc != null
536: && layoutManager.canAddNode(
537: addTargetsNodeDesc,
538: nodeId, nextNodeId))
539: createMarkingLeaf(contentHandler,
540: ADD_TARGET, nodeId,
541: nextNodeId);
542: if (moveTargetsNodeId != null
543: && !moveTargetsNodeId
544: .equals(nextNodeId)
545: && layoutManager.canMoveNode(
546: moveTargetsNodeId,
547: nodeId, nextNodeId))
548: createMarkingLeaf(contentHandler,
549: MOVE_TARGET, nodeId,
550: nextNodeId);
551: }
552: }
553:
554: // Recurrence
555: writeTo(nextNodeId, contentHandler);
556: nextNodeId = getLayoutNode(nextNodeId)
557: .getNextNodeId();
558: }
559:
560: // if necessary we add marking nodes to the end of the sibling line
561: if (layoutManager != null
562: && !node.getNodeDescription().isHidden()) {
563: IALNodeDescription nodeDesc = layoutManager
564: .getNodeBeingMoved();
565: String moveTargetsNodeId = (nodeDesc != null) ? nodeDesc
566: .getId()
567: : null;
568: IALNodeDescription addTargetsNodeDesc = layoutManager
569: .getNodeBeingAdded();
570: if (addTargetsNodeDesc != null
571: && layoutManager.canAddNode(
572: addTargetsNodeDesc, nodeId,
573: null))
574: createMarkingLeaf(contentHandler,
575: ADD_TARGET, nodeId, null);
576: if (moveTargetsNodeId != null
577: && layoutManager
578: .canMoveNode(moveTargetsNodeId,
579: nodeId, null))
580: createMarkingLeaf(contentHandler,
581: MOVE_TARGET, nodeId, null);
582: }
583:
584: // Putting restrictions to the content handler
585: bindRestrictions(folderDescription, contentHandler);
586:
587: contentHandler.endElement("", FOLDER, FOLDER);
588:
589: // Start document if we have the root node
590: if (nodeId.equals(getRootId()))
591: contentHandler.endElement("", LAYOUT, LAYOUT);
592: if (nodeId.equals(getRootId()))
593: contentHandler.endDocument();
594:
595: // If we have a channel
596: } else {
597:
598: channelDescription = (IALChannelDescription) node
599: .getNodeDescription();
600:
601: attributes.addAttribute("", "ID", "ID", "ID",
602: nodeId);
603: attributes.addAttribute("", "typeID", "typeID",
604: "CDATA", channelDescription
605: .getChannelTypeId());
606: attributes.addAttribute("", "hidden", "hidden",
607: "CDATA", CommonUtils
608: .boolToStr(channelDescription
609: .isHidden()));
610: attributes.addAttribute("", "editable", "editable",
611: "CDATA", CommonUtils
612: .boolToStr(channelDescription
613: .isEditable()));
614: attributes.addAttribute("", "unremovable",
615: "unremovable", "CDATA", CommonUtils
616: .boolToStr(channelDescription
617: .isUnremovable()));
618: attributes.addAttribute("", "immutable",
619: "immutable", "CDATA", CommonUtils
620: .boolToStr(channelDescription
621: .isImmutable()));
622: attributes.addAttribute("", "name", "name",
623: "CDATA", channelDescription.getName());
624: attributes.addAttribute("", "description",
625: "description", "CDATA", channelDescription
626: .getDescription());
627: attributes.addAttribute("", "title", "title",
628: "CDATA", channelDescription.getTitle());
629: attributes.addAttribute("", "class", "class",
630: "CDATA", channelDescription.getClassName());
631: attributes.addAttribute("", "chanID", "chanID",
632: "CDATA", channelDescription
633: .getChannelPublishId());
634: attributes.addAttribute("", "fname", "fname",
635: "CDATA", channelDescription
636: .getFunctionalName());
637: attributes.addAttribute("", "timeout", "timeout",
638: "CDATA", String.valueOf(channelDescription
639: .getTimeout()));
640: attributes.addAttribute("", "hasHelp", "hasHelp",
641: "CDATA", CommonUtils
642: .boolToStr(channelDescription
643: .hasHelp()));
644: attributes.addAttribute("", "hasAbout", "hasAbout",
645: "CDATA", CommonUtils
646: .boolToStr(channelDescription
647: .hasAbout()));
648: attributes.addAttribute("", "secure", "secure",
649: "CDATA", CommonUtils
650: .boolToStr(channelDescription
651: .isSecure()));
652: attributes.addAttribute("", "isPortlet",
653: "isPortlet", "CDATA", CommonUtils
654: .boolToStr(channelDescription
655: .isPortlet()));
656: attributes.addAttribute("", "priority", "priority",
657: "CDATA", node.getPriority() + "");
658:
659: contentHandler.startElement("", CHANNEL, CHANNEL,
660: attributes);
661:
662: if (channelDescription.hasParameters()) {
663: Enumeration paramNames = channelDescription
664: .getParameterNames();
665: while (paramNames.hasMoreElements()) {
666: String name = (String) paramNames
667: .nextElement();
668: String value = channelDescription
669: .getParameterValue(name);
670: AttributesImpl paramAttrs = new AttributesImpl();
671: paramAttrs.addAttribute("", "name", "name",
672: "CDATA", name);
673: paramAttrs.addAttribute("", "value",
674: "value", "CDATA", value);
675: paramAttrs
676: .addAttribute(
677: "",
678: "override",
679: "override",
680: "CDATA",
681: channelDescription
682: .canOverrideParameter(name) ? "yes"
683: : "no");
684: contentHandler.startElement("", PARAMETER,
685: PARAMETER, paramAttrs);
686: contentHandler.endElement("", PARAMETER,
687: PARAMETER);
688: }
689:
690: }
691:
692: // Putting restrictions to the content handler
693: bindRestrictions(channelDescription, contentHandler);
694:
695: contentHandler.endElement("", CHANNEL, CHANNEL);
696:
697: }
698:
699: } catch (SAXException saxe) {
700: throw new PortalException(saxe);
701: }
702:
703: }
704:
705: }
706:
707: /**
708: * Writes user layout content (with appropriate markings) into
709: * a <code>Document</code> object
710: *
711: * @param document a <code>Document</code> value
712: * @exception PortalException if an error occurs
713: */
714: public void writeTo(Document document) throws PortalException {
715: writeTo(getRootId(), document);
716: }
717:
718: /**
719: * Writes subtree of a user layout (with appropriate markings) defined by a particular node into
720: * a <code>Document</code>
721: *
722: * @param nodeId a <code>String</code> a node determining a user layout subtree.
723: * @param document a <code>Document</code> object
724: * @exception PortalException if an error occurs
725: */
726: public void writeTo(String nodeId, Document document)
727: throws PortalException {
728: try {
729: Element layoutNode = document.createElement((nodeId
730: .equals(getRootId())) ? LAYOUT : FRAGMENT);
731: document.appendChild(layoutNode);
732: // Build the DOM
733: appendDescendants(document, layoutNode, nodeId);
734: } catch (Exception e) {
735: LOG.error(e, e);
736: throw new PortalException(
737: "Couldn't create the DOM representation: " + e);
738: }
739: }
740:
741: /**
742: * Obtain a description of a node (channel or a folder) in a given user layout.
743: *
744: * @param nodeId a <code>String</code> channel subscribe id or folder id.
745: * @return an <code>UserLayoutNodeDescription</code> value
746: * @exception PortalException if an error occurs
747: */
748: public IUserLayoutNodeDescription getNodeDescription(String nodeId)
749: throws PortalException {
750: ALNode node = getLayoutNode(nodeId);
751: if (node != null)
752: return node.getNodeDescription();
753: throw new PortalException("The node with nodeID=" + nodeId
754: + " does not exist in the layout!");
755: }
756:
757: /**
758: * Returns a node specified by a node ID.
759: *
760: * @param nodeId a <code>String</code> value
761: * @return a <code>ALNode</code> object
762: * @exception PortalException if an error occurs
763: */
764: public ALNode getNode(String nodeId) throws PortalException {
765: return getLayoutNode(nodeId);
766: }
767:
768: /**
769: * Returns an Id of a parent user layout node.
770: * The user layout root node always has ID={@link org.jasig.portal.layout.IUserLayout#ROOT_NODE_NAME}
771: *
772: * @param nodeId a <code>String</code> value
773: * @return a <code>String</code> value
774: * @exception PortalException if an error occurs
775: */
776: public String getParentId(String nodeId) throws PortalException {
777: ALNode node = getLayoutNode(nodeId);
778: if (node != null)
779: return node.getParentNodeId();
780: throw new PortalException("The node with nodeID=" + nodeId
781: + " does not exist in the layout!");
782: }
783:
784: /**
785: * Returns a list of child node Ids for a given node.
786: *
787: * @param nodeId a <code>String</code> value
788: * @return a <code>Enumeration</code> of <code>String</code> child node Ids.
789: * @exception PortalException if an error occurs
790: */
791: public Enumeration getChildIds(String nodeId)
792: throws PortalException {
793: Vector childIds = new Vector();
794: String firstChildId = getLayoutFolder(nodeId)
795: .getFirstChildNodeId();
796: for (String nextNodeId = firstChildId; nextNodeId != null;) {
797: childIds.add(nextNodeId);
798: nextNodeId = getLayoutNode(nextNodeId).getNextNodeId();
799: }
800: return childIds.elements();
801: }
802:
803: /**
804: * Determine an Id of a next sibling node.
805: *
806: * @param nodeId a <code>String</code> value
807: * @return a <code>String</code> Id value of a next sibling node, or <code>null</code> if this is the last sibling.
808: * @exception PortalException if an error occurs
809: */
810: public String getNextSiblingId(String nodeId)
811: throws PortalException {
812: ALNode node = getLayoutNode(nodeId);
813: if (node != null)
814: return node.getNextNodeId();
815: throw new PortalException("The node with nodeID=" + nodeId
816: + " does not exist in the layout!");
817: }
818:
819: /**
820: * Determine an Id of a previous sibling node.
821: *
822: * @param nodeId a <code>String</code> value
823: * @return a <code>String</code> Id value of a previous sibling node, or <code>null</code> if this is the first sibling.
824: * @exception PortalException if an error occurs
825: */
826: public String getPreviousSiblingId(String nodeId)
827: throws PortalException {
828: ALNode node = getLayoutNode(nodeId);
829: if (node != null)
830: return node.getPreviousNodeId();
831: throw new PortalException("The node with nodeID=" + nodeId
832: + " does not exist in the layout!");
833: }
834:
835: /**
836: * Return a cache key, uniqly corresponding to the composition and the structure of the user layout.
837: *
838: * @return a <code>String</code> value
839: * @exception PortalException if an error occurs
840: */
841: public String getCacheKey() throws PortalException {
842: return cacheKey;
843: }
844:
845: /**
846: * Register a layout event listener
847: *
848: * @param l a <code>LayoutEventListener</code> object
849: * @return a <code>boolean</code> success status
850: */
851: public boolean addLayoutEventListener(LayoutEventListener l) {
852: // TO IMPLEMENT
853: return false;
854: }
855:
856: /**
857: * Remove a registered layout event listener.
858: *
859: * @param l a <code>LayoutEventListener</code> object
860: * @return a <code>boolean</code> success status
861: */
862: public boolean removeLayoutEventListener(LayoutEventListener l) {
863: // TO IMPLEMENT
864: return false;
865: }
866:
867: /**
868: * Returns a layout Id associated with this manager/
869: *
870: * @return an <code>String</code> layout Id value;
871: */
872: public String getId() {
873: return layoutId;
874: }
875:
876: /**
877: * Returns a node id associated with the supplied functional name.
878: *
879: * @param fname the functional name to lookup
880: * @return a <code>String</code> subscription id
881: * @exception PortalException if an error occurs
882: */
883: public String getNodeId(String fname) throws PortalException {
884: for (Enumeration nodeIds = layout.keys(); nodeIds
885: .hasMoreElements();) {
886: String nodeId = nodeIds.nextElement().toString();
887: ALNode node = getLayoutNode(nodeId);
888: if (node.getNodeType() == IUserLayoutNodeDescription.CHANNEL) {
889: ALChannelDescription channelDesc = (ALChannelDescription) node
890: .getNodeDescription();
891: if (fname.equals(channelDesc.getFunctionalName()))
892: return node.getId();
893: }
894: }
895: return null;
896: }
897:
898: /**
899: * Returns a list of node Ids in the layout.
900: *
901: * @return a <code>Enumeration</code> of node Ids
902: * @exception PortalException if an error occurs
903: */
904: public Enumeration getNodeIds() throws PortalException {
905: if (layout == null)
906: throw new PortalException("The layout is NULL!");
907: return layout.keys();
908: }
909:
910: /**
911: * Returns an id of the root node.
912: *
913: * @return a <code>String</code> value
914: */
915: public String getRootId() {
916: return IALFolderDescription.ROOT_FOLDER_ID;
917: }
918:
919: }
|