/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/search/basic/ComparableResourceImpl.java,v 1.7.2.1 2004/02/05 16:05:10 mholz Exp $
* $Revision: 1.7.2.1 $
* $Date: 2004/02/05 16:05:10 $
*
* ====================================================================
*
* 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.search.basic;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.slide.common.Domain;
import org.apache.slide.common.PropertyName;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.UriPath;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.search.CompareHint;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.SearchToken;
import org.apache.slide.search.SlideUri;
import org.apache.slide.search.basic.Literals;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.ObjectNode;
/**
* Represents one Resource. Implements operators like greaterThan,
* equals, ...
*
* @author <a href="mailto:martin.wallmer@softwareag.com">Martin Wallmer</a>
* @version $Revision: 1.7.2.1 $
*/
public class ComparableResourceImpl implements ComparableResource {
// TODO: properties with namespace...
/** The ObjectNode of this resource */
private ObjectNode objectNode;
/** the latest revision of this resource */
protected NodeRevisionDescriptor revisionDescriptor;
private Content contentHelper;
private NodeRevisionDescriptors revisionDescriptors;
private SlideToken slideToken;
private SearchToken searchToken;
/**
* The PropertyProvider to use (may be <code>null</code>).
*/
protected PropertyProvider propertyProvider = null;
/**
* The scope.
*/
protected QueryScope scope = null;
/** coantains allowed on */
static final private Set containsForbiddenOn = new HashSet();
static {
containsForbiddenOn.add ("image/gif");
containsForbiddenOn.add ("image/jpeg");
containsForbiddenOn.add ("image/pjpeg");
containsForbiddenOn.add ("image/jpg");
containsForbiddenOn.add ("audio/mpg");
containsForbiddenOn.add ("audio/mpeg");
};
private static final int EQ = 1;
private static final int GT = 2;
private static final int LT = 3;
private static final int GTE = 4;
private static final int LTE = 5;
/**
* Constructs a RequestedResource.
*
* @param objectNode the ObjectNode for this resource
* @param searchToken the SearchToken for this request
* @param scope the scope of the query.
* @param propertyProvider the PropertyProvider to use (may be
* <code>null</code>).
*
* @throws BadQueryException
*/
public ComparableResourceImpl (ObjectNode objectNode, SearchToken searchToken, QueryScope scope, PropertyProvider propertyProvider)
throws SlideException
{
this (objectNode, searchToken.getSlideToken(), searchToken.getContentHelper(), scope, propertyProvider);
this.searchToken = searchToken;
}
// private boolean isCollection;
/**
* Constructs a RequestedResource.
*
* @param objectNode the ObjectNode for this resource
* @param slideToken the slideToken for this request
* @param contentHelper you won't believe, the ContentHelper
* @param scope the scope of the query.
* @param propertyProvider the PropertyProvider to use (may be
* <code>null</code>).
*
* @throws BadQueryException
*/
public ComparableResourceImpl (ObjectNode objectNode, SlideToken slideToken, Content contentHelper, QueryScope scope, PropertyProvider propertyProvider) throws SlideException {
this.objectNode = objectNode;
this.contentHelper = contentHelper;
this.slideToken = slideToken;
this.propertyProvider = propertyProvider;
this.scope = scope;
try {
revisionDescriptors =
contentHelper.retrieve (slideToken, objectNode.getUri());
try {
revisionDescriptor =
contentHelper.retrieve (slideToken, revisionDescriptors);
}
catch (org.apache.slide.content.RevisionDescriptorNotFoundException e) {
// The object doesn't have any revision, we create a dummy
// NodeRevisionDescriptor object
// isCollection = true;
revisionDescriptor = new NodeRevisionDescriptor(0);
revisionDescriptor.setName(new UriPath(objectNode.getUri()).lastSegment());
}
}
catch (AccessDeniedException e) {
e.fillInStackTrace();
throw e;
}
catch (Exception e) {
e.printStackTrace();
throw new SlideException (e.getMessage()); // TODO: clean exception handling
}
}
protected ComparableResourceImpl () {}
/**
* Checks, if a property, represented by its name and value (as String),
* is greater than the matching property within this item.
*
* @param propName the name of the property to check
* @param literal the value as String to check again
*
* @return Literals.TRUE, Literals.FALSE or Literals.UNKNOWN
*
*/
public int greaterThan (String propName, String propNamespace, String literal) {
return compare (propName, propNamespace, literal, GT);
}
public int greaterThanEquals (String propName, String propNamespace, String literal) {
return compare (propName, propNamespace, literal, GTE);
}
public int lowerThan (String propName, String propNamespace, String literal) {
return compare (propName, propNamespace, literal, LT);
}
public int lowerThanEquals (String propName, String propNamespace, String literal) {
return compare (propName, propNamespace, literal, LTE);
}
/**
* Checks, if a property, represented by its name and value (as String),
* is EQUAL the matching property within this item.
*
* @param propName the name of the property to check
* @param literal the value as String to check again
*
* @return Literals.TRUE, Literals.FALSE or Literals.UNKNOWN
*
*/
public int equals (String propName, String propNamespace, String literal) {
return compare (propName, propNamespace, literal, EQ);
}
/**
* checks, if a properties' value contains a literal
*
* @param propName a String
* @param literal a String
*
* @return Literal.TRUE, if propName's value contains literal
*
*/
public int propContains (String propName, String propNamespace, String literal) {
Object o = getThisValue (propName, propNamespace);
if (o instanceof String == false)
return Literals.UNKNOWN;
String thisValue = (String)o;
if (thisValue.indexOf(literal) == -1)
return Literals.FALSE;
return Literals.TRUE;
}
/**
* href accessor
*
* @return the href of this item
*/
public String getInternalHref() {
return objectNode.getUri();
}
/**
* Method getExternalHref
*
* @return a String
* @deprecated
*/
public String getExternalHref () {
SlideUri slideContext = searchToken.getSlideContext();
return slideContext.getContextPath (objectNode.getUri());
}
/**
* Method getThisValue
*
* @param propName the property name
*
* @return the value of the property within this item
*/
public Object getThisValue (String propName, String propNamespace) {
Object result = null;
// special handling for properties as contenlength, contenttype, ...
// all other properties...
NodeProperty property = null;
try {
property = getProperty(propName, propNamespace);
}
catch (SlideException e) {
Domain.error("ComparableResourceImpl.getThisValue()", e);
}
result = (property == null) ? null : property.getValue();
return result;
}
/**
* Returns the NodeProperty with the given name and
* {@link org.apache.slide.content.NodeProperty.NamespaceCache#DEFAULT_URI
* default} namespace.
*
* @param propName the name of the property.
*
* @return the requested NodeProperty.
*/
protected NodeProperty getProperty(String propName) {
NodeProperty property = null;
try {
property = getProperty(propName, NamespaceCache.DEFAULT_URI);
}
catch (SlideException e) {
Domain.error("ComparableResourceImpl.getProperty()", e);
}
return property;
}
/**
* Returns the URI of the resource.
*
* @return the URI of the resource.
*/
public String getUri() {
return getInternalHref();
}
/**
* Returns the property with the given <code>propertyName</code>.
*
* @param propertyName the PropertyName of the property.
*
* @return the property with the given <code>npropertyNameame</code>.
*
* @throws SlideException
*/
public NodeProperty getProperty(PropertyName propertyName) throws SlideException {
return getProperty(propertyName.getName(), propertyName.getNamespace());
}
/**
* Returns the property with the given <code>name</code> and
* <code>namespace</code>.
*
* @param name the name of the property.
* @param namespace the namespace URI of the property.
*
* @return the property with the given <code>name</code> and
* <code>namespace</code>.
*
* @throws SlideException
*/
public NodeProperty getProperty(String name, String namespace) throws SlideException {
NodeProperty property = null;
if ( (propertyProvider != null) && propertyProvider.isSupportedProperty(getUri(), name, namespace) ) {
property = propertyProvider.getProperty(getUri(), name, namespace);
}
else {
property = revisionDescriptor.getProperty (name, namespace);
}
return property;
}
/**
* Returns an Iterator of PropertyName of all properties.
*
* @return an Iterator of PropertyName.
*
* @throws SlideException
*/
public Iterator getAllPropertiesNames() throws SlideException {
Set propertyNamesSet = new HashSet();
Enumeration enum = revisionDescriptor.enumerateProperties();
NodeProperty property = null;
if (enum != null) {
while (enum.hasMoreElements()) {
property = (NodeProperty)enum.nextElement();
propertyNamesSet.add(new PropertyName(property.getName(),
property.getNamespace()));
}
}
Iterator iterator = propertyProvider.getSupportedPropertiesNames(getUri());
while (iterator.hasNext()) {
propertyNamesSet.add(iterator.next());
}
return propertyNamesSet.iterator();
}
/**
* Returns all properties as an Iterator of NodeProperty objects.
*
* @return all properties as an Iterator of NodeProperty objects.
*
* @throws SlideException
*/
public Iterator getAllProperties() throws SlideException {
Set propertySet = new HashSet();
Enumeration enum = revisionDescriptor.enumerateProperties();
if (enum != null) {
while (enum.hasMoreElements()) {
propertySet.add(enum.nextElement());
}
}
if (propertyProvider != null) {
Iterator iterator = propertyProvider.getSupportedProperties(getUri());
while (iterator.hasNext()) {
propertySet.add(iterator.next());
}
}
return propertySet.iterator();
}
// brauchen wir die???
/**
* Method isCollection
*
* @param revisionDescriptor a NodeRevisionDescriptor
*
* @return a boolean
*
*/
public boolean isCollection (NodeRevisionDescriptor revisionDescriptor) {
boolean result = false;
if (revisionDescriptor == null)
return true;
NodeProperty property = revisionDescriptor.getProperty("resourcetype");
if ((property != null)
&& (property.getValue().equals("<collection/>"))) {
result = true;
}
return result;
}
/**
* compares two RequestedResources according to OrderByHint. NULL values are
* always considered as lessThan. (see [DASL] 5.6). Called in orderBy context
* May only return 0 if the URIs are equal.
*
* @param otherResource a RequestedResource
* @param hint an OrderByHint
*
* @return an int
*
*/
public int compareTo (ComparableResource otherResource, CompareHint hint) {
int result = 0;
Comparable otherValue = (Comparable) otherResource.getThisValue (hint.getPropName(), hint.getPropNamespace());
Comparable thisValue = (Comparable) getThisValue (hint.getPropName(), hint.getPropNamespace());
if (getInternalHref().equals (otherResource.getInternalHref()))
result = 0;
else if (thisValue != null && otherValue != null) {
result = thisValue.compareTo(otherValue);
// if (result == 0)
// result = 1;
}
else if (thisValue == null)
result = -1;
else if (otherValue == null)
result = 1;
if (hint.isAscending() == false)
result = result * -1;
// todo: take casesensitive into account
return result;
}
/**
* Method isDefined
*
* @param propName a String
*
* @return true if propName is defined in this resource.
*
*/
public boolean isDefined (String propName, String propNamespace) {
return getThisValue (propName, propNamespace) == null ? false : true;
}
/**
* Checks, if the content of the resource contains a specific literal.
*
* @param literal a String
*
* @return true if literal is contained in this resources' content
*
*/
public int contains (String literal) {
int result = Literals.UNKNOWN;
NodeProperty property = getProperty("getcontenttype");
if (property != null) {
String contentType = (String) property.getValue();
if (!containsForbiddenOn.contains (contentType)) {
try {
NodeRevisionContent revisionContent = contentHelper.retrieve (slideToken, revisionDescriptors, revisionDescriptor);
// TODO: be aware of I18N
String content = new String (revisionContent.getContentBytes());
if (content.indexOf (literal) > -1)
result = Literals.TRUE;
else
result = Literals.FALSE;
}
catch (org.apache.slide.common.SlideException e) {
// error handling ???
}
}
}
return result;
}
/**
* Compares the value of this resources property (propname) to the
* propname / literal pair. Returns an integer greater, equal or less than
* 0 according java.lang.Comparable
*
* @param propName a String
* @param literal a String
*
* @return an int
*
* @throws NumberFormatException
* @throws UnknownException
*
*/
private int compareTo (String propName, String propNamespace, String literal)
throws NumberFormatException, UnknownException
{
int result = 0;
Object thisValue = getThisValue (propName, propNamespace);
if (thisValue == null)
throw new UnknownException ();
Object otherValue = null;
otherValue = getOtherValue (thisValue, literal);
result = ((Comparable)thisValue).compareTo((Comparable)otherValue);
return result;
}
/**
* Method getOtherValue
*
* @param thisValue an Object
* @param literal a String
*
* @return an Object
*
* @throws NumberFormatException
*/
private Object getOtherValue (Object thisValue, String literal)
throws NumberFormatException
{
Object otherValue = null;
if (thisValue instanceof Boolean)
otherValue = new Boolean (literal);
else if (thisValue instanceof Date) {
otherValue = new Date (); // TODO: dateTime.iso8601tz
// otherValue = new Date (literal); // TODO: dateTime.iso8601tz
}
else if (thisValue instanceof Float)
otherValue = new Float (literal);
else if (thisValue instanceof Integer)
otherValue = new Integer (literal);
else if (thisValue instanceof Long)
otherValue = new Long (literal);
else
otherValue = literal;
return otherValue;
}
private int compare (String propName, String propNamespace, String literal, int op) {
int result = Literals.FALSE;
Object thisValue = getThisValue (propName, propNamespace);
if (thisValue == null)
return Literals.UNKNOWN;
Object otherValue = null;
try {
otherValue = getOtherValue (thisValue, literal);
switch (op)
{
case EQ:
if (compareTo (propName, propNamespace, literal) == 0)
result = Literals.TRUE;
break;
case GT:
if (compareTo (propName, propNamespace, literal) > 0)
result = Literals.TRUE;
break;
case LT:
if (compareTo (propName, propNamespace, literal) < 0)
result = Literals.TRUE;
break;
case GTE:
if (compareTo (propName, propNamespace, literal) >= 0)
result = Literals.TRUE;
break;
case LTE:
if (compareTo (propName, propNamespace, literal) <= 0)
result = Literals.TRUE;
break;
default:
break;
}
}
catch (NumberFormatException e) {
result = Literals.UNKNOWN;
}
catch (UnknownException e) {
result = Literals.UNKNOWN;
}
return result;
}
public boolean equals (Object otherObject) {
if (!(otherObject instanceof ComparableResource))
return false;
String otherUri = null;
try {
otherUri = ((ComparableResource)otherObject).getUri();
} catch (SlideException e) {}
if (getUri().equals (otherUri))
return true;
else
return false;
}
public int hashCode () {
return getUri().hashCode();
}
/**
* Dummy Exception to indicate UNKNOWN state
*/
private class UnknownException extends Exception {
}
}