/* Copyright 2014 MITRE Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mitre.provenance.npe; import java.util.Calendar; import java.util.Date; import java.util.logging.Logger; import org.mitre.provenance.EdgeMarking; import org.mitre.provenance.PLUSException; import org.mitre.provenance.plusobject.AbstractDirectedEdge; import org.mitre.provenance.plusobject.PLUSObject; import org.mitre.provenance.tools.PLUSUtils; /** * A Non-Provenance Edge (NPE) is an edge that expresses a relationship between a PLUSObject, and a non-PLUSObject data structure * that is stored outside of a provenance store. For example, to express the fact that a PLUSObject is equivalent to, or * the same as some other item of data in another store, a non-provenance edge between the PLUSObject and the other data item * might be created. * * <p>Non-Provenance edges always have the constraint that the "from" portion of the edge must be a provenance object, that is, * it must have a valid PLUS OID. * * <p>NPEs may connect two provenance objects. If an NPE connects a PLUSObject to something else, it is essentially only a single atomic * value. That is, if the "to" end of the NPE does not refer to a PLUSObject, there is no further way to elaborate that data. This is * an intentional constraint placed on NPEs; they are envisioned to be used as a way to connect to external sources of data by reference, * but it isn't within the scope of PLUS to store arbitrary graph information. As a result, there is no way to connect a PLUSObject to * another node with an arbitrary set of properties or metadata. * * <p>Common use cases for NPEs will be when you want to associate external identifiers for items (like a URI/URL, or a unique ID in a * different database outside of the scope of PLUS) * * <p>Here are a few examples of valid NPEs, let's start by assuming that "A" refers to a PLUSDataObject node, and "B" refers to another * "PLUSDataObject" node. <ul> * <li>A -- (similar to) --> B</li> * <li>A -- (URI) --> http://www.google.com/</li> * <li>A -- (reviewed by) --> "James Smith"</li> * <li>A -- (comment) --> "I think this looks goofy"</li> * </ul> * * @author dmallen */ public class NonProvenanceEdge extends AbstractDirectedEdge { /** The unique ID of the NPE itself */ protected String oid; /** The time when the NPE was created, in milliseconds since the epoch */ protected long created; /** The ID of the head of the edge */ protected String from; /** The ID of the tail of the edge */ protected String to; /** The type of the edge */ protected String type; /** Default NPE edge type to use when you are using an NPE to indicate hashed content. */ public static final String NPE_TYPE_CONTENT_HASH = "content hash"; /** Default NPE edge type to indicate when you are using an NPE to indicate a URI for a resource */ public static final String NPE_TYPE_URI = "URI"; /** Default NPE edge type indicating that the edge expresses an "alias" relationship. */ public static final String NPE_TYPE_ALIAS = "alias"; /** Default NPE edge type indicating that the edge expresses a "containment" relationship */ public static final String NPE_TYPE_CONTAINMENT = "contains"; /** Default NPE edge type indicating a set of sequenced steps */ public static final String NPE_TYPE_SEQUENCE_STEP = "sequence step"; protected static Logger log = Logger.getLogger(NonProvenanceEdge.class.getName()); /** * Create a new NPE * @param from the ID of the starting object. This must be a PLUSObject ID. * @param to the destination of the edge (can be any string, see examples) * @param type the type of the edge (can be anything, but see provided example edge types) * @throws PLUSException */ public NonProvenanceEdge(String from, String to, String type) throws PLUSException { // this is for a NEW NPE. this(PLUSUtils.generateID(), from, to, type, System.currentTimeMillis()); } // End NonProvenanceEdge /** * Create a new NPE between two PLUSObjects. * @param from the head of the edge * @param to the tail of the edge * @param type the type of the edge (can be anything, but see provided example edge types) * @throws PLUSException */ public NonProvenanceEdge(PLUSObject from, PLUSObject to, String type) throws PLUSException { this(PLUSUtils.generateID(), from.getId(), to.getId(), type, System.currentTimeMillis()); } /** * Create a new NPE * @param from the head of the edge * @param npid a non-provenance identifier (can be anything, but see provided examples for how to use this) * @param type the type of the edge (can be anything, but see provided example edge types) * @throws PLUSException */ public NonProvenanceEdge(PLUSObject from, String npid, String type) throws PLUSException { this(PLUSUtils.generateID(), from.getId(), npid, type, System.currentTimeMillis()); } /** * Raw constructor. No touchy! You probably shouldn't be using this. * @param oid * @param from * @param to * @param type * @param created * @throws PLUSException if the 'from' side of the link is not a PLUS ID. */ public NonProvenanceEdge(String oid, String from, String to, String type, long created) throws PLUSException { if(!PLUSUtils.isPLUSOID(from)) throw new PLUSException("The from portion of all NonProvenanceEdge objects must be a valid PLUS ID"); setCreated(created); setId(oid); setFrom(from); setTo(to); setType(type); setFromMarking(EdgeMarking.SHOW); setToMarking(EdgeMarking.SHOW); } /** Return the head identifier of the edge */ public String getFrom() { return from; } /** Set the head identifier of the edge */ protected void setFrom(String from) { this.from = from; } /** Get the tail identifier of the edge */ public String getTo() { return to; } /** Set the tail identifier of the edge */ protected void setTo(String to) { this.to = to; } /** Return the type of the edge */ public String getType() { return type; } /** Set the type of the edge */ public void setType(String type) { this.type = type; } /** Get the edge's ID. Note that this is *not* an incident node ID, it is the edge itself's ID */ public String getId() { return oid; } /** Set the edge's ID. */ protected void setId(String oid) { this.oid = oid; } /** Get the edge's create time (ms since the epoch) */ public long getCreated() { return created; } /** Return the edge's creation time as a java Date. */ public Date getCreatedAsDate() { return new java.util.Date(created); } /** Set the edge's created time */ protected void setCreated(long creationTime) { created = creationTime; } /** * Sets the object's created timestamp to this moment in milliseconds since the epoch, UTC */ public void setCreated() { Calendar calInitial = Calendar.getInstance(); int offsetInitial = calInitial.get(Calendar.ZONE_OFFSET) + calInitial.get(Calendar.DST_OFFSET); long current = System.currentTimeMillis(); // Check right time created = current - offsetInitial; } public String toString() { return "NPE: from=" + getFrom() + " to=" + getTo() + " type=" + getType(); } } // End NonProvenanceEdge