EQMessageProductCreator.java
package gov.usgs.earthquake.eids;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
//Does it make sense to import objects from quakeml when we're parsing eqxml?
//import org.quakeml.FocalMechanism;
//import org.quakeml.NodalPlane;
//import org.quakeml.NodalPlanes;
import gov.usgs.ansseqmsg.Action;
import gov.usgs.ansseqmsg.Comment;
import gov.usgs.ansseqmsg.EQMessage;
import gov.usgs.ansseqmsg.EventAction;
import gov.usgs.ansseqmsg.EventScope;
import gov.usgs.ansseqmsg.EventType;
import gov.usgs.ansseqmsg.EventUsage;
import gov.usgs.ansseqmsg.Fault;
import gov.usgs.ansseqmsg.Magnitude;
import gov.usgs.ansseqmsg.Method;
import gov.usgs.ansseqmsg.MomentTensor;
import gov.usgs.ansseqmsg.NodalPlanes;
import gov.usgs.ansseqmsg.Origin;
import gov.usgs.ansseqmsg.Event;
import gov.usgs.ansseqmsg.ProductLink;
import gov.usgs.ansseqmsg.Tensor;
import gov.usgs.earthquake.cube.CubeAddon;
import gov.usgs.earthquake.cube.CubeDelete;
import gov.usgs.earthquake.cube.CubeEvent;
import gov.usgs.earthquake.cube.CubeMessage;
import gov.usgs.earthquake.eqxml.EQMessageParser;
import gov.usgs.earthquake.event.Converter;
import gov.usgs.earthquake.product.ByteContent;
import gov.usgs.earthquake.product.Content;
import gov.usgs.earthquake.product.Product;
import gov.usgs.earthquake.product.ProductId;
import gov.usgs.util.FileUtils;
import gov.usgs.util.StreamUtils;
import gov.usgs.util.XmlUtils;
/**
* Convert EQXML messages to Products.
*
* <p>
* Product source is EQMessage/Source.
* </p>
* <p>
* Product type is "origin", "magnitude", or "addon". Types may be prefixed by
* non-Public Event/Scope, and suffixed by non-Actual Event/Usage
* (internal-magnitude-scenario).
* </p>
* <p>
* Product code is Event/DataSource + Event/EventId. When an addon product,
* either ProductLink/Code or Comment/TypeKey is appended to code.
* </p>
* <p>
* Product updateTime is EQMessage/Sent.
* </p>
*
* <p>
* Origin properties appear only on origin type products. Magnitude properties
* appear on both magnitude and origin products.
* </p>
*/
public class EQMessageProductCreator implements ProductCreator {
private static final Logger LOGGER = Logger
.getLogger(EQMessageProductCreator.class.getName());
/** Static var for the xml content type */
public static final String XML_CONTENT_TYPE = "application/xml";
/** Path to content where source message is stored in created product. */
public static final String EQMESSAGE_CONTENT_PATH = "eqxml.xml";
/** Path to contests xml */
public static final String CONTENTS_XML_PATH = "contents.xml";
/**
* When phases exist is is a "phase" type product. When this flag is set to
* true, a lightweight, origin-only type product is also sent.
*/
private boolean sendOriginWhenPhasesExist = false;
/**
* Whether to validate when parsing and serializing. When validating, only
* native EQXML is supported via the ProductCreator interface.
*/
private boolean validate = false;
// the eqmessage currently being processed.
private EQMessage eqmessage;
// xml for the eqmessage currently being processed
private String eqmessageXML;
private String eqmessageSource;
private Date eqmessageSent;
private String eventDataSource;
private String eventEventId;
private String eventVersion;
private EventAction eventAction;
private EventUsage eventUsage;
private EventScope eventScope;
private BigDecimal originLatitude;
private BigDecimal originLongitude;
private BigDecimal originDepth;
private Date originEventTime;
private BigDecimal magnitude;
/**
* Default, empty constructor.
*/
public EQMessageProductCreator() {
}
/**
* Get all the products contained in an EQMessage.
*
* Same as getEQMessageProducts(message, null).
*
* @param message
* the EQMessage containing products.
* @return a list of created products.
* @throws Exception if error occurs
*/
public synchronized List<Product> getEQMessageProducts(
final EQMessage message) throws Exception {
return getEQMessageProducts(message, null);
}
/**
* Get all the products contained in an EQMessage.
*
* Parses rawEqxml string into an EQMessage, but preserves raw eqxml in
* created products.
*
* Same as getEQMessageProducts(EQMessageParser.parse(rawEqxml), rawEqxml);
*
* @param rawEqxml
* the raw EQXML message.
* @return a list of created products.
* @throws Exception if error occurs
*/
public synchronized List<Product> getEQMessageProducts(final String rawEqxml)
throws Exception {
EQMessage message = EQMessageParser.parse(rawEqxml, validate);
return getEQMessageProducts(message, rawEqxml);
}
/**
* Get all the products contained in an EQMessage.
*
* @param message
* the EQMessage containing products.
* @param rawEqxml
* the raw EQXML message. When null, an EQXML message is
* serialized from the object.
* @return a list of created products.
* @throws Exception if error occurs
*/
public synchronized List<Product> getEQMessageProducts(
final EQMessage message, final String rawEqxml) throws Exception {
List<Product> products = new LinkedList<Product>();
if (message == null) {
return products;
}
this.eqmessage = message;
this.eqmessageSource = message.getSource();
this.eqmessageSent = message.getSent();
if (this.eqmessageSent == null) {
this.eqmessageSent = new Date();
}
// convert to xml
if (rawEqxml != null) {
this.eqmessageXML = rawEqxml;
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
EQMessageParser.serialize(message, baos, validate);
this.eqmessageXML = baos.toString();
}
// process each event
List<Event> events = message.getEvent();
if (events != null) {
Iterator<Event> iter = events.iterator();
while (iter.hasNext()) {
products.addAll(getEventProducts(iter.next()));
}
}
this.eqmessageSource = null;
this.eqmessageSent = null;
this.eqmessageXML = null;
return products;
}
/**
* Get products from an event.
*
* @param event
* the event containing products.
* @return a list of created products.
* @throws Exception if error occurs
*/
protected synchronized List<Product> getEventProducts(final Event event)
throws Exception {
List<Product> products = new LinkedList<Product>();
if (event == null) {
return products;
}
eventDataSource = event.getDataSource();
eventEventId = event.getEventID();
eventVersion = event.getVersion();
eventAction = event.getAction();
eventUsage = event.getUsage();
eventScope = event.getScope();
// default values
if (eventAction == null) {
eventAction = EventAction.UPDATE;
}
if (eventUsage == null) {
eventUsage = EventUsage.ACTUAL;
}
if (eventScope == null) {
eventScope = EventScope.PUBLIC;
}
if (eventAction == EventAction.DELETE) {
// delete origin product (only product with location)
Product deleteProduct = getProduct("origin", eventAction.toString());
products.add(deleteProduct);
} else {
// update origin product
products.addAll(getOriginProducts(event.getOrigin(), event));
}
for (ProductLink eventLink : event.getProductLink()) {
products.addAll(getProductLinkProducts(eventLink));
}
for (Comment eventComment : event.getComment()) {
products.addAll(getCommentProducts(eventComment));
}
eventDataSource = null;
eventEventId = null;
eventVersion = null;
eventAction = null;
eventUsage = null;
eventScope = null;
return products;
}
/**
* Get origin product(s).
*
* This implementation only creates one origin (the first one) regardless of
* how many origins are provided.
*
* @param origins
* the list of origins.
* @param event
* A specific event
* @return a list of created products.
* @throws Exception if error occurs
*/
protected synchronized List<Product> getOriginProducts(
final List<Origin> origins, final Event event) throws Exception {
List<Product> products = new LinkedList<Product>();
if (origins == null || origins.size() == 0) {
return products;
}
// only process first origin
Origin origin = origins.get(0);
// get sub-products
products.addAll(getFocalMechanismProducts(origin.getMomentTensor()));
this.originLatitude = origin.getLatitude();
this.originLongitude = origin.getLongitude();
this.originDepth = origin.getDepth();
this.originEventTime = origin.getTime();
boolean preferred = (origin.getPreferredFlag() == null || origin
.getPreferredFlag());
// only process "preferred" origins
// this is how hydra differentiates between origins as input parameters
// to focal mechanisms, and origins as origins
if (preferred && this.originLatitude != null
&& this.originLongitude != null && this.originEventTime != null) {
// create an origin/magnitude product only if origin has
// lat+lon+time
List<Product> magnitudeProducts = getMagnitudeProducts(origin
.getMagnitude());
// now build origin product
Action originAction = origin.getAction();
Product originProduct = getProduct("origin",
originAction == null ? null : originAction.toString());
// origin specific properties
Map<String, String> properties = originProduct.getProperties();
// set event type
properties.put(
"event-type",
(event.getType() == null ? EventType.EARTHQUAKE : event
.getType()).value().toLowerCase());
if (magnitudeProducts.size() > 0) {
// transfer magnitude product properties to origin
properties.putAll(magnitudeProducts.get(0).getProperties());
}
if (origin.getSourceKey() != null) {
properties.put("origin-source", origin.getSourceKey());
}
if (origin.getAzimGap() != null) {
properties.put("azimuthal-gap", origin.getAzimGap().toString());
}
if (origin.getDepthError() != null) {
properties
.put("depth-error", origin.getDepthError().toString());
}
if (origin.getDepthMethod() != null) {
properties.put("depth-method", origin.getDepthMethod());
}
if (origin.getErrh() != null) {
properties.put("horizontal-error", origin.getErrh().toString());
}
if (origin.getErrz() != null) {
properties.put("vertical-error", origin.getErrz().toString());
}
if (origin.getLatError() != null) {
properties.put("latitude-error", origin.getLatError()
.toString());
}
if (origin.getLonError() != null) {
properties.put("longitude-error", origin.getLonError()
.toString());
}
if (origin.getMinDist() != null) {
properties.put("minimum-distance", origin.getMinDist()
.toString());
}
if (origin.getNumPhaUsed() != null) {
properties.put("num-phases-used", origin.getNumPhaUsed()
.toString());
}
if (origin.getNumStaUsed() != null) {
properties.put("num-stations-used", origin.getNumStaUsed()
.toString());
}
if (origin.getRegion() != null) {
properties.put("region", origin.getRegion());
}
if (origin.getStatus() != null) {
properties.put("review-status", origin.getStatus().toString());
}
if (origin.getStdError() != null) {
properties.put("standard-error", origin.getStdError()
.toString());
}
// origin method
Iterator<Method> methods = origin.getMethod().iterator();
if (methods.hasNext()) {
Method method = methods.next();
if (method.getClazz() != null) {
properties.put("location-method-class", method.getClazz());
}
if (method.getAlgorithm() != null) {
properties.put("location-method-algorithm",
method.getAlgorithm());
}
if (method.getModel() != null) {
properties.put("location-method-model", method.getModel());
}
String cubeLocationMethod = getCubeCode(method.getComment());
if (cubeLocationMethod != null) {
properties.put("cube-location-method", cubeLocationMethod);
}
}
if (origin.getPhase() != null && origin.getPhase().size() > 0) {
originProduct.getId().setType("phase-data");
products.add(originProduct);
if (sendOriginWhenPhasesExist) {
// create lightweight origin product
Product lightweightOrigin = new Product(originProduct);
lightweightOrigin.getId().setType("origin");
lightweightOrigin.getContents().remove(
EQMESSAGE_CONTENT_PATH);
// seek and destroy phases
Iterator<Origin> iter = origins.iterator();
while (iter.hasNext()) {
Origin next = iter.next();
if (next.getPhase() != null) {
next.getPhase().clear();
}
}
// serialize xml without phase data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
EQMessageParser.serialize(this.eqmessage, baos, validate);
lightweightOrigin.getContents().put(EQMESSAGE_CONTENT_PATH,
new ByteContent(baos.toByteArray()));
products.add(0, lightweightOrigin);
}
} else {
// insert origin at start of list
products.add(0, originProduct);
}
}
this.originDepth = null;
this.originEventTime = null;
this.originLatitude = null;
this.originLongitude = null;
this.magnitude = null;
for (Comment originComment : origin.getComment()) {
products.addAll(getCommentProducts(originComment));
}
return products;
}
/**
* Build magnitude products.
*
* This implementation builds at most one magnitude product (the first).
*
* @param magnitudes
* a list of candidate magsnitude objects.
* @return a list of built magnitude products, which may be empty.
*/
protected synchronized List<Product> getMagnitudeProducts(
final List<Magnitude> magnitudes) {
List<Product> products = new LinkedList<Product>();
if (magnitudes == null || magnitudes.size() == 0) {
return products;
}
// build product based on the first magnitude
Magnitude magnitude = magnitudes.get(0);
// set "globalish" property before getProduct()
this.magnitude = magnitude.getValue();
Action magnitudeAction = magnitude.getAction();
// build magnitude product
Product product = getProduct("magnitude",
magnitudeAction == null ? null : magnitudeAction.toString());
Map<String, String> properties = product.getProperties();
if (magnitude.getSourceKey() != null) {
properties.put("magnitude-source", magnitude.getSourceKey());
}
if (magnitude.getTypeKey() != null) {
properties.put("magnitude-type", magnitude.getTypeKey());
}
if (magnitude.getAzimGap() != null) {
properties.put("magnitude-azimuthal-gap", magnitude.getAzimGap()
.toString());
}
if (magnitude.getError() != null) {
properties.put("magnitude-error", magnitude.getError().toString());
}
if (magnitude.getNumStations() != null) {
properties.put("magnitude-num-stations-used", magnitude
.getNumStations().toString());
}
String cubeMagnitudeType = getCubeCode(magnitude.getComment());
if (cubeMagnitudeType != null) {
properties.put("cube-magnitude-type", cubeMagnitudeType);
}
// don't clear property here, so origin can borrow magnitude property
// this.magnitude = null;
products.add(product);
return products;
}
/**
* Gets a list of Focal Mechanism products from momentTensors
* @param momentTensors List of Moment Tensors
* @return a list of products
*/
protected synchronized List<Product> getFocalMechanismProducts(
final List<MomentTensor> momentTensors) {
List<Product> products = new LinkedList<Product>();
if (momentTensors == null || momentTensors.size() == 0) {
return products;
}
// build moment tensors
Iterator<MomentTensor> iter = momentTensors.iterator();
while (iter.hasNext()) {
MomentTensor mt = iter.next();
Action mtAction = mt.getAction();
// may be set to "moment-tensor" below
Product product = getProduct("focal-mechanism",
mtAction == null ? null : mtAction.toString());
Map<String, String> properties = product.getProperties();
// fill in product properties
if (mt.getSourceKey() != null) {
properties.put("beachball-source", mt.getSourceKey());
}
if (mt.getTypeKey() != null) {
properties.put("beachball-type", mt.getTypeKey());
// append source+type to code
ProductId productId = product.getId();
productId.setCode((productId.getCode() + "-"
+ mt.getSourceKey() + "-" + mt.getTypeKey())
.toLowerCase());
}
if (mt.getMagMw() != null) {
product.setMagnitude(mt.getMagMw());
}
if (mt.getM0() != null) {
properties.put("scalar-moment", mt.getM0().toString());
}
if (mt.getTensor() != null) {
// if the tensor is included, it is a "moment-tensor" instead of
// a "focal-mechanism"
product.getId().setType("moment-tensor");
Tensor t = mt.getTensor();
if (t.getMtt() != null) {
properties.put("tensor-mtt", t.getMtt().toString());
}
if (t.getMpp() != null) {
properties.put("tensor-mpp", t.getMpp().toString());
}
if (t.getMrr() != null) {
properties.put("tensor-mrr", t.getMrr().toString());
}
if (t.getMtp() != null) {
properties.put("tensor-mtp", t.getMtp().toString());
}
if (t.getMrp() != null) {
properties.put("tensor-mrp", t.getMrp().toString());
}
if (t.getMrt() != null) {
properties.put("tensor-mrt", t.getMrt().toString());
}
}
if (mt.getNodalPlanes() != null) {
NodalPlanes np = mt.getNodalPlanes();
List<Fault> faults = np.getFault();
if (faults.size() == 2) {
Fault fault1 = faults.get(0);
if (fault1.getDip() != null) {
properties.put("nodal-plane-1-dip", fault1.getDip()
.toString());
}
if (fault1.getSlip() != null) {
properties.put("nodal-plane-1-slip", fault1.getSlip()
.toString());
}
if (fault1.getStrike() != null) {
properties.put("nodal-plane-1-strike", fault1
.getStrike().toString());
}
Fault fault2 = faults.get(1);
if (fault2.getDip() != null) {
properties.put("nodal-plane-2-dip", fault2.getDip()
.toString());
}
if (fault2.getSlip() != null) {
properties.put("nodal-plane-2-slip", fault2.getSlip()
.toString());
}
if (fault2.getStrike() != null) {
properties.put("nodal-plane-2-strike", fault2
.getStrike().toString());
}
}
}
if (mt.getDerivedOriginTime() != null) {
properties.put("derived-eventtime",
XmlUtils.formatDate(mt.getDerivedOriginTime()));
}
if (mt.getDerivedLatitude() != null) {
properties.put("derived-latitude", mt.getDerivedLatitude()
.toString());
}
if (mt.getDerivedLongitude() != null) {
properties.put("derived-longitude", mt.getDerivedLongitude()
.toString());
}
if (mt.getDerivedDepth() != null) {
properties
.put("derived-depth", mt.getDerivedDepth().toString());
}
if (mt.getPerDblCpl() != null) {
properties.put("percent-double-couple", mt.getPerDblCpl()
.toString());
}
if (mt.getNumObs() != null) {
properties.put("num-stations-used", mt.getNumObs().toString());
}
// attach original message as product content
ByteContent xml = new ByteContent(eqmessageXML.getBytes());
xml.setLastModified(eqmessageSent);
xml.setContentType("application/xml");
product.getContents().put(EQMESSAGE_CONTENT_PATH, xml);
// add to list of built products
products.add(product);
}
return products;
}
/**
* Get product(s) from a ProductLink object.
*
* @param link
* the link object.
* @return a list of found products.
* @throws Exception if error occurs
*/
protected synchronized List<Product> getProductLinkProducts(
final ProductLink link) throws Exception {
List<Product> products = new LinkedList<Product>();
String linkType = getLinkAddonProductType(link.getCode());
if (linkType == null) {
LOGGER.finer("No product type found for productlink with code '"
+ link.getCode() + "', skipping");
return products;
}
Action linkAction = link.getAction();
Product linkProduct = getProduct(linkType, linkAction == null ? null
: linkAction.toString());
// remove the EQXML, only send product link attributes with link
// products
linkProduct.getContents().clear();
// add addon code to product code
ProductId id = linkProduct.getId();
id.setCode(id.getCode() + "-" + link.getCode().toLowerCase());
if (link.getVersion() != null) {
linkProduct.setVersion(link.getVersion());
}
Map<String, String> properties = linkProduct.getProperties();
if (link.getLink() != null) {
properties.put("url", link.getLink());
}
if (link.getNote() != null) {
properties.put("text", link.getNote());
}
if (link.getCode() != null) {
properties.put("addon-code", link.getCode());
}
properties.put("addon-type", link.getTypeKey());
products.add(linkProduct);
return products;
}
/**
* Get product(s) from a Comment object.
*
* @param comment
* the comment object.
* @return a list of found products.
* @throws Exception if error occurs
*/
protected synchronized List<Product> getCommentProducts(
final Comment comment) throws Exception {
List<Product> products = new LinkedList<Product>();
// CUBE_Codes are attributes of the containing product.
String typeKey = comment.getTypeKey();
if (typeKey != null && !typeKey.equals("CUBE_Code")) {
String commentType = getTextAddonProductType(typeKey);
if (commentType == null) {
LOGGER.finer("No product type found for comment with type '"
+ comment.getTypeKey() + "'");
return products;
}
Action commentAction = comment.getAction();
Product commentProduct = getProduct(commentType,
commentAction == null ? null : commentAction.toString());
// remove the EQXML, only send comment text with comment products
commentProduct.getContents().clear();
// one product per comment type
ProductId id = commentProduct.getId();
id.setCode(id.getCode() + "_" + comment.getTypeKey().toLowerCase());
Map<String, String> properties = commentProduct.getProperties();
properties.put("addon-type", "comment");
if (comment.getTypeKey() != null) {
properties.put("code", comment.getTypeKey());
}
// store the comment text as content instead of a property, it may
// contain newlines
commentProduct.getContents().put("",
new ByteContent(comment.getText().getBytes()));
products.add(commentProduct);
}
return products;
}
/**
* Build a product skeleton based on the current state.
*
* Product type is : [internal-](origin,magnitude,addon)[-(scenario|test)]
* where the optional scope is not "Public", and the optional usage is not
* "Actual".
*
* @param type
* short product type, like "origin", "magnitude".
* @param action
* override the global message action.
* @return a Product so that properties and content can be added.
*/
protected synchronized Product getProduct(final String type,
final String action) {
String productType = type;
// prepend type with non Public scopes (Internal)
if (eventScope != EventScope.PUBLIC) {
productType = eventScope.toString() + "-" + productType;
}
// append to type with non Actual usages
if (eventUsage != EventUsage.ACTUAL) {
productType = productType + "-" + eventUsage.toString();
}
// make it all lower case
productType = productType.toLowerCase();
// use event id
String productCode = eventDataSource + eventEventId;
productCode = productCode.toLowerCase();
ProductId id = new ProductId(eqmessageSource.toLowerCase(),
productType, productCode, eqmessageSent);
Product product = new Product(id);
// figure out whether this is a delete
String productAction = action;
if (productAction == null) {
productAction = eventAction.toString();
if (productAction == null) {
productAction = "Update";
}
}
String productStatus;
if (productAction.equalsIgnoreCase("Delete")) {
productStatus = Product.STATUS_DELETE;
} else {
productStatus = Product.STATUS_UPDATE;
}
product.setStatus(productStatus);
if (eventDataSource != null && eventEventId != null) {
product.setEventId(eventDataSource, eventEventId);
}
if (originEventTime != null) {
product.setEventTime(originEventTime);
}
if (originLongitude != null) {
product.setLongitude(originLongitude);
}
if (originLatitude != null) {
product.setLatitude(originLatitude);
}
if (originDepth != null) {
product.setDepth(originDepth);
}
if (magnitude != null) {
product.setMagnitude(magnitude);
}
if (eventVersion != null) {
product.setVersion(eventVersion);
}
/*
* Map<String, String> properties = product.getProperties(); if
* (eventUsage != null) { properties.put("eqxml-usage",
* eventUsage.toString()); } if (eventScope != null) {
* properties.put("eqxml-scope", eventScope.toString()); } if
* (eventAction != null) { properties.put("eqxml-action",
* eventAction.toString()); }
*/
ByteContent xml = new ByteContent(eqmessageXML.getBytes());
xml.setLastModified(eqmessageSent);
product.getContents().put(EQMESSAGE_CONTENT_PATH, xml);
// add contents.xml to product to describe above content
product.getContents().put(CONTENTS_XML_PATH, getContentsXML());
return product;
}
/**
* @return a buffer of XML content
*/
protected Content getContentsXML() {
StringBuffer buf = new StringBuffer();
buf.append("<?xml version=\"1.0\"?>\n");
buf.append("<contents xmlns=\"http://earthquake.usgs.gov/earthquakes/event/contents\">\n");
buf.append("<file title=\"Earthquake XML (EQXML)\" id=\"eqxml\">\n");
buf.append("<format type=\"xml\" href=\"")
.append(EQMESSAGE_CONTENT_PATH).append("\"/>\n");
buf.append("</file>\n");
buf.append("<page title=\"Location\" slug=\"location\">\n");
buf.append("<file refid=\"eqxml\"/>\n");
buf.append("</page>\n");
buf.append("</contents>\n");
ByteContent content = new ByteContent(buf.toString().getBytes());
content.setLastModified(eqmessageSent);
// this breaks things
// content.setContentType("application/xml");
return content;
}
/**
* Extract a CUBE_Code from a Comment.
*
* This is the ISTI convention for preserving CUBE information in EQXML
* messages. Checks a list of Comment objects for one with
* TypeKey="CUBE_Code" and Text="CUBE_Code X", where X is the returned cube
* code.
*
* @param comments
* the list of comments.
* @return the cube code, or null if not found.
*/
protected synchronized String getCubeCode(final List<Comment> comments) {
String cubeCode = null;
if (comments != null) {
Iterator<Comment> iter = comments.iterator();
while (iter.hasNext()) {
Comment comment = iter.next();
if (comment.getTypeKey().equals("CUBE_Code")) {
cubeCode = comment.getText().replace("CUBE_Code ", "");
break;
}
}
}
return cubeCode;
}
/**
* @return boolean sendOriginWhenPhasesExist
*/
public boolean isSendOriginWhenPhasesExist() {
return sendOriginWhenPhasesExist;
}
/** @param sendOriginWhenPhasesExist boolean to set */
public void setSendOriginWhenPhasesExist(boolean sendOriginWhenPhasesExist) {
this.sendOriginWhenPhasesExist = sendOriginWhenPhasesExist;
}
@Override
public boolean isValidate() {
return validate;
}
@Override
public void setValidate(boolean validate) {
this.validate = validate;
}
@Override
public List<Product> getProducts(File file) throws Exception {
EQMessage eqxml = null;
String content = new String(FileUtils.readFile(file));
String rawEqxml = null;
// try to read eqxml
try {
eqxml = EQMessageParser.parse(
StreamUtils.getInputStream(content.getBytes()), validate);
rawEqxml = content;
} catch (Exception e) {
if (validate) {
throw e;
}
// try to read cube
try {
Converter converter = new Converter();
CubeMessage cube = converter.getCubeMessage(content);
eqxml = converter.getEQMessage(cube);
} catch (Exception e2) {
if (content.startsWith(CubeEvent.TYPE) ||
content.startsWith(CubeDelete.TYPE) ||
content.startsWith(CubeAddon.TYPE)) {
// throw cube parsing exception
throw e2;
} else {
// log cube parsing exception
LOGGER.log(Level.FINE, "Unable to parse cube message", e2);
}
// try to read eventaddon xml
try {
EventAddonParser parser = new EventAddonParser();
parser.parse(content);
eqxml = parser.getAddon().getEQMessage();
} catch (Exception e3) {
// log eventaddon parsing exception
LOGGER.log(Level.FINE, "Unable to parse eventaddon", e3);
// throw original exception
throw e;
}
}
}
return this.getEQMessageProducts(eqxml, rawEqxml);
}
/** Type for general text */
public static final String GENERAL_TEXT_TYPE = "general-text";
/** Empty string array for general text addons */
public static final String[] GENERAL_TEXT_ADDONS = new String[] {};
/** Type for scitech text */
public static final String SCITECH_TEXT_TYPE = "scitech-text";
/** Empty string array for scitech text addons */
public static final String[] SCITECH_TEXT_ADDONS = new String[] {};
/** Type for impact text */
public static final String IMPACT_TEXT_TYPE = "impact-text";
/** String array for impact text addons */
public static final String[] IMPACT_TEXT_ADDONS = new String[] { "feltreports" };
/** Selected link type products have a mapping. */
public static final String GENERAL_LINK_TYPE = "general-link";
/** String array for general link addons */
public static final String[] GENERAL_LINK_ADDONS = new String[] {
"aftershock", "afterwarn", "asw", "generalmisc" };
/** Type for scitech link */
public static final String SCITECH_LINK_TYPE = "scitech-link";
/** String array for scitech link */
public static final String[] SCITECH_LINK_ADDONS = new String[] { "energy",
"focalmech", "ncfm", "histmomenttensor", "finitefault",
"momenttensor", "mtensor", "phase", "seiscrosssec", "seisrecsec",
"traveltimes", "waveform", "seismograms", "scitechmisc" };
/** Type for impact link */
public static final String IMPACT_LINK_TYPE = "impact-link";
/** String array for impact link */
public static final String[] IMPACT_LINK_ADDONS = new String[] {
"tsunamilinks", "impactmisc" };
/**
* Map from cube style link addon to product type.
*
* @param addonType String to find correct link type
* @return null if link should not be converted to a product.
*/
public String getLinkAddonProductType(final String addonType) {
String c = addonType.toLowerCase();
for (String general : GENERAL_LINK_ADDONS) {
if (c.startsWith(general)) {
return GENERAL_LINK_TYPE;
}
}
for (String scitech : SCITECH_LINK_ADDONS) {
if (c.startsWith(scitech)) {
return SCITECH_LINK_TYPE;
}
}
for (String impact : IMPACT_LINK_ADDONS) {
if (c.startsWith(impact)) {
return IMPACT_LINK_TYPE;
}
}
return null;
}
/**
* Map from cube style text addon to product type.
*
* @param addonType to find correct addon type
* @return null if comment should not be converted to a product.
*/
public String getTextAddonProductType(final String addonType) {
String c = addonType.toLowerCase();
for (String general : GENERAL_TEXT_ADDONS) {
if (c.startsWith(general)) {
return GENERAL_TEXT_TYPE;
}
}
for (String impact : IMPACT_TEXT_ADDONS) {
if (c.startsWith(impact)) {
return IMPACT_TEXT_TYPE;
}
}
for (String scitech : SCITECH_TEXT_ADDONS) {
if (c.startsWith(scitech)) {
return SCITECH_TEXT_TYPE;
}
}
return null;
}
}