/**
* JHOVE2 - Next-generation architecture for format-aware characterization
*
* Copyright (c) 2009 by The Regents of the University of California,
* Ithaka Harbors, Inc., and The Board of Trustees of the Leland Stanford
* Junior University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of the University of California/California Digital
* Library, Ithaka Harbors/Portico, or Stanford University, nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jhove2.core;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import org.jhove2.annotation.ReportableProperty;
import org.jhove2.core.reportable.AbstractReportable;
import org.jhove2.core.reportable.Reportable;
import com.sleepycat.persist.model.Persistent;
/**
* A JHOVE2 identifier. Note that this class is named "I8R", not
* "IdentifierModule" to avoid confusion between "identifier" as a label and
* "identifier" as a process that determines a format.
*
* @author mstrong, slabrams, smorrissey
*/
@Persistent
public class I8R
extends AbstractReportable
implements Comparable<I8R>
{
/** JHOVE2 namespace identifier prefix. */
public static final String JHOVE2_PREFIX = "http://jhove2.org/terms";
/** JHOVE2 namespace identifier format infix. */
public static final String JHOVE2_FORMAT_INFIX = "format";
/** JHOVE2 namespace identifier {@link org.jhove2.core.Message} infix. */
public static final String JHOVE2_MESSAGE_INFIX = "message";
/**
* JHOVE2 reportable property identifier infix
* {@link org.jhove2.annotation.ReportableProperty} infix label.
*/
public static final String JHOVE2_PROPERTY_INFIX = "property";
/**
* JHOVE2 reportable identifier infix
* {@link org.jhove2.core.reportable.Reportable} infix label.
*/
public static final String JHOVE2_REPORTABLE_INFIX = "reportable";
protected static String messageClassName = null;
/** Identifier types, or namespaces. */
public enum Namespace {
AFNOR, /* AFNOR standard */
AIIM, /* AIIM standard */
ANSI, /* ANSI standard */
ARK, /* ARK identifier */
BCP, /* IETF Best Community Practice */
BSI, /* BSI standard */
CallNumber, /* Call number */
CCITT, /* CCITT standard */
Charset, /* IANA charset */
DDC, /* Dewey Decimal Classification */
DOI, /* Digital Object IdentifierModule */
EBU, /* EBU standard. */
ECMA, /* ECMA standard */
FDD, /* Library of Congress FDD identifier */
FIPS, /* FIPS standard */
FourCC, /* 4CC Standard */
GUID, /* Globally Unique IdentifierModule */
Handle, /* Handle */
I3A, /* I3A standard */
IEC, /* IEC standard */
ISBN, /* International Standard Book Number */
ISO, /* ISO standard */
ISSN, /* International Standard Serial Nummber */
ITU, /* ITU standard */
JEITA, /* JEITA standard */
JHOVE2, /* JHOVE2 identifier */
LCC, /* Library of Congress Classification */
LCCN, /* Library of Congress Control Number */
MIME, /* MIME media scope */
NISO, /* NISO standard */
OCLC, /* OCLC number */
PII, /* Publisher Item IdentifierModule */
PUID, /* PRONOM Unique IdentifierModule */
PURL, /* Persistent URL */
RFC, /* IETF Request for Comments */
Shelfmark, /* Shelfmark */
SICI, /* Serial Item and Contribution IdentifierModule */
SMPTE, /* SMPTE standard */
SN, /* Serial number */
STD, /* IETF standard */
TOM, /* TOM identifier */
UUID, /* Universally Unique IdentifierModule */
URI, /* W3C Uniform Resource IdentifierModule */
URL, /* W3C Uniform Resource Locator */
URN, /* W3C Uniform Resource Name */
UTI, /* Apple Uniform Scope IdentifierModule */
Other
}
/** IdentifierModule namespace. */
protected Namespace namespace;
/** IdentifierModule value. */
protected String value;
@SuppressWarnings("unused")
private I8R (){
this(null, Namespace.JHOVE2);
}
/**
* Instantiate a <code>I8R</code> identifier in the JHOVE2 namespace.
*
* @param value
* IdentifierModule value
*/
public I8R(String value) {
this(value, Namespace.JHOVE2);
}
/**
* Instantiate a new <code>I8R</code>.
*
* @param value
* IdentifierModule value
* @param namespace
* IdentifierModule namespace
*/
public I8R(String value, Namespace namespace) {
super();
this.value = value;
this.namespace = namespace;
}
/**
* Get the identifier namespace.
*
* @return IdentifierModule namespace
*/
@ReportableProperty(order=1, value="Identifier namespace.")
public Namespace getNamespace() {
return this.namespace;
}
/**
* Get the identifier value.
*
* @return IdentifierModule value
*/
@ReportableProperty(order=1, value="Identifier value.")
public String getValue() {
return this.value;
}
/**
* Get a String representation of the identifier, in the form
* "namespace:identifier".
*
* @return String representation of the identifier
*/
@Override
public String toString() {
return "[" + this.namespace.toString() + "] " + value;
}
/**
* Lexically compare identifier.
*
* @param identifier
* IdentifierModule to be compared
* @return -1, 0, or 1 if this identifier value is less than, equal to, or
* greater than the second
* @see java.lang.Comparable#compareTo(Object)
*/
@Override
public int compareTo(I8R identifier) {
if (identifier==null){
return 1;
}
if (this==identifier){
return 0;
}
int ret = this.namespace.toString().compareToIgnoreCase(
identifier.getNamespace().toString());
if (ret > 0){
return 1;
}
else if (ret < 0){
return -1;
}
ret = this.value.compareToIgnoreCase(identifier.getValue());
if (ret > 0){
return 1;
}
else if (ret < 0){
return -1;
}
else return ret;
}
/** Determine equality between I8Rs.
* @param obj I8R whose equality is being tested
* @return True, if the two I8Rs are equal
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj){
if (this.compareTo((I8R) obj) == 0) {
return true;
}
return false;
}
/** Get hash code for the I8R.
* @return Hash code for the I8R
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result
+ ((namespace == null) ? 0 : namespace.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
/**
* Get the singular form of a plural property name.
*
* @param name
* Property name
* @return Singular form of a property name
*/
public static String singularName(String name) {
String singular = null;
int len = name.length();
if (name.substring(len - 3).equals("ies")) {
singular = name.substring(0, len - 3) + "y";
} else {
singular = name.substring(0, len - 1);
}
return singular;
}
/**
* Get the singular form of a plural property identifier.
*
* @param identifier
* Property identifier
* @return Singular form of a property identifier
*/
public static I8R singularIdentifier(I8R identifier) {
I8R singular = null;
String value = identifier.getValue();
int in = value.lastIndexOf('/') + 1;
int len = value.length();
if (value.substring(len - 3).equals("ies")) {
singular = new I8R(value + "/" + value.substring(in, len - 3) + "y");
} else {
singular = new I8R(value + "/" + value.substring(in, len - 1));
}
return singular;
}
/**
* Creates a JHOVE2 namespace identifier for a Reportable object
* @param r Reportable object for which we want JHOVE2 namespace Identifier
* @return I8R object containing JHOVE2 namespace identifier for a Reportable object
*/
public static I8R makeReportableI8R (Reportable r) {
Class<? extends Reportable> c1 = r.getClass();
String qName = c1.getName();
I8R identifier = new I8R(I8R.JHOVE2_PREFIX + "/" +
I8R.JHOVE2_REPORTABLE_INFIX + "/" +
qName.replace('.', '/'));
return identifier;
}
/**
* A reportable instance has an I8R field, but that I8R is for the
* instance as a whole. For each (reportable) field in the instance,
* we have to construct an I8R.
* @param method accessor method for the reportable field
* @param reportableClass Class instance for the reportable
* @return I8R for the reportable field in a reportable object
*/
public static I8R makeFeatureI8RFromMethod(Method method,
Class <? extends Reportable> reportableClass){
I8R featureI8R = null;
String name = method.getName();
int i = name.indexOf("get");
if (i == 0) {
name = name.substring(3);
}
String featureId = I8R.JHOVE2_PREFIX + "/";
Type type = method.getGenericReturnType();
boolean isMessage = false;
try {
isMessage = isMessage(type);
}
catch(ClassNotFoundException e)
{}
if (isMessage) {
featureId += I8R.JHOVE2_MESSAGE_INFIX;
}
else {
featureId += I8R.JHOVE2_PROPERTY_INFIX;
}
featureId += "/" + reportableClass.getName().replace('.', '/') + "/" + name;
featureI8R = new I8R(featureId);
return featureI8R;
}
/**
* Determine if Type is a JHOVE2 Message
*
* @param type Java Type
* @return True if the Type is a message; otherwise, false
* @throws ClassNotFoundException
*/
public static synchronized boolean isMessage(Type type)
throws ClassNotFoundException
{
boolean isMessage = false;
String tname = type.toString();
if (tname != null){
int i = tname.lastIndexOf("<");
if (i>0){
tname = tname.substring(i+1);
int j = tname.indexOf(">");
tname = tname.substring(0, j);
}
String messageCn = getMessageClassName();
isMessage = tname.endsWith(messageCn);
}
return isMessage;
}
/**
*
* @return
* @throws ClassNotFoundException
*/
protected static String getMessageClassName()
throws ClassNotFoundException
{
if (messageClassName==null){
messageClassName = Message.class.getName();
}
return messageClassName;
}
}