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("\n"); try { resource.append("" + this.resource.getResourceName() + "\n"); resource.append("" + this.getSource() + "\n"); resource.append("" + this.getSourceKey() + "\n"); resource.append("" + this.getCompleteSourceKey() + "\n"); resource.append("" + this.getEntryKey() + "\n"); resource.append("" + this.getGroupKey() + "\n"); resource.append("" + this.getTerminationTime().getTimeInMillis() + "\n"); resource.append("" + this.getTerminationTime().getTime().toString() + "\n"); resource.append("" + this.lastUpdateTime.getTimeInMillis() + "\n"); resource.append("" + this.lastUpdateTime.getTime().toString() + "\n"); resource.append("\n"); resource.append(this.resource.toString() + "\n"); resource.append("\n"); resource.append("\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("\n"); resource.append(this.resource.toString() + "\n"); resource.append("\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"); } } }