/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/NodeProperty.java,v 1.21.2.2 2004/02/05 16:05:07 mholz Exp $
* $Revision: 1.21.2.2 $
* $Date: 2004/02/05 16:05:07 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.content;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.slide.common.Domain;
import org.apache.slide.common.ObjectValidationFailedException;
import org.apache.slide.security.NodePermission;
import org.apache.slide.util.Messages;
import org.jdom.Namespace;
/**
* Node property class
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @version $Revision: 1.21.2.2 $
*/
public final class NodeProperty implements Serializable, Cloneable {
// -------------------------------------------------------------- Constants
public static final String DEFAULT_NAMESPACE = "DAV:";
public static final String SLIDE_NAMESPACE =
"http://jakarta.apache.org/slide/";
protected static final String I_STANDARDLIVEPROPERTIESCLASS = "standardLivePropertiesClass";
protected static final String I_STANDARDLIVEPROPERTIESCLASS_DEFAULT = "org.apache.slide.webdav.util.resourcekind.AbstractResourceKind";
/**
* The standard live properties.
*/
public static Set allLiveProperties;
/**
* The standard protected properties.
*/
public static Set allProtectedProperties;
/**
* The standard computed properties.
*/
public static Set allComputedProperties;
static {
try {
if (Domain.isInitialized()) {
Class slpc = Class.forName( Domain.getParameter(I_STANDARDLIVEPROPERTIESCLASS, I_STANDARDLIVEPROPERTIESCLASS_DEFAULT) );
Method lp = slpc.getMethod( "getAllLiveProperties", new Class[]{} );
allLiveProperties = (Set)lp.invoke( null, new Object[]{} ); // obj=null since method is static
Method pp = slpc.getMethod( "getAllProtectedProperties", new Class[]{} );
allProtectedProperties = (Set)pp.invoke( null, new Object[]{} ); // obj=null since method is static
Method cp = slpc.getMethod( "getAllComputedProperties", new Class[]{} );
allComputedProperties = (Set)cp.invoke( null, new Object[]{} ); // obj=null since method is static
}
}
catch( Exception x ) {
Domain.warn( "Loading of standard live properties class failed: "+x.getMessage() );
}
if( allLiveProperties == null ) allLiveProperties = Collections.EMPTY_SET;
if( allProtectedProperties == null ) allProtectedProperties = Collections.EMPTY_SET;
if( allComputedProperties == null ) allComputedProperties = Collections.EMPTY_SET;
}
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*
* @param name Name
* @param value Value
*/
public NodeProperty(String name, Object value) {
setName(name);
setValue(value);
this.namespace = DEFAULT_NAMESPACE;
this.type = new String();
this.permissions = new Vector();
this.kind = determineKind( namespace, name );
}
/**
* Constructor.
*
* @param name Name
* @param value Value
* @param namespace Namespace
*/
public NodeProperty(String name, Object value, String namespace) {
this(name, value);
setNamespace(namespace);
this.kind = determineKind( namespace, name );
}
/**
* Constructor.
*
* @param name Name
* @param value Value
* @param namespace Namespace
* @param type the type
*/
public NodeProperty(String name, Object value, String namespace, String type) {
this(name, value);
setNamespace(namespace);
this.type = type;
this.kind = determineKind( namespace, name );
}
/**
* Constructor.
*
* @param name Name
* @param value Value
* @param protectedProperty Is the property protected?
*/
public NodeProperty(String name, Object value, boolean protectedProperty) {
this(name, value);
if( protectedProperty )
this.kind = Kind.PROTECTED;
else
this.kind = determineKind( DEFAULT_NAMESPACE, name );
}
/**
* Constructor.
*
* @param name Name
* @param value Value
* @param namespace Namespace
* @param type Type info
* @param protectedProperty Protected property
*/
public NodeProperty(String name, Object value, String namespace,
String type, boolean protectedProperty) {
this(name, value, namespace);
setType(type);
if( protectedProperty )
setKind( Kind.PROTECTED );
else
this.kind = determineKind( namespace, name );
}
// ----------------------------------------------------- Instance Variables
/**
* Property name.
*/
private String name;
/**
* Namespace of the property.
*/
private String namespace;
/**
* Property value.
*/
private Object value;
/**
* Value Type. If the value is stored as a String representation of the
* value, the type field is used.
* FIXME : Remove that
*/
private String type;
/** The kind of property: dead, live, protected, computed */
private Kind kind = Kind.DEAD;
/**
* Permission list.
*/
private Vector permissions;
// ------------------------------------------------------------- Properties
/**
* Determine the kind of the property given by the specified namespace and name.
*/
private static Kind determineKind( String namespace, String name ) {
Kind result = Kind.DEAD;
if( DEFAULT_NAMESPACE.equals(namespace) ) {
if( allComputedProperties.contains(name) )
result = Kind.COMPUTED;
else if( allProtectedProperties.contains(name) )
result = Kind.PROTECTED;
else if( allLiveProperties.contains(name) )
result = Kind.LIVE;
}
return result;
}
/**
* Kind accessor.
*
* @return true, if this is a dead property
*/
public boolean isDeadProperty() {
return( (this.kind == Kind.DEAD) );
}
/**
* Kind accessor.
*
* @return true, if this is a computed (live) property
*/
public boolean isComputed() {
return( (this.kind == Kind.COMPUTED) );
}
/**
* Kind accessor.
*
* @return true, if this is a protected (live) property
*/
public boolean isProtected() {
return(
(this.kind == Kind.PROTECTED) || (this.kind == Kind.COMPUTED) );
}
/**
* Kind accessor.
*
* @return true, if this is a live property
*/
public boolean isLiveProperty() {
return(
(this.kind == Kind.LIVE) || (this.kind == Kind.PROTECTED) || (this.kind == Kind.COMPUTED) );
}
/**
* Property name accessor.
*
* @return String property name
*/
public String getName() {
return this.name;
}
/**
* Property name mutator.
*
* @param name Name
*/
void setName(String name) {
if (name == null) {
this.name = new String();
} else {
this.name = name;
}
}
/**
* Namespace accessor.
*
* @return String definition
*/
public String getNamespace() {
return this.namespace;
}
/**
* Namespace mutator.
*
* @param namespace New namespace
*/
void setNamespace(String namespace) {
if (namespace == null) {
this.namespace = "";
} else {
this.namespace = namespace;
}
}
/**
* Value accessor.
*
* @return Object value
*/
public Object getValue() {
return value;
}
/**
* Value mutator.
*
* @param value Value
*/
void setValue(Object value) {
if (value == null) {
this.value = new String();
} else {
this.value = value;
}
}
/**
* Type accessor.
*
* @return String type
*/
public String getType() {
return type;
}
/**
* Type mutator.
*
* @param type Type
*/
void setType(String type) {
if (type == null) {
this.type = new String();
} else {
this.type = type;
}
}
/**
* Kind accessor.
*
* @return the property kind (dead, live, protected, computed)
*/
public Kind getKind() {
return kind;
}
/**
* Kind mutator.
*
* @param kind the kind
*/
public void setKind( Kind kind ) {
if( kind == null ) {
this.kind = Kind.DEAD;
} else {
this.kind = kind;
}
}
/**
* Add permission.
*
* @param permission Permission
*/
public void addPermission(NodePermission permission) {
permissions.addElement(permission);
}
/**
* Remove permission.
*
* @param permission Permission to remove
*/
public void removePermission(NodePermission permission) {
permissions.removeElement(permission);
}
/**
* Enumerate permissions.
*
* @return Enumeration permissions
*/
public Enumeration enumeratePermissions() {
return permissions.elements();
}
// --------------------------------------------------------- Object Methods
/**
* Clone.
*
* @return Object clone
*/
NodeProperty cloneObject() {
NodeProperty result = null;
try {
result = (NodeProperty) super.clone();
} catch(CloneNotSupportedException e) {
}
return result;
}
/**
* Hash Code.
*
* @return int Hash code value
*/
public int hashCode() {
return getName().hashCode();
}
/**
* String representation of the permission.
* <p/>
* Format : ObjectUri-SubjectUri-ActionUri-InheritanceFlag
*
* @return String String representation
*/
public String toString() {
return getName();
}
/**
* Equals.
*
* @param obj Object to test
* @return boolean True if the two object are equal :
* <li>obj is of type NodeProperty and is not null</li>
* <li>The property names are equal</li>
*/
public boolean equals(Object obj) {
if (!(obj instanceof NodeProperty)) {
return false;
}
NodeProperty other = (NodeProperty) obj;
return this.getName().equals(other.getName())
&& this.getNamespace().equals(other.getNamespace());
}
/**
* Validate.
*/
public void validate() {
if (name == null)
throw new ObjectValidationFailedException
(Messages.message(NodeProperty.class.getName() + ".nullName"));
if (namespace == null)
throw new ObjectValidationFailedException
(Messages.message
(NodeProperty.class.getName() + ".nullNamespace"));
if (value == null)
throw new ObjectValidationFailedException
(Messages.message
(NodeProperty.class.getName() + ".nullValue"));
}
/**
* The kind of a property: dead, live, protected, computed
*/
public static class Kind implements Serializable {
private static int
DEAD_ID = 0,
LIVE_ID = 1,
PROTECTED_ID = 2,
COMPUTED_ID = 3;
/** The discrete values */
public static Kind
DEAD = new Kind( DEAD_ID ),
LIVE = new Kind( LIVE_ID ),
PROTECTED = new Kind( PROTECTED_ID ),
COMPUTED = new Kind( COMPUTED_ID );
private int id = 0;
/**
* Private constructor
*/
private Kind( int id ) {
this.id = id;
}
}
/**
* The usage of this class avoids the creation of mutliple Namespace objects
* with the same URI but different prefix. Just use it as a replacement
* for the <code>org.jdom.Namespace</code>.
* It also predefines Namespace objects for the <code>DAV:</code> and
* the <code>http://jakarta.apache.org/slide/</code> namespace
* (with an appropriate prefix).
*/
public static class NamespaceCache {
/**
* String constant for <code>S</code>.
*/
public final static String SLIDE_PREFIX = "S";
/**
* String constant for <code>http://jakarta.apache.org/slide/</code>.
*/
public final static String SLIDE_URI = NodeProperty.SLIDE_NAMESPACE;
/**
* Namespace with {@link #SLIDE_PREFIX SLIDE_PREFIX} and
* {@link #SLIDE_URI SLIDE_URI}.
*/
public final static Namespace SLIDE_NAMESPACE = getNamespace(SLIDE_PREFIX, SLIDE_URI);;
/**
* String constant for <code>D</code>.
*/
public final static String DEFAULT_PREFIX = "D";
/**
* String constant for <code>DAV:</code>.
*/
public final static String DEFAULT_URI = NodeProperty.DEFAULT_NAMESPACE;
/**
* Namespace with {@link #DEFAULT_PREFIX DEFAULT_PREFIX} and
* {@link #DEFAULT_URI DEFAULT_URI}.
*/
public final static Namespace DEFAULT_NAMESPACE = getNamespace(DEFAULT_PREFIX, DEFAULT_URI);;
/**
* Maps the namespace' URI to the Namespace object.
*/
protected static Map namespaceMap;
/**
* Returns the Namespace for the given <code>uri</code>.
* If there is already an entry in the cache for this URI,
* this Namespace will be returned.
* Otherwise a new Namespace with the prefix <code>""</code>
* (default namespace) will be created and put into the cache.
*
* @param uri the URI for which to return the Namespace.
*
* @return the Namespace for the given URI.
*/
public static Namespace getNamespace(String uri) {
return getNamespace("", uri);
}
/**
* Returns the Namespace for the given <code>prefix</code> and
* <code>uri</code>.
* If there is already an entry in the cache for this URI,
* this Namespace will be returned.
* Otherwise a new Namespace with the given <code>prefix</code>
* and <code>uri</code> will be created and put into the cache.
*
* @param prefix the prefix for which to return the Namespace.
* @param uri the URI for which to return the Namespace.
*
* @return the Namespace for the given URI.
*/
public static Namespace getNamespace(String prefix, String uri) {
Namespace namespace = (Namespace)getNamespaceMap().get(uri);
if (namespace == null) {
namespace = Namespace.getNamespace(prefix, uri);
getNamespaceMap().put(namespace.getURI(), namespace);
}
return namespace;
}
/**
* Returns the {@link #namespaceMap namespaceMap}.
*
* @return the {@link #namespaceMap namespaceMap}.
*/
protected static Map getNamespaceMap() {
if (namespaceMap == null) {
namespaceMap = new HashMap();
}
return namespaceMap;
}
}
}