001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.core.impl.model.portal;
023:
024: import java.util.ArrayList;
025: import java.util.Collection;
026: import java.util.Collections;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.Locale;
030: import java.util.Map;
031: import java.util.NoSuchElementException;
032: import java.util.Set;
033: import java.util.SortedSet;
034: import java.util.TreeMap;
035: import java.util.TreeSet;
036:
037: import org.apache.log4j.Logger;
038: import org.jboss.portal.common.NotYetImplemented;
039: import org.jboss.portal.common.i18n.LocalizedString;
040: import org.jboss.portal.core.model.portal.DuplicatePortalObjectException;
041: import org.jboss.portal.core.model.portal.NoSuchPortalObjectException;
042: import org.jboss.portal.core.model.portal.PortalObject;
043: import org.jboss.portal.core.model.portal.PortalObjectId;
044:
045: /**
046: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
047: * @version $Revision: 9158 $
048: */
049: public abstract class PortalObjectImpl implements PortalObject {
050:
051: /** The logger. */
052: protected static final Logger log = Logger
053: .getLogger(PortalObjectImpl.class);
054:
055: /** . */
056: protected static final int ALL_TYPES_MASK = CONTEXT_MASK
057: | PORTAL_MASK | PAGE_MASK | WINDOW_MASK;
058:
059: // Persistent fields
060:
061: /** The primary key when the object is persisted */
062: private Long key;
063:
064: /** . */
065: private Map declaredPropertyMap;
066:
067: /** . */
068: private String listener;
069:
070: /** . */
071: private Map displayNames;
072:
073: /** The node. */
074: private ObjectNode objectNode;
075:
076: // Runtime fields
077:
078: private Map childrenMap;
079: private Map properties;
080: private Map unmodifiableProperties;
081: private SortedSet accessedChildren;
082:
083: public PortalObjectImpl() {
084: this (true);
085: }
086:
087: public PortalObjectImpl(boolean initState) {
088: this .declaredPropertyMap = new HashMap();
089: this .listener = null;
090:
091: //
092: this .childrenMap = null;
093: this .properties = null;
094: this .unmodifiableProperties = null;
095: this .accessedChildren = null;
096: }
097:
098: public Long getKey() {
099: return key;
100: }
101:
102: public void setKey(Long key) {
103: this .key = key;
104: }
105:
106: public ObjectNode getObjectNode() {
107: return objectNode;
108: }
109:
110: public void setObjectNode(ObjectNode objectNode) {
111: this .objectNode = objectNode;
112: }
113:
114: //
115:
116: public PortalObjectId getId() {
117: return objectNode.getPath();
118: }
119:
120: public int compareTo(Object o) {
121: PortalObject po = (PortalObject) o;
122:
123: return getId().compareTo(po.getId());
124: }
125:
126: public void destroyChild(String name)
127: throws NoSuchPortalObjectException {
128: objectNode.removeChild(name);
129: }
130:
131: public String getName() {
132: return objectNode.getName();
133: }
134:
135: public void setDisplayNames(Map displayNames) {
136: this .displayNames = displayNames;
137: }
138:
139: public Map getDisplayNames() {
140: return displayNames;
141: }
142:
143: public void setDisplayName(LocalizedString displayName) {
144: if (displayName == null) {
145: throw new IllegalArgumentException(
146: "No null display name accepted");
147: }
148:
149: displayNames = new HashMap();
150:
151: Map map = displayName.getValues();
152: Iterator it = map.values().iterator();
153: while (it.hasNext()) {
154: LocalizedString.Value value = (LocalizedString.Value) it
155: .next();
156: displayNames.put(value.getLocale(), value.getString());
157: }
158: }
159:
160: public LocalizedString getDisplayName() {
161: if (displayNames != null) {
162: return new LocalizedString(displayNames, Locale.ENGLISH);
163: } else {
164: return null;
165: }
166: }
167:
168: public PortalObject copy(PortalObject parent, String name,
169: boolean deep) throws DuplicatePortalObjectException,
170: IllegalArgumentException {
171: if (parent == null) {
172: throw new IllegalArgumentException(
173: "No null parent accepted");
174: }
175: if (name == null) {
176: throw new IllegalArgumentException("No null name accepted");
177: }
178: return copy((PortalObjectImpl) parent, name, deep);
179: }
180:
181: public Collection getChildren() {
182: return getChildren(ALL_TYPES_MASK);
183: }
184:
185: private class ChildrenCollection implements Collection {
186:
187: /** . */
188: private final int mask;
189:
190: public ChildrenCollection(int mask) {
191: this .mask = mask;
192: }
193:
194: public void clear() {
195: throw new UnsupportedOperationException();
196: }
197:
198: public boolean add(Object o) {
199: throw new UnsupportedOperationException();
200: }
201:
202: public boolean remove(Object o) {
203: throw new UnsupportedOperationException();
204: }
205:
206: public boolean addAll(Collection c) {
207: throw new UnsupportedOperationException();
208: }
209:
210: public boolean removeAll(Collection c) {
211: throw new UnsupportedOperationException();
212: }
213:
214: public boolean retainAll(Collection c) {
215: throw new UnsupportedOperationException();
216: }
217:
218: public boolean containsAll(Collection c) {
219: throw new NotYetImplemented();
220: }
221:
222: public boolean contains(Object o) {
223: throw new NotYetImplemented();
224: }
225:
226: public boolean isEmpty() {
227: return objectNode.getChildren().isEmpty();
228: }
229:
230: public int size() {
231: if (mask == ALL_TYPES_MASK) {
232: return objectNode.getChildren().size();
233: } else {
234: int count = 0;
235: for (Iterator i = iterator(); i.hasNext();) {
236: i.next();
237: count++;
238: }
239: return count;
240: }
241: }
242:
243: public Object[] toArray() {
244: return toArray(new Object[0]);
245: }
246:
247: public Iterator iterator() {
248: return new ChildrenIterator();
249: }
250:
251: public Object[] toArray(Object a[]) {
252: ArrayList tmp = new ArrayList(objectNode.getChildren()
253: .size());
254:
255: //
256: Set accessedChildren = getAccessedChildren();
257:
258: //
259: for (Iterator i = iterator(); i.hasNext();) {
260: PortalObject childObject = (PortalObject) i.next();
261:
262: //
263: accessedChildren.add(childObject);
264:
265: //
266: tmp.add(childObject);
267: }
268: return tmp.toArray(a);
269: }
270:
271: private class ChildrenIterator implements Iterator {
272:
273: /** . */
274: private final Iterator iterator;
275:
276: /** . */
277: private PortalObject nextChild = null;
278:
279: public ChildrenIterator() {
280: // Make sure the children are sorted for consistent ordering downstream
281: Map childrenMap = new TreeMap(objectNode.getChildren());
282: Collection children = childrenMap.values();
283: iterator = children.iterator();
284: }
285:
286: public void remove() {
287: throw new UnsupportedOperationException();
288: }
289:
290: public boolean hasNext() {
291: if (nextChild == null) {
292: while (nextChild == null && iterator.hasNext()) {
293: ObjectNode childNode = (ObjectNode) iterator
294: .next();
295: PortalObjectImpl childObject = childNode
296: .getObject();
297: if (mask == ALL_TYPES_MASK
298: || (childObject.getMask() & mask) != 0) {
299: nextChild = childObject;
300: }
301: }
302: }
303: return nextChild != null;
304: }
305:
306: public Object next() {
307: if (this .nextChild == null) {
308: hasNext();
309: }
310: if (this .nextChild == null) {
311: throw new NoSuchElementException();
312: }
313:
314: //
315: getAccessedChildren().add(nextChild);
316:
317: //
318: PortalObject nextChild = this .nextChild;
319: this .nextChild = null;
320:
321: //
322: return nextChild;
323: }
324: }
325: }
326:
327: public Collection getChildren(int wantedMask) {
328: /// Correct eventually the mask
329: final int mask = wantedMask & ALL_TYPES_MASK;
330:
331: // Compute the lookup cache key
332: Integer key = new Integer(mask);
333:
334: //
335: Collection children = null;
336: if (childrenMap == null) {
337: childrenMap = new HashMap();
338: } else {
339: children = (Collection) childrenMap.get(key);
340: }
341:
342: //
343: if (children == null) {
344: children = new ChildrenCollection(mask);
345: childrenMap.put(key, children);
346: }
347: return children;
348: }
349:
350: public String getListener() {
351: return listener;
352: }
353:
354: public void setListener(String listener) {
355: this .listener = listener;
356: }
357:
358: public PortalObject getParent() {
359: if (objectNode.getParent() != null) {
360: return objectNode.getParent().getObject();
361: } else {
362: return null;
363: }
364: }
365:
366: public PortalObject getChild(String name) {
367: if (name == null) {
368: throw new IllegalArgumentException();
369: }
370: ObjectNode childNode = (ObjectNode) objectNode.getChildren()
371: .get(name);
372: if (childNode != null) {
373: PortalObjectImpl childObject = childNode.getObject();
374:
375: // Track it
376: getAccessedChildren().add(childObject);
377:
378: //
379: return childObject;
380: } else {
381: return null;
382: }
383: }
384:
385: private Set getAccessedChildren() {
386: if (accessedChildren == null) {
387: accessedChildren = new TreeSet();
388: }
389: return accessedChildren;
390: }
391:
392: /** Get the aggregated properties in a lazy manner. */
393: public Map getProperties() {
394: // Lazy compute properties
395: if (properties == null) {
396: ObjectNode parent = objectNode.getParent();
397: if (parent == null) {
398: this .properties = declaredPropertyMap;
399: } else {
400: Map properties = new HashMap();
401: properties.putAll(parent.getObject().getProperties());
402: properties.putAll(declaredPropertyMap);
403: this .properties = properties;
404: }
405:
406: //
407: this .unmodifiableProperties = Collections
408: .unmodifiableMap(properties);
409: }
410:
411: //
412: return unmodifiableProperties;
413: }
414:
415: public Map getDeclaredPropertyMap() {
416: return declaredPropertyMap;
417: }
418:
419: public void setDeclaredPropertyMap(Map properties) {
420: this .declaredPropertyMap = properties;
421: }
422:
423: public Map getDeclaredProperties() {
424: return Collections.unmodifiableMap(declaredPropertyMap);
425: }
426:
427: public String getDeclaredProperty(String name) {
428: if (name == null) {
429: throw new IllegalArgumentException();
430: }
431: return (String) declaredPropertyMap.get(name);
432: }
433:
434: public void setDeclaredProperty(String name, String value) {
435: if (name == null) {
436: throw new IllegalArgumentException();
437: }
438: if (value == null) {
439: declaredPropertyMap.remove(name);
440: PortalObject parent = getParent();
441: String parentValue = null;
442: if (parent != null) {
443: parentValue = parent.getProperty(name);
444: }
445:
446: propagatePropertyUpdate(name, parentValue, true);
447: } else {
448: declaredPropertyMap.put(name, value);
449: propagatePropertyUpdate(name, value, true);
450: }
451: }
452:
453: /**
454: * This method propagates a property value update to descendants which have been *loaded* from the database. It
455: * considers that if the <code>properties</code> field of the runtime state is null then it means that the object is
456: * loaded but children have not made an attempt to read the properties of this object. Indeed if a child is loaded
457: * any attempt to access its aggregated properties will trigger the computation of the aggregated properties of this
458: * object.
459: * <p/>
460: * Null property values are considered as removal
461: *
462: * @param name the property name
463: * @param value the new property value
464: * @param force the update
465: */
466: private void propagatePropertyUpdate(String name, String value,
467: boolean force) {
468: if (properties != null) {
469: if (force || !declaredPropertyMap.containsKey(name)) {
470: if (value == null) {
471: properties.remove(name);
472: } else {
473: properties.put(name, value);
474: }
475:
476: //
477: if (accessedChildren != null) {
478: for (Iterator i = accessedChildren.iterator(); i
479: .hasNext();) {
480: PortalObjectImpl child = (PortalObjectImpl) i
481: .next();
482: child.propagatePropertyUpdate(name, value,
483: false);
484: }
485: }
486: }
487: }
488: }
489:
490: public String getProperty(String name) {
491: if (name == null) {
492: throw new IllegalArgumentException();
493: }
494:
495: // Trigger the lazy loading
496: Map properties = getProperties();
497:
498: // Lookup the property
499: return (String) properties.get(name);
500: }
501:
502: public abstract int getType();
503:
504: public String toString() {
505: return objectNode.toString();
506: }
507:
508: public boolean equals(Object obj) {
509: if (obj == this ) {
510: return true;
511: }
512: if (obj instanceof PortalObjectImpl) {
513: PortalObjectImpl that = (PortalObjectImpl) obj;
514: return getId().equals(that.getId());
515: }
516: return false;
517: }
518:
519: public int hashCode() {
520: return getId().hashCode();
521: }
522:
523: /** Return the default child of this object based on the declared property that specifies the default object name. */
524: protected PortalObject getDefaultChild() {
525: String portalName = getDeclaredProperty(PORTAL_PROP_DEFAULT_OBJECT_NAME);
526: if (portalName == null) {
527: portalName = DEFAULT_OBJECT_NAME;
528: }
529: return getChild(portalName);
530: }
531:
532: protected abstract PortalObjectImpl cloneObject();
533:
534: /** Overridable callback. */
535: protected void destroy() {
536: }
537:
538: protected final int getMask() {
539: return getMask(getType());
540: }
541:
542: /** Returns the mask for this kind of object. */
543: protected final int getMask(int portalObjectType) {
544: switch (portalObjectType) {
545: case TYPE_CONTEXT:
546: return CONTEXT_MASK;
547: case TYPE_PORTAL:
548: return PORTAL_MASK;
549: case TYPE_PAGE:
550: return PAGE_MASK;
551: case TYPE_WINDOW:
552: return WINDOW_MASK;
553: default:
554: throw new IllegalArgumentException("Unknown type "
555: + portalObjectType);
556: }
557: }
558:
559: // protected final DashboardContext getDashboardContext()
560: // {
561: // if (dashboardContext == null)
562: // {
563: // // Get parent object
564: // PortalObjectImpl parent = (PortalObjectImpl)getParent();
565: //
566: // // We need the parent to find out the context details
567: // if (this instanceof ContextImpl)
568: // {
569: // String dashboard = getDeclaredProperty("dashboard");
570: // if ("true".equals(dashboard))
571: // {
572: // String dashboardId = getName();
573: // dashboardContext = new DashboardContext(dashboardId);
574: // }
575: // }
576: // else if (parent != null)
577: // {
578: // dashboardContext = parent.getDashboardContext();
579: // }
580: // }
581: //
582: // //
583: // return dashboardContext;
584: // }
585:
586: protected final void addChild(String name,
587: PortalObjectImpl childObject)
588: throws DuplicatePortalObjectException,
589: IllegalArgumentException {
590: objectNode.addChild(name, childObject);
591:
592: //
593: getAccessedChildren().add(childObject);
594: }
595:
596: private PortalObjectImpl copy(PortalObjectImpl parent, String name,
597: boolean deep) throws DuplicatePortalObjectException {
598: // Clone this node
599: PortalObjectImpl clone = cloneObject();
600:
601: // Add the clone to the specified parent
602: parent.addChild(name, clone);
603:
604: // Clone children recursively
605: if (deep) {
606: for (Iterator i = getChildren().iterator(); i.hasNext();) {
607: PortalObjectImpl child = (PortalObjectImpl) i.next();
608:
609: //
610: child.copy(clone, child.getName(), true);
611: }
612: }
613:
614: //
615: return clone;
616: }
617: }
|