Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.modeshape.jcr.value.ValueComparators Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* 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.modeshape.jcr.value;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.UUID;
import javax.jcr.RepositoryException;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.common.util.SecureHash;
import org.modeshape.jcr.GraphI18n;
import org.modeshape.jcr.api.value.DateTime;
import org.modeshape.jcr.value.basic.StringValueFactory;
/**
* A set of {@link Comparator} objects for the different kinds of property values.
*
* @see PropertyType#getComparator()
*/
@Immutable
public final class ValueComparators {
/**
* A comparator of string values.
*/
public static final Comparator STRING_COMPARATOR = new StringComparator();
/**
* A comparator of long values.
*/
public static final Comparator LONG_COMPARATOR = new LongComparator();
/**
* A comparator of double values.
*/
public static final Comparator DOUBLE_COMPARATOR = new DoubleComparator();
/**
* A comparator of decimal values.
*/
public static final Comparator DECIMAL_COMPARATOR = new DecimalComparator();
/**
* A comparator of boolean values.
*/
public static final Comparator BOOLEAN_COMPARATOR = new BooleanComparator();
/**
* A comparator of binary values. Although {@link BinaryValue} is {@link Comparable}, this comparator does not rely upon any
* particular Binary implementation. Thus, Binary implementations can use this for their {@link Comparable#compareTo(Object)}
* implementation.
*/
public static final Comparator BINARY_COMPARATOR = new BinaryValueComparator();
/**
* A comparator of date-time instances.
*/
public static final Comparator DATE_TIME_COMPARATOR = new DateTimeComparator();
/**
* A comparator of date values.
*/
public static final Comparator DATE_COMPARATOR = new DateComparator();
/**
* A comparator of calendar values.
*/
public static final Comparator CALENDAR_COMPARATOR = new CalendarComparator();
/**
* A comparator of name values.
*/
public static final Comparator NAME_COMPARATOR = new NameComparator();
/**
* A comparator of path values.
*/
public static final Comparator PATH_COMPARATOR = new PathComparator();
/**
* A comparator of path segment values.
*/
public static final Comparator PATH_SEGMENT_COMPARATOR = new PathSegmentComparator();
/**
* A comparator of path segment names, excluding same-name-sibling indexes.
*/
public static final Comparator PATH_SEGMENT_NAME_COMPARATOR = new PathSegmentNameComparator();
/**
* A comparator of URI values.
*/
public static final Comparator URI_COMPARATOR = new UriComparator();
/**
* A comparator of UUID values.
*/
public static final Comparator UUID_COMPARATOR = new UuidComparator();
/**
* A comparator of reference values.
*/
public static final Comparator REFERENCE_COMPARATOR = new ReferenceComparator();
/**
* A comparator of other values.
*/
public static final Comparator OBJECT_COMPARATOR = new ObjectComparator();
protected static final class StringComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( String o1,
String o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof StringComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class BooleanComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Boolean o1,
Boolean o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof BooleanComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class LongComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Long o1,
Long o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof LongComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class DoubleComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Double o1,
Double o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof DoubleComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class DecimalComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( BigDecimal o1,
BigDecimal o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof DecimalComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class DateTimeComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( DateTime o1,
DateTime o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof DateTimeComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class DateComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Date o1,
Date o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof DateComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class CalendarComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Calendar o1,
Calendar o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof CalendarComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class NameComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Name o1,
Name o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof NameComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class PathComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Path o1,
Path o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof PathComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class PathSegmentComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Path.Segment o1,
Path.Segment o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof PathSegmentComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class PathSegmentNameComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Path.Segment o1,
Path.Segment o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.getName().compareTo(o2.getName());
}
@Override
public boolean equals( Object obj ) {
return obj instanceof PathSegmentNameComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class UriComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( URI o1,
URI o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof UriComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class UuidComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( UUID o1,
UUID o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof UuidComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class ReferenceComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( Reference o1,
Reference o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof ReferenceComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class ObjectComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@SuppressWarnings( "unchecked" )
@Override
public int compare( Object o1,
Object o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
PropertyType type1 = PropertyType.discoverType(o1);
PropertyType type2 = PropertyType.discoverType(o2);
// Canonicalize the values ...
o1 = type1.getCanonicalValue(o1);
o2 = type2.getCanonicalValue(o2);
if (type1 != PropertyType.OBJECT && type2 != PropertyType.OBJECT) {
if (type1 == type2) return ((Comparator)type1.getComparator()).compare(o1, o2);
// The types are different but the classes are the same ...
if (type1.getValueClass().isAssignableFrom(type2.getValueClass())) {
return ((Comparator)type1.getComparator()).compare(o1, o2);
}
if (type2.getValueClass().isAssignableFrom(type1.getValueClass())) {
return ((Comparator)type2.getComparator()).compare(o1, o2);
}
}
// The types are different. See if one is a BINARY value (because we can use the secure
// hashes to efficiently do the comparison) ...
ValueFactory stringFactory = getStringValueFactory();
String value1 = null;
String value2 = null;
if (type1 == PropertyType.BINARY || type2 == PropertyType.BINARY) {
try {
byte[] hash1 = null;
byte[] hash2 = null;
// We don't have access to a binary factory, so do this brute force.
// Conver the non-binary value to a string, then compute the hash of the string ...
if (type1 == PropertyType.BINARY) {
value2 = stringFactory.create(o2);
hash2 = SecureHash.getHash(SecureHash.Algorithm.SHA_1, value2.getBytes());
hash1 = ((BinaryValue)o1).getHash();
} else {
assert type2 == PropertyType.BINARY;
value1 = stringFactory.create(o1);
hash1 = SecureHash.getHash(SecureHash.Algorithm.SHA_1, value1.getBytes());
hash2 = ((BinaryValue)o2).getHash();
}
// Compute the difference in the hashes ...
if (hash1.length == hash2.length) {
for (int i = 0; i != hash1.length; ++i) {
int diff = hash1[i] - hash2[i];
if (diff != 0) return diff;
}
return 0;
}
} catch (Throwable error) {
// If anything went wrong, just continue with the string comparison
}
}
// The types are different and must be converted ...
if (value1 == null) value1 = stringFactory.create(o1);
if (value2 == null) value2 = stringFactory.create(o2);
return value1.compareTo(value2);
}
@Override
public boolean equals( Object obj ) {
return obj instanceof ObjectComparator;
}
@Override
public int hashCode() {
return 1;
}
}
protected static final class BinaryValueComparator implements Comparator, Serializable {
private static final long serialVersionUID = 1L;
@Override
public int compare( BinaryValue o1,
BinaryValue o2 ) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
try {
try {
// Check the lengths first ...
final long len1 = o1.getSize();
final long len2 = o2.getSize();
if (len1 < len2) return -1;
if (len1 > len2) return 1;
// Compare using the hashes, if available
String hash1 = o1.getHexHash();
String hash2 = o2.getHexHash();
if (hash1 != null && hash2 != null) {
// If the hashes match, then we should assume that the values match.
// That's the whole point of using a secure hash.
return hash1.compareTo(hash2);
}
// One or both of the hashes could not be generated, so we have to go compare
// the whole values. This is unfortunate, but should happen very rarely (if ever)
// as long as the BinaryValue.getHash() is always implemented
// Otherwise they are the same length ...
InputStream stream1 = null;
InputStream stream2 = null;
try {
stream1 = o1.getStream();
stream2 = o2.getStream();
byte[] buffer1 = new byte[1024];
byte[] buffer2 = new byte[1024];
while (true) {
int numRead1 = stream1.read(buffer1);
if (numRead1 < 0) break;
int numRead2 = stream2.read(buffer2);
if (numRead1 != numRead2) {
throw new IoException(GraphI18n.errorReadingPropertyValueBytes.text());
}
for (int i = 0; i != numRead1; ++i) {
int diff = buffer1[i] - buffer2[i];
if (diff != 0) return diff;
}
}
return 0;
} catch (RepositoryException e) {
throw new IoException(GraphI18n.errorReadingPropertyValueBytes.text());
} catch (IOException e) {
throw new IoException(GraphI18n.errorReadingPropertyValueBytes.text());
} finally {
if (stream1 != null) {
try {
stream1.close();
} catch (IOException e) {
// do nothing
}
}
if (stream2 != null) {
try {
stream2.close();
} catch (IOException e) {
// do nothing
}
}
}
} finally {
o2.dispose();
}
} finally {
o1.dispose();
}
}
@Override
public boolean equals( Object obj ) {
return obj instanceof BinaryValueComparator;
}
@Override
public int hashCode() {
return 1;
}
}
// This is loaded lazily so that there is not a circular dependency between PropertyType (depends on this),
// StringValueFactory (depends on PropertyType), and OBJECT_COMPARATOR (which depends on StringValueFactory) ...
private static ValueFactory STRING_VALUE_FACTORY;
protected static final ValueFactory getStringValueFactory() {
// No locking is required, because it doesn't matter if we create several instances during initialization ...
if (STRING_VALUE_FACTORY == null) {
STRING_VALUE_FACTORY = new StringValueFactory(Path.NO_OP_DECODER, Path.NO_OP_ENCODER);
}
return STRING_VALUE_FACTORY;
}
}