/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/resourcekind/AbstractResourceKind.java,v 1.30.2.1 2004/10/08 16:33:22 luetzkendorf Exp $
* $Revision: 1.30.2.1 $
* $Date: 2004/10/08 16:33:22 $
*
* ====================================================================
*
* 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.webdav.util.resourcekind;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.util.AclConstants;
import org.apache.slide.webdav.util.BindConstants;
import org.apache.slide.webdav.util.DaslConstants;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.WebdavConstants;
import org.jdom.Element;
import org.jdom.JDOMException;
/**
* Abstraction of a WebDAV-compliant resource kind.
*/
abstract public class AbstractResourceKind implements ResourceKind, WebdavConstants, DeltavConstants, AclConstants, DaslConstants, BindConstants {
/**
** String constant for an empty (<code>""</code>) string.
**/
public static final String EMPTY_STRING = "";
// supported reports
protected static Set supportedFeatures = new HashSet();
// protected properties
protected static Set liveProperties = new HashSet();
// protected properties
protected static Set protectedProperties = new HashSet();
// computed properties
protected static Set computedProperties = new HashSet();
/**
* A String array containing the names of the Elements supported as a
* value of the <code><auto-version></code> property,
* e.g. <code>checkout-checkin</code>.
*/
protected final static String[] SUPPORTED_AUTO_VERSION_ELEMENTS =
new String[] {EMPTY_STRING, E_CHECKOUT, E_CHECKOUT_IGNORE_UNLOCK, E_CHECKOUT_CHECKIN, E_CHECKOUT_UNLOCKED_CHECKIN, E_LOCKED_CHECKOUT};
/**
* A String array containing the names of the Elements supported as a
* value of the <code><checkout-fork></code> property,
* e.g. <code>discouraged</code>.
*/
protected final static String[] SUPPORTED_CHECKOUT_FORK_ELEMENTS =
new String[] {EMPTY_STRING, E_DISCOURAGED, E_FORBIDDEN};
/**
* A String array containing the names of the Elements supported as a
* value of the <code><checkin-fork></code> property,
* e.g. <code>discouraged</code>.
*/
protected final static String[] SUPPORTED_CHECKIN_FORK_ELEMENTS =
new String[] {EMPTY_STRING, E_DISCOURAGED, E_FORBIDDEN};
/**
* The values of {@link #SUPPORTED_AUTO_VERSION_ELEMENTS SUPPORTED_AUTO_VERSION_ELEMENTS}
* as a (unmodifiable) List.
*/
protected final static List SUPPORTED_AUTO_VERSION_ELEMENTS_LIST = Collections.unmodifiableList(Arrays.asList(SUPPORTED_AUTO_VERSION_ELEMENTS));
/**
* The values of {@link #SUPPORTED_CHECKOUT_FORK_ELEMENTS SUPPORTED_CHECKOUT_FORK_ELEMENTS}
* as a (unmodifiable) List.
*/
protected final static List SUPPORTED_CHECKOUT_FORK_ELEMENTS_LIST = Collections.unmodifiableList(Arrays.asList(SUPPORTED_CHECKOUT_FORK_ELEMENTS));
/**
* The values of {@link #SUPPORTED_CHECKIN_FORK_ELEMENTS SUPPORTED_CHECKIN_FORK_ELEMENTS}
* as a (unmodifiable) List.
*/
protected final static List SUPPORTED_CHECKIN_FORK_ELEMENTS_LIST = Collections.unmodifiableList(Arrays.asList(SUPPORTED_CHECKIN_FORK_ELEMENTS));
/**
* Maps the names of the properties that have a restricted set of supported
* Element values to the List of names of these supported Elements
* (e.g. {@link #SUPPORTED_AUTO_VERSION_ELEMENTS_LIST SUPPORTED_AUTO_VERSION_ELEMENTS_LIST}.
*/
protected final static Map RESTRICTED_PROPERTY_VALUE_MAP = new HashMap();
// static initialization
static {
// features
supportedFeatures.add( F_WEBDAV );
supportedFeatures.add( F_SLIDE );
if( Configuration.useIntegratedLocking() )
supportedFeatures.add( F_LOCKING );
if( Configuration.useIntegratedSecurity() )
supportedFeatures.add( F_ACCESS_CONTROL );
if( Configuration.useSearch() )
supportedFeatures.add( F_SEARCHING_AND_LOCATING );
if( Configuration.useVersionControl() ) {
supportedFeatures.add( F_VERSION_CONTROL );
supportedFeatures.add( F_VERSION_HISTORY );
supportedFeatures.add( F_CHECKOUT_IN_PLACE );
supportedFeatures.add( F_WORKSPACE );
supportedFeatures.add( F_WORKING_RESOURCE );
supportedFeatures.add( F_LABEL );
supportedFeatures.add( F_UPDATE );
}
if (Configuration.useGlobalBinding()) {
supportedFeatures.add( F_BINDING );
}
// Computed properties
computedProperties.add( P_ACL);
computedProperties.add( P_ACL_RESTRICTIONS );
computedProperties.add( P_ACTIVITY_CHECKOUT_SET );
computedProperties.add( P_ACTIVITY_VERSION_SET );
computedProperties.add( P_BASELINE_CONTROLLED_COLLECTION_SET );
computedProperties.add( P_CREATIONUSER );
computedProperties.add( P_CURRENT_USER_PRIVILEGE_SET);
computedProperties.add( P_CURRENT_WORKSPACE_SET );
computedProperties.add( P_ECLIPSED_SET );
computedProperties.add( P_GROUP_MEMBERSHIP );
computedProperties.add( P_INHERITED_ACL_SET );
computedProperties.add( P_LOCKDISCOVERY );
computedProperties.add( P_MODIFICATIONUSER );
computedProperties.add( P_OWNER);
computedProperties.add( P_PRINCIPAL_COLLECTION_SET);
computedProperties.add( P_PRIVILEGE_COLLECTION_SET);
computedProperties.add( P_ROOT_VERSION );
computedProperties.add( P_SUCCESSOR_SET );
computedProperties.add( P_SUPPORTEDLOCK );
computedProperties.add( P_SUPPORTED_LIVE_PROPERTY_SET ); //"protected" in spec but too long for some datastores
computedProperties.add( P_SUPPORTED_METHOD_SET ); //"protected" in spec but too long for some datastores
computedProperties.add( P_SUPPORTED_PRIVILEGE_SET);
computedProperties.add( P_SUPPORTED_REPORT_SET ); //"protected" in spec but too long for some datastores
computedProperties.add( P_VERSION_CONTROLLED_CONFIGURATION );
computedProperties.add( P_VERSION_HISTORY );
computedProperties.add( P_WORKSPACE ); //"protected" in spec but made computed for BIND
computedProperties.add( P_WORKSPACE_CHECKOUT_SET );
// Protected properties
protectedProperties.addAll( computedProperties );
protectedProperties.add( P_ALTERNATE_URI_SET );
protectedProperties.add( P_AUTO_UPDATE );
protectedProperties.add( P_BASELINE_COLLECTION );
protectedProperties.add( P_BASELINE_CONTROLLED_COLLECTION );
protectedProperties.add( P_CHECKED_IN );
protectedProperties.add( P_CHECKED_OUT );
protectedProperties.add( P_CHECKOUT_SET ); //"computed" in spec but made protected for performance reasons
protectedProperties.add( P_CREATIONDATE );
protectedProperties.add( P_MODIFICATIONDATE );
protectedProperties.add( P_GETLASTMODIFIED );
// protectedProperties.add( P_GETCONTENTTYPE ); // so what ... let the client set the content-type via PROPPATCH
protectedProperties.add( P_GETCONTENTLENGTH );
protectedProperties.add( P_GETETAG );
protectedProperties.add( P_LABEL_NAME_SET );
protectedProperties.add( P_PARENT_SET );
protectedProperties.add( P_PREDECESSOR_SET );
protectedProperties.add( P_RESOURCE_ID );
protectedProperties.add( P_RESOURCETYPE );
protectedProperties.add( P_SOURCE );
protectedProperties.add( P_SUBBASELINE_SET );
protectedProperties.add( P_VERSION_CONTROLLED_BINDING_SET );
protectedProperties.add( P_VERSION_NAME );
protectedProperties.add( P_VERSION_SET );
protectedProperties.add( P_PRIVILEGE_MEMBERSHIP ); // TODO: make computed??
// Live properties
liveProperties.addAll( WebdavConstants.WEBDAV_PROPERTY_LIST );
liveProperties.addAll( AclConstants.ACL_PROPERTY_LIST );
liveProperties.addAll( DeltavConstants.DELTAV_PROPERTY_LIST );
liveProperties.addAll( BindConstants.BIND_PROPERTY_LIST );
// restricted property values
RESTRICTED_PROPERTY_VALUE_MAP.put(P_AUTO_VERSION, SUPPORTED_AUTO_VERSION_ELEMENTS_LIST);
RESTRICTED_PROPERTY_VALUE_MAP.put(P_CHECKOUT_FORK, SUPPORTED_CHECKOUT_FORK_ELEMENTS_LIST);
RESTRICTED_PROPERTY_VALUE_MAP.put(P_CHECKIN_FORK, SUPPORTED_CHECKIN_FORK_ELEMENTS_LIST);
}
/**
* Factory method.
*/
static public ResourceKind getInstance() {
return null;
}
/**
* Factory method.
*/
static public ResourceKind determineResourceKind( NamespaceAccessToken nsaToken, NodeRevisionDescriptors nrds, NodeRevisionDescriptor nrd ) {
UriHandler uh = UriHandler.getUriHandler( nrds, nrd );
return determineResourceKind( nsaToken, uh.toString(), nrd );
}
/**
* Factory method.
*/
static public ResourceKind determineResourceKind( NamespaceAccessToken nsaToken, String resourcePath, NodeRevisionDescriptor nrd ) {
UriHandler uh = UriHandler.getUriHandler( resourcePath );
NamespaceConfig config = nsaToken.getNamespaceConfig();
if( nrd == null ) {
return DeltavCompliantUnmappedUrlImpl.getInstance();
}
else if( uh.isHistoryUri() ) {
return VersionHistoryImpl.getInstance();
}
else if( uh.isVersionUri() ) {
return VersionImpl.getInstance();
}
else if( uh.isWorkspaceUri() ) {
return WorkspaceImpl.getInstance();
}
else if( uh.isWorkingresourceUri() ) {
return WorkingImpl.getInstance();
}
else if( nrd.exists(P_CHECKED_IN) ) {
return CheckedInVersionControlledImpl.getInstance();
}
else if( nrd.exists(P_CHECKED_OUT) ) {
return CheckedOutVersionControlledImpl.getInstance();
}
else if( config.isPrincipal(resourcePath) ) {
return PrincipalImpl.getInstance();
}
else if( nrd.propertyValueContains(P_RESOURCETYPE, E_COLLECTION) ) {
return DeltavCompliantCollectionImpl.getInstance();
}
else {
return VersionableImpl.getInstance();
}
}
/**
*
*/
protected static boolean isSupportedFeature( String feature ) {
return supportedFeatures.contains( feature );
}
/**
*
*/
protected static boolean isSupportedFeature( String feature, String[] excludedFeatures ) {
return supportedFeatures.contains( feature )
&& (Arrays.binarySearch(excludedFeatures, feature) < 0);
}
/**
* Return true if the specified property is a DAV: live property.
*/
public static boolean isLiveProperty( String propName ) {
return( liveProperties.contains(propName) );
}
/**
* Return true if the specified property is a protected DAV: live property.
*/
public static boolean isProtectedProperty( String propName ) {
return( protectedProperties.contains(propName) );
}
/**
* Return true if the specified property is a computed DAV: live property.
*/
public static boolean isComputedProperty( String propName ) {
return( computedProperties.contains(propName) );
}
/**
* Return the set of all DAV: live properties.
*/
public static Set getAllLiveProperties() {
return( Collections.unmodifiableSet(liveProperties) );
}
/**
* Return the set of all DAV: protected live properties.
*/
public static Set getAllProtectedProperties() {
return( Collections.unmodifiableSet(protectedProperties) );
}
/**
* Return the set of all DAV: computed live properties.
*/
public static Set getAllComputedProperties() {
return( Collections.unmodifiableSet(computedProperties) );
}
/**
* Get the set properties supported by this resource kind.
*/
public Set getSupportedLiveProperties() {
return getSupportedLiveProperties( new String[0] );
}
/**
* Get the set properties supported by this resource kind.
* @param filter Q_PROTECTED_ONLY or Q_COMPUTED_ONLY (no filtering if null)
* @see org.apache.slide.webdav.util.WebdavConstants
* @see org.apache.slide.webdav.util.DeltavConstants
* @see org.apache.slide.webdav.util.AclConstants
* @see org.apache.slide.webdav.util.DaslConstants
*/
public Set getSupportedLiveProperties( String filter ) {
Set s = getSupportedLiveProperties( new String[0] );
if( Q_COMPUTED_ONLY.equals(filter) ) {
s.retainAll( computedProperties );
}
if( Q_PROTECTED_ONLY.equals(filter) ) {
s.retainAll( protectedProperties );
}
return s;
}
/**
* Get the set properties supported by this resource kind.
* @param excludedFeatures array of F_* constants (no filtering if null or empty)
* @see org.apache.slide.webdav.util.WebdavConstants
* @see org.apache.slide.webdav.util.DeltavConstants
* @see org.apache.slide.webdav.util.AclConstants
* @see org.apache.slide.webdav.util.DaslConstants
*/
public Set getSupportedLiveProperties( String[] excludedFeatures ) {
Set s = new HashSet();
Iterator it = getSuperKinds().iterator();
while( it.hasNext() ) {
ResourceKind superkind = (ResourceKind)it.next();
s.addAll( superkind.getSupportedLiveProperties(excludedFeatures) );
}
return s;
}
/**
* Get the set properties supported by this resource kind.
* @param filter Q_PROTECTED_ONLY or Q_COMPUTED_ONLY (no filtering if null)
* @param excludedFeatures array of F_* constants (no filtering if null or empty)
* @see org.apache.slide.webdav.util.WebdavConstants
* @see org.apache.slide.webdav.util.DeltavConstants
* @see org.apache.slide.webdav.util.AclConstants
* @see org.apache.slide.webdav.util.DaslConstants
*/
public Set getSupportedLiveProperties( String filter, String[] excludedFeatures ) {
Set s = getSupportedLiveProperties( excludedFeatures );
if( Q_COMPUTED_ONLY.equals(filter) ) {
s.retainAll( computedProperties );
}
if( Q_PROTECTED_ONLY.equals(filter) ) {
s.retainAll( protectedProperties );
}
return s;
}
/**
* Get the set methods supported by this resource kind.
*/
public Set getSupportedMethods() {
Set result = new HashSet();
Iterator it = getSuperKinds().iterator();
while( it.hasNext() ) {
ResourceKind superkind = (ResourceKind)it.next();
result.addAll( superkind.getSupportedMethods() );
}
return result;
}
/**
* Return true, if the specified property is supported by this resource kind.
*/
public boolean isSupportedLiveProperty( String prop ) {
return getSupportedLiveProperties().contains( prop );
}
/**
* Return true, if the specified method is supported by this resource kind.
*/
public boolean isSupportedMethod( String method ) {
return getSupportedMethods().contains( method );
}
/**
* Get the set reports supported by this resource kind.
*/
public Set getSupportedReports() {
Set result = new HashSet();
Iterator it = getSuperKinds().iterator();
while( it.hasNext() ) {
ResourceKind superkind = (ResourceKind)it.next();
result.addAll( superkind.getSupportedReports() );
}
return result;
}
/**
* Some properties (e.g. <code><auto-version></code>) have a
* restricted set of supported values.
* If the value set of the given <code>property</code> is restricted and
* the given <code>value</code> is not contained in that set, this method
* returns <code>false</code>, otherwise <code>true</code>.
*
* @param propertyName the name of the property.
* @param value the value to check.
*
* @return <code>false</code> if the value is not allowed, otherwise
* <code>true</code>.
*/
public boolean isSupportedPropertyValue(String propertyName, Object value) {
boolean isSupported = true;
List listOfRestrictedValues = (List)RESTRICTED_PROPERTY_VALUE_MAP.get(propertyName);
if (listOfRestrictedValues != null) {
if (value == null) {
return false;
}
// handle "" value
if (EMPTY_STRING.equals(value.toString())) {
return listOfRestrictedValues.contains(EMPTY_STRING);
}
XMLValue xmlValue = null;
if (value instanceof XMLValue) {
xmlValue = (XMLValue)value;
}
else {
try {
xmlValue = new XMLValue(value.toString());
}
catch (JDOMException e) {
return false;
}
}
isSupported =
(xmlValue.size() > 0) &&
listOfRestrictedValues.contains(((Element)xmlValue.iterator().next()).getName());
}
return isSupported;
}
/**
*
*/
public String toString() {
return plainClassName( getClass() );
}
protected List getSuperKinds() {
List result = new ArrayList();
Class myclass = getClass();
String myclassName = plainClassName( myclass );
Class[] ifs = myclass.getInterfaces();
for( int i = 0; i < ifs.length; i++ ) {
Class myif = ifs[i];
String myifName = plainClassName( myif );
if( !myclassName.startsWith(myifName) )
continue;
Class[] superifs = myif.getInterfaces();
for( int j = 0; j < superifs.length; j++ ) {
Class superif = superifs[j];
String superifName = plainClassName( superif );
if( "ResourceKind".equals(superifName) )
continue;
Class superclass = null;
ResourceKind superkind = null;
try {
superclass = Class.forName( superif.getName()+"Impl" );
Class[] ptypes = new Class[0];
Method facmeth = superclass.getMethod( "getInstance", ptypes );
Object[] parms = new Object[0];
result.add( facmeth.invoke(null, parms) );
}
catch( Exception x ) {
x.printStackTrace();
throw new IllegalStateException( x.getMessage() );
}
}
}
return result;
}
private String plainClassName( Class c ) {
String n = c.getName();
int i = n.lastIndexOf( '.' );
return n.substring( i + 1 );
}
/**
*
*/
public static void main(String[] args) {
String rkn = args[0];
Class[] pt = new Class[0];
Object[] p = new Object[0];
Iterator i;
if( rkn == null || rkn.length() == 0 )
return;
try {
Class rkc = Class.forName(
"org.apache.slide.webdav.util.resourcekind."+rkn+"Impl");
ResourceKind rk =
(ResourceKind)rkc.getMethod("getInstance", pt).invoke(null, p);
System.out.println("\nResource kind: "+rk);
System.out.println("\nSupported live properties:");
i = rk.getSupportedLiveProperties().iterator();
while( i.hasNext() )
System.out.println("- "+i.next());
System.out.println("\nSupported methods:");
i = rk.getSupportedMethods().iterator();
while( i.hasNext() )
System.out.println("- "+i.next());
System.out.println("\nSupported reports:");
i = rk.getSupportedReports().iterator();
while( i.hasNext() )
System.out.println("- "+i.next());
}
catch( Exception x ) { x.printStackTrace(); }
}
}