001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.page.document.impl;
018:
019: import java.util.Collection;
020: import java.util.List;
021: import java.util.Locale;
022: import java.util.StringTokenizer;
023:
024: import org.apache.jetspeed.om.common.GenericMetadata;
025: import org.apache.jetspeed.om.folder.Folder;
026: import org.apache.jetspeed.om.page.PageMetadataImpl;
027: import org.apache.jetspeed.om.page.PageSecurity;
028: import org.apache.jetspeed.om.page.impl.BaseElementImpl;
029: import org.apache.jetspeed.om.page.impl.SecurityConstraintsImpl;
030: import org.apache.jetspeed.page.document.Node;
031: import org.apache.jetspeed.page.impl.DatabasePageManagerUtils;
032: import org.apache.ojb.broker.core.proxy.ProxyHelper;
033:
034: /**
035: * NodeImpl
036: *
037: * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
038: * @version $Id$
039: */
040: public abstract class NodeImpl extends BaseElementImpl implements Node {
041: private Node parent;
042: private boolean hidden;
043: private Collection metadataFields;
044: private String path = Folder.PATH_SEPARATOR;
045: private String subsite;
046: private String user;
047: private String role;
048: private String group;
049: private String mediatype;
050: private String locale;
051: private String extendedAttributeName;
052: private String extendedAttributeValue;
053:
054: private PageMetadataImpl pageMetadata;
055: private String logicalPath;
056:
057: public NodeImpl(SecurityConstraintsImpl constraints) {
058: super (constraints);
059: }
060:
061: /**
062: * getCanonicalNodePath
063: *
064: * Format paths used to set and query NodeImpl instances.
065: *
066: * @param path specified path
067: * @return canonical path
068: */
069: public static String getCanonicalNodePath(String path) {
070: // validate and format path
071: if ((path == null) || (path.length() == 0)) {
072: path = Folder.PATH_SEPARATOR;
073: }
074: if (!path.startsWith(Folder.PATH_SEPARATOR)) {
075: path = Folder.PATH_SEPARATOR + path;
076: }
077: if (path.endsWith(Folder.PATH_SEPARATOR)
078: && !path.equals(Folder.PATH_SEPARATOR)) {
079: path = path.substring(0, path.length() - 1);
080: }
081: return path;
082: }
083:
084: /**
085: * newPageMetadata
086: *
087: * Construct page manager specific metadata implementation.
088: *
089: * @param fields mutable fields collection
090: * @return page metadata
091: */
092: public PageMetadataImpl newPageMetadata(Collection fields) {
093: // no metadata available by default
094: return null;
095: }
096:
097: /**
098: * getPageMetadata
099: *
100: * Get page manager specific metadata implementation.
101: *
102: * @return page metadata
103: */
104: public PageMetadataImpl getPageMetadata() {
105: if (pageMetadata == null) {
106: if (metadataFields == null) {
107: metadataFields = DatabasePageManagerUtils.createList();
108: }
109: pageMetadata = newPageMetadata(metadataFields);
110: }
111: return pageMetadata;
112: }
113:
114: /**
115: * defaultTitleFromName
116: *
117: * Compute default title from name.
118: *
119: * @return default title
120: */
121: protected String defaultTitleFromName() {
122: // transform name to title
123: String title = getName();
124: if (title != null) {
125: // strip extensions and default root folder name
126: if ((getType() != null) && title.endsWith(getType())) {
127: title = title.substring(0, title.length()
128: - getType().length());
129: } else if (title.equals(Folder.PATH_SEPARATOR)) {
130: title = "top";
131: }
132: // use space as word separator
133: title = title.replace('_', ' ');
134: title = title.replace('-', ' ');
135: // use title case for title words
136: int wordIndex = -1;
137: do {
138: if (!Character.isTitleCase(title.charAt(wordIndex + 1))) {
139: StringBuffer makeTitle = new StringBuffer();
140: makeTitle.append(title.substring(0, wordIndex + 1));
141: makeTitle.append(Character.toTitleCase(title
142: .charAt(wordIndex + 1)));
143: makeTitle.append(title.substring(wordIndex + 2));
144: title = makeTitle.toString();
145: }
146: wordIndex = title.indexOf(' ', wordIndex + 1);
147: } while (wordIndex != -1);
148: }
149: return title;
150: }
151:
152: /* (non-Javadoc)
153: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#getName()
154: */
155: public String getName() {
156: // get name or compute from path
157: String name = super .getName();
158: if (name == null) {
159: if (path != null) {
160: if (!path.equals(Folder.PATH_SEPARATOR)) {
161: name = path.substring(path
162: .lastIndexOf(Folder.PATH_SEPARATOR) + 1);
163: } else {
164: name = Folder.PATH_SEPARATOR;
165: }
166: super .setName(name);
167: }
168: }
169: return name;
170: }
171:
172: /* (non-Javadoc)
173: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#setName(java.lang.String)
174: */
175: public void setName(String name) {
176: // set path based on name
177: if (name != null) {
178: if (path != null) {
179: // set path
180: if (!name.equals(Folder.PATH_SEPARATOR)) {
181: path = path.substring(0, path
182: .lastIndexOf(Folder.PATH_SEPARATOR) + 1)
183: + name;
184: } else {
185: path = Folder.PATH_SEPARATOR;
186: }
187:
188: // reset logicalPath
189: logicalPath = null;
190: }
191: super .setName(name);
192: }
193: }
194:
195: /* (non-Javadoc)
196: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#getEffectivePageSecurity()
197: */
198: public PageSecurity getEffectivePageSecurity() {
199: // by default, delegate to real parent node implementation
200: NodeImpl parentNodeImpl = (NodeImpl) ProxyHelper
201: .getRealObject(parent);
202: if (parentNodeImpl != null) {
203: return parentNodeImpl.getEffectivePageSecurity();
204: }
205: return null;
206: }
207:
208: /* (non-Javadoc)
209: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#checkConstraints(java.util.List, java.util.List, java.util.List, java.util.List, boolean, boolean)
210: */
211: public void checkConstraints(List actions, List userPrincipals,
212: List rolePrincipals, List groupPrincipals,
213: boolean checkNodeOnly, boolean checkParentsOnly)
214: throws SecurityException {
215: // check constraints in node hierarchy
216: if (checkNodeOnly) {
217: // check node constraints if available; otherwise,
218: // recursively check parent constraints until
219: // default constraints for node are checked
220: SecurityConstraintsImpl constraintsImpl = (SecurityConstraintsImpl) getSecurityConstraints();
221: if ((constraintsImpl != null) && !constraintsImpl.isEmpty()) {
222: constraintsImpl.checkConstraints(actions,
223: userPrincipals, rolePrincipals,
224: groupPrincipals, getEffectivePageSecurity());
225: } else {
226: NodeImpl parentNodeImpl = (NodeImpl) ProxyHelper
227: .getRealObject(parent);
228: if (parentNodeImpl != null) {
229: parentNodeImpl.checkConstraints(actions,
230: userPrincipals, rolePrincipals,
231: groupPrincipals, checkNodeOnly, false);
232: }
233: }
234: } else {
235: // check node constraints if available and not
236: // to be skipped due to explicity granted access
237: if (!checkParentsOnly) {
238: SecurityConstraintsImpl constraintsImpl = (SecurityConstraintsImpl) getSecurityConstraints();
239: if ((constraintsImpl != null)
240: && !constraintsImpl.isEmpty()) {
241: constraintsImpl
242: .checkConstraints(actions, userPrincipals,
243: rolePrincipals, groupPrincipals,
244: getEffectivePageSecurity());
245: }
246: }
247:
248: // recursively check all parent constraints in hierarchy
249: NodeImpl parentNodeImpl = (NodeImpl) ProxyHelper
250: .getRealObject(parent);
251: if (parentNodeImpl != null) {
252: parentNodeImpl.checkConstraints(actions,
253: userPrincipals, rolePrincipals,
254: groupPrincipals, false, false);
255: }
256: }
257: }
258:
259: /* (non-Javadoc)
260: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#checkPermissions(java.lang.String, int, boolean, boolean)
261: */
262: public void checkPermissions(String path, int mask,
263: boolean checkNodeOnly, boolean checkParentsOnly)
264: throws SecurityException {
265: // check granted node permissions unless the check is
266: // to be skipped due to explicity granted access
267: if (!checkParentsOnly) {
268: super .checkPermissions(path, mask, true, false);
269: }
270:
271: // if not checking node only, recursively check
272: // all parent permissions in hierarchy
273: if (!checkNodeOnly) {
274: NodeImpl parentNodeImpl = (NodeImpl) ProxyHelper
275: .getRealObject(parent);
276: if (parentNodeImpl != null) {
277: parentNodeImpl.checkPermissions(mask, false, false);
278: }
279: }
280: }
281:
282: /* (non-Javadoc)
283: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#getLogicalPermissionPath()
284: */
285: public String getLogicalPermissionPath() {
286: // compute logical path if required
287: if (logicalPath == null) {
288: // check for path attributes
289: if ((subsite != null) || (user != null) || (role != null)
290: || (group != null) || (mediatype != null)
291: || (locale != null)
292: || (extendedAttributeName != null)
293: || (extendedAttributeValue != null)) {
294: // parse path, stripping reserved folders from path
295: boolean skipAttribute = false;
296: StringBuffer logicalPathBuffer = new StringBuffer();
297: StringTokenizer pathElements = new StringTokenizer(
298: path, Folder.PATH_SEPARATOR);
299: while (pathElements.hasMoreTokens()) {
300: // classify path element
301: String pathElement = pathElements.nextToken();
302: if (!skipAttribute) {
303: if (!pathElement
304: .startsWith(Folder.RESERVED_SUBSITE_FOLDER_PREFIX)) {
305: if (!pathElement
306: .startsWith(Folder.RESERVED_FOLDER_PREFIX)) {
307: // append to logical path
308: logicalPathBuffer
309: .append(Folder.PATH_SEPARATOR);
310: logicalPathBuffer.append(pathElement);
311: } else {
312: // skip next attribute path element
313: skipAttribute = true;
314: }
315: }
316: } else {
317: // attribute path element skipped
318: skipAttribute = false;
319: }
320: }
321:
322: // set logical path
323: if (logicalPathBuffer.length() > 0) {
324: logicalPath = logicalPathBuffer.toString();
325: } else {
326: logicalPath = Folder.PATH_SEPARATOR;
327: }
328: } else {
329: // no path attributes: logical path and physical path equivalent
330: logicalPath = path;
331: }
332: }
333:
334: return logicalPath;
335: }
336:
337: /* (non-Javadoc)
338: * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#getPhysicalPermissionPath()
339: */
340: public String getPhysicalPermissionPath() {
341: // return path
342: return path;
343: }
344:
345: /* (non-Javadoc)
346: * @see org.apache.jetspeed.page.document.Node#getParent()
347: */
348: public Node getParent() {
349: return parent;
350: }
351:
352: /* (non-Javadoc)
353: * @see org.apache.jetspeed.page.document.Node#setParent(org.apache.jetspeed.page.document.Node)
354: */
355: public void setParent(Node parent) {
356: // set node parent
357: this .parent = parent;
358:
359: // update path if required
360: if (parent != null) {
361: String parentPath = parent.getPath();
362: if ((parentPath.equals(Folder.PATH_SEPARATOR) && (path
363: .lastIndexOf(Folder.PATH_SEPARATOR) > 0))
364: || (!parentPath.equals(Folder.PATH_SEPARATOR) && !parentPath
365: .equals(path
366: .substring(
367: 0,
368: path
369: .lastIndexOf(Folder.PATH_SEPARATOR))))) {
370: // set path
371: path = parentPath + Folder.PATH_SEPARATOR + getName();
372:
373: // reset logicalPath
374: logicalPath = null;
375: }
376: }
377: }
378:
379: /* (non-Javadoc)
380: * @see org.apache.jetspeed.page.document.Node#getPath()
381: */
382: public String getPath() {
383: // return path from attributes and base path
384: return path;
385: }
386:
387: /* (non-Javadoc)
388: * @see org.apache.jetspeed.page.document.Node#setPath(java.lang.String)
389: */
390: public void setPath(String path) {
391: // set canonical node path
392: this .path = getCanonicalNodePath(path);
393:
394: // reset logical path
395: logicalPath = null;
396:
397: // parse and set informational attributes from path
398: String attributeName = null;
399: StringTokenizer pathElements = new StringTokenizer(this .path,
400: Folder.PATH_SEPARATOR);
401: while (pathElements.hasMoreTokens()) {
402: String pathElement = pathElements.nextToken();
403: if (attributeName != null) {
404: // set last attribute name with attribute value
405: if (attributeName
406: .startsWith(Folder.RESERVED_USER_FOLDER_NAME)) {
407: user = pathElement.toLowerCase();
408: } else if (attributeName
409: .startsWith(Folder.RESERVED_ROLE_FOLDER_NAME)) {
410: role = pathElement.toLowerCase();
411: } else if (attributeName
412: .startsWith(Folder.RESERVED_GROUP_FOLDER_NAME)) {
413: group = pathElement.toLowerCase();
414: } else if (attributeName
415: .startsWith(Folder.RESERVED_MEDIATYPE_FOLDER_NAME)) {
416: mediatype = pathElement.toLowerCase();
417: } else if (attributeName
418: .startsWith(Folder.RESERVED_LANGUAGE_FOLDER_NAME)) {
419: if (locale != null) {
420: // compose locale from language + country
421: locale = pathElement.toLowerCase() + "_"
422: + locale;
423: } else {
424: locale = pathElement.toLowerCase();
425: }
426: } else if (attributeName
427: .startsWith(Folder.RESERVED_COUNTRY_FOLDER_NAME)) {
428: if (locale != null) {
429: // compose locale from language + country
430: locale = locale + "_"
431: + pathElement.toLowerCase();
432: } else {
433: locale = pathElement.toLowerCase();
434: }
435: } else if (attributeName
436: .startsWith(Folder.RESERVED_FOLDER_PREFIX)) {
437: extendedAttributeName = attributeName
438: .substring(Folder.RESERVED_FOLDER_PREFIX
439: .length());
440: extendedAttributeValue = pathElement.toLowerCase();
441: }
442:
443: // reset attribute name
444: attributeName = null;
445: } else if (pathElement
446: .startsWith(Folder.RESERVED_SUBSITE_FOLDER_PREFIX)) {
447: subsite = pathElement.substring(
448: Folder.RESERVED_SUBSITE_FOLDER_PREFIX.length())
449: .toLowerCase();
450: } else if (pathElement
451: .startsWith(Folder.RESERVED_FOLDER_PREFIX)) {
452: // save attribute name
453: attributeName = pathElement.toLowerCase();
454: }
455: }
456:
457: // set name based on path
458: if (!this .path.equals(Folder.PATH_SEPARATOR)) {
459: super .setName(this .path.substring(this .path
460: .lastIndexOf(Folder.PATH_SEPARATOR) + 1));
461: } else {
462: super .setName(Folder.PATH_SEPARATOR);
463: }
464:
465: // reset parent if required
466: if (parent != null) {
467: String parentPath = parent.getPath();
468: if ((parentPath.equals(Folder.PATH_SEPARATOR) && (this .path
469: .lastIndexOf(Folder.PATH_SEPARATOR) > 0))
470: || (!parentPath.equals(Folder.PATH_SEPARATOR) && !parentPath
471: .equals(this .path
472: .substring(
473: 0,
474: this .path
475: .lastIndexOf(Folder.PATH_SEPARATOR))))) {
476: parent = null;
477: }
478: }
479: }
480:
481: /* (non-Javadoc)
482: * @see org.apache.jetspeed.page.document.Node#getMetadata()
483: */
484: public GenericMetadata getMetadata() {
485: return getPageMetadata();
486: }
487:
488: /* (non-Javadoc)
489: * @see org.apache.jetspeed.page.document.Node#getTitle(java.util.Locale)
490: */
491: public String getTitle(Locale locale) {
492: // get title from metadata or use default title
493: String title = getPageMetadata().getText("title", locale);
494: if (title == null) {
495: title = getTitle();
496: }
497: return title;
498: }
499:
500: /* (non-Javadoc)
501: * @see org.apache.jetspeed.page.document.Node#getShortTitle(java.util.Locale)
502: */
503: public String getShortTitle(Locale locale) {
504: // get short title from metadata or use title from metadata,
505: // default short title, or default title
506: String shortTitle = getPageMetadata().getText("short-title",
507: locale);
508: if (shortTitle == null) {
509: shortTitle = getPageMetadata().getText("title", locale);
510: if (shortTitle == null) {
511: shortTitle = getShortTitle();
512: if (shortTitle == null) {
513: shortTitle = getTitle();
514: }
515: }
516: }
517: return shortTitle;
518: }
519:
520: /* (non-Javadoc)
521: * @see org.apache.jetspeed.page.document.Node#getType()
522: */
523: public abstract String getType();
524:
525: /* (non-Javadoc)
526: * @see org.apache.jetspeed.page.document.Node#getUrl()
527: */
528: public String getUrl() {
529: return path;
530: }
531:
532: /* (non-Javadoc)
533: * @see org.apache.jetspeed.page.document.Node#isHidden()
534: */
535: public boolean isHidden() {
536: return hidden;
537: }
538:
539: /* (non-Javadoc)
540: * @see org.apache.jetspeed.page.document.Node#setHidden(boolean)
541: */
542: public void setHidden(boolean hidden) {
543: this.hidden = hidden;
544: }
545: }
|