QuakemlProductCreator.java
package gov.usgs.earthquake.eids;
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.earthquake.product.io.ObjectProductSource;
import gov.usgs.earthquake.product.io.XmlProductHandler;
import gov.usgs.earthquake.quakeml.FileToQuakemlConverter;
import gov.usgs.util.StreamUtils;
import gov.usgs.util.XmlUtils;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.quakeml_1_2.Axis;
import org.quakeml_1_2.ConfidenceEllipsoid;
import org.quakeml_1_2.CreationInfo;
import org.quakeml_1_2.EvaluationMode;
import org.quakeml_1_2.Event;
import org.quakeml_1_2.EventDescription;
import org.quakeml_1_2.EventDescriptionType;
import org.quakeml_1_2.EventParameters;
import org.quakeml_1_2.EventType;
import org.quakeml_1_2.FocalMechanism;
import org.quakeml_1_2.InternalEvent;
import org.quakeml_1_2.Magnitude;
import org.quakeml_1_2.MomentTensor;
import org.quakeml_1_2.NodalPlane;
import org.quakeml_1_2.NodalPlanes;
import org.quakeml_1_2.Origin;
import org.quakeml_1_2.OriginQuality;
import org.quakeml_1_2.OriginUncertainty;
import org.quakeml_1_2.OriginUncertaintyDescription;
import org.quakeml_1_2.Quakeml;
import org.quakeml_1_2.RealQuantity;
import org.quakeml_1_2.ScenarioEvent;
import org.quakeml_1_2.SourceTimeFunction;
import org.quakeml_1_2.SourceTimeFunctionType;
import org.quakeml_1_2.Tensor;
import org.quakeml_1_2.TimeQuantity;
import org.quakeml_1_2.PrincipalAxes;
import org.quakeml_1_2.EvaluationStatus;
/**
* Create Products from ANSS Quakeml files.
*/
public class QuakemlProductCreator implements ProductCreator {
/** For use in logging issues */
public static final Logger LOGGER = Logger
.getLogger(QuakemlProductCreator.class.getName());
/** Content type for xml */
public static final String XML_CONTENT_TYPE = "application/xml";
/** Content path for quakeml */
public static final String QUAKEML_CONTENT_PATH = "quakeml.xml";
/** Contents XML path */
public static final String CONTENTS_XML_PATH = "contents.xml";
/** Var for number of meters/kilometer... */
public static final BigDecimal METERS_PER_KILOMETER = new BigDecimal("1000");
/** Version */
public static final String VERSION = "1.0";
/**
* When phases exist it is a "phase" type product. When this flag is set to
* true, a lightweight, origin-only type product (without bulky phase data)
* is also sent.
*/
private boolean sendOriginWhenPhasesExist = false;
private boolean sendMechanismWhenPhasesExist = false;
// xml for the eqmessage currently being processed
private String quakemlXML;
private CreationInfo eventParametersCreationInfo;
// attributes of current quakeml being processed
private String productSource;
private String productCode;
private String eventSource;
private String eventCode;
private Date updateTime;
private FileToQuakemlConverter converter = null;
private Converter formatConverter = new Converter();
private boolean validate = false;
// default to fixing padding issues
private boolean padForBase64Bug = true;
/** Default Constructor */
public QuakemlProductCreator() {
super();
}
/**
* Constructor taking in argument for Base64 bug padding
* @param padForBase64Bug Boolean if needed to pad
*/
public QuakemlProductCreator(boolean padForBase64Bug) {
this.padForBase64Bug = padForBase64Bug;
}
/**
* Gets Quakeml products with no rawQuakeml
* @param message Parsed quakeml message
* @return List of products
* @throws Exception if error occurs
*/
public List<Product> getQuakemlProducts(final Quakeml message)
throws Exception {
return getQuakemlProducts(message, null);
}
/**
* Gets Quakeml products with the message as a rawQuakeml
* @param message Parsed quakeml message
* @return List of products
* @throws Exception if error occurs
*/
public List<Product> getQuakemlProducts(final String message)
throws Exception {
Quakeml quakeml = formatConverter.getQuakeml(message, validate);
return getQuakemlProducts(quakeml, message);
}
/**
* Get products in a quakeml message.
*
* @param message
* the parsed quakeml message.
* @param rawQuakeml
* bytes of quakeml message. If null, the quakeml object will be
* serialized into xml. This parameter is used to preserve the
* original input, instead of always serializing from the quakeml
* object.
* @return list of products generated from quakeml message.
* @throws Exception if error occurs
*/
public List<Product> getQuakemlProducts(final Quakeml message,
final String rawQuakeml) throws Exception {
List<Product> products = new ArrayList<Product>();
// serialize for embedding in product
quakemlXML = rawQuakeml;
if (quakemlXML == null) {
quakemlXML = convertQuakemlToString(message);
} else {
quakemlXML = fixRawQuakeml(quakemlXML);
}
EventParameters eventParameters = message.getEventParameters();
eventParametersCreationInfo = eventParameters.getCreationInfo();
// only process first event
Event firstEvent = QuakemlUtils.getFirstEvent(eventParameters);
if (firstEvent != null) {
if (firstEvent instanceof InternalEvent) {
products.addAll(getInternalEventProducts(message, (InternalEvent) firstEvent));
} else if (firstEvent instanceof ScenarioEvent) {
products.addAll(getScenarioEventProducts(message, (ScenarioEvent) firstEvent));
} else {
products.addAll(getEventProducts(message, firstEvent));
}
}
// add property to all products to indicate they all come from the same
// eventParameters "envelope"
String eventParametersPublicID = eventParameters.getPublicID();
Iterator<Product> productIter = products.iterator();
while (productIter.hasNext()) {
Product next = productIter.next();
setProperty(next.getProperties(), "eventParametersPublicID",
eventParametersPublicID);
}
eventParametersCreationInfo = null;
quakemlXML = null;
return products;
}
/**
* Get internal products in quakeml event element.
*
* Calls {@link #getEventProducts(Quakeml, Event)}, and adds "internal-"
* prefix to each type in the returned list of products.
*
* @param message
* the quakeml message.
* @param event
* the internal event element.
* @return list of internal products found in event element, may be empty.
* @throws Exception if error occurs
*/
public List<Product> getInternalEventProducts(final Quakeml message,
final InternalEvent event) throws Exception {
List<Product> products = getEventProducts(message, event);
Iterator<Product> iter = products.iterator();
while (iter.hasNext()) {
ProductId nextId = iter.next().getId();
nextId.setType("internal-" + nextId.getType());
}
return products;
}
/**
* Get scenario products in quakeml event element.
*
* Calls {@link #getEventProducts(Quakeml, Event)}, and adds "-scenario"
* suffix to each type in the returned list of products.
*
* @param message
* the quakeml message.
* @param event
* the scenario event element.
* @return list of scenario products found in event element, may be empty.
* @throws Exception if error occurs
*/
public List<Product> getScenarioEventProducts(final Quakeml message,
final ScenarioEvent event) throws Exception {
List<Product> products = getEventProducts(message, event);
Iterator<Product> iter = products.iterator();
while (iter.hasNext()) {
ProductId nextId = iter.next().getId();
nextId.setType(nextId.getType() + "-scenario");
}
return products;
}
/**
* Get products in quakeml event element.
*
* @param message
* the quakeml message.
* @param event
* the event element in the quakeml message.
* @return list of products found in event element, may be empty.
* @throws Exception if error occurs
*/
public List<Product> getEventProducts(final Quakeml message, Event event)
throws Exception {
List<Product> products = new ArrayList<Product>();
// read catalog attributes for product source and code, and event source
// and code
productSource = event.getDatasource();
productCode = event.getDataid();
eventSource = event.getEventsource();
eventCode = event.getEventid();
if (productSource == null || eventSource == null || eventCode == null) {
LOGGER.warning("Missing catalog attributes from event element, skipping");
// not anss information, don't convert to products
return products;
} else if (productCode == null) {
productCode = eventSource + eventCode;
}
productSource = productSource.toLowerCase();
// product update time
updateTime = null;
if (eventParametersCreationInfo != null) {
updateTime = eventParametersCreationInfo.getCreationTime();
} else {
LOGGER.warning("Missing eventParameters creationTime, using now for update time");
updateTime = new Date();
}
ByteContent quakemlContent = new ByteContent(quakemlXML.getBytes());
quakemlContent.setContentType(XML_CONTENT_TYPE);
quakemlContent.setLastModified(updateTime);
boolean hasPhaseData = QuakemlUtils.hasPhaseData(event);
// create this object, may go unused
Product originProduct = new Product(new ProductId(productSource,
(hasPhaseData ? "phase-data" : "origin"), productCode,
updateTime));
originProduct.setEventId(eventSource, eventCode);
if (event.getCreationInfo() != null) {
originProduct.setVersion(event.getCreationInfo().getVersion());
}
originProduct.getContents().put(QUAKEML_CONTENT_PATH, quakemlContent);
originProduct.getContents().put(CONTENTS_XML_PATH, getContentsXML());
// track which event this product is from
setProperty(originProduct.getProperties(), "quakeml-publicid",
event.getPublicID());
// delete origin product
if (event.getType() == EventType.NOT_EXISTING) {
originProduct.setStatus(Product.STATUS_DELETE);
products.add(originProduct);
Product phaseDelete = new Product(originProduct);
phaseDelete.getId().setType("phase-data");
products.add(phaseDelete);
// don't need to delete other stuff
// when origins for event are deleted, event is deleted
return products;
}
Origin origin = QuakemlUtils.getPreferredOrigin(event);
if (origin != null) {
// track which origin this product is from
setProperty(originProduct.getProperties(), "quakeml-origin-publicid",
origin.getPublicID());
// update origin product
Map<String, String> properties = originProduct.getProperties();
TimeQuantity eventTime = origin.getTime();
if (eventTime != null) {
originProduct.setEventTime(eventTime.getValue());
setProperty(properties, "eventtime-error",
eventTime.getUncertainty());
}
RealQuantity eventLatitude = origin.getLatitude();
if (eventLatitude != null) {
originProduct.setLatitude(eventLatitude.getValue());
setProperty(properties, "latitude-error",
eventLatitude.getUncertainty());
}
RealQuantity eventLongitude = origin.getLongitude();
if (eventLongitude != null) {
originProduct.setLongitude(eventLongitude.getValue());
setProperty(properties, "longitude-error",
eventLongitude.getUncertainty());
}
RealQuantity depth = origin.getDepth();
if (depth != null) {
originProduct.setDepth(depth.getValue().divide(
METERS_PER_KILOMETER));
if (depth.getUncertainty() != null) {
setProperty(properties, "vertical-error", depth
.getUncertainty().divide(METERS_PER_KILOMETER));
}
if (origin.getDepthType() != null) {
setProperty(properties, "depth-type", origin.getDepthType()
.value());
}
}
// read horizontal error
OriginUncertainty originUncertainty = origin.getOriginUncertainty();
if (originUncertainty != null) {
if (originUncertainty.getHorizontalUncertainty() != null) {
setProperty(properties, "horizontal-error",
originUncertainty.getHorizontalUncertainty()
.divide(METERS_PER_KILOMETER));
} else if (originUncertainty.getPreferredDescription() == OriginUncertaintyDescription.HORIZONTAL_UNCERTAINTY) {
throw new IllegalArgumentException(
"Missing horizontal uncertainty value");
}
ConfidenceEllipsoid ellipse = originUncertainty.getConfidenceEllipsoid();
if (ellipse != null) {
setProperty(properties, "error-ellipse-azimuth",
ellipse.getMajorAxisAzimuth());
setProperty(properties, "error-ellipse-plunge",
ellipse.getMajorAxisPlunge());
setProperty(properties, "error-ellipse-rotation",
ellipse.getMajorAxisRotation());
setProperty(properties, "error-ellipse-major",
ellipse.getSemiMajorAxisLength());
setProperty(properties, "error-ellipse-minor",
ellipse.getSemiMinorAxisLength());
setProperty(properties, "error-ellipse-intermediate",
ellipse.getSemiIntermediateAxisLength());
}
}
EventType eventType = event.getType();
properties.put("event-type",
((eventType == null) ? EventType.EARTHQUAKE : eventType)
.value());
CreationInfo originCreationInfo = origin.getCreationInfo();
if (originCreationInfo != null) {
setProperty(properties, "origin-source",
originCreationInfo.getAgencyID());
}
OriginQuality originQuality = origin.getQuality();
if (originQuality != null) {
setProperty(properties, "azimuthal-gap",
originQuality.getAzimuthalGap());
setProperty(properties, "num-phases-used",
originQuality.getUsedPhaseCount());
setProperty(properties, "num-stations-used",
originQuality.getUsedStationCount());
setProperty(properties, "minimum-distance",
originQuality.getMinimumDistance());
setProperty(properties, "standard-error",
originQuality.getStandardError());
}
if (origin.getEvaluationMode() == EvaluationMode.MANUAL) {
properties.put("review-status", "reviewed");
} else {
properties.put("review-status", "automatic");
}
if (origin.getEvaluationStatus() != null) {
properties.put("evaluation-status", origin
.getEvaluationStatus().value());
} else {
properties.put("evaluation-status",
EvaluationStatus.PRELIMINARY.value());
}
// add magnitude properties
Magnitude magnitude = QuakemlUtils.getPreferredMagnitude(event);
if (magnitude != null) {
// track which origin this product is from
setProperty(originProduct.getProperties(), "quakeml-magnitude-publicid",
magnitude.getPublicID());
CreationInfo magnitudeCreationInfo = magnitude
.getCreationInfo();
if (magnitudeCreationInfo != null) {
setProperty(properties, "magnitude-source",
magnitudeCreationInfo.getAgencyID());
}
originProduct.setMagnitude(QuakemlUtils.getValue(magnitude
.getMag()));
setProperty(properties, "magnitude-type",
QuakemlUtils.getMagnitudeType(magnitude.getType()));
setProperty(properties, "magnitude-azimuthal-gap",
magnitude.getAzimuthalGap());
try {
setProperty(properties, "magnitude-error", magnitude
.getMag().getUncertainty());
} catch (Exception e) {
// no magnitude uncertainty
}
setProperty(properties, "magnitude-num-stations-used",
magnitude.getStationCount());
} else {
// a location without a magnitude
}
products.add(originProduct);
} else {
// no preferred origin found
// signal origin product hasn't been created
originProduct = null;
}
// look for event description products
Iterator<EventDescription> iter = event.getDescriptions().iterator();
while (iter.hasNext()) {
EventDescription next = iter.next();
EventDescriptionType type = next.getType();
if (type == EventDescriptionType.EARTHQUAKE_NAME) {
if (originProduct != null) {
// Region name overrides should be sent
// from the admin pages, or attached to an origin. That way
// only a preferred origin, or a manually sent region,
// can alter the displayed region name
setProperty(originProduct.getProperties(), "title", next
.getText().trim());
}
} else if (type == EventDescriptionType.TECTONIC_SUMMARY) {
Product product = new Product(new ProductId(productSource,
"tectonic-summary", productCode, updateTime));
product.setEventId(eventSource, eventCode);
ByteContent content = new ByteContent(next.getText().getBytes());
content.setLastModified(updateTime);
product.getContents().put("tectonic-summary.inc.html", content);
products.add(product);
} else if (type == EventDescriptionType.FELT_REPORT) {
Product product = new Product(new ProductId(productSource,
"impact-text", productCode, updateTime));
product.setEventId(eventSource, eventCode);
ByteContent content = new ByteContent(next.getText().getBytes());
content.setLastModified(updateTime);
product.getContents().put("", content);
products.add(product);
}
}
if (sendMechanismWhenPhasesExist || originProduct == null
|| !hasPhaseData) {
Iterator<FocalMechanism> focalMechanisms = event
.getFocalMechanisms().iterator();
while (focalMechanisms.hasNext()) {
FocalMechanism mech = focalMechanisms.next();
Product mechProduct = null;
if (hasPhaseData && originProduct != null) {
// when a phase data product was created, send lightweight
// focal mechanism
Quakeml lightweightQuakeml = QuakemlUtils
.getLightweightFocalMechanism(message,
mech.getPublicID());
Event lightweightEvent = QuakemlUtils.getFirstEvent(
lightweightQuakeml.getEventParameters());
FocalMechanism lightweightMech = QuakemlUtils
.getFocalMechanism(lightweightEvent,
mech.getPublicID());
mechProduct = getFocalMechanismProduct(lightweightQuakeml,
lightweightEvent, lightweightMech,
convertQuakemlToString(lightweightQuakeml));
} else {
// otherwise, fall back to original
mechProduct = getFocalMechanismProduct(message, event,
mech, quakemlXML);
}
if (mechProduct != null) {
products.add(mechProduct);
}
}
}
// send lightweight origin product
if (sendOriginWhenPhasesExist && hasPhaseData && originProduct != null) {
// create lightweight origin product
Product lightweightOrigin = new Product(originProduct);
lightweightOrigin.getId().setType("origin");
Quakeml lightweightQuakeml = QuakemlUtils
.getLightweightOrigin(message);
// serialize xml without phase data
ByteContent lightweightContent = new ByteContent(convertQuakemlToString(lightweightQuakeml).getBytes());
lightweightContent.setContentType(XML_CONTENT_TYPE);
lightweightContent.setLastModified(updateTime);
lightweightOrigin.getContents().put(QUAKEML_CONTENT_PATH,
lightweightContent);
// insert at front of list
products.add(0, lightweightOrigin);
}
return products;
}
/**
* @param quakeml Quakeml
* @param event the event element in the quakeml message
* @param mech A focal mechanism
* @param quakemlContent String of content in Quakeml
* @return A product derived from a focal mechanism
*/
protected Product getFocalMechanismProduct(final Quakeml quakeml,
final Event event, final FocalMechanism mech,
final String quakemlContent) {
MomentTensor momentTensor = mech.getMomentTensor();
// determine product id
String mechSource = mech.getDatasource();
String mechCode = mech.getDataid();
String mechType = mech.getDatatype();
if (mechType == null) {
// automatically determine mechanism type based on available data
mechType = "focal-mechanism";
if (momentTensor != null && momentTensor.getTensor() != null) {
mechType = "moment-tensor";
if (mechCode == null && momentTensor.getMethodID() != null) {
mechCode = productCode + "_" + momentTensor.getMethodID();
}
}
}
if (mechSource == null) {
mechSource = productSource;
}
if (mechCode == null) {
mechCode = productCode;
}
Product product = new Product(new ProductId(mechSource, mechType,
mechCode, updateTime));
if (mech.getEvaluationStatus() == EvaluationStatus.REJECTED) {
// this is a delete
product.setStatus(Product.STATUS_DELETE);
}
// product is being contributed to containing event
product.setEventId(eventSource, eventCode);
ByteContent tensorContent = new ByteContent(quakemlContent.getBytes());
tensorContent.setContentType(XML_CONTENT_TYPE);
tensorContent.setLastModified(updateTime);
product.getContents().put(QUAKEML_CONTENT_PATH, tensorContent);
product.getContents().put(CONTENTS_XML_PATH, getContentsXML());
Map<String, String> properties = product.getProperties();
// track which mechanism is used in this product, for later
// extraction
setProperty(properties, "quakeml-publicid", mech.getPublicID());
// also track original event if set, in case this is a recontributed
// product
setProperty(properties, "original-eventsource", mech.getEventsource());
setProperty(properties, "original-eventsourcecode", mech.getEventid());
if (mech.getEvaluationMode() == EvaluationMode.MANUAL) {
properties.put("review-status", "reviewed");
} else {
properties.put("review-status", "automatic");
}
if (mech.getEvaluationStatus() != null) {
properties.put("evaluation-status", mech.getEvaluationStatus()
.value());
} else {
properties.put("evaluation-status", EvaluationStatus.PRELIMINARY
.value());
}
CreationInfo focalMechanismCreationInfo = mech.getCreationInfo();
if (focalMechanismCreationInfo != null) {
product.setVersion(focalMechanismCreationInfo.getVersion());
setProperty(properties, "beachball-source",
focalMechanismCreationInfo.getAgencyID());
}
NodalPlanes planes = mech.getNodalPlanes();
if (planes != null) {
NodalPlane plane1 = planes.getNodalPlane1();
setProperty(properties, "nodal-plane-1-strike", plane1.getStrike());
setProperty(properties, "nodal-plane-1-dip", plane1.getDip());
setProperty(properties, "nodal-plane-1-rake", plane1.getRake());
NodalPlane plane2 = planes.getNodalPlane2();
setProperty(properties, "nodal-plane-2-strike", plane2.getStrike());
setProperty(properties, "nodal-plane-2-dip", plane2.getDip());
setProperty(properties, "nodal-plane-2-rake", plane2.getRake());
}
// add properties for principal axes
PrincipalAxes axes = mech.getPrincipalAxes();
if (axes != null) {
Axis tAxis = axes.getTAxis();
if (tAxis != null) {
setProperty(properties, "t-axis-azimuth", tAxis.getAzimuth());
setProperty(properties, "t-axis-plunge", tAxis.getPlunge());
setProperty(properties, "t-axis-length", tAxis.getLength(), true);
}
Axis nAxis = axes.getNAxis();
if (nAxis != null) {
setProperty(properties, "n-axis-azimuth", nAxis.getAzimuth());
setProperty(properties, "n-axis-plunge", nAxis.getPlunge());
setProperty(properties, "n-axis-length", nAxis.getLength(), true);
}
Axis pAxis = axes.getPAxis();
if (pAxis != null) {
setProperty(properties, "p-axis-azimuth", pAxis.getAzimuth());
setProperty(properties, "p-axis-plunge", pAxis.getPlunge());
setProperty(properties, "p-axis-length", pAxis.getLength(), true);
}
}
setProperty(properties, "num-stations-used",
mech.getStationPolarityCount());
// try to read triggering origin attributes for association
Origin triggeringOrigin = QuakemlUtils.getOrigin(event,
mech.getTriggeringOriginID());
if (triggeringOrigin != null) {
// set properties for association purposes.
product.setLatitude(triggeringOrigin.getLatitude().getValue());
product.setLongitude(triggeringOrigin.getLongitude().getValue());
product.setEventTime(triggeringOrigin.getTime().getValue());
// add triggering depth if present
if (triggeringOrigin.getDepth() != null) {
product.setDepth(triggeringOrigin.getDepth().getValue()
.divide(METERS_PER_KILOMETER));
}
}
Tensor tensor = null;
if (momentTensor != null) {
setProperty(properties, "percent-double-couple",
momentTensor.getDoubleCouple());
setProperty(properties, "scalar-moment",
momentTensor.getScalarMoment(), true);
setProperty(properties, "beachball-type",
momentTensor.getMethodID());
if (momentTensor.getInversionType() != null) {
setProperty(properties, "inversion-type",
momentTensor.getInversionType().value());
}
tensor = momentTensor.getTensor();
if (tensor != null) {
setProperty(properties, "tensor-mpp", tensor.getMpp(), true);
setProperty(properties, "tensor-mrp", tensor.getMrp(), true);
setProperty(properties, "tensor-mrr", tensor.getMrr(), true);
setProperty(properties, "tensor-mrt", tensor.getMrt(), true);
setProperty(properties, "tensor-mtp", tensor.getMtp(), true);
setProperty(properties, "tensor-mtt", tensor.getMtt(), true);
}
SourceTimeFunction sourceTimeFunction = momentTensor
.getSourceTimeFunction();
if (sourceTimeFunction != null) {
SourceTimeFunctionType sourceTimeFunctionType = sourceTimeFunction
.getType();
if (sourceTimeFunctionType != null) {
setProperty(properties, "sourcetime-type",
sourceTimeFunctionType.value());
}
setProperty(properties, "sourcetime-duration",
sourceTimeFunction.getDuration());
setProperty(properties, "sourcetime-risetime",
sourceTimeFunction.getRiseTime());
setProperty(properties, "sourcetime-decaytime",
sourceTimeFunction.getDecayTime());
}
Origin derivedOrigin = QuakemlUtils.getOrigin(event,
momentTensor.getDerivedOriginID());
if (derivedOrigin != null) {
setProperty(properties, "derived-latitude",
derivedOrigin.getLatitude());
setProperty(properties, "derived-longitude",
derivedOrigin.getLongitude());
RealQuantity depth = derivedOrigin.getDepth();
if (depth != null) {
setProperty(properties, "derived-depth", depth.getValue()
.divide(METERS_PER_KILOMETER));
}
setProperty(properties, "derived-eventtime",
derivedOrigin.getTime());
}
Magnitude derivedMagnitude = QuakemlUtils.getMagnitude(event,
momentTensor.getMomentMagnitudeID());
if (derivedMagnitude != null) {
String derivedMagnitudeType = derivedMagnitude.getType();
setProperty(properties, "derived-magnitude-type",
derivedMagnitudeType);
setProperty(properties, "derived-magnitude",
derivedMagnitude.getMag());
if (derivedMagnitudeType.equalsIgnoreCase("Mwd")) {
product.getId().setType("broadband-depth");
}
}
}
if (!Product.STATUS_DELETE.equals(product.getStatus())) {
// if not deleting, do some validation
String type = product.getId().getType();
if ("focal-mechanism".equals(type) && planes == null) {
LOGGER.warning("Focal mechanism missing nodal planes");
return null;
} else if ("moment-tensor".equals(type) && tensor == null) {
LOGGER.warning("Moment tensor missing tensor parameters");
return null;
}
}
return product;
}
/**
* setProperty for RealQuantity values. No exponentials
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final RealQuantity value) {
setProperty(properties, name, value, false);
}
/**
* setProperty for RealQuantity values
* @param properties to add
* @param name of property
* @param value of property
* @param allowExponential if allowed
*/
public void setProperty(final Map<String, String> properties,
final String name, final RealQuantity value,
final boolean allowExponential) {
if (value == null) {
return;
}
setProperty(properties, name, value.getValue(), allowExponential);
}
/**
* setProperty for strings
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final String value) {
if (value == null) {
return;
}
properties.put(name, value);
}
/**
* setProperty for TimeQuantities
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final TimeQuantity value) {
if (value == null) {
return;
}
properties.put(name, XmlUtils.formatDate(value.getValue()));
}
/**
* setProperty taking in BigDecimals. No exponentials
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final BigDecimal value) {
setProperty(properties, name, value, false);
}
/**
* setProperty taking in BigDecimals
* @param properties to add
* @param name of property
* @param value of property
* @param allowExponential boolean
*/
public void setProperty(final Map<String, String> properties,
final String name, final BigDecimal value,
final boolean allowExponential) {
if (value == null) {
return;
}
properties.put(name, allowExponential ? value.toString()
: value.toPlainString());
}
/**
* setProperty taking in BigIntegers. No exponentials
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final BigInteger value) {
if (value == null) {
return;
}
properties.put(name, value.toString());
}
/**
* setProperty taking in Integers
* @param properties to add
* @param name of property
* @param value of property
*/
public void setProperty(final Map<String, String> properties,
final String name, final Integer value) {
if (value == null) {
return;
}
properties.put(name, value.toString());
}
/** @param converter FileToQuakeml Converter to set */
public void setConverter(FileToQuakemlConverter converter) {
this.converter = converter;
}
/** @return FileToQuakeml converter */
public FileToQuakemlConverter getConverter() {
return converter;
}
@Override
public boolean isValidate() {
return validate;
}
@Override
public void setValidate(boolean validate) {
this.validate = validate;
}
/**
* Implement the ProductCreator interface.
*/
@Override
public List<Product> getProducts(File file) throws Exception {
if (this.converter == null) {
// preserve quakeml input
String contents = new String(StreamUtils.readStream(file));
return this.getQuakemlProducts(contents);
} else {
Quakeml quakeml = this.converter.parseFile(file);
return this.getQuakemlProducts(quakeml);
}
}
/**
* @return XML contents
*/
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 (Quakeml)\">\n");
buf.append("<format type=\"xml\" href=\"").append(QUAKEML_CONTENT_PATH)
.append("\"/>\n");
buf.append("</file>\n");
buf.append("</contents>\n");
ByteContent content = new ByteContent(buf.toString().getBytes());
content.setContentType("application/xml");
return content;
}
/** @return boolean sendOriginWhenPhasesExist */
public boolean isSendOriginWhenPhasesExist() {
return sendOriginWhenPhasesExist;
}
/** @param sendOriginWhenPhasesExist boolean to set */
public void setSendOriginWhenPhasesExist(boolean sendOriginWhenPhasesExist) {
this.sendOriginWhenPhasesExist = sendOriginWhenPhasesExist;
}
/** @param sendMechanismWhenPhasesExist boolean to set */
public void setSendMechanismWhenPhasesExist(
boolean sendMechanismWhenPhasesExist) {
this.sendMechanismWhenPhasesExist = sendMechanismWhenPhasesExist;
}
/** @return sendMechanismWhenPhasesExist boolean */
public boolean isSendMechanismWhenPhasesExist() {
return sendMechanismWhenPhasesExist;
}
/** @param padForBase64Bug to set */
public void setPadForBase64Bug(boolean padForBase64Bug) {
this.padForBase64Bug = padForBase64Bug;
}
/** @return padForBase64Bug */
public boolean isPadForBase64Bug() {
return padForBase64Bug;
}
/**
* Utility function that converts quakeml to a string
*
* @param message
* The quakeml to be converted
*
* @return raw string
* @throws Exception if quakeml doesn't validate
*/
private String convertQuakemlToString(Quakeml message) throws Exception{
return fixRawQuakeml(formatConverter.getString(message,validate));
}
/**
* Fixes base 64 bug: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8222187
*
* @param rawMessage
* the message to edit
* @return the fixed string
*/
public String fixRawQuakeml(String rawMessage) {
if (padForBase64Bug && rawMessage.getBytes().length % 4096 == 1) {
rawMessage += ' ';
}
return rawMessage;
}
/**
* Convert quakeml files to products.
*
* @param args
* a list of files to convert from quakeml to products.
* @throws Exception if error occurs
*/
public static void main(final String[] args) throws Exception {
QuakemlProductCreator creator = new QuakemlProductCreator();
creator.setSendOriginWhenPhasesExist(true);
creator.setSendMechanismWhenPhasesExist(true);
if (args.length == 0) {
System.err
.println("Quakeml to product converter utility. "
+ "For visually inspecting products that would be created from quakeml files.");
System.err.println();
System.err.println("Usage: QuakemlProductCreator FILE [ FILE ]");
System.err
.println("\tFILE - a quakeml file to convert to products, repeat as needed");
System.exit(1);
}
for (String arg : args) {
File quakeml = new File(arg);
System.err.println("reading quakeml from "
+ quakeml.getCanonicalPath());
Iterator<Product> iter = creator.getProducts(quakeml).iterator();
while (iter.hasNext()) {
Product next = iter.next();
new ObjectProductSource(next).streamTo(new XmlProductHandler(
new StreamUtils.UnclosableOutputStream(System.err)));
}
System.err.println();
}
}
}