package org.nexml.model.impl;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import org.nexml.model.Annotatable;
import org.nexml.model.Annotation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
abstract class AnnotatableImpl extends NexmlWritableImpl implements Annotatable {
private Set<Annotation> mAnnotations;
/**
* Protected constructors are intended for recursive parsing, i.e.
* starting from the root element (which maps onto DocumentImpl) we
* traverse the element tree such that for every child element that maps
* onto an Impl class the containing class calls that child's protected
* constructor, passes in the element of the child. From there the
* child takes over, populates itself and calls the protected
* constructors of its children. These should probably be protected
* because there is all sorts of opportunity for outsiders to call
* these in the wrong context, passing in the wrong elements etc.
* @param document the containing DOM document object. Every Impl
* class needs a reference to this so that it can create DOM element
* objects
* @param element the equivalent NeXML element (e.g. for OTUsImpl, it's
* the <otus/> element)
* @author rvosa
*/
protected AnnotatableImpl(Document document, Element element) {
super(document, element);
mAnnotations = new HashSet<Annotation>();
for ( Element metaElement : getChildrenByTagName(element,AnnotationImpl.getTagNameClass())) {
AnnotationImpl anno = new AnnotationImpl(document,metaElement);
mAnnotations.add(anno);
}
}
/**
* Protected constructors that take a DOM document object but not
* an element object are used for generating new element nodes in
* a NeXML document. On calling such constructors, a new element
* is created, which can be retrieved using getElement(). After this
* step, the Impl class that called this constructor would still
* need to attach the element in the proper location (typically
* as a child element of the class that called the constructor).
* @param document a DOM document object
* @author rvosa
*/
protected AnnotatableImpl(Document document) {
super(document);
mAnnotations = new HashSet<Annotation>();
}
protected AnnotatableImpl() {}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#getAnnotationValues(java.lang.String)
*/
public Set<Object> getAnnotationValues(String property) {
Set<Object> annotationValues = new HashSet<Object>();
if ( property == null ) {
return annotationValues;
}
for ( Annotation annotation : mAnnotations ) {
if ( property.equals(annotation.getProperty()) ) {
annotationValues.add(annotation.getValue());
}
}
return annotationValues;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#getRelValues(java.lang.String)
*/
public Set<Object> getRelValues(String rel) {
Set<Object> annotationValues = new HashSet<Object>();
if ( rel == null ) {
return annotationValues;
}
for ( Annotation annotation : mAnnotations ) {
if ( rel.equals(annotation.getRel()) ) {
annotationValues.add(annotation.getValue());
}
}
return annotationValues;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#getAllAnnotations()
*/
public Set<Annotation> getAllAnnotations() {
return mAnnotations;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#getAllAnnotationsForURI(java.net.URI)
*/
public Set<Annotation> getAllAnnotationsForURI(URI uri) {
Set<Annotation> results = new HashSet<Annotation>();
String requestedUri = uri.toString();
for ( Annotation annotation : getAllAnnotations() ) {
String property = annotation.getProperty();
if ( null == property ) {
property = annotation.getRel();
}
String[] curie = property.split(":");
String prefix = curie[0];
String uriString = getNamespaceForPrefix(prefix,((AnnotationImpl)annotation).getElement());
if ( uriString.equals(requestedUri) ) {
results.add(annotation);
}
}
return results;
}
private String getNamespaceForPrefix(String prefix,
org.w3c.dom.Node namespaceContext) {
Node parent = namespaceContext;
String namespace = null;
if ( prefix.equals("xml") ) {
namespace = "http://www.w3.org/XML/1998/namespace";
}
else {
int type;
while ((null != parent) && (null == namespace) && (((type = parent.getNodeType()) == Node.ELEMENT_NODE) || (type == Node.ENTITY_REFERENCE_NODE))) {
if (type == Node.ELEMENT_NODE) {
if ( parent.getNodeName().indexOf(prefix+":") == 0 )
return parent.getNamespaceURI();
NamedNodeMap nnm = parent.getAttributes();
for (int i = 0; i < nnm.getLength(); i++) {
Node attr = nnm.item(i);
String aname = attr.getNodeName();
boolean isPrefix = aname.startsWith("xmlns:");
if (isPrefix || aname.equals("xmlns")) {
int index = aname.indexOf(':');
String p = isPrefix ? aname.substring(index + 1) : "";
if (p.equals(prefix)) {
namespace = attr.getNodeValue();
break;
}
}
}
}
parent = parent.getParentNode();
}
}
return namespace;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#getAnnotations(java.lang.String)
*/
public Set<Annotation> getAnnotations(String rel) {
Set<Annotation> annotations = new HashSet<Annotation>();
if ( rel == null ) {
return annotations;
}
for ( Annotation annotation : mAnnotations ) {
if ( rel.equals(annotation.getProperty()) || rel.equals(annotation.getRel()) ) {
annotations.add(annotation);
}
}
return annotations;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Object value){
if ( value instanceof BigDecimal ) {
return addAnnotationValue(property,nameSpaceURI,(BigDecimal)value);
}
else if ( value instanceof BigInteger ) {
return addAnnotationValue(property,nameSpaceURI,(BigInteger)value);
}
else if ( value instanceof Boolean ) {
return addAnnotationValue(property,nameSpaceURI,(Boolean)value);
}
else if ( value instanceof Byte ) {
return addAnnotationValue(property,nameSpaceURI,(Byte)value);
}
else if ( value instanceof Byte[] ) {
return addAnnotationValue(property,nameSpaceURI,(Byte[])value);
}
else if ( value instanceof Calendar ) {
return addAnnotationValue(property,nameSpaceURI,(Calendar)value);
}
else if ( value instanceof java.lang.Character ) {
return addAnnotationValue(property,nameSpaceURI,(java.lang.Character)value);
}
else if ( value instanceof Date ) {
return addAnnotationValue(property,nameSpaceURI,(Date)value);
}
else if ( value instanceof Double ) {
return addAnnotationValue(property,nameSpaceURI,(Double)value);
}
else if ( value instanceof Duration ) {
return addAnnotationValue(property,nameSpaceURI,(Duration)value);
}
else if ( value instanceof Element ) {
return addAnnotationValue(property,nameSpaceURI,(Element)value);
}
else if ( value instanceof Float ) {
return addAnnotationValue(property,nameSpaceURI,(Float)value);
}
else if ( value instanceof Integer ) {
return addAnnotationValue(property,nameSpaceURI,(Integer)value);
}
else if ( value instanceof java.awt.Image ) {
return addAnnotationValue(property,nameSpaceURI,(java.awt.Image)value);
}
else if ( value instanceof Long ) {
return addAnnotationValue(property,nameSpaceURI,(Long)value);
}
else if ( value instanceof NodeList ) {
return addAnnotationValue(property,nameSpaceURI,(NodeList)value);
}
else if ( value instanceof Node ) {
return addAnnotationValue(property,nameSpaceURI,(Node)value);
}
else if ( value instanceof QName ) {
return addAnnotationValue(property,nameSpaceURI,(QName)value);
}
else if ( value instanceof Set ) {
return addAnnotationValue(property,nameSpaceURI,(Set<Annotation>)value);
}
else if ( value instanceof Short ) {
return addAnnotationValue(property,nameSpaceURI,(Short)value);
}
else if ( value instanceof Source ) {
return addAnnotationValue(property,nameSpaceURI,(Source)value);
}
else if ( value instanceof String ) {
return addAnnotationValue(property,nameSpaceURI,(String)value);
}
else if ( value instanceof URI ) {
return addAnnotationValue(property,nameSpaceURI,(URI)value);
}
else if ( value instanceof UUID ) {
return addAnnotationValue(property,nameSpaceURI,(UUID)value);
}
else if ( value instanceof XMLGregorianCalendar ) {
return addAnnotationValue(property,nameSpaceURI,(XMLGregorianCalendar)value);
}
// XXX etc.
else {
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, org.w3c.dom.NodeList)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, NodeList value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, org.w3c.dom.Node)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Node value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, org.w3c.dom.Element)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Element value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.net.URI)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, URI value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,true);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Byte[])
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Byte[] value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.math.BigDecimal)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, BigDecimal value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.math.BigInteger)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, BigInteger value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Boolean)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Boolean value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Byte)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Byte value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.util.Calendar)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Calendar value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.util.Date)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Date value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Double)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Double value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Float)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Float value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Integer)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Integer value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Long)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Long value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.Short)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Short value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.net.URI, java.lang.Character)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, java.lang.Character value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.util.UUID)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, UUID value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.lang.String)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, String value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.awt.Image)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, java.awt.Image value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, javax.xml.datatype.Duration)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Duration value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, javax.xml.namespace.QName)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, QName value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, javax.xml.transform.Source)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Source value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, javax.xml.datatype.XMLGregorianCalendar)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, XMLGregorianCalendar value){
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,false);
annotation.setValue(value);
return annotation;
}
/*
* (non-Javadoc)
* @see org.nexml.model.Annotatable#addAnnotationValue(java.lang.String, java.util.Set)
*/
public Annotation addAnnotationValue(String property, URI nameSpaceURI, Set<Annotation> value) {
Annotation annotation = addAnnotationValueHelper(property,nameSpaceURI,true);
annotation.setValue(value);
return annotation;
}
/**
* Helper method to fill out the boiler plate attributes for an annotation
* @param property the predicate as a CURIE, e.g. cdao:hasSupportValue
* @param nameSpaceURI the namespace to which the CURIE's prefix is bound
* @param propertyIsRel the property string is serialized as a rel attribute
* @return
*/
private Annotation addAnnotationValueHelper(String property, URI nameSpaceURI, boolean propertyIsRel) {
AnnotationImpl annotation = new AnnotationImpl(getDocument());
if ( null == property ) {
return null;
}
String[] curie = property.split(":");
if ( propertyIsRel ) {
annotation.setRel(property);
}
else {
annotation.setProperty(property);
}
mAnnotations.add(annotation);
setNameSpace(getElement(), curie[0], nameSpaceURI.toString());
// getElement().setAttributeNS(
// "http://www.w3.org/2000/xmlns/",
// "xmlns:" + curie[0],
// nameSpaceURI.toString()
// );
if ( getElement().getFirstChild() != null ) {
getElement().insertBefore(annotation.getElement(),getElement().getFirstChild());
}
else {
getElement().appendChild(annotation.getElement());
}
if ( this instanceof Annotation ) {
getElement().removeAttribute("content");
getElement().removeAttribute("datatype");
getElement().setAttribute("xsi:type","nex:ResourceMeta");
if ( getElement().hasAttribute("property") ) {
String rel = getElement().getAttribute("property");
getElement().setAttribute("rel",rel);
getElement().removeAttribute("property");
}
}
else {
String about = getElement().getAttribute("about");
if ( null == about || about.equals("") ) {
String id = getId();
if ( null == id || id.equals("") ) {
id = identify(getElement(),false);
}
getElement().setAttribute("about","#" + id.replace(':', '_'));
}
}
return annotation;
}
}