1
2
3
4
5
6 package org.astrogrid.datacenter.queriers.fits;
7
8
9 /***
10 * A standalone tool that generates an index based on the fits files it is
11 * is pointed at.
12 *
13 * @author M Hill
14 */
15
16 import java.io.*;
17 import org.astrogrid.datacenter.fits.*;
18
19 import java.net.HttpURLConnection;
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.text.DateFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26 import java.util.Enumeration;
27 import java.util.Locale;
28 import javax.xml.parsers.ParserConfigurationException;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.astrogrid.datacenter.queriers.QuerierPluginException;
32 import org.astrogrid.util.DomHelper;
33 import org.w3c.dom.Document;
34 import org.xml.sax.SAXException;
35
36
37 public class IndexGenerator
38 {
39 /*** this is meant to run as a command-line program, so output should go to the
40 * console, but it uses routines that use commons-logging anyway...
41 */
42 public static Log log = LogFactory.getLog(IndexGenerator.class);
43
44 /*** Should we test for extensions. There is no standard way of checking if
45 * a FITS file has extensions (the EXTEND keyword merely says that it *may*
46 * have extensions), and for large FITS files where you *know* there are no
47 * extensions, this can take some time. So set this to false */
48 public boolean checkForExtensions = true;
49
50 /*** Configures which axis is the RA (if any) */
51 public int raAxis = -1;
52
53 /*** Configures which axis is the DEC (if any) */
54 public int decAxis = -1;
55
56 /*** Configures the format of dates in the fits file headers so they can be parsed*/
57 public DateFormat fitsDateFormat = DateFormat.getDateTimeInstance();
58
59 /*** Defines the format of the dates in the index - although they will also be output in seconds */
60 public SimpleDateFormat indexDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
61
62 /*** The root element */
63 public static final String ROOT_START = "<FitsIndex>";
64 public static final String ROOT_END = "</FitsIndex>";
65
66 /***
67 * Generates a single index FitsFile 'snippet' for the FITS file at the
68 * given url
69 */
70 public String makeIndexSnippet(URL fitsUrl) throws IOException
71 {
72 assert fitsUrl != null;
73
74 log.info("Examining file "+fitsUrl+"...");
75 return makeIndexSnippet(new FitsStreamReader(fitsUrl), fitsUrl.toString());
76 }
77
78 /***
79 * Generates an index 'snippet' for the FITS file at the
80 * given url
81 * @todo tidy up so that, for example, multiline comments become one tag
82 * @TODO max pixels are WRONG
83 */
84 public String makeIndexSnippet(FitsReader reader, String filename) throws IOException
85 {
86 StringBuffer snippet = new StringBuffer();
87
88 FitsHeader header = new FitsHeader();
89 reader.readHeaderKeywords(header, null);
90
91 snippet.append(makeIndexSnippet(header, filename));
92
93 FitsHdu primaryHdu = new FitsHdu(header);
94
95
96 if ((checkForExtensions) && primaryHdu.getHeader().getValue("EXTEND").equals("T"))
97 {
98
99 reader.readData(primaryHdu);
100
101 try {
102 /
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public String makeIndexSnippet(FitsHeader header, String fileLocation) throws IOException
129 {
130 if(header == null) {
131 return "";
132 }
133
134
135 StringBuffer keywordSnippet = new StringBuffer();
136 String key = null;
137 String val = null;
138
139 Enumeration enum = header.getKeywords();
140 while (enum.hasMoreElements())
141 {
142 FitsKeyword keyword = (FitsKeyword) enum.nextElement();
143 val = keyword.getValue();
144
145
146 if (val == null) {
147 keywordSnippet.append(" <"+keyword.getKey()+"/>\n");
148 } else {
149 try {
150 Date dateVal = fitsDateFormat.parse(val);
151 keywordSnippet.append(" <"+keyword.getKey()+" units='s'>"+dateVal.getTime()+"</"+keyword.getKey()+">\n");
152 val = indexDateFormat.format(dateVal);
153 } catch (ParseException e) {
154
155 }
156 keywordSnippet.append(" <"+keyword.getKey()+">"+val+"</"+keyword.getKey()+">\n");
157 }
158 }
159
160
161
162 String snippet = "<FitsFile>\n"+
163 " <Filename>"+fileLocation+"</Filename>\n"+
164 makeCoverageSnippet(header)+
165 " <Keywords>\n"+
166 keywordSnippet.toString()+
167 " </Keywords>\n"+
168 "</FitsFile>\n";
169
170 validate(snippet);
171
172 return snippet;
173 }
174
175 /***
176 * Makes a Coverage snippet from the keywords in the given header, depending
177 * on the raAxis, decAxis settings */
178 private String makeCoverageSnippet(FitsHeader header) {
179 if ((header.getNumAxis() >= 2) && (raAxis != -1) && (decAxis != -1)) {
180
181
182
183
184
185 FitsWCS wcsCalculator = new FitsWCS(header);
186 double maxPixelRA = header.get("NAXIS"+raAxis).toInt();
187 double maxPixelDec = header.get("NAXIS"+decAxis).toInt();
188
189 double[] point1 = wcsCalculator.toWCS( new double[] {0,0});
190 double[] point2 = wcsCalculator.toWCS( new double[] {0,maxPixelDec});
191 double[] point3 = wcsCalculator.toWCS( new double[] {maxPixelRA,maxPixelDec});
192 double[] point4 = wcsCalculator.toWCS( new double[] {maxPixelRA,0});
193
194
195 return
196 " <Coverage shape='Polygon'>\n"+
197 " <Point><RA>"+point1[0]+"</RA><Dec>"+point1[1]+"</Dec></Point>\n"+
198 " <Point><RA>"+point2[0]+"</RA><Dec>"+point2[1]+"</Dec></Point>\n"+
199 " <Point><RA>"+point3[0]+"</RA><Dec>"+point3[1]+"</Dec></Point>\n"+
200 " <Point><RA>"+point4[0]+"</RA><Dec>"+point4[1]+"</Dec></Point>\n"+
201 " </Coverage>\n";
202 }
203 return "";
204 }
205 /*** Checks that the given snippet is valid XML */
206 public static void validate(String snippet) throws IOException
207 {
208 try
209 {
210 DomHelper.newDocument(new ByteArrayInputStream(snippet.getBytes()));
211 }
212 catch (org.xml.sax.SAXException e) { throw new IOException(e.toString()); }
213 catch (javax.xml.parsers.ParserConfigurationException e) { throw new IOException(e.toString()); }
214
215 }
216
217 /***
218 * Generates an index XML file for the FITS files at the given urls
219 */
220 public String generateIndex(Object[] urls) throws IOException
221 {
222 StringBuffer index = new StringBuffer(ROOT_START+"\n");
223
224 for (int i=0;i<urls.length;i++)
225 {
226 assert urls[i] != null;
227 index.append(makeIndexSnippet((URL)urls[i]));
228 }
229
230 index.append(ROOT_END+"\n");
231
232 return index.toString();
233
234 }
235
236 /***
237 * Generates an index XML file for the FITS files at the URLs listed in the
238 * given file, writing them out to the target stream
239 */
240 public void generateIndex(InputStream urlsIn, Writer out) throws IOException
241 {
242 PrintWriter dout = new PrintWriter(new BufferedWriter(out));
243 dout.println(ROOT_START);
244
245 BufferedReader in = new BufferedReader(new InputStreamReader(urlsIn));
246
247 String line = null;
248 while( (line = in.readLine()) != null) {
249 try {
250 dout.println(makeIndexSnippet(new URL(line)).getBytes());
251 dout.flush();
252 } catch (IOException ioe) {
253
254 log.error(ioe+", processing URL "+line, ioe);
255 }
256 }
257 in.close();
258 dout.println(ROOT_END);
259 dout.flush();
260 }
261
262 /***
263 * Generates an index XML file for the FITS files at the given URLs, writing it out to the target stream
264 */
265 public void generateIndex(URL[] urls, Writer out) throws IOException
266 {
267 PrintWriter dout = new PrintWriter(new BufferedWriter(out));
268 dout.println(ROOT_START);
269
270 for (int i=0;i<urls.length;i++)
271 {
272 assert urls[i] != null : "No URLs Given";
273 dout.println(makeIndexSnippet(urls[i]));
274 dout.flush();
275 }
276 dout.println(ROOT_END);
277 dout.flush();
278 }
279
280 /***
281 * Test harness
282 */
283 public static void main(String args[]) throws IOException, MalformedURLException
284 {
285
286
287
288
289
290 IndexGenerator generator = new IndexGenerator();
291
292 Locale.setDefault(Locale.UK);
293 Document indexDoc = null;
294 if(args == null || args.length < 2) {
295 System.out.println("java IndexGenerator -f <filename of urls (one url per line)> or");
296 System.out.println("java IndexGenerator -u <URLs seperated by spaces>");
297 return;
298 }
299 String indexFile = null;
300 if("-f".equals(args[0])) {
301 StringWriter out = new StringWriter();
302 generator.generateIndex(new FileInputStream(args[1]), out);
303 indexFile = out.toString();
304 } else if("-u".equals(args[0])) {
305 Object []fitsURLS = new Object[(args.length-1)];
306 for(int i = 1;i < args.length;i++) {
307 fitsURLS[(i-1)] = new URL(args[i]);
308 }
309 indexFile = generator.generateIndex(fitsURLS);
310 log.trace(indexFile);
311 }
312
313 if(indexFile != null) {
314 try {
315 indexDoc = DomHelper.newDocument(indexFile);
316 }catch(ParserConfigurationException pce) {
317 throw new RuntimeException("Server configuration error",pce);
318 }catch(SAXException se) {
319 throw new QuerierPluginException("FitsQuerierPlugin index not valid xml",se);
320 }
321 }
322
323 long fileTime = System.currentTimeMillis();
324 if(indexDoc != null) {
325
326 FileWriter fw = new FileWriter(String.valueOf(fileTime) + ".xml");
327 PrintWriter pw = new PrintWriter(fw);
328 DomHelper.DocumentToWriter(indexDoc,pw);
329 pw.flush();
330 fw.close();
331 pw.close();
332 System.out.println("Successfull creation of fits file index, it was created as = " + String.valueOf(fileTime) + ".xml");
333 System.out.println("Now the file must be uploaded to the eXist xml database to be used for querying the file");
334 System.out.println("You may do this manually or this program can do it automatically by calling \"java -s IndexGenerator <filename>\" by using the file name just created");
335
336 }
337
338 if("-s".equals(args[0])) {
339 try {
340 indexDoc = DomHelper.newDocument(new File(args[1]));
341 }catch(ParserConfigurationException pce) {
342 throw new RuntimeException("Server configuration error",pce);
343 }catch(SAXException se) {
344 throw new QuerierPluginException("FitsQuerierPlugin index not valid xml",se);
345 }
346 if(indexDoc != null) {
347
348 InputStreamReader consoleReader = new InputStreamReader(System.in);
349 BufferedReader consoleInput = new BufferedReader(consoleReader);
350
351
352
353 System.out.println("This program will now ask three questions to do this automatically and it will update or insert the new xml file for queyring");
354 System.out.println("What is the name of the file you wish for it to live in the db?");
355 System.out.println("Please keep it unique, but remember it so you can update it later. Now the Name?");
356 String line = null;
357 String fileName = null;
358 URL eXistLocation = null;
359 while( (line = consoleInput.readLine()) != null) ;
360 line = line.replaceAll("[^//w*]","_");
361 if(!line.endsWith(".xml")) line += ".xml";
362 fileName = line;
363 System.out.println("What is the url to the exist database? ex: http://localhost:8080/exist is a typical url");
364 System.out.println("We only need it up to the \"exist\" part");
365 while( (line = consoleInput.readLine()) != null) ;
366
367 if(!line.endsWith("/")) {
368 line += "servlet/db/dcfitsfiles/" + fileName;
369 }
370 else {
371 line += "/servlet/db/dcfitsfiles/" + fileName;
372 }
373 eXistLocation = new URL(line);
374 System.out.println("The Full URL to Exist is\n: " + line + "\n");
375 System.out.println("Remember this url you may need it on the final configuration of your datacenter");
376 updateFile(eXistLocation,indexFile);
377 }
378 }
379 }
380
381 private static void updateFile(URL urlLocation, String contents) throws IOException {
382 HttpURLConnection huc = (HttpURLConnection)
383 urlLocation.openConnection();
384 huc.setRequestProperty("Content-Type", "text/xml");
385 huc.setDoOutput(true);
386 huc.setRequestMethod("PUT");
387 huc.connect();
388 try {
389 DataOutputStream dos = new DataOutputStream(huc.getOutputStream());
390 DomHelper.DocumentToStream(DomHelper.newDocument(contents),dos);
391 dos.flush();
392 dos.close();
393 huc.disconnect();
394 } catch (javax.xml.parsers.ParserConfigurationException e) {
395 throw new IOException(e.toString());
396 } catch (org.xml.sax.SAXException e) {
397 throw new IOException(e.toString());
398 }
399 }
400
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498