1
2
3
4
5
6 package org.astrogrid.fitsserver.setup;
7 import org.astrogrid.fitsserver.fits.*;
8
9
10 /***
11 * A standalone tool that generates an index based on the fits files it is
12 * is pointed at.
13 *
14 * @author M Hill
15 */
16
17 import java.io.*;
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.Calendar;
27 import java.util.Locale;
28 import javax.xml.parsers.ParserConfigurationException;
29 import nom.tam.fits.Fits;
30 import nom.tam.fits.FitsException;
31 import nom.tam.fits.Header;
32 import nom.tam.fits.HeaderCard;
33 import nom.tam.fits.BasicHDU;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.astrogrid.cfg.ConfigFactory;
37 import org.astrogrid.dataservice.queriers.QuerierPluginException;
38 import org.astrogrid.xml.DomHelper;
39 import org.w3c.dom.Document;
40 import org.xml.sax.SAXException;
41
42
43 import org.astrogrid.xmldb.client.QueryService;
44 import org.astrogrid.xmldb.client.XMLDBFactory;
45
46 import org.xmldb.api.base.ResourceSet;
47 import org.xmldb.api.modules.XMLResource;
48 import org.xmldb.api.base.Resource;
49 import org.xmldb.api.base.Collection;
50 import org.xmldb.api.base.XMLDBException;
51
52
53
54 public class IndexGenerator
55 {
56 /*** this is meant to run as a command-line program, so output should go to the
57 * console, but it uses routines that use commons-logging anyway...
58 */
59 public static Log log = LogFactory.getLog(IndexGenerator.class);
60
61 /*** Should we test for extensions. There is no standard way of checking if
62 * a FITS file has extensions (the EXTEND keyword merely says that it *may*
63 * have extensions), and for large FITS files where you *know* there are no
64 * extensions, this can take some time. So set this to false */
65 public boolean checkForExtensions = true;
66
67 /*** Configures which axis is the RA (if any) */
68 public int raAxis = -1;
69
70 /*** Configures which axis is the DEC (if any) */
71 public int decAxis = -1;
72
73 /*** Configures the format of dates in the fits file headers so they can be parsed*/
74 public DateFormat fitsDateFormat = DateFormat.getDateTimeInstance();
75
76 /*** Defines the format of the dates in the index - although they will also be output in seconds */
77 public SimpleDateFormat indexDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
78
79 /*** The root element */
80 public static final String ROOT_START = "<FitsIndex>";
81 public static final String ROOT_END = "</FitsIndex>";
82
83 /***
84 * Generates a single index FitsFile 'snippet' for the FITS file at the
85 * given url
86 */
87 public String makeIndexSnippet(URL fitsUrl) throws IOException, FitsException
88 {
89 assert fitsUrl != null;
90 fileNameFromDate = null;
91
92 log.info("Examining file "+fitsUrl+"...");
93 return makeIndexSnippet(new Fits(fitsUrl), fitsUrl.toString());
94 }
95
96 /***
97 * Generates an index 'snippet' for the FITS file at the
98 * given url
99 * @todo tidy up so that, for example, multiline comments become one tag
100 * @TODO max pixels are WRONG
101 */
102 public String makeIndexSnippet(Fits reader, String filename) throws IOException, FitsException
103 {
104 StringBuffer snippet = new StringBuffer();
105 System.out.println("entered makeIndexNippet(fitsreader,file)");
106 System.out.println("Number of hdus = " + reader.getNumberOfHDUs());
107 System.out.println("Number of BAsicHDus again from read = " + reader.read().length);
108 for (int i = 0; i < reader.getNumberOfHDUs(); i++)
109 {
110 log.trace("");
111 log.trace("");
112 Header header = reader.getHDU(i).getHeader();
113
114 snippet.append(makeIndexSnippet(header, filename));
115 }
116
117 return snippet.toString();
118 }
119
120 /***
121 * Generates an index snippet for the given header.
122 * Could probably do with tidying this up a bit, for example so that multiline comments become one tag
123 * End of line comments are included as 'Comment' attributes within the keyword tag, so that they are searchable
124 */
125 public String makeIndexSnippet(Header header, String fileLocation) throws IOException, FitsException
126 {
127 System.out.println("entered makeIndexSnippet(header,filelocation)");
128 if(header == null) {
129 return "";
130 }
131 System.out.println("header not null");
132
133
134 StringBuffer keywordSnippet = new StringBuffer();
135
136
137 for (int i = 0; i < header.getNumberOfCards(); i++)
138 {
139 String key = header.getKey(i).trim();
140 String value = header.getStringValue(key);
141
142 String eolComment = null;
143 String commentAtt = "";
144
145
146
147
148
149
150
151
152
153
154
155
156
157 if (value == null || value.trim().length() <= 0) {
158
159
160 } else {
161 try {
162
163
164 Date dateVal = indexDateFormat.parse(value);
165 keywordSnippet.append(" <"+key+" unit='s'"+commentAtt+">"+dateVal.getTime()+"</"+key+">\n");
166
167 value = indexDateFormat.format(dateVal);
168 if(fileNameFromDate == null && key.equals("DATE_OBS")) {
169 fileNameFromDate = value.replaceAll("[^//w*]","-");
170
171 }
172 } catch (ParseException e) {
173
174
175 }
176 System.out.println("The key = " + key + " the value = " + value);
177 if(fileNameFromDate == null && key.equals("DATE_OBS")) {
178 fileNameFromDate = value.replaceAll("[^//w*]","-");
179 }
180 keywordSnippet.append(" <"+key+commentAtt+">"+value+"</"+key+">\n");
181
182 }
183 }
184
185
186
187 String snippet = "<FitsFile>\n"+
188 " <Filename>"+fileLocation+"</Filename>\n"+
189 makeCoverageSnippet(header) + "<Keywords>" +
190 keywordSnippet.toString() + "</Keywords>" +
191 "</FitsFile>\n";
192
193 validate(snippet);
194
195 return snippet;
196 }
197
198 /***
199 * Makes a Coverage snippet from the keywords in the given header, depending
200 * on the raAxis, decAxis settings */
201 private String makeCoverageSnippet(Header header) {
202 if ((header.getIntValue("NAXIS") >= 2) && (raAxis != -1) && (decAxis != -1)) {
203 System.out.println("the invalid for naxis = " + header.getIntValue("NAXIS") + " raaxis = " + raAxis + " decAxis = " + decAxis);
204
205
206
207
208
209 FitsWCS wcsCalculator = new FitsWCS(header);
210 double maxPixelRA = header.getDoubleValue("NAXIS"+raAxis);
211 double maxPixelDec = header.getDoubleValue("NAXIS"+decAxis);
212
213 double[] point1 = wcsCalculator.toWCS( new double[] {0,0});
214 double[] point2 = wcsCalculator.toWCS( new double[] {0,maxPixelDec});
215 double[] point3 = wcsCalculator.toWCS( new double[] {maxPixelRA,maxPixelDec});
216 double[] point4 = wcsCalculator.toWCS( new double[] {maxPixelRA,0});
217
218
219 return
220 " <Coverage shape='Polygon'>\n"+
221 " <Point><RA>"+point1[0]+"</RA><Dec>"+point1[1]+"</Dec></Point>\n"+
222 " <Point><RA>"+point2[0]+"</RA><Dec>"+point2[1]+"</Dec></Point>\n"+
223 " <Point><RA>"+point3[0]+"</RA><Dec>"+point3[1]+"</Dec></Point>\n"+
224 " <Point><RA>"+point4[0]+"</RA><Dec>"+point4[1]+"</Dec></Point>\n"+
225 " </Coverage>\n";
226 }
227 return "";
228 }
229
230 /*** Checks that the given snippet is valid XML */
231 public static void validate(String snippet) throws IOException
232 {
233 try
234 {
235 DomHelper.newDocument(new ByteArrayInputStream(snippet.getBytes()));
236 }
237 catch (org.xml.sax.SAXException e) { throw new IOException(e.toString()); }
238
239 }
240
241 private static File fileIndexDir = null;
242 private File getIndexDirectory() {
243 String indexPath = String.valueOf(System.currentTimeMillis());
244 String indexGenHomePath = ConfigFactory.getCommonConfig().getString("indexgen.path", ("." + File.separator) );
245 if(!indexGenHomePath.endsWith(File.separator))
246 indexGenHomePath += File.separator;
247 fileIndexDir = new File(indexGenHomePath + indexPath);
248 if(!fileIndexDir.exists())
249 fileIndexDir.mkdir();
250 return fileIndexDir;
251 }
252
253
254 /***
255 * Generates an index XML file for the FITS files at the URLs listed in the
256 * given file, writing them out to the target stream
257 */
258 public File generateIndex(InputStream urlsIn) throws IOException, FitsException
259 {
260 System.out.println("entered generateIndex(inputstream)");
261 BufferedReader in = new BufferedReader(new InputStreamReader(urlsIn));
262 String line = null;
263 while( (line = in.readLine()) != null) {
264 generateIndex(new URL(line));
265 seqNum++;
266 }
267 return fileIndexDir;
268 }
269
270 /***
271 * Generates an index XML file for the FITS files at the URLs listed in the
272 * given file, writing them out to the target stream
273 */
274 public File generateIndex(URL []urls) throws IOException, FitsException
275 {
276 System.out.println("entered generateIndex(urls[])");
277 for(int i = 0; i < urls.length;i++) {
278 generateIndex(urls[i]);
279 seqNum++;
280 }
281 return fileIndexDir;
282 }
283
284 long seqNum = 0;
285 private String fileNameFromDate = null;
286
287 /***
288 * Generates an index XML file for the FITS files at the given URLs, writing it out to the target stream
289 */
290 public File generateIndex(URL url) throws IOException, FitsException
291 {
292 System.out.println("entered generateIndex(url)");
293 if(url == null)
294 System.out.println("the url is null");
295 Calendar rightNow = Calendar.getInstance();
296 int year = rightNow.get(Calendar.YEAR);
297 int month = rightNow.get(Calendar.MONTH);
298 int day = rightNow.get(Calendar.DATE);
299 String dirPath = String.valueOf(year) + "_" + String.valueOf(month) + "_" + String.valueOf(day);
300
301 if(fileIndexDir == null)
302 getIndexDirectory();
303 File xmlFile = null;
304 FileWriter fw = null;
305 PrintWriter pw = null;
306
307 String xmlSnippet = null;
308 try {
309 xmlSnippet = "<FitsIndex>" + makeIndexSnippet(url) + "</FitsIndex>";
310 String fileName = null;
311 if(fileNameFromDate != null) {
312 fileName = fileNameFromDate + "_" + String.valueOf((seqNum)) + ".xml";
313 }else {
314 fileName = dirPath + "_" + String.valueOf((seqNum)) + ".xml";
315 }
316 System.out.println("the xmlsnippet = " + xmlSnippet);
317 xmlFile = new File(fileIndexDir,fileName);
318 fw = new FileWriter(xmlFile);
319 pw = new PrintWriter(fw);
320 try {
321 DomHelper.DocumentToWriter(DomHelper.newDocument(xmlSnippet),pw);
322 }catch(Exception e) {
323 e.printStackTrace();
324 }
325 pw.flush();
326 fw.close();
327 pw.close();
328 } catch (IOException ioe) {
329
330 log.error(ioe+", processing URL "+url.toString(), ioe);
331 }
332 return fileIndexDir;
333 }
334
335 private void updateXMLDB(String directoryName) throws Exception {
336 File fi = new File(directoryName);
337 if(!fi.exists()) {
338 String indexGenHomePath = ConfigFactory.getCommonConfig().getString("indexgen.path", ("." + File.separator));
339 if(!indexGenHomePath.endsWith(File.separator))
340 indexGenHomePath += File.separator;
341 fi = new File(indexGenHomePath + directoryName);
342 if(!fi.exists()) {
343 System.out.println("The directory or path does not seem to exist: directory=" + directoryName +
344 "or " + indexGenHomePath + directoryName);
345 System.exit(1);
346 }
347 }
348 if(!fi.isDirectory()) {
349 System.out.println("There is a file that exists here, but is reported to not be a directory. Now exiting");
350 System.exit(1);
351 }
352 updateXMLDB(fi);
353 }
354
355 public void updateXMLDB(File fi) throws Exception {
356
357 String line = null;
358 String correct = "N";
359 String uploadCollection = ConfigFactory.getCommonConfig().getString("upload.collection", null);
360 String adminUser = ConfigFactory.getCommonConfig().getString("xmldb.admin.user", "admin");
361 String adminPass = ConfigFactory.getCommonConfig().getString("xmldb.admin.password", "");
362 String xmldbURI = ConfigFactory.getCommonConfig().getString("xmldb.uri", "xmldb:exist://");
363 String xmldbConfig = ConfigFactory.getCommonConfig().getString("exist.config.file", "../exist.xml");
364 String xmldbDriver = ConfigFactory.getCommonConfig().getString("xmldb.driver", "org.exist.xmldb.DatabaseImpl");
365 String testBypass = ConfigFactory.getCommonConfig().getString("test.bypass", "no");
366 String fileNamePattern = "1*//.xml";
367
368 if(testBypass.equals("no")) {
369 InputStreamReader consoleReader = new InputStreamReader(System.in);
370 BufferedReader consoleInput = new BufferedReader(consoleReader);
371 System.out.println("What is the Table Name (Collection Name) you wish to put in the xml files into. Example: TraceData, EITData");
372 System.out.println("You may also do sub-tables (sub-collections) with a '/' such as: CDSData/CDS2001, Soho/CDSData, MSSL/Soho/CDSData, RAL/Soho/Tape/CDSData");
373 while(!correct.equals("Y")) {
374 while( (line = consoleInput.readLine()) != null) ;
375 line = line.replaceAll("[^//w*]","_");
376 uploadCollection = line;
377 System.out.println("The full location of placing xml files will be: (You cannot get rid of /db/dcfitsfiles");
378 System.out.println("/db/dcfitsfiles/" + uploadCollection);
379 System.out.println("Is this all correct Y|N");
380 while( (correct = consoleInput.readLine()) != null) ;
381 correct = correct.toUpperCase();
382 }
383
384 System.out.println("What is the file name pattern you wish to upload? ex: 2002*, *.xml,");
385 while( (line = consoleInput.readLine()) != null) ;
386 fileNamePattern = line;
387
388 correct = "N";
389
390
391 int changeNum = -1;
392 while(!correct.equals("Y")) {
393 System.out.println("Do you need to correct|change any of the below settings, Normally No if running pal with internal eXist db. [Y|N]");
394 System.out.println("Commonly number 1 may be changed, and at times 4");
395 System.out.println("1.) xmldb.uri = URI to the database. Default: " + xmldbURI + " (external example: xmldb:exist://localhost:9080/exist/xmlrpc)");
396 System.out.println("2.) xmldb.admin.user = Administration user for adding xml files. Default: " + adminUser);
397 System.out.println("3.) xmldb.admin.password = Administration password for adding xml files. Default: " + adminPass);
398 System.out.println("4.) xmldb.configuration = Location of the xml db configuration file; If your running eXist internally advise to change read pal configuration page. Default: " + xmldbConfig);
399 System.out.println("5.) xmldb.driver = The XML database driver. Default: " + xmldbDriver);
400 while( (line = consoleInput.readLine()) != null) ;
401 correct = correct.toUpperCase();
402 if(correct.equals("N")) {
403 System.out.println("Which number would you like to change [1-5], or 0 to exit changing");
404 while(changeNum < 0) {
405 while( (line = consoleInput.readLine()) != null) ;
406 changeNum = Integer.parseInt(line);
407 if(changeNum > 5 || changeNum < 0) {
408 System.out.println("Invalid Number");
409 changeNum = -1;
410 }
411 if(changeNum == 1)
412 xmldbURI = askQuestion("What xmldb.uri do you wish to use?");
413 else if(changeNum == 2)
414 adminUser = askQuestion("What is the admin user?");
415 else if(changeNum == 3)
416 adminPass = askQuestion("What is the admin password?");
417 else if(changeNum == 4)
418 xmldbConfig = askQuestion("What is the location of the xmldb configuration file 'exist.xml'?");
419 else if(changeNum == 5)
420 xmldbDriver = askQuestion("What is the XMLDB driver?");
421 }
422 }
423 }
424 }
425
426
427 ConfigFactory.getCommonConfig().setProperty("xmldb.uri", xmldbURI);
428 ConfigFactory.getCommonConfig().setProperty("xmldb.driver", xmldbDriver);
429 ConfigFactory.getCommonConfig().setProperty("xmldb.admin.user", adminUser);
430 ConfigFactory.getCommonConfig().setProperty("xmldb.admin.password", adminPass);
431
432 if(!dbRegistered) {
433 XMLDBFactory.registerDB(xmldbConfig);
434 dbRegistered = true;
435 }
436
437 XMLDBFactory xdb = new XMLDBFactory();
438 System.out.println("Now Registering the database");
439
440 File []xmlFiles = fi.listFiles();
441 Document xmlDoc = null;
442 Collection coll = null;
443 try {
444 coll = xdb.openAdminCollection(("dcfitsfiles/" + uploadCollection));
445
446 for(int i = 0;i < xmlFiles.length;i++) {
447
448
449
450 xmlDoc = DomHelper.newDocument(xmlFiles[i]);
451 xdb.storeXMLResource(coll,xmlFiles[i].getName(),xmlDoc);
452
453 }
454 }finally {
455 if(coll != null) {
456 xdb.closeCollection(coll);
457 }
458 }
459 }
460
461 private static boolean dbRegistered = false;
462
463 private static String askQuestion(String question) throws Exception {
464 InputStreamReader consoleReader = new InputStreamReader(System.in);
465 BufferedReader consoleInput = new BufferedReader(consoleReader);
466 String line = null;
467 while( (line = consoleInput.readLine()) != null) ;
468 return line;
469 }
470
471
472 /***
473 * Test harness
474 */
475 public static void main(String args[]) throws IOException, MalformedURLException, FitsException, Exception
476 {
477
478
479 IndexGenerator generator = new IndexGenerator();
480
481 Locale.setDefault(Locale.UK);
482 Document indexDoc = null;
483 if(args == null || args.length < 2) {
484 System.out.println("java IndexGenerator -file <filename of urls (one url per line)> or");
485 System.out.println("java IndexGenerator -url <single url>");
486 System.out.println("java IndexGenerator -update <directory of xml files>");
487 return;
488 }
489
490 if("-file".equals(args[0])) {
491 generator.generateIndex(new FileInputStream(args[1]));
492 }else if("-url".equals(args[0])) {
493 String urlString = args[1];
494 generator.generateIndex(new URL(urlString));
495 }else if("-update".equals(args[0])) {
496 generator.updateXMLDB(args[1]);
497 }
498 }
499
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634