1
2
3
4
5
6
7
8
9
10
11 package org.astrogrid.datacenter.impl.cds;
12
13 import java.io.IOException;
14 import java.io.StringWriter;
15 import java.net.URL;
16 import java.util.Hashtable;
17 import javax.xml.parsers.ParserConfigurationException;
18 import javax.xml.rpc.ServiceException;
19 import org.astrogrid.community.Account;
20 import org.astrogrid.datacenter.delegate.DatacenterException;
21 import org.astrogrid.datacenter.impl.cds.generated.vizier.VizieR;
22 import org.astrogrid.datacenter.impl.cds.generated.vizier.VizieRService;
23 import org.astrogrid.datacenter.impl.cds.generated.vizier.VizieRServiceLocator;
24 import org.astrogrid.datacenter.impl.cds.vizier.VizierUnit;
25 import org.astrogrid.datacenter.impl.cds.vizier.VizierWavelength;
26 import org.astrogrid.datacenter.queriers.DefaultPlugin;
27 import org.astrogrid.datacenter.queriers.Querier;
28 import org.astrogrid.datacenter.queriers.QueryResults;
29 import org.astrogrid.datacenter.queriers.VotableDomResults;
30 import org.astrogrid.datacenter.queriers.VotableInResults;
31 import org.astrogrid.datacenter.queriers.sql.RdbmsResourceReader;
32 import org.astrogrid.datacenter.queriers.status.QuerierQuerying;
33 import org.astrogrid.datacenter.query.Query;
34 import org.astrogrid.datacenter.returns.ReturnTable;
35 import org.astrogrid.slinger.targets.TargetMaker;
36 import org.astrogrid.util.DomHelper;
37 import org.xml.sax.SAXException;
38
39 /*** Datacenter querier SPI that performs queries against CDS Vizier webservice.
40 * <p>
41 * The Vizier SOAP services take the following arguments:
42 * String target - name of an object, or RA DEC, eg "12.0 23.2" in decimal degrees (can also handle sexagesimal but let's ignore that...)
43 * double radius - in units given by:
44 * double units - not sure what's valid. @see VizierUnits for enuemeration
45 * String text - no idea. Some kind of keyword?
46 * String wavelength - not sure what's valid. @see VizierWavelengths for enumeration
47 *
48 * @see http://cdsweb.u-strasbg.fr/cdsws/vizierAccess.gml
49 * @author M Hill
50 */
51 public class VizierQuerierPlugin extends DefaultPlugin {
52
53 String[] mirrorUrls = new String[] {
54 "http://cdsws.u-strasbg.fr/axis/services/VizieR",
55 "http://archive.ast.cam.ac.uk/axis/services/VizieR"
56 };
57
58
59 /*** default constructor */
60 public VizierQuerierPlugin() {
61 super();
62 }
63
64
65
66
67 public void askQuery(Account user, Query query, Querier querier) throws IOException {
68
69 querier.setStatus(new QuerierQuerying(querier.getStatus()));
70
71
72 KeywordMaker maker = new KeywordMaker(query);
73
74 String text = (String) maker.getValue("TEXT");
75 String r = (String) maker.getRequiredValue(KeywordMaker.RADIUS_KEYWORD);
76 double radius = 0;
77 try {
78 radius = Double.parseDouble(r);
79 }
80 catch (NumberFormatException nfe) {
81 throw new IllegalArgumentException(KeywordMaker.RADIUS_KEYWORD+" has non-numeric value "+r);
82 }
83
84 String u = (String) maker.getValue("UNIT");
85 VizierUnit unit = VizierUnit.getFor(RdbmsResourceReader.getUnitsOf("Vizier","Radius"));
86 if (u != null) {
87 unit = VizierUnit.getFor(u);
88 }
89
90 String w = (String) maker.getValue("WAVELENGTH");
91 VizierWavelength wavelength = null;
92 if (w != null) { wavelength = VizierWavelength.getFor(w); }
93
94 String target = (String) maker.getValue("TARGET");
95 String ra = (String) maker.getValue(KeywordMaker.RA_KEYWORD);
96 String dec = (String) maker.getValue(KeywordMaker.DEC_KEYWORD);
97 if ( ((ra == null) && (dec != null)) || ((ra != null) && (dec == null)) ) {
98 throw new IllegalArgumentException("RA is "+ra+" but DEC is "+dec);
99 }
100 if ( (target == null) && (ra == null) ) {
101 throw new IllegalArgumentException("TARGET or RA + DEC or CIRCLE must be specified in query");
102 }
103 if ( (target != null) && (ra != null) ) {
104 throw new IllegalArgumentException("Don't specify both TARGET and RA + DEC in query");
105 }
106 if (target == null) {
107 if (!dec.startsWith("-") && !dec.startsWith("+")) {
108 dec = "+"+dec;
109 }
110
111 target = ra+" "+dec;
112 }
113
114
115 QueryResults results = null;
116 int site=0;
117 while ((results == null) && (site<mirrorUrls.length) && (!aborted)) {
118 try {
119 results = useSoap(mirrorUrls[site], querier, target, radius, unit, text, wavelength);
120 }
121 catch (IOException ioe) {
122 querier.getStatus().addDetail(ioe+" accessing "+mirrorUrls[site]);
123 }
124 site++;
125 }
126 if (aborted) return;
127
128 if (results != null) {
129 results.send(query.getResultsDef(), user);
130 } else {
131 throw new IOException("No results from any of the Vizier services, details in the query status:\n"+querier.getStatus().asFullMessage());
132 }
133 }
134
135
136 protected QueryResults useSoap(String siteUrl, Querier querier, String target, double radius, VizierUnit unit, String text, VizierWavelength wavelength) throws IOException {
137
138 try {
139
140 VizieRService service = new VizieRServiceLocator();
141 VizieR vizier = service.getVizieR(new URL(siteUrl));
142 String response;
143 if (wavelength == null) {
144 querier.getStatus().addDetail("Calling vizier at "+siteUrl+" via SOAP, target='"+target+"', radius='"+radius+"', unit='"+unit+"' text='"+text+"'...");
145 response = vizier.cataloguesData(target, radius, unit.toString(), text);
146 }
147 else {
148 querier.getStatus().addDetail("Calling vizier at "+siteUrl+" via SOAP, target='"+target+"', radius='"+radius+"', unit='"+unit+"' text='"+text+"' wavelength='"+wavelength+"'...");
149 response = vizier.cataloguesData(target, radius, unit.toString(), text, wavelength.toString());
150 }
151 querier.getStatus().addDetail("Vizier Responded");
152 if (!aborted) {
153 if (response == null) {
154 throw new DatacenterException("Vizier returned null");
155 }
156 return new VotableDomResults(querier, response);
157 }
158 return null;
159 }
160 catch (ServiceException e) {
161 throw new IOException("Could not connect to Vizier: "+e);
162 }
163 catch (SAXException e) {
164 throw new DatacenterException("XML Error in Vizier results: "+e,e);
165 }
166 catch (ParserConfigurationException e) {
167 throw new DatacenterException("Server not configured properly: "+e,e);
168 }
169
170 }
171
172 /*** Uses the http post provided by Axis along with the SOAP. This is better
173 for larger result sets than naively using SOAP, but seems to have troubles
174 * with timeouts as the socket timeout is not exposed here. There are ways
175 around this see http://www.logicamente.com/sockets.html for example... */
176 protected QueryResults useHttp(String siteUrl, Querier querier, String target, double radius, VizierUnit unit, String text, VizierWavelength wavelength) throws IOException {
177 String url = siteUrl+"?method=cataloguesData&target="+target+"&radius="+radius+"&unit="+unit+"&text="+text;
178 if (wavelength != null) {
179 url = url + "&wavelength="+wavelength;
180 }
181 querier.getStatus().addDetail("Calling vizier via Url "+url+"...");
182
183 return new VotableInResults(querier, new URL(url).openStream());
184 }
185
186
187 /*** Returns just the number of matches rather than the list of matches. Since there's no way to do this yet
188 * directly with Vizier (I don't think?), we just do a normal query then count the rows */
189 public long getCount(Account user, Query query, Querier querier) throws IOException {
190 return getCountFromResults(user, query, querier);
191 }
192
193 /*** Returns the formats that this plugin can provide. Asks the results class; override in subclasse if nec */
194 public String[] getFormats() {
195 return VotableInResults.getFormats();
196 }
197
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287