001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019: package de.schlund.pfixxml;
020:
021: import java.io.ByteArrayInputStream;
022: import java.io.ByteArrayOutputStream;
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import java.util.Properties;
026:
027: import javax.servlet.ServletConfig;
028: import javax.servlet.ServletException;
029: import javax.servlet.http.HttpServlet;
030: import javax.servlet.http.HttpServletRequest;
031: import javax.servlet.http.HttpServletResponse;
032: import javax.xml.parsers.DocumentBuilder;
033: import javax.xml.parsers.DocumentBuilderFactory;
034: import javax.xml.parsers.ParserConfigurationException;
035: import javax.xml.transform.TransformerConfigurationException;
036: import javax.xml.transform.TransformerException;
037: import javax.xml.transform.TransformerFactory;
038: import javax.xml.transform.dom.DOMResult;
039: import javax.xml.transform.dom.DOMSource;
040: import javax.xml.transform.sax.SAXTransformerFactory;
041: import javax.xml.transform.sax.TransformerHandler;
042: import javax.xml.transform.stream.StreamResult;
043: import javax.xml.transform.stream.StreamSource;
044:
045: import org.apache.log4j.Logger;
046: import org.apache.log4j.xml.DOMConfigurator;
047: import org.w3c.dom.Document;
048: import org.xml.sax.EntityResolver;
049: import org.xml.sax.ErrorHandler;
050: import org.xml.sax.InputSource;
051: import org.xml.sax.SAXException;
052: import org.xml.sax.SAXParseException;
053: import org.xml.sax.XMLReader;
054: import org.xml.sax.helpers.DefaultHandler;
055: import org.xml.sax.helpers.XMLReaderFactory;
056:
057: import de.schlund.pfixxml.config.CustomizationHandler;
058: import de.schlund.pfixxml.config.GlobalConfigurator;
059: import de.schlund.pfixxml.config.XMLPropertiesUtil;
060: import de.schlund.pfixxml.resources.FileResource;
061: import de.schlund.pfixxml.resources.ResourceUtil;
062: import de.schlund.pfixxml.util.TransformerHandlerAdapter;
063: import de.schlund.pfixxml.util.logging.ProxyLogUtil;
064:
065: /**
066: * This Servlet is just there to have it's init method called on startup of the
067: * VM. It starts all VM-global factories by calling their 'init' method from the
068: * {@link FactoryInit} interface. These factories are located by analyzing the
069: * "servlet.propfile" parameter which points to a file where all factories are
070: * listed.
071: */
072: public class FactoryInitServlet extends HttpServlet {
073:
074: // ~ Instance/static variables
075: // ..................................................................
076: public final static String PROP_DOCROOT = "pustefix.docroot";
077:
078: private final static String PROP_LOG4J = "pustefix.log4j.config";
079:
080: private final static String PROP_PREFER_CONTAINER_LOGGING = "pustefix.logging.prefercontainer";
081:
082: private Object LOCK = new Object();
083:
084: private final static Logger LOG = Logger
085: .getLogger(FactoryInitServlet.class);
086:
087: private static boolean configured = false;
088:
089: private static FactoryInitException initException;
090:
091: private static String log4jconfig = null;
092:
093: private static long log4jmtime = -1;
094:
095: private boolean warMode = false;
096: private boolean standaloneMode = false;
097:
098: // ~ Methods
099: // ....................................................................................
100:
101: /**
102: * Handle the HTTP-Post method.
103: *
104: * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest,
105: * HttpServletResponse)
106: * @throws ServletException
107: * on all
108: */
109: public void doPost(HttpServletRequest req, HttpServletResponse res)
110: throws ServletException {
111: doGet(req, res);
112: }
113:
114: /**
115: * Handle the HTTP-Get method
116: *
117: * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest,
118: * HttpServletResponse)
119: * @throws ServletException
120: * on call
121: */
122: public void doGet(HttpServletRequest req, HttpServletResponse res)
123: throws ServletException {
124: throw new ServletException(
125: "This servlet can't be called interactively");
126: }
127:
128: public static void tryReloadLog4j() {
129: if (log4jconfig != null) {
130: FileResource l4jfile = ResourceUtil
131: .getFileResourceFromDocroot(log4jconfig);
132: long tmpmtime = l4jfile.lastModified();
133: if (tmpmtime > log4jmtime) {
134: LOG.error("\n\n################################\n"
135: + "#### Reloading log4j config ####\n"
136: + "################################\n");
137: try {
138: configureLog4j(l4jfile);
139: } catch (FileNotFoundException e) {
140: Logger.getLogger(FactoryInitServlet.class).error(
141: "Reloading log4j config failed!", e);
142: } catch (SAXException e) {
143: Logger.getLogger(FactoryInitServlet.class).error(
144: "Reloading log4j config failed!", e);
145: } catch (IOException e) {
146: Logger.getLogger(FactoryInitServlet.class).error(
147: "Reloading log4j config failed!", e);
148: }
149: log4jmtime = tmpmtime;
150: }
151: }
152: }
153:
154: /**
155: * Initialize this servlet. Also call the 'init' method of all classes
156: * listed in the configuration. These classes must implement the FactoryInit
157: * interface.
158: *
159: * @param config
160: * the servlet configuration
161: * @see javax.servlet.Servlet#init(ServletConfig)
162: * @throws ServletException
163: * on errors
164: */
165: @SuppressWarnings("deprecation")
166: public void init(ServletConfig Config) throws ServletException {
167: super .init(Config);
168: Properties properties = new Properties(System.getProperties());
169: // old webapps specify docroot -- true webapps don't
170: String docrootstr = Config.getInitParameter(PROP_DOCROOT);
171: if (docrootstr != null && !docrootstr.equals("")) {
172: standaloneMode = true;
173: } else {
174: docrootstr = Config.getServletContext().getRealPath(
175: "/WEB-INF/pfixroot");
176: if (docrootstr == null) {
177: warMode = true;
178: }
179: }
180:
181: // Setup global configuration before doing anything else
182: if (docrootstr != null) {
183: GlobalConfigurator.setDocroot(docrootstr);
184: }
185: if (warMode) {
186: GlobalConfigurator.setServletContext(getServletContext());
187: }
188:
189: if (docrootstr != null) {
190: // For compatibility with old apps, initialize PathFactory
191: PathFactory.getInstance().init(docrootstr);
192: }
193:
194: String confname = Config.getInitParameter("servlet.propfile");
195: if (confname != null) {
196: FileResource confFile = ResourceUtil
197: .getFileResourceFromDocroot(confname);
198: try {
199: XMLPropertiesUtil.loadPropertiesFromXMLFile(confFile,
200: properties);
201: } catch (FileNotFoundException e) {
202: throw new ServletException("*** [" + confname
203: + "] Not found: " + e.toString());
204: } catch (IOException e) {
205: throw new ServletException("*** [" + confname
206: + "] IO-error: " + e.toString());
207: } catch (SAXException e) {
208: throw new ServletException("*** [" + confname
209: + "] Parsing-error: " + e.toString());
210: }
211: } else {
212: throw new ServletException(
213: "*** FATAL: Need the servlet.propfile property as init parameter! ***");
214: }
215:
216: if (docrootstr != null) {
217: // this is for stuff that can't use the PathFactory. Should not be used
218: // when possible...
219: properties.setProperty("pustefix.docroot", docrootstr);
220: }
221:
222: synchronized (LOCK) {
223: if (!configured) {
224: configureLogging(properties);
225: LOG.debug(">>>> LOG4J Init OK <<<<");
226:
227: try {
228: FactoryInitUtil.initialize(properties);
229: } catch (FactoryInitException e) {
230: throw new ServletException(e.getCause().toString());
231: }
232: }
233: configured = true;
234: LOG.debug("***** INIT of FactoryInitServlet done *****");
235:
236: }
237: }
238:
239: private void configureLogging(Properties properties)
240: throws ServletException {
241: String containerProp = properties
242: .getProperty(PROP_PREFER_CONTAINER_LOGGING);
243: if (warMode
244: || (!standaloneMode && (containerProp != null && containerProp
245: .toLowerCase().equals("true")))) {
246: ProxyLogUtil.getInstance().configureLog4jProxy();
247: ProxyLogUtil.getInstance().setServletContext(
248: getServletContext());
249: } else {
250: log4jconfig = properties.getProperty(PROP_LOG4J);
251: if (log4jconfig == null || log4jconfig.equals("")) {
252: throw new ServletException(
253: "*** FATAL: Need the pustefix.log4j.config property in factory.xml! ***");
254: }
255: FileResource l4jfile = ResourceUtil
256: .getFileResourceFromDocroot(log4jconfig);
257: try {
258: configureLog4j(l4jfile);
259: } catch (FileNotFoundException e) {
260: throw new ServletException(
261: "File for log4j configuration not found!", e);
262: } catch (SAXException e) {
263: throw new ServletException(
264: "Error on parsing log4j configuration file!", e);
265: } catch (IOException e) {
266: throw new ServletException(
267: "Error on reading log4j configuration file!", e);
268: }
269:
270: }
271: }
272:
273: private static void configureLog4j(FileResource configFile)
274: throws SAXException, FileNotFoundException, IOException {
275: log4jmtime = configFile.lastModified();
276: XMLReader xreader = XMLReaderFactory.createXMLReader();
277: TransformerFactory tf = TransformerFactory.newInstance();
278: if (tf.getFeature(SAXTransformerFactory.FEATURE)) {
279: SAXTransformerFactory stf = (SAXTransformerFactory) tf;
280: TransformerHandler th;
281: try {
282: th = stf.newTransformerHandler();
283: } catch (TransformerConfigurationException e) {
284: throw new RuntimeException(
285: "Failed to configure TransformerFactory!", e);
286: }
287: DOMResult dr = new DOMResult();
288: th.setResult(dr);
289: DefaultHandler dh = new TransformerHandlerAdapter(th);
290: DefaultHandler cushandler = new CustomizationHandler(dh);
291: xreader.setContentHandler(cushandler);
292: xreader.setDTDHandler(cushandler);
293: xreader.setErrorHandler(cushandler);
294: xreader.setEntityResolver(cushandler);
295: xreader.parse(new InputSource(configFile.getInputStream()));
296: ByteArrayOutputStream bufferStream = new ByteArrayOutputStream();
297: try {
298: tf
299: .newTransformer(
300: new StreamSource(
301: ResourceUtil
302: .getFileResourceFromDocroot(
303: "core/build/create_log4j_config.xsl")
304: .toURL().toString()))
305: .transform(new DOMSource(dr.getNode()),
306: new StreamResult(bufferStream));
307: } catch (TransformerException e) {
308: throw new SAXException(e);
309: }
310: DocumentBuilderFactory dbf = DocumentBuilderFactory
311: .newInstance();
312: dbf.setValidating(true);
313: dbf.setNamespaceAware(true);
314: Document confDoc;
315: try {
316: DocumentBuilder db = dbf.newDocumentBuilder();
317: db.setEntityResolver(new EntityResolver() {
318:
319: public InputSource resolveEntity(String publicId,
320: String systemId) throws SAXException,
321: IOException {
322: if (systemId
323: .equals("http://logging.apache.org/log4j/docs/api/org/apache/log4j/xml/log4j.dtd")) {
324: return new InputSource(ResourceUtil
325: .getFileResourceFromDocroot(
326: "core/schema/log4j.dtd")
327: .getInputStream());
328: }
329: return null;
330: }
331:
332: });
333: db.setErrorHandler(new ErrorHandler() {
334:
335: public void warning(SAXParseException exception)
336: throws SAXException {
337: System.err
338: .println("Warning while parsing log4j configuration: ");
339: exception.printStackTrace(System.err);
340: }
341:
342: public void error(SAXParseException exception)
343: throws SAXException {
344: System.err
345: .println("Error while parsing log4j configuration: ");
346: exception.printStackTrace(System.err);
347: }
348:
349: public void fatalError(SAXParseException exception)
350: throws SAXException {
351: System.err
352: .println("Fatal error while parsing log4j configuration: ");
353: exception.printStackTrace(System.err);
354: }
355:
356: });
357: confDoc = db.parse(new ByteArrayInputStream(
358: bufferStream.toByteArray()));
359: } catch (SAXException e) {
360: throw e;
361: } catch (IOException e) {
362: throw e;
363: } catch (ParserConfigurationException e) {
364: String msg = "Error while trying to create DOM document";
365: throw new RuntimeException(msg, e);
366: }
367: DOMConfigurator.configure(confDoc.getDocumentElement());
368: } else {
369: throw new RuntimeException(
370: "Could not get instance of SAXTransformerFactory!");
371: }
372: }
373:
374: public static boolean isConfigured() {
375: return configured;
376: }
377:
378: public static FactoryInitException getInitException() {
379: return initException;
380: }
381:
382: }
|