Quadcap Embeddable Server

com/quadcap/server/ServerConfigParser.java

Go to the documentation of this file.
00001 package com.quadcap.server; 00002 00003 /* Copyright 2000 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.BufferedInputStream; 00042 import java.io.BufferedReader; 00043 import java.io.FileInputStream; 00044 import java.io.FileReader; 00045 import java.io.IOException; 00046 00047 import java.util.ArrayList; 00048 import java.util.Collections; 00049 import java.util.Comparator; 00050 import java.util.HashMap; 00051 import java.util.Properties; 00052 00053 import org.xml.sax.AttributeList; 00054 import org.xml.sax.DocumentHandler; 00055 import org.xml.sax.ErrorHandler; 00056 import org.xml.sax.InputSource; 00057 import org.xml.sax.Parser; 00058 import org.xml.sax.Locator; 00059 import org.xml.sax.SAXException; 00060 import org.xml.sax.SAXParseException; 00061 00062 import org.xml.sax.helpers.ParserFactory; 00063 00064 import com.quadcap.util.ConfigString; 00065 import com.quadcap.util.Debug; 00066 00067 /*{com.quadcap.server.ServerConfigParser.xml} 00068 * 00069 * <el><name>server</name> 00070 * <p>This document is used to configure and initialize QED services.</p> 00071 * 00072 * <el><name>service</name> 00073 * <p>Each service definition has the following allowed elements.</p> 00074 * 00075 * <el><name>service-name</name> 00076 * <p>The name of the service.</p> 00077 * </el> 00078 * 00079 * <el><name>service-class</name> 00080 * <p>The name of the Java class which implements the service.</p> 00081 * </el> 00082 * 00083 * <el><name>service-config</name> 00084 * <p>The name of a service configuration file.</p> 00085 * </el> 00086 * 00087 * <el><name>load-on-startup</name> 00088 * <p>An integer value used to control the order in which 00089 * services are loaded. Lower values are started first.</p> 00090 * </el> 00091 * 00092 * <el><name>init-parameter</name> 00093 * <p>String-valued configuration parameters may be supplied to 00094 * a service.</p> 00095 * 00096 * <el><name>param-name</name> 00097 * <p>The initialization/configuration parameter name.</p> 00098 * </el> 00099 * 00100 * <el><name>param-value</name> 00101 * <p>The initialization/configuration parameter value.</p> 00102 * </el> 00103 * </el> 00104 * </el> 00105 * </el> 00106 */ 00107 00108 /** 00109 * Parser the <code>server.xml</code> file to determine which services 00110 * should be loaded on startup. 00111 * 00112 * @author Stan Bailes 00113 */ 00114 public class ServerConfigParser implements DocumentHandler, ErrorHandler { 00115 ServiceContainer container; 00116 Parser parser; 00117 Locator locator; 00118 StringBuffer data = new StringBuffer(); 00119 ArrayList services = new ArrayList(); 00120 ServiceWrapper service = null; 00121 Properties props = null; 00122 String paramName = null; 00123 String paramValue = null; 00124 00125 static final int INIT = 0; 00126 static final int SERVER = 1; 00127 static final int SERVICE = 2; 00128 static final int SERVICE_NAME = 3; 00129 static final int SERVICE_CLASS = 4; 00130 static final int SERVICE_CONFIG = 5; 00131 static final int LOAD_ON_STARTUP = 6; 00132 static final int INIT_PARAMETER = 7; 00133 static final int PARAM_NAME = 8; 00134 static final int PARAM_VALUE = 9; 00135 00136 00137 static HashMap elemMap = new HashMap(); 00138 static { 00139 elemMap.put("server", new Integer(SERVER)); 00140 elemMap.put("service", new Integer(SERVICE)); 00141 elemMap.put("service-name", new Integer(SERVICE_NAME)); 00142 elemMap.put("service-class", new Integer(SERVICE_CLASS)); 00143 elemMap.put("service-config", new Integer(SERVICE_CONFIG)); 00144 elemMap.put("load-on-startup", new Integer(LOAD_ON_STARTUP)); 00145 elemMap.put("init-parameter", new Integer(INIT_PARAMETER)); 00146 elemMap.put("param-name", new Integer(PARAM_NAME)); 00147 elemMap.put("param-value", new Integer(PARAM_VALUE)); 00148 } 00149 00150 static final int mapElement(String name) { 00151 Integer i = (Integer)elemMap.get(name); 00152 if (i == null) return -1; 00153 return i.intValue(); 00154 } 00155 00156 /** 00157 * No-argument constructor. The new object needs a database connection 00158 * before it can do anything useful. 00159 * 00160 * @exception Exception may be thrown if there's a problem constructing 00161 * the XML parser. 00162 */ 00163 public ServerConfigParser(ServiceContainer c) throws Exception { 00164 this.container = c; 00165 ConfigString ps = ConfigString.find("xml.sax.parser", 00166 "com.quadcap.text.sax.Parser"); 00167 00168 try { 00169 ClassLoader cl = ClassLoader.getSystemClassLoader(); 00170 this.parser = 00171 (Parser)(Class.forName(ps.toString(), true, cl).newInstance()); 00172 } catch (Throwable t) { 00173 Debug.print(t); 00174 } 00175 parser.setDocumentHandler(this); 00176 parser.setErrorHandler(this); 00177 } 00178 00179 /** 00180 * Parse the specified file 00181 * 00182 * @exception may be thrown 00183 */ 00184 public void parse(String fileName) throws Exception { 00185 FileReader f = new FileReader(fileName); 00186 try { 00187 BufferedReader r = new BufferedReader(f); 00189 parser.parse(is); 00190 } finally { 00191 f.close(); 00192 } 00193 } 00194 00195 /** 00196 * SAX parser callback to handle XML Parser errors. 00197 * This implementation just prints them 00198 * to System.err. 00199 * 00200 * @param exception the exception generated by the parser. 00201 */ 00203 System.err.println("error"); 00204 exception.printStackTrace(System.err); 00205 } 00206 00207 /** 00208 * SAX parser callback to handle XML Parser fatal errors. 00209 * This implementation just prints them 00210 * to System.err. 00211 * 00212 * @param exception the exception generated by the parser. 00213 */ 00215 System.err.println("fatal error"); 00216 exception.printStackTrace(System.err); 00217 } 00218 00219 /** 00220 * SAX parser callback to handle XML Parser fatal errors. 00221 * This implementation just prints them 00222 * to System.err. 00223 * 00224 * @param exception the exception generated by the parser. 00225 */ 00227 System.err.println("warning"); 00228 exception.printStackTrace(System.err); 00229 } 00230 00231 /** 00232 * SAX parser callback to handle character data found in the 00233 * parsed document. 00234 * 00235 * @param ch the buffer containing the parsed characters. 00236 * @param star the buffer position of the first character 00237 * @param length the number of characters 00238 * 00239 * @exception SAXException may be thrown if this data represents 00240 * a database value and there's a SQL exception thrown while 00241 * trying to update the underlying resultset object with this 00242 * data. 00243 */ 00244 public void characters(char[] ch, int start, int length) 00246 { 00247 data.append(ch, start, length); 00248 } 00249 00250 /** 00251 * SAX parser callback function that is called when the end of the 00252 * document is reached. This implementation does nothing. 00253 */ 00254 public void endDocument() { 00255 } 00256 00257 /** 00258 * SAX parser callback function called for the end of an element. 00259 * If this element 00260 * represents the <code>&lt;database&gt;</code> element, we finish up 00261 * by closing the active statement. If this element represents a table 00262 * row element, we insert the current row. Otherwise, we do nothing. 00263 * 00264 * @param name the name of this element 00265 * @exception SAXException may be thrown to wrap any underlying database 00266 * exception. 00267 */ 00269 switch (mapElement(name)) { 00270 case SERVER: 00271 addServices(); 00272 break; 00273 case SERVICE: 00274 if (props != null) { 00275 service.setServiceProperties(props); 00276 props = null; 00277 } 00278 services.add(service); 00279 break; 00280 case SERVICE_NAME: 00281 service.setServiceName(consume()); 00282 break; 00283 case SERVICE_CLASS: 00284 service.setServiceClass(consume()); 00285 break; 00286 case LOAD_ON_STARTUP: 00287 service.setLoadOnStartup(Integer.parseInt(consume())); 00288 break; 00289 case SERVICE_CONFIG: 00290 { 00291 String cname = consume(); 00292 getProps().setProperty("service.config", cname); 00293 try { 00294 getProps().putAll(parseProps(cname)); 00295 } catch (IOException ex) { 00296 } 00297 } 00298 break; 00299 case PARAM_NAME: 00300 paramName = consume(); 00301 break; 00302 case PARAM_VALUE: 00303 paramValue = consume(); 00304 break; 00305 case INIT_PARAMETER: 00306 if (paramName != null && paramValue != null) { 00307 getProps().put(paramName, paramValue); 00308 paramName = null; 00309 paramValue = null; 00310 } 00311 break; 00312 default: 00314 } 00315 } 00316 00317 final private Properties getProps() { 00318 if (props == null) props = new Properties(); 00319 return props; 00320 } 00321 00322 final public static Properties parseProps(String fileName) 00323 throws IOException 00324 { 00325 FileInputStream f = new FileInputStream(fileName); 00326 Properties p = new Properties(); 00327 try { 00328 BufferedInputStream b = new BufferedInputStream(f); 00329 p.load(b); 00330 } finally { 00331 f.close(); 00332 } 00333 return p; 00334 } 00335 00336 /** 00337 * SAX parser callback for ignorable whitespace. We just ignore it 00338 * 00339 * @param ch the buffer containing the parsed characters. 00340 * @param star the buffer position of the first character 00341 * @param length the number of characters 00342 */ 00343 public void ignorableWhitespace(char[] ch, int start, int length) { 00344 } 00345 00346 /** 00347 * SAX parser callback for processing instructions. This implementation 00348 * does nothing. 00349 * 00350 * @param target the processing instruction target. 00351 * @param data the processing instruction data. 00352 */ 00353 public void processingInstruction(String target, String data) { 00354 } 00355 00356 /** 00357 * SAX parser callback used to receive a document locator. 00358 * 00359 * @param locator the parser's locator object. 00360 */ 00361 public void setDocumentLocator(Locator locator) { 00362 this.locator = locator; 00363 } 00364 00365 /** 00366 * SAX parser callback for document start. 00367 * This implementation does nothing. 00368 */ 00369 public void startDocument() { 00370 } 00371 00372 /** 00373 * SAX parser callback for the start of an element. If this element 00374 * represents a table row, and the table is different from the last 00375 * table seen, we establish an updatable <code>ResultSet</code> for the 00376 * new table which can be used to insert new rows into the table. 00377 * If this element represents a table row, we move to the insert row. 00378 * If this element represents a column, we remember the column name. 00379 * 00380 * @param name the element name 00381 * @param attrs the element's attributes 00382 * 00383 * @exception SAXException may be thrown to wrap an underlying database 00384 * error, or if there is a problem with the XML document itself. 00385 */ 00388 { 00389 data.setLength(0); 00390 switch (mapElement(name)) { 00391 case SERVICE: 00392 service = new ServiceWrapper(); 00393 break; 00394 default: 00395 break; 00396 case -1: 00398 } 00399 } 00400 00401 /** 00402 * Get and return all of the accumulated character data as a String. 00403 * Reset the character data buffer to be empty. 00404 */ 00405 final String consume() { 00406 String s = data.toString().trim(); 00407 data.setLength(0); 00408 return s; 00409 } 00410 00411 /** 00412 * At the end of the file, add the services in the specified order 00413 */ 00415 Exception ex = null; 00416 00417 Collections.sort(services, new Comparator() { 00418 public int compare(Object a, Object b) { 00419 ServiceWrapper wa = (ServiceWrapper)a; 00420 ServiceWrapper wb = (ServiceWrapper)b; 00421 if (wa.getLoadOnStartup() < wb.getLoadOnStartup()) return -1; 00422 if (wa.getLoadOnStartup() > wb.getLoadOnStartup()) return 1; 00423 return 0; 00424 } 00425 }); 00426 for (int i = 0; i < services.size(); i++) { 00427 ServiceWrapper w = (ServiceWrapper)services.get(i); 00428 try { 00429 container.addService(w.getServiceName(), 00430 w.getServiceClass(), 00431 w.getServiceProperties()); 00432 } catch (Exception e) { 00433 ex = e; 00434 Debug.print(e); 00435 } 00436 } 00437 00438 if (ex != null) throw new SAXException(ex); 00439 } 00440 }