package org.openxdm.xcap.server.slee.appusage.resourcelists;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import javax.xml.validation.Validator;
import org.openxdm.xcap.common.appusage.AppUsage;
import org.openxdm.xcap.common.datasource.DataSource;
import org.openxdm.xcap.common.error.ConstraintFailureConflictException;
import org.openxdm.xcap.common.error.InternalServerErrorException;
import org.openxdm.xcap.common.error.UniquenessFailureConflictException;
import org.openxdm.xcap.common.uri.DocumentSelector;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ResourceListsAppUsage extends AppUsage {
public static final String ID = "resource-lists";
public static final String DEFAULT_DOC_NAMESPACE = "urn:ietf:params:xml:ns:resource-lists";
public static final String MIMETYPE = "application/resource-lists+xml";
public ResourceListsAppUsage(Validator schemaValidator) {
super(ID,DEFAULT_DOC_NAMESPACE,MIMETYPE,schemaValidator);
}
public static void checkNodeResourceListConstraints(Node node) throws UniquenessFailureConflictException, ConstraintFailureConflictException {
Set<String> nameSet = new HashSet<String>();
Set<String> uriSet = new HashSet<String>();
Set<String> refUriSet = new HashSet<String>();
Set<String> anchorUriSet = new HashSet<String>();
// get childs
NodeList childNodes = node.getChildNodes();
// process each one
for(int i=0;i<childNodes.getLength();i++) {
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getLocalName().equals("list")) {
// list element
Attr nameAttr = ((Element)childNode).getAttributeNode("name");
if (nameAttr != null) {
/*
o The "name" attribute in a <list> element MUST be unique amongst
all other "name" attributes of <list> elements within the same
parent element. Uniqueness is determined by case sensitive string
comparison.
*/
// name attr exists, it must be unique
if (nameSet.contains(nameAttr.getNodeValue())) {
// not unique, raise exception
throw new UniquenessFailureConflictException();
}
else {
// unique so far, add it to the name set
nameSet.add(nameAttr.getNodeValue());
// and process this list
checkNodeResourceListConstraints(childNode);
}
}
}
else if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getLocalName().equals("entry")) {
// entry element
Attr uriAttr = ((Element)childNode).getAttributeNode("uri");
/*
o The "uri" attribute in a <entry> element MUST be unique amongst
all other "uri" attributes of <entry> elements within the same
parent element. Uniqueness is determined by case sensitive string
comparison.
*/
// uri attr must be unique
if (uriSet.contains(uriAttr.getNodeValue())) {
// not unique, raise exception
throw new UniquenessFailureConflictException();
}
else {
// unique so far, add it to the uri set
uriSet.add(uriAttr.getNodeValue());
}
}
else if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getLocalName().equals("entry-ref")) {
// entry-ref element
Attr refUriAttr = ((Element)childNode).getAttributeNode("ref");
/*
o The URI in the "ref" attribute of the <entry-ref> element MUST be
unique amongst all other "ref" attributes of <entry-ref> elements
within the same parent element. Uniqueness is determined by case
sensitive string comparison. The value of the attribute MUST be a
relative path reference. Note that the server is not responsible
for verifying that the reference resolves to an <entry> element in
a document within the same XCAP root.
*/
// ref attr must be unique
if (refUriSet.contains(refUriAttr.getNodeValue())) {
// not unique, raise exception
throw new UniquenessFailureConflictException();
}
else {
// unique so far
// check is relative ref
try {
URI uri = new URI(refUriAttr.getNodeValue());
if(uri.isAbsolute()) {
throw new Exception();
}
}
catch (Exception e) {
throw new ConstraintFailureConflictException("Bad URI in resource-list element >> "+refUriAttr.getNodeValue());
}
// add it to the ref uri set
refUriSet.add(refUriAttr.getNodeValue());
}
}
else if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getLocalName().equals("external")) {
// external element
Attr anchorUriAttr = ((Element)childNode).getAttributeNode("anchor");
/*
o The URI in the "anchor" attribute of the <external> element MUST
be unique amongst all other "anchor" attributes of <external>
elements within the same parent element. Uniqueness is determined
by case sensitive string comparison. The value of the attribute
MUST be an absolute HTTP URI. Note that the server is not
responsible for verifying that the URI resolves to a <list>
element in a document. Indeed, since the URI may reference a
server in another domain, referential integrity cannot be
guaranteed without adding substantial complexity to the system.
*/
// anchor attr must be unique
if (anchorUriSet.contains(anchorUriAttr.getNodeValue())) {
// not unique, raise exception
throw new UniquenessFailureConflictException();
}
else {
// unique so far
// check is absolute http uri
try {
URI uri = new URI(anchorUriAttr.getNodeValue());
if(uri == null || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https"))) {
throw new Exception();
}
}
catch (Exception e) {
throw new ConstraintFailureConflictException("Bad URI in resource-list element >> "+anchorUriAttr.getNodeValue());
}
// add it to the anchor uri set
anchorUriSet.add(anchorUriAttr.getNodeValue());
}
}
}
}
public void checkConstraintsOnPut(Document document, String xcapRoot, DocumentSelector documentSelector, DataSource dataSource) throws UniquenessFailureConflictException, ConstraintFailureConflictException, InternalServerErrorException {
// reuse default check
super.checkConstraintsOnPut(document, xcapRoot, documentSelector, dataSource);
// check this app usage constraints below the root resource-lists node
checkNodeResourceListConstraints(document.getDocumentElement());
}
}