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.api.node;
023:
024: import org.jboss.portal.api.PortalRuntimeContext;
025: import org.jboss.portal.api.node.PortalNode;
026: import org.jboss.portal.api.node.PortalNodeURL;
027: import org.jboss.portal.common.i18n.LocalizedString;
028: import org.jboss.portal.common.i18n.ResourceBundleManager;
029: import org.jboss.portal.common.i18n.SimpleResourceBundleFactory;
030: import org.jboss.portal.common.path.RelativePathParser;
031: import org.jboss.portal.core.impl.api.PortalRuntimeContextImpl;
032: import org.jboss.portal.core.model.portal.PortalObject;
033: import org.jboss.portal.core.model.portal.PortalObjectId;
034: import org.jboss.portal.core.model.portal.PortalObjectPermission;
035: import org.jboss.portal.security.spi.auth.PortalAuthorizationManager;
036:
037: import java.util.ArrayList;
038: import java.util.Collection;
039: import java.util.Collections;
040: import java.util.Comparator;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.Locale;
045: import java.util.Map;
046: import java.util.MissingResourceException;
047: import java.util.ResourceBundle;
048:
049: /**
050: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
051: * @version $Revision: 8924 $
052: */
053: public class PortalNodeImpl implements PortalNode {
054:
055: /** Order. */
056: private static final String ORDER = "order";
057:
058: /** The prefix for resources in the bundle. */
059: private static final String RESOURCE_PREFIX = "PAGENAME_";
060:
061: /** . */
062: private static final String BUNDLE_BASE_NAME = "conf.bundles.Resource";
063:
064: /** . */
065: private static final ResourceBundleManager resourceBundles = new ResourceBundleManager(
066: null, new SimpleResourceBundleFactory(BUNDLE_BASE_NAME,
067: PortalNodeImpl.class.getClassLoader()));
068:
069: /** The wrapped portal object. */
070: final PortalObject object;
071:
072: /** The parent node. */
073: private PortalNodeImpl parentNode;
074:
075: /** The children. */
076: private final NodeList children;
077:
078: /** The root node. */
079: private PortalNode root;
080:
081: /** The key for the display name in the resource bundle. */
082: private String displayNameKey;
083:
084: /** The security checks. */
085: private final PortalAuthorizationManager portalAuthorizationManager;
086:
087: /**
088: * Build a portal node object wrapping the specified portal object.
089: *
090: * @param object the wrapped portal object
091: * @throws IllegalArgumentException if the specified object is null
092: */
093: public PortalNodeImpl(
094: PortalAuthorizationManager portalAuthorizationManager,
095: PortalObject object) throws IllegalArgumentException {
096: if (object == null) {
097: throw new IllegalArgumentException();
098: }
099: this .portalAuthorizationManager = portalAuthorizationManager;
100: this .object = object;
101: this .children = new Children(this );
102: }
103:
104: /**
105: * Used during the construction of a children list.
106: *
107: * @param parentNode the parent node of this node
108: * @param object the wrapped portal object
109: */
110: private PortalNodeImpl(PortalNodeImpl parentNode,
111: PortalObject object) {
112: this .portalAuthorizationManager = parentNode.portalAuthorizationManager;
113: this .parentNode = parentNode;
114: this .object = object;
115: this .children = new Children(this );
116: }
117:
118: /**
119: * Used when building the parent.
120: *
121: * @param object the wrapped portal object
122: * @param childNode the child node creating that object
123: */
124: private PortalNodeImpl(PortalObject object, PortalNodeImpl childNode) {
125: this .portalAuthorizationManager = childNode.portalAuthorizationManager;
126: this .object = object;
127: this .children = new Siblings(childNode);
128: }
129:
130: public int getType() {
131: return object.getType();
132: }
133:
134: public PortalNode getRoot() {
135: if (root == null) {
136: PortalNode parent = getParent();
137: if (parent == null) {
138: root = this ;
139: } else {
140: root = parent.getRoot();
141: }
142: }
143: return root;
144: }
145:
146: public PortalNode getParent() {
147: if (parentNode == null) {
148: PortalObject objectParent = object.getParent();
149: if (objectParent != null) {
150: parentNode = new PortalNodeImpl(objectParent, this );
151: }
152: }
153: return parentNode;
154: }
155:
156: public String getName() {
157: return object.getName();
158: }
159:
160: public String getDisplayName(Locale locale) {
161: LocalizedString ldisplayName = object.getDisplayName();
162: if (ldisplayName != null) {
163: String result = ldisplayName.getString(locale, true);
164: if (result != null) {
165: return result;
166: }
167: }
168:
169: // Lazily compute the display name
170: if (displayNameKey == null) {
171: displayNameKey = RESOURCE_PREFIX + object.getName();
172: }
173:
174: // Try to get the display name from the resource bundles for backward compatibility
175: String displayName = null;
176: ResourceBundle bundle = null;
177: try {
178: bundle = resourceBundles.getResourceBundle(locale);
179: } catch (MissingResourceException ignore) {
180: }
181:
182: if (bundle != null) {
183: try {
184: displayName = bundle.getString(displayNameKey);
185: } catch (MissingResourceException ignore) {
186: }
187: }
188:
189: // If nothing found just use the name
190: if (displayName == null) {
191: displayName = object.getName();
192: }
193:
194: //
195: return displayName;
196: }
197:
198: public PortalNode getChild(String name) {
199: return (PortalNode) children.getMap().get(name);
200: }
201:
202: public Collection getChildren() {
203: return children.getList();
204: }
205:
206: public PortalNode resolve(String relativePath) {
207: // Use this as a starting point
208: PortalNode node = this ;
209:
210: //
211: RelativePathParser cursor = new RelativePathParser(relativePath);
212: for (int i = cursor.next(); i != RelativePathParser.NONE
213: && node != null; i = cursor.next()) {
214: switch (i) {
215: case RelativePathParser.DOWN:
216: String name = relativePath.substring(
217: cursor.getOffset(), cursor.getOffset()
218: + cursor.getLength());
219: node = node.getChild(name);
220: break;
221: case RelativePathParser.UP:
222: node = node.getParent();
223: break;
224: }
225: }
226: return node;
227: }
228:
229: public Map getProperties() {
230: return object.getProperties();
231: }
232:
233: public PortalNodeURL createURL(
234: PortalRuntimeContext portalRuntimeContext) {
235: PortalRuntimeContextImpl crc = (PortalRuntimeContextImpl) portalRuntimeContext;
236:
237: //
238: return crc.getURLFactory().createURL(this );
239: }
240:
241: public PortalObjectId getObjectId() {
242: return object.getId();
243: }
244:
245: private float getWeight() {
246: switch (object.getType()) {
247: case PortalObject.TYPE_CONTEXT:
248: return 0;
249: case PortalObject.TYPE_PORTAL:
250: return 1;
251: case PortalObject.TYPE_PAGE:
252: String orderProperty = object.getDeclaredProperty(ORDER);
253: if (orderProperty == null) {
254: return 2.999f;
255: }
256: try {
257: return Float.parseFloat("2." + orderProperty);
258: } catch (NumberFormatException e) {
259: return 2.999f;
260: }
261: case PortalObject.TYPE_WINDOW:
262: return 3;
263: default:
264: return 4;
265: }
266: }
267:
268: private static final Comparator siblingComparator = new Comparator() {
269: public int compare(Object o1, Object o2) {
270: PortalNodeImpl node1 = (PortalNodeImpl) o1;
271: PortalNodeImpl node2 = (PortalNodeImpl) o2;
272: float weight1 = node1.getWeight();
273: float weight2 = node2.getWeight();
274: if (weight1 == weight2) {
275: return node1.getName().compareTo(node2.getName());
276: } else if (weight1 < weight2) {
277: return -1;
278: } else {
279: return 1;
280: }
281: }
282: };
283:
284: private abstract class NodeList {
285:
286: /** . */
287: private Map map;
288:
289: /** . */
290: private List list;
291:
292: protected abstract Map createMap();
293:
294: public final List getList() {
295: if (list == null) {
296: Map childrenMap = getMap();
297:
298: //
299: list = new ArrayList(childrenMap.values());
300: Collections.sort(list, siblingComparator);
301: list = Collections.unmodifiableList(list);
302: }
303:
304: //
305: return list;
306: }
307:
308: public final Map getMap() {
309: if (map == null) {
310: map = createMap();
311: }
312:
313: //
314: return map;
315: }
316:
317: /** Compute and returns a modifiable map made of the children nodes. */
318: protected final Map buildChildMap(PortalNodeImpl objectNode) {
319: PortalObject object = objectNode.object;
320:
321: //
322: Collection tmp = object.getChildren();
323:
324: //
325: if (tmp.size() > 0) {
326: Map childrenMap = new HashMap();
327:
328: // See if we have recursive permission on the provided node that will avoid to make a check for each of them
329: boolean allVisible = portalAuthorizationManager
330: .checkPermission(new PortalObjectPermission(
331: objectNode.object.getId(),
332: PortalObjectPermission.VIEW_RECURSIVE_ACTION));
333:
334: //
335: for (Iterator i = tmp.iterator(); i.hasNext();) {
336: PortalObject childObject = (PortalObject) i.next();
337:
338: // It is visible if the parent has recursive view enabled
339: boolean visible = allVisible;
340:
341: // Check for the particular node
342: if (!visible) {
343: visible = portalAuthorizationManager
344: .checkPermission(new PortalObjectPermission(
345: childObject.getId(),
346: PortalObjectPermission.VIEW_MASK));
347: }
348:
349: // We only add it if the user can view the node
350: if (visible) {
351: PortalNodeImpl child = new PortalNodeImpl(
352: objectNode, childObject);
353: childrenMap.put(child.getName(), child);
354: }
355: }
356:
357: //
358: return childrenMap;
359: } else {
360: return Collections.EMPTY_MAP;
361: }
362: }
363: }
364:
365: private class Children extends NodeList {
366:
367: /** . */
368: private PortalNodeImpl node;
369:
370: public Children(PortalNodeImpl node) {
371: this .node = node;
372: }
373:
374: protected Map createMap() {
375: return buildChildMap(node);
376: }
377: }
378:
379: private class Siblings extends NodeList {
380:
381: /** . */
382: private PortalNodeImpl node;
383:
384: private Siblings(PortalNodeImpl node) {
385: this .node = node;
386: }
387:
388: protected Map createMap() {
389: Map childrenNodes = buildChildMap(node.parentNode);
390:
391: // Replace the node with the one provided
392: childrenNodes.put(node.getName(), node);
393:
394: //
395: return childrenNodes;
396: }
397: }
398: }
|