447 lines
14 KiB
Java
447 lines
14 KiB
Java
package org.gcube.informationsystem.collector.impl.resources;
|
|
|
|
import java.io.StringReader;
|
|
import java.io.StringWriter;
|
|
import java.util.Calendar;
|
|
import java.util.GregorianCalendar;
|
|
import java.util.TimeZone;
|
|
|
|
import javax.xml.parsers.DocumentBuilder;
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
import javax.xml.transform.OutputKeys;
|
|
import javax.xml.transform.Transformer;
|
|
import javax.xml.transform.TransformerFactory;
|
|
import javax.xml.transform.dom.DOMSource;
|
|
import javax.xml.transform.stream.StreamResult;
|
|
import javax.xml.xpath.XPath;
|
|
import javax.xml.xpath.XPathFactory;
|
|
|
|
import org.gcube.common.core.utils.logging.GCUBELog;
|
|
import org.gcube.informationsystem.collector.impl.resources.DAIXResource.MalformedResourceException;
|
|
|
|
import org.w3c.dom.Document;
|
|
import org.w3c.dom.Node;
|
|
import org.xml.sax.InputSource;
|
|
|
|
|
|
/**
|
|
*
|
|
*
|
|
* @author Manuele Simi (ISTI-CNR)
|
|
*
|
|
*/
|
|
public class GCUBEXMLResource {
|
|
|
|
/**
|
|
* the resource type states if the resource contains a profile or generic WS-ResourceProperties
|
|
*/
|
|
public enum RESOURCETYPE {
|
|
Profile, Properties
|
|
}
|
|
|
|
protected RESOURCETYPE type = null;
|
|
|
|
protected static GCUBELog logger = new GCUBELog(GCUBEXMLResource.class);
|
|
|
|
protected Calendar terminationTime = null, lastUpdateTime = null;
|
|
|
|
protected String entryKey, groupKey, source, sourceKey = "", completeSourceKey = "";
|
|
|
|
// xpath factory to evaluate Xpath expressions
|
|
private XPath path = XPathFactory.newInstance().newXPath();
|
|
|
|
private DAIXResource resource;
|
|
|
|
public GCUBEXMLResource(DAIXResource resource) throws MalformedXMLResourceException {
|
|
this.resource = resource;
|
|
this.terminationTime = new GregorianCalendar();
|
|
this.terminationTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
this.lastUpdateTime = new GregorianCalendar();
|
|
this.lastUpdateTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
try {
|
|
if (resource.getResourceName() == null)
|
|
throw new MalformedXMLResourceException("Invalid resource name");
|
|
} catch (MalformedResourceException e) {
|
|
throw new MalformedXMLResourceException("Invalid resource name");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @return the name of the collection including the resource
|
|
* @throws MalformedResourceException
|
|
*/
|
|
public String getCollectionName() throws MalformedXMLResourceException {
|
|
try {
|
|
return this.resource.getCollectionName();
|
|
} catch (MalformedResourceException e) {
|
|
throw new MalformedXMLResourceException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the resource name
|
|
* @throws MalformedResourceException
|
|
*/
|
|
public String getResourceName() throws MalformedXMLResourceException {
|
|
try {
|
|
return this.resource.getResourceName();
|
|
} catch (MalformedResourceException e) {
|
|
throw new MalformedXMLResourceException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the terminationTime of this resource
|
|
*/
|
|
public Calendar getTerminationTime() {
|
|
return this.terminationTime;
|
|
}
|
|
|
|
/**
|
|
* @return the lastUpdateTime of this resource
|
|
*/
|
|
public Calendar getLastUpdateTime() {
|
|
return this.lastUpdateTime;
|
|
}
|
|
|
|
/**
|
|
* @param terminationTime
|
|
* the terminationTime to set
|
|
*/
|
|
public void setTerminationTime(final Calendar terminationTime) {
|
|
this.terminationTime = (Calendar) terminationTime.clone();
|
|
this.terminationTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
}
|
|
|
|
/**
|
|
* @return the lastUpdateTime in milliseconds
|
|
* @throws Exception
|
|
* if an error occurs when accessing the LastUpdateMs field
|
|
*/
|
|
public long getLastUpdateTimeinMills() throws MalformedResourceException {
|
|
|
|
if (lastUpdateTime != null)
|
|
return lastUpdateTime.getTimeInMillis();
|
|
else
|
|
throw new MalformedResourceException("unable to retrieve last update time for resource " + this.resource.getResourceName());
|
|
}
|
|
|
|
/**
|
|
* Accesses the source GroupKey
|
|
*
|
|
* @return the ID
|
|
*/
|
|
public String getGroupKey() {
|
|
return this.groupKey;
|
|
}
|
|
|
|
/**
|
|
* Sets the source GroupKey
|
|
*
|
|
* @param groupKey
|
|
* the new group key
|
|
*
|
|
*/
|
|
public void setGroupKey(String groupKey) {
|
|
this.groupKey = groupKey;
|
|
}
|
|
|
|
/**
|
|
* Accesses the source EntryKey
|
|
*
|
|
* @return the ID
|
|
*/
|
|
public String getEntryKey() {
|
|
return this.entryKey;
|
|
}
|
|
|
|
/**
|
|
* Sets the source EntryKey
|
|
*
|
|
* @param entryKey
|
|
* the new entry key
|
|
*/
|
|
public void setEntryKey(String entryKey) {
|
|
this.entryKey = entryKey;
|
|
}
|
|
|
|
/**
|
|
* Sets the source address of the RI that publishes resource as reported in the servicegroup
|
|
* entry
|
|
*
|
|
* @param source
|
|
* the new source address
|
|
*/
|
|
public void setSource(String source) {
|
|
this.source = source;
|
|
}
|
|
|
|
/**
|
|
* Accesses the source address of the service that published the data
|
|
*
|
|
* @return the source
|
|
*/
|
|
public String getSource() {
|
|
return this.source;
|
|
}
|
|
|
|
/**
|
|
* Sets the key of the WS-Resource that published the data
|
|
*
|
|
* @param key
|
|
* the new source key
|
|
*/
|
|
public void setSourceKey(String key) {
|
|
this.sourceKey = key;
|
|
}
|
|
|
|
/**
|
|
* Gets the key of the WS-Resource that published the data
|
|
*
|
|
* @return the key
|
|
*/
|
|
public String getSourceKey() {
|
|
return this.sourceKey;
|
|
}
|
|
|
|
/**
|
|
* Sets the complete source key
|
|
*
|
|
* @param completeKey
|
|
* the new complete key
|
|
*/
|
|
public void setCompleteSourceKey(String completeKey) {
|
|
this.completeSourceKey = completeKey;
|
|
}
|
|
|
|
/**
|
|
* Gets the complete source key
|
|
*
|
|
* @return the complete source key
|
|
/*
|
|
if ((lastUpdateTime == null) && (this.resource.getContent() != null)) {
|
|
String value = "";
|
|
try {
|
|
value = path.evaluate("Document/LastUpdateMs", this.resource.getContent());
|
|
} catch (XPathExpressionException xpee) {
|
|
logger.error("" + xpee.getMessage());
|
|
logger.error("" + xpee.getStackTrace());
|
|
throw new MalformedResourceException("XPath evaluation error");
|
|
}
|
|
try {
|
|
return Long.parseLong(value);
|
|
} catch (NumberFormatException nfe) {
|
|
logger.error("Invalid last update time format found in resource " + this.resource.getContent());
|
|
logger.error("Parsed string was " + value);
|
|
throw new MalformedResourceException("Unable to retrieve last update time for resource " + this.resource.getContent());
|
|
}
|
|
|
|
} else
|
|
throw new MalformedResourceException("unable to retrieve last update time for resource " + this.resource.getResourceName());
|
|
|
|
*/
|
|
public String getCompleteSourceKey() {
|
|
return this.completeSourceKey;
|
|
}
|
|
|
|
|
|
public void setContent(String content, boolean... enveloped) {
|
|
try {
|
|
if (enveloped != null && enveloped.length > 0 && enveloped[0]) {
|
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
StringReader reader = new StringReader(content);
|
|
InputSource source = new InputSource(reader);
|
|
Document doc = builder.parse(source);
|
|
this.parseEnvelop(doc);
|
|
resource.setContent(this.removeEnvelop(doc));
|
|
}
|
|
else
|
|
resource.setContent(content);
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Extract the resource informantion from the envelop
|
|
* @param doc the enveloped content
|
|
* @throws MalformedXMLResourceException
|
|
*/
|
|
private void parseEnvelop(Document doc) throws MalformedXMLResourceException {
|
|
String value = "";
|
|
try {
|
|
value = path.evaluate("Document/LastUpdateMs", doc);
|
|
this.lastUpdateTime.setTimeInMillis(Long.parseLong(value));
|
|
value = path.evaluate("Document/TerminationTime", doc);
|
|
this.terminationTime.setTimeInMillis(Long.parseLong(value));
|
|
value = path.evaluate("Document/Source", doc);
|
|
this.setSource(value);
|
|
value = path.evaluate("Document/SourceKey", doc);
|
|
this.setCompleteSourceKey(value);
|
|
value = path.evaluate("Document/EntryKey", doc);
|
|
this.setEntryKey(value);
|
|
value = path.evaluate("Document/GroupKey", doc);
|
|
this.setGroupKey(value);
|
|
} catch (Exception xpee) {
|
|
logger.error("" + xpee.getMessage());
|
|
logger.error("" + xpee.getStackTrace());
|
|
throw new MalformedXMLResourceException("Unable to retrieve last update time for resource");
|
|
}
|
|
|
|
}
|
|
|
|
public String toString() {
|
|
// we do not use an XML parser for performance reasons
|
|
StringBuilder resource = new StringBuilder("<Document>\n");
|
|
try {
|
|
resource.append("<ID>" + this.resource.getResourceName() + "</ID>\n");
|
|
resource.append("<Source>" + this.getSource() + "</Source>\n");
|
|
resource.append("<SourceKey>" + this.getSourceKey() + "</SourceKey>\n");
|
|
resource.append("<CompleteSourceKey>" + this.getCompleteSourceKey() + "</CompleteSourceKey>\n");
|
|
resource.append("<EntryKey>" + this.getEntryKey() + "</EntryKey>\n");
|
|
resource.append("<GroupKey>" + this.getGroupKey() + "</GroupKey>\n");
|
|
resource.append("<TerminationTime>" + this.getTerminationTime().getTimeInMillis() + "</TerminationTime>\n");
|
|
resource.append("<TerminationTimeHuman>" + this.getTerminationTime().getTime().toString() + "</TerminationTimeHuman>\n");
|
|
resource.append("<LastUpdateMs>" + this.lastUpdateTime.getTimeInMillis() + "</LastUpdateMs>\n");
|
|
resource.append("<LastUpdateHuman>" + this.lastUpdateTime.getTime().toString() + "</LastUpdateHuman>\n");
|
|
resource.append("<Data>\n");
|
|
resource.append(this.resource.toString() + "\n");
|
|
resource.append("</Data>\n");
|
|
resource.append("</Document>\n");
|
|
} catch (MalformedResourceException e) {
|
|
logger.error("invalid content", e);
|
|
|
|
}
|
|
return resource.toString();
|
|
}
|
|
|
|
/**
|
|
* Removes the document envelop from the document
|
|
*
|
|
* @param doc the content to clean up
|
|
* @return the content string without the document envelop
|
|
* @throws MalformedResourceException
|
|
*/
|
|
private String removeEnvelop(Document doc) throws MalformedXMLResourceException {
|
|
try {
|
|
return this.toStringFromElement(doc, "Data"); // Data/*
|
|
} catch (Exception e) {
|
|
logger.error("unable to retrieve parse the resource's content ", e);
|
|
}
|
|
throw new MalformedXMLResourceException("unable to retrieve parse the resource's content");
|
|
}
|
|
|
|
/**
|
|
* Returns a sub-serialization of the given XML, starting from the element name
|
|
*
|
|
* @param xml
|
|
* the source XML serialization
|
|
* @param elementName
|
|
* the name of the element
|
|
* @return the node content serialized as string
|
|
* @throws Exception
|
|
* if the serialization fails
|
|
*/
|
|
private String toStringFromElement(String xml, String elementName) throws MalformedXMLResourceException {
|
|
try {
|
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
StringReader reader = new StringReader(xml);
|
|
InputSource source = new InputSource(reader);
|
|
return toStringFromElement(builder.parse(source), elementName);
|
|
|
|
} catch (Exception e) {
|
|
logger.error("Unable to deserialise content data", e);
|
|
throw new MalformedXMLResourceException("Unable to deserialise the resource");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns a sub-serialization of the given XML, starting from the element name
|
|
*
|
|
* @param xml
|
|
* the source XML serialization
|
|
* @param elementName
|
|
* the name of the element
|
|
* @return the node content serialized as string
|
|
* @throws Exception
|
|
* if the serialization fails
|
|
*/
|
|
private String toStringFromElement(Document xml, String elementName) throws MalformedXMLResourceException {
|
|
|
|
try {
|
|
Node targetNode = xml.getElementsByTagName(elementName).item(0);
|
|
TransformerFactory transFactory = TransformerFactory.newInstance();
|
|
Transformer transformer = transFactory.newTransformer();
|
|
StringBuilder ret = new StringBuilder();
|
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
|
int index = 0;
|
|
Node node = targetNode.getChildNodes().item(index);
|
|
while (node != null) {
|
|
StringWriter buffer = new StringWriter();
|
|
transformer.transform(new DOMSource(node), new StreamResult(buffer));
|
|
ret.append(buffer.toString().trim());
|
|
node = targetNode.getChildNodes().item(index++);
|
|
}
|
|
return ret.toString();
|
|
|
|
} catch (Exception e) {
|
|
logger.error("Unable to deserialise content data", e);
|
|
throw new MalformedXMLResourceException("Unable to deserialise the resource");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Malformed XML resource exception
|
|
*
|
|
* @author Manuele Simi (ISTI-CNR)
|
|
*
|
|
*/
|
|
public static class MalformedXMLResourceException extends Exception {
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
public MalformedXMLResourceException(Exception e) {
|
|
super(e);
|
|
}
|
|
|
|
public MalformedXMLResourceException(String message) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the wrapped {@link BaseDAIXResource}'s content
|
|
* @return
|
|
* @throws MalformedXMLResourceException
|
|
*/
|
|
public Document getContent() throws MalformedXMLResourceException {
|
|
try {
|
|
try {
|
|
return resource.getContent();
|
|
} catch (Exception e) {
|
|
//try to wrap with a root element
|
|
StringBuilder resource = new StringBuilder("<Data>\n");
|
|
resource.append(this.resource.toString() + "\n");
|
|
resource.append("</Data>\n");
|
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
StringReader reader = new StringReader(resource.toString());
|
|
InputSource source = new InputSource(reader);
|
|
return builder.parse(source);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
logger.error("Invalid data", e);
|
|
throw new MalformedXMLResourceException("Invalid data");
|
|
}
|
|
}
|
|
|
|
|
|
}
|