AIDWebServiceXMLAttributeObservationSourcePlugin.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2010 AAVSO (http://www.aavso.org/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.plugin.ob.src.impl;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.aavso.tools.vstar.data.DateInfo;
import org.aavso.tools.vstar.data.InvalidObservation;
import org.aavso.tools.vstar.data.MTypeType;
import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.data.ValidObservation;
import org.aavso.tools.vstar.data.ValidationType;
import org.aavso.tools.vstar.exception.ObservationReadError;
import org.aavso.tools.vstar.input.AbstractObservationRetriever;
import org.aavso.tools.vstar.ui.mediator.StarInfo;
import org.aavso.tools.vstar.util.locale.LocaleProps;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This intrinsic observation source plug-in retrieves AID observations via the
* VSX web service.
*/
public class AIDWebServiceXMLAttributeObservationSourcePlugin extends
AIDWebServiceObservationSourcePluginBase {
public AIDWebServiceXMLAttributeObservationSourcePlugin() {
super("api.object", "&att");
}
@Override
public AbstractObservationRetriever getObservationRetriever() {
return new VSXAIDAttributeObservationRetriever();
}
@Override
protected String addURLs(String auid) {
String urlStr = null;
// Create a list of URLs with different series for the same target
// and time range.
for (SeriesType series : starSelector.getSelectedSeries()) {
if (starSelector.wantAllData()) {
// Request all AID data for object for requested series.
urlStr = createAIDUrlForAUID(auid);
} else {
// Request AID data for object over a range and for the
// zeroth requested series.
urlStr = createAIDUrlForAUID(auid, starSelector.getMinDate()
.getJulianDay(), starSelector.getMaxDate()
.getJulianDay(), series.getShortName(), null, false);
}
urlStrs.add(urlStr);
}
return urlStr;
}
class VSXAIDAttributeObservationRetriever extends
AbstractObservationRetriever {
public VSXAIDAttributeObservationRetriever() {
super(getVelaFilterStr());
info.setRetriever(this);
}
@Override
public StarInfo getStarInfo() {
return info;
}
@Override
public Integer getNumberOfRecords() throws ObservationReadError {
return info.getObsCount();
}
@Override
public void retrieveObservations() throws ObservationReadError,
InterruptedException {
// Iterate over each series-based URL reading observations over
// potentially many "pages" for each URL.
for (String urlStr : urlStrs) {
Integer pageNum = 1;
do {
try {
String currUrlStr = urlStr;
if (pageNum != null) {
currUrlStr += "&page=" + pageNum;
}
URL vsxUrl = new URL(currUrlStr);
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream stream = new UTF8FilteringInputStream(
vsxUrl.openStream());
Document document = builder.parse(stream);
document.getDocumentElement().normalize();
pageNum = requestObservationDetails(document, pageNum);
} catch (MalformedURLException e) {
throw new ObservationReadError(
"Unable to obtain information for "
+ info.getDesignation());
} catch (ParserConfigurationException e) {
throw new ObservationReadError(
"Unable to obtain information for "
+ info.getDesignation());
} catch (SAXException e) {
throw new ObservationReadError(
"Unable to obtain information for "
+ info.getDesignation());
} catch (IOException e) {
throw new ObservationReadError(
"Unable to obtain information for "
+ info.getDesignation());
}
} while (pageNum != null && !interrupted);
}
}
@Override
public String getSourceType() {
return LocaleProps.get("DATABASE_OBS_SOURCE");
}
@Override
public String getSourceName() {
return info.getDesignation();
}
// Helpers
/**
* Retrieve all observation details from the document.
*
* @param document
* The document from which to extract observations.
* @param pageNum
* The page number of the document to read.
* @return The next page number to read or null if not a multi-page
* document.
* @throws ObservationReadError
* If an error occurs when reading the document.
*/
private Integer requestObservationDetails(Document document,
Integer pageNum) throws ObservationReadError {
// Has an observation count been supplied?
// If so, more observations remain than the ones about to be
// retrieved here.
Integer obsCount = null;
NodeList dataNodes = document.getElementsByTagName("Data");
if (dataNodes.getLength() == 1) {
Element dataElt = (Element) dataNodes.item(0);
String count = dataElt.getAttribute("Count");
if (count != null && count.trim().length() != 0) {
obsCount = Integer.parseInt(count);
}
}
if (obsCount == null) {
pageNum = null;
}
NodeList obsNodes = document.getElementsByTagName("Observation");
for (int i = 0; i < obsNodes.getLength(); i++) {
if (interrupted)
break;
NamedNodeMap obsDetails = obsNodes.item(i).getAttributes();
ValidObservation ob = retrieveObservation(new NamedNodeMapSequence(
obsDetails));
if (ob != null) {
collectObservation(ob);
}
incrementProgress();
}
if (pageNum != null) {
pageNum++;
}
return pageNum;
}
/**
* Given an XML node of some kind (Element, Node) corresponding to the
* details of a single observation, retrieve that observation.
*
* @param obsDetails
* A sequence of observation details.
* @return The observation.
* @throws ObservationReadError
* if an error occurred during observation processing.
*/
private ValidObservation retrieveObservation(INodeSequence obsDetails)
throws ObservationReadError {
Integer id = null;
Double jd = null;
Double mag = null;
Double error = 0.0;
SeriesType band = null;
String obscode = null;
String obsType = null;
ValidationType valType = null;
String comp1 = null;
String comp2 = null;
String kMag = null;
String charts = null;
String commentCode = null;
String comments = null;
boolean transformed = false;
boolean fainterThan = false;
boolean isUncertain = false;
DateInfo hJD = null;
String airmass = null;
String group = null;
MTypeType mType = null;
String credit = null;
String pubref = null;
String digitizer = null;
String name = info.getDesignation();
for (int j = 0; j < obsDetails.getLength(); j++) {
if (interrupted)
break;
Node detailNode = obsDetails.item(j);
String nodeName = detailNode.getNodeName();
String nodeValue = detailNode.getTextContent();
if ("Id".equalsIgnoreCase(nodeName)) {
id = Integer.parseInt(nodeValue);
} else if ("JD".equalsIgnoreCase(nodeName)) {
jd = getPossiblyNullDouble(nodeValue);
} else if ("Mag".equalsIgnoreCase(nodeName)) {
mag = getPossiblyNullDouble(nodeValue);
} else if ("uncertainty".equalsIgnoreCase(nodeName)) {
error = getPossiblyNullDouble(nodeValue);
} else if ("uncertain".equalsIgnoreCase(nodeName)) {
isUncertain = Boolean.parseBoolean(nodeValue);
} else if ("fainterthan".equalsIgnoreCase(nodeName)) {
fainterThan = Boolean.parseBoolean(nodeValue);
} else if ("band".equalsIgnoreCase(nodeName)) {
band = SeriesType.getSeriesFromShortName(nodeValue);
} else if ("transformed".equalsIgnoreCase(nodeName)) {
transformed = "true".equalsIgnoreCase(nodeValue);
} else if ("airmass".equalsIgnoreCase(nodeName)) {
airmass = nodeValue;
} else if ("comp1".equalsIgnoreCase(nodeName)) {
comp1 = nodeValue;
} else if ("comp2".equalsIgnoreCase(nodeName)) {
comp2 = nodeValue;
} else if ("KMag".equalsIgnoreCase(nodeName)) {
kMag = nodeValue;
} else if ("hjd".equalsIgnoreCase(nodeName)) {
Double hjd = getPossiblyNullDouble(nodeValue);
if (hjd != null) {
hJD = new DateInfo(hjd);
}
} else if ("group".equalsIgnoreCase(nodeName)) {
group = nodeValue;
} else if ("obscode".equalsIgnoreCase(nodeName)) {
obscode = nodeValue;
} else if ("obstype".equalsIgnoreCase(nodeName)) {
obsType = nodeValue;
} else if ("charts".equalsIgnoreCase(nodeName)) {
charts = nodeValue;
} else if ("commentcode".equalsIgnoreCase(nodeName)) {
commentCode = nodeValue;
} else if ("comments".equalsIgnoreCase(nodeName)) {
comments = nodeValue;
} else if ("valflag".equalsIgnoreCase(nodeName)) {
valType = getValidationType(nodeValue);
} else if ("mtype".equalsIgnoreCase(nodeName)) {
mType = getMType(nodeValue);
} else if ("credit".equalsIgnoreCase(nodeName)) {
credit = nodeValue;
} else if ("pubref".equalsIgnoreCase(nodeName)) {
pubref = nodeValue;
} else if ("digitizer".equalsIgnoreCase(nodeName)) {
digitizer = nodeValue;
} else if ("name".equalsIgnoreCase(nodeName)) {
name = nodeValue;
}
}
ValidObservation ob = null;
if (id != null && jd != null && mag != null && error != null
&& valType != ValidationType.BAD) {
ob = new ValidObservation();
if (id != null) {
ob.setRecordNumber(id);
}
ob.setDateInfo(new DateInfo(jd));
ob.setMagnitude(getMagnitude(mag, error, fainterThan,
isUncertain));
ob.setBand(band);
ob.setObsCode(obscode);
ob.setObsType(obsType);
ob.setValidationType(valType);
ob.setCompStar1(comp1);
ob.setCompStar2(comp2);
ob.setKMag(kMag);
ob.setHJD(hJD);
ob.setCharts(charts);
ob.setCommentCode(commentCode);
ob.setComments(comments);
ob.setTransformed(transformed);
ob.setAirmass(airmass);
ob.setGroup(group);
ob.setMType(mType);
ob.setCredit(credit);
ob.setADSRef(pubref);
ob.setDigitizer(digitizer);
ob.setName(name);
} else {
invalidObservations.add(new InvalidObservation(id + "",
"Invalid"));
}
return ob;
}
}
}