ProductId.java
/*
* ProductId
*/
package gov.usgs.earthquake.product;
import java.util.Date;
import java.util.Objects;
/**
* Attributes that uniquely identify a product.
*
* <dl>
* <dt>Source</dt>
* <dd>
* The organization <u>sending</u> the product;
* not necessarily the author of the product.
*
* Typically a FDSN network code.
* </dd>
*
* <dt>Type</dt>
* <dd>
* The type of product being sent.
* </dd>
*
* <dt>Code</dt>
* <dd>
* A unique code assigned by the <code>source</code> and <code>type</code>.
* Source and Type are effectively a namespace for codes.
*
* If the same <code>code</code> is re-used, it indicates a different
* version of the same product.
* </dd>
*
* <dt>Update Time</dt>
* <dd>
* A timestamp representing when a product was created.
*
* Update Time is also used as a <strong>version</strong>.
* Products from the same <code>source</code> and <code>type</code> with
* the same <code>code</code> are considered different versions of the
* same product.
*
* More recent (newer) <code>updateTime</code>s
* supersede less recent (older) <code>updateTimes</code>.
* </dd>
* </dl>
*/
public class ProductId implements Comparable<ProductId> {
/** Product source. */
private String source;
/** Product type. */
private String type;
/** Product code. */
private String code;
/** Product update time. */
private Date updateTime;
/**
* Create a new ProductId.
*
* Same as new ProductId(type, code, source, new Date()).
* @param source
* the product source.
* @param type
* the product type.
* @param code
* the product code.
*/
public ProductId(final String source, final String type, final String code) {
this(source, type, code, new Date());
}
/**
* Create a new ProductId.
*
* @param source
* the product source.
* @param type
* the product type.
* @param code
* the product code.
* @param updateTime
* when the product was updated.
*/
public ProductId(final String source, final String type, final String code,
final Date updateTime) {
setSource(source);
setType(type);
setCode(code);
setUpdateTime(updateTime);
}
/**
* @return the source
*/
public String getSource() {
return source;
}
/**
* @param source
* the source to set
*/
public void setSource(String source) {
this.source = escapeIdPart(source);
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type
* the type to set
*/
public void setType(String type) {
this.type = escapeIdPart(type);
}
/**
* @return the code
*/
public String getCode() {
return code;
}
/**
* @param code
* the code to set
*/
public void setCode(String code) {
this.code = escapeIdPart(code);
}
/**
* @return the updateTime
*/
public Date getUpdateTime() {
return updateTime;
}
/**
* @param updateTime
* the updateTime to set
*/
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
/**
* Convert this product id to a string. This string does not include the
* update time.
*
* @return a product id string.
*/
public String toString() {
return "urn:usgs-product:" + source + ":" + type + ":" + code + ":"
+ Long.toString(updateTime.getTime());
}
/**
* Parse a product id string.
*
* @param str
* a valid product id string.
* @return a ProductId object.
*/
public static ProductId parse(final String str) {
String[] parts = str.split(":");
try {
if (!"urn".equals(parts[0]) || !"usgs-product".equals(parts[1])) {
throw new Exception("Expected product urn");
}
String source = parts[2];
String type = parts[3];
String code = parts[4];
String updateTime = parts[5];
return new ProductId(source, type, code, new Date(Long
.valueOf(updateTime)));
} catch (Exception e) {
throw new IllegalArgumentException("Invalid ProductId '" + str + "'");
}
}
/**
* Override the default Object.equals().
*/
@Override
public boolean equals(final Object obj) {
return obj != null && obj instanceof ProductId
&& this.compareTo((ProductId) obj) == 0;
}
/**
* Implement the Comparable interface.
*
* @param that
* product id being compared.
* @return -1 if this precedes that, 0 if same, and 1 if that precedes this.
*/
@Override
public int compareTo(ProductId that) {
int compare = getUpdateTime().compareTo(that.getUpdateTime());
// same update time?
if (compare == 0) {
// to string includes source, type, code
compare = toString().compareTo(that.toString());
}
return compare;
}
/**
* Override default Object.hashCode().
*/
@Override
public int hashCode() {
return Objects.hash(getSource(), getType(), getCode(), getUpdateTime());
}
/**
* Whether these are the same product, even if they are different versions.
*
* It is possible for isSameProduct to return true if equals returns false,
* but if equals returns true isSameProduct will also return true.
*
* @param that
* a ProductId to test.
* @return true if these are the same product (source,type,code), false
* otherwise.
*/
public boolean isSameProduct(ProductId that) {
if (getSource().equals(that.getSource())
&& getType().equals(that.getType())
&& getCode().equals(that.getCode())) {
return true;
}
return false;
}
/**
* Escape id parts so they do not interfere with formatting/parsing.
*
* @param part
* part to escape.
* @return escaped part.
*/
private String escapeIdPart(final String part) {
if (part == null) {
return null;
}
String escaped = part;
if (escaped.indexOf(":") != -1) {
escaped = escaped.replace(":", "_");
}
return escaped;
}
}