1 /* 2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package test.astro; 24 25 import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; 26 import static test.astro.AstroConstants.DEC_MAX; 27 import static test.astro.AstroConstants.DEC_MIN; 28 import static test.astro.AstroConstants.JAXP_SCHEMA_LANGUAGE; 29 import static test.astro.AstroConstants.JAXP_SCHEMA_SOURCE; 30 import static test.astro.AstroConstants.RA_MAX; 31 import static test.astro.AstroConstants.RA_MIN; 32 33 import java.io.File; 34 import java.io.IOException; 35 36 import javax.xml.parsers.ParserConfigurationException; 37 import javax.xml.parsers.SAXParser; 38 import javax.xml.parsers.SAXParserFactory; 39 import javax.xml.transform.TransformerConfigurationException; 40 import javax.xml.transform.sax.SAXResult; 41 import javax.xml.transform.sax.TransformerHandler; 42 import javax.xml.transform.stream.StreamResult; 43 44 import org.xml.sax.ErrorHandler; 45 import org.xml.sax.InputSource; 46 import org.xml.sax.SAXException; 47 import org.xml.sax.SAXParseException; 48 import org.xml.sax.XMLReader; 49 50 /* 51 * AstroProcessor is to carry out the user's query with filters and produce a table of 52 * star records that match the criterion, and finally output with HTML format. 53 */ 54 public class AstroProcessor { 55 private String catalogFileName; 56 57 private FilterFactory ffact; 58 private InputSourceFactory isfact; 59 60 private SAXParserFactory spf; 61 62 /* 63 * Constructor for the Main astro class. 64 * 65 * @param fFactClass the class of the FilterFactory implementation 66 * 67 * @param catalogfilename the name of the XML input document (database) 68 * 69 * @param isFactClass the class of the Input Source Factory implementation 70 */ 71 public AstroProcessor(Class<FilterFactory> fFactClass, String catalogFileName, Class<InputSourceFactory> isFactClass) throws Exception { 72 // create the Filter Factory instance... 73 74 ffact = fFactClass.newInstance(); 75 76 // create the Input Source Instance 77 78 isfact = isFactClass.newInstance(); 79 80 spf = SAXParserFactory.newInstance(); 81 spf.setNamespaceAware(true); 82 spf.setValidating(true); 83 84 // All XML Readers are required to recognize these two: 85 spf.setFeature("http://xml.org/sax/features/namespaces", true); 86 spf.setFeature("http://xml.org/sax/features/namespace-prefixes", true); 87 88 // Other features... 89 spf.setFeature("http://xml.org/sax/features/validation", true); 90 spf.setFeature("http://apache.org/xml/features/validation/schema", true); 91 spf.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true); 92 93 this.catalogFileName = catalogFileName; 94 } 95 96 /* 97 * Sets the star stellar type query. 98 * 99 * @param arg stellar type string, can be a substring. 100 */ 101 public TransformerHandler getStellarTypeFilter(String arg) throws TransformerConfigurationException, SAXException, ParserConfigurationException, 102 IOException { 103 String stellarType = null; 104 if (arg != null && arg.length() != 0) { 105 stellarType = arg; // set value of query 106 } else { 107 throw new IllegalArgumentException("\n Stellar type string of length zero found."); 108 } 109 110 return ffact.newStellarTypeFilter(stellarType); 111 } 112 113 /* 114 * Sets the right ascension parameters for a query. Parameters are validated 115 * to be in the range of 0h and 24h inclusive. 116 * 117 * @param min minimum right ascension in hours. 118 * 119 * @param max maximum right ascension in hours. 120 */ 121 public TransformerHandler getRAFilter(double min, double max) throws TransformerConfigurationException, SAXException, ParserConfigurationException, 122 IOException { 123 double raMin = RA_MIN; // hours 124 double raMax = RA_MAX; // hours 125 if (min < max) { 126 if ((min >= RA_MIN && min <= RA_MAX) && (max >= RA_MIN && max <= RA_MAX)) { 127 raMin = min; // set value of query 128 raMax = max; // set value of query 129 130 } 131 } else { 132 throw new IllegalArgumentException("min must be less than max.\n" + "min=" + min + ", max=" + max); 133 } 134 135 return ffact.newRAFilter(raMin, raMax); 136 } 137 138 /* 139 * Sets the right ascension and dec parameters for a query. Parameters are 140 * validated to be in the range of ra 0h and 24h and dec -90 to +90 141 * inclusive. 142 * 143 * @param rmin minimum right ascension in hours. 144 * 145 * @param rmax maximum right ascension in hours. 146 * 147 * @param dmin minimum declination in degs. 148 * 149 * @param dmax maximum declination in degs. 150 */ 151 public TransformerHandler getRADECFilter(double rmin, double rmax, double dmin, double dmax) throws TransformerConfigurationException, SAXException, 152 ParserConfigurationException, IOException { 153 double raMin = RA_MIN; // hours 154 double raMax = RA_MAX; // hours 155 double decMin = DEC_MIN; // degrees 156 double decMax = DEC_MAX; // degrees 157 if (rmin < rmax && dmin < dmax) { 158 if ((rmin >= RA_MIN && rmin <= RA_MAX) && (rmax >= RA_MIN && rmax <= RA_MAX)) { 159 raMin = rmin; // set value of query 160 raMax = rmax; // set value of query 161 } 162 if ((dmin >= DEC_MIN && dmin <= DEC_MAX) && (dmax >= DEC_MIN && dmax <= DEC_MAX)) { 163 decMin = dmin; // set value of query 164 decMax = dmax; // set value of query 165 } 166 167 } else { 168 throw new IllegalArgumentException("min must be less than max.\n" + "rmin=" + rmin + ", rmax=" + rmax + ", dmin=" + dmin + ", dmax=" + dmax); 169 } 170 171 return ffact.newRADECFilter(raMin, raMax, decMin, decMax); 172 } 173 174 /* 175 * Sets the declination parameters for a query. Parameters are validated to 176 * be in the range of -90 and +90 degrees inclusive. 177 * 178 * @param min minimum declination in degrees. 179 * 180 * @param max maximum declination in degrees. 181 */ 182 public TransformerHandler getDecFilter(double min, double max) throws TransformerConfigurationException, SAXException, ParserConfigurationException, 183 IOException { 184 double decMin = DEC_MIN; // degrees 185 double decMax = DEC_MAX; // degrees 186 if (min < max) { 187 if ((min >= DEC_MIN && min <= DEC_MAX) && (max >= DEC_MIN && max <= DEC_MAX)) { 188 decMin = min; // set value of query 189 decMax = max; // set value of query 190 } 191 } else { 192 throw new IllegalArgumentException("min must be less than max.\n" + "min=" + min + ", max=" + max); 193 } 194 195 return ffact.newDECFilter(decMin, decMax); 196 } 197 198 /* 199 * Runs the filter process against the astronomical database. 200 * 201 * @throws Exception 202 */ 203 public void process(String outputfile, TransformerHandler... filters) throws Exception { 204 XMLReader catparser = getXMLReader(); 205 206 File catalogfile = new File(catalogFileName); 207 InputSource catsrc = isfact.newInputSource(catalogfile.getPath()); 208 209 TransformerHandler outfilter = ffact.newHTMLOutput(); 210 // create an array from the Vector of filters... 211 212 // hook the filters up to each other, there may be zero filters 213 int nfilters = filters.length; 214 if (nfilters != 0) { 215 TransformerHandler prev = null; 216 for (int i = 0; i < filters.length; i++) { 217 TransformerHandler curr = filters[i]; 218 if (prev != null) { 219 prev.setResult(new SAXResult(curr)); 220 } 221 prev = curr; 222 } 223 // hook up the last filter to the output filter 224 prev.setResult(new SAXResult(outfilter)); 225 // hook up the catalog parser to the first filter... 226 catparser.setContentHandler(filters[0]); 227 } else { 228 // There are no query filters, 229 // hook up the catalog parser directly to output filter... 230 catparser.setContentHandler(outfilter); 231 } 232 // hook up the output filter to the output file or std out 233 if (outputfile != null) { 234 outfilter.setResult(new StreamResult(outputfile)); 235 } else { 236 outfilter.setResult(new StreamResult(System.out)); 237 } 238 239 catparser.parse(catsrc); 240 } 241 242 private XMLReader getXMLReader() throws Exception { 243 SAXParser parser = spf.newSAXParser(); 244 parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA_NS_URI); 245 parser.setProperty(JAXP_SCHEMA_SOURCE, "catalog.xsd"); 246 XMLReader catparser = parser.getXMLReader(); 247 catparser.setErrorHandler(new CatalogErrorHandler()); 248 return catparser; 249 } 250 251 /* 252 * Error Handler for the parsing of the XML astronomical catalog. 253 */ 254 private static class CatalogErrorHandler implements ErrorHandler { 255 private String getParseExceptionInfo(SAXParseException spe) { 256 String systemId = spe.getSystemId(); 257 if (systemId == null) { 258 systemId = "null"; 259 } 260 String info = "Catalog URI=" + systemId + " Line=" + spe.getLineNumber() + ": " + spe.getMessage(); 261 return info; 262 } 263 264 public void warning(SAXParseException spe) throws SAXException { 265 String message = "Warning: " + getParseExceptionInfo(spe); 266 throw new SAXException(message); 267 } 268 269 public void error(SAXParseException spe) throws SAXException { 270 String message = "Error: " + getParseExceptionInfo(spe); 271 throw new SAXException(message); 272 } 273 274 public void fatalError(SAXParseException spe) throws SAXException { 275 String message = "Fatal Error: " + getParseExceptionInfo(spe); 276 throw new SAXException(message); 277 } 278 } 279 }