001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.module.core;
011:
012: import java.util.*;
013: import java.io.*;
014: import javax.servlet.*;
015: import java.text.DateFormat;
016:
017: import org.mmbase.core.util.DaemonTask;
018: import org.mmbase.core.util.DaemonThread;
019: import org.mmbase.util.ResourceLoader;
020: import org.mmbase.util.logging.Logger;
021: import org.mmbase.util.logging.Logging;
022:
023: /**
024: * Using MMBaseContext class you can retrieve the servletContext from anywhere
025: * using the get method.
026: *
027: * @author Daniel Ockeloen
028: * @author David van Zeventer
029: * @author Jaco de Groot
030: * @version $Id: MMBaseContext.java,v 1.57 2008/03/17 13:20:18 michiel Exp $
031: */
032: public class MMBaseContext {
033: private static final Logger log = Logging
034: .getLoggerInstance(MMBaseContext.class);
035: private static boolean initialized = false;
036: static boolean htmlRootInitialized = false;
037: private static ServletContext sx;
038: private static String userDir;
039: private static String javaVersion;
040:
041: private static String htmlRoot;
042: private static String htmlRootUrlPath = "/";
043: private static boolean htmlRootUrlPathInitialized = false;
044: private static String outputFile;
045: private static ThreadGroup threadGroup;
046:
047: /**
048: * Initialize MMBase using a <code>ServletContext</code>. This method will
049: * check the servlet configuration for context parameters mmbase.outputfile
050: * and mmbase.config. If not found it will look for system properties.
051: *
052: * @throws ServletException if mmbase.config is not set or is not a
053: * directory or doesn't contain the expected
054: * config files.
055: *
056: */
057: public synchronized static void init(ServletContext servletContext) {
058: if (!initialized || (initialized && sx == null)) { // initialized, but with init(configPath)
059:
060: if (servletContext == null) {
061: throw new IllegalArgumentException();
062: }
063:
064: if (initialized) {
065: log
066: .info("Reinitializing, this time with ServletContext");
067: }
068:
069: // get the java version we are running
070: javaVersion = System.getProperty("java.version");
071: // store the current context
072: sx = servletContext;
073: // Get the user directory using the user.dir property.
074: // default set to the startdir of the appserver
075: userDir = sx.getInitParameter("user.dir");
076: if (userDir == null) {
077: userDir = System.getProperty("user.dir");
078: }
079: // take into account userdir can start at webrootdir
080: if (userDir != null && userDir.indexOf("$WEBROOT") == 0) {
081: userDir = servletContext.getRealPath(userDir
082: .substring(8));
083: }
084: // Init outputfile.
085: String outputFile = sx
086: .getInitParameter("mmbase.outputfile");
087: if (outputFile == null) {
088: outputFile = System.getProperty("mmbase.outputfile");
089: }
090: // take into account configpath can start at webrootdir
091: if (outputFile != null
092: && outputFile.indexOf("$WEBROOT") == 0) {
093: outputFile = servletContext.getRealPath(outputFile
094: .substring(8));
095: }
096: initOutputfile(outputFile);
097:
098: ResourceLoader.init(sx);
099:
100: // Init logging.
101: initLogging();
102: initialized = true;
103: }
104: }
105:
106: /**
107: * Initialize MMBase using a config path. Useful when testing
108: * MMBase classes with a main. You can also configure to init
109: * logging or not.
110: *
111: * @throws Exception if mmbase.config is not set or is not a
112: * directory or doesn't contain the expected
113: * config files.
114: *
115: */
116: public synchronized static void init(String configPath,
117: boolean initLogging) throws Exception {
118: if (!initialized) {
119: log.service("Initializing with " + configPath);
120: // Get the current directory using the user.dir property.
121: userDir = System.getProperty("user.dir");
122:
123: // Init outputfile. // use of mmbase.outputfile is deprecated!
124: initOutputfile(System.getProperty("mmbase.outputfile"));
125:
126: // Init logging.
127: if (initLogging) {
128: initLogging();
129: }
130: initialized = true;
131: }
132: }
133:
134: /**
135: * Initialize MMBase using system properties only. This may be useful in
136: * cases where MMBase is used without a servlet. For example when running
137: * JUnit tests.
138: *
139: * @throws Exception if mmbase.config is not set or is not a
140: * directory or doesn't contain the expected
141: * config files.
142: */
143: public synchronized static void init() throws Exception {
144: init(System.getProperty("mmbase.config"), true);
145: }
146:
147: /**
148: * Returns the MMBase thread group.
149: * @since MMBase-1.8
150: */
151: public synchronized static ThreadGroup getThreadGroup() {
152: if (threadGroup == null) {
153: String groupName = org.mmbase.Version.get();// + "" + new Date();
154: log.service("Creating threadGroup: " + groupName);
155: threadGroup = new ThreadGroup(groupName);
156: }
157: return threadGroup;
158: }
159:
160: /**
161: * Starts a daemon thread using the MMBase thread group.
162: * @param task the task to run as a thread
163: * @param name the thread's name
164: * @since MMBase-1.8
165: */
166: public static Thread startThread(Runnable task, String name) {
167: DaemonThread kicker = new DaemonThread(task, name);
168: kicker.start();
169: return kicker;
170: }
171:
172: /**
173: * Starts a daemon thread using the MMBase thread group.
174: * @param task the task to run as a thread
175: * @param name the thread's name
176: * @since MMBase-1.8
177: */
178: public static Thread startThread(DaemonTask task, String name) {
179: DaemonThread kicker = new DaemonThread(name);
180: kicker.setTask(task);
181: kicker.start();
182: return kicker;
183: }
184:
185: private static void initOutputfile(String o) {
186: outputFile = o;
187: if (outputFile != null) {
188: if (!new File(outputFile).isAbsolute()) {
189: outputFile = userDir + File.separator + outputFile;
190: }
191: try {
192: PrintStream stream = new PrintStream(
193: new FileOutputStream(outputFile, true));
194: System.setOut(stream);
195: System.setErr(stream);
196: } catch (IOException e) {
197: outputFile = null;
198: log.error("Failed to set mmbase.outputfile to '"
199: + outputFile + "'.");
200: log.error(Logging.stackTrace(e));
201: }
202: }
203: }
204:
205: private static void initLogging() {
206: // Starting the logger
207: Logging.configure(ResourceLoader.getConfigurationRoot()
208: .getChildResourceLoader("log"), "log.xml");
209: log.info("===========================");
210: log.info("MMBase logging initialized.");
211: log.info("===========================");
212: log.info("java.version : " + javaVersion);
213: log.info("user.dir : " + userDir);
214: String configPath = ResourceLoader.getConfigurationRoot()
215: .toString();
216: log.info("configuration : " + configPath);
217: log.info("webroot : " + ResourceLoader.getWebRoot());
218: String version = org.mmbase.Version.get();
219: log.info("version : " + version);
220: Runtime rt = Runtime.getRuntime();
221: log.info("total memory : " + rt.totalMemory()
222: / (1024 * 1024) + " Mbyte");
223: log.info("free memory : " + rt.freeMemory()
224: / (1024 * 1024) + " Mbyte");
225: log.info("system locale : " + Locale.getDefault());
226: log.info("start time : "
227: + DateFormat.getDateTimeInstance(DateFormat.FULL,
228: DateFormat.FULL).format(
229: new Date(1000 * (long) MMBase.startTime)));
230: }
231:
232: /**
233: * Initialize mmbase.htmlroot parameter. This method is only needed for
234: * SCAN related servlets and should be called after the init(ServletContext)
235: * method. If the mmbase.htmlroot parameter is not found in the servlet
236: * context or system properties this method will try to set it to the
237: * root directory of the webapp.
238: *
239: * @throws ServletException if mmbase.htmlroot is not set or is not a
240: * directory
241: *
242: */
243: public synchronized static void initHtmlRoot()
244: throws ServletException {
245: if (!initialized) {
246: throw new RuntimeException(
247: "The init(ServletContext) method should be called first. (Not initalized)");
248: }
249: if (sx == null) {
250: throw new RuntimeException(
251: "The init(ServletContext) method should be called first. (No servlet context was given)");
252: }
253: if (!htmlRootInitialized) {
254: // Init htmlroot.
255: htmlRoot = sx.getInitParameter("mmbase.htmlroot");
256: if (htmlRoot == null) {
257: htmlRoot = System.getProperty("mmbase.htmlroot");
258: }
259: if (htmlRoot == null) {
260: htmlRoot = sx.getRealPath("");
261: }
262: if (htmlRoot == null) {
263: log.error("Parameter mmbase.htmlroot not set.");
264: } else {
265: if (userDir != null && !new File(htmlRoot).isAbsolute()) {
266: htmlRoot = userDir + File.separator + htmlRoot;
267: }
268: if (!new File(htmlRoot).isDirectory()) {
269: userDir = null;
270: htmlRoot = null;
271: throw new ServletException(
272: "Parameter mmbase.htmlroot is not pointing to a directory.");
273: } else {
274: if (htmlRoot.endsWith(File.separator)) {
275: htmlRoot = htmlRoot.substring(0, htmlRoot
276: .length() - 1);
277: }
278: }
279: }
280: htmlRootInitialized = true;
281: log.info("mmbase.htmlroot : " + htmlRoot);
282: log.info("context : " + getHtmlRootUrlPath());
283: }
284: }
285:
286: /**
287: * Returns the <code>ServletContext</code> used to initialize MMBase.
288: * Before calling this method the init method should be called.
289: *
290: * @return the <code>ServletContext</code> used to initialize MMBase or
291: * <code>null</code> if MMBase was initialized without
292: * <code>ServletContext</code>
293: */
294: public synchronized static ServletContext getServletContext() {
295: if (!initialized) {
296: throw new RuntimeException(
297: "The init method should be called first.");
298: }
299: return sx;
300: }
301:
302: /**
303: * Returns a string representing the mmbase.config parameter without a
304: * final <code>File.separator</code>. Before calling this method the
305: * init method should be called to make sure this parameter is set.
306: *
307: * @return the mmbase.config parameter or WEB-INF/config
308: * @deprecated use {@link org.mmbase.util.ResourceLoader#getConfigurationRoot} with relative path
309: */
310: public synchronized static String getConfigPath() {
311: List<File> files = ResourceLoader.getConfigurationRoot()
312: .getFiles("");
313: if (files.size() == 0) {
314: return null;
315: } else {
316: return files.get(0).getAbsolutePath();
317: }
318: }
319:
320: /**
321: * Returns a string representing the mmbase.htmlroot parameter without a
322: * final <code>File.separator</code>. Before calling this method the
323: * initHtmlRoot method should be called to make sure this parameter is set.
324: *
325: * @return the mmbase.htmlroot parameter or <code>null</code> if not
326: * initialized
327: */
328: public synchronized static String getHtmlRoot() {
329: if (!htmlRootInitialized) {
330: throw new RuntimeException(
331: "The initHtmlRoot method should be called first.");
332: }
333: return htmlRoot;
334: }
335:
336: /**
337: * Returns a string representing the mmbase.outputfile parameter. If set,
338: * this is the file to wich all <code>System.out</code> and
339: * <code>System.err</code> output is redirected. Before calling this method
340: * the init method should be called.
341: *
342: * @return the mmbase.outputFile parameter or <code>null</code> if not set
343: * @deprecated use logging system
344: */
345: public synchronized static String getOutputFile() {
346: if (!initialized) {
347: throw new RuntimeException(
348: "The init method should be called first.");
349: }
350: return outputFile;
351: }
352:
353: /**
354: * Returns a string representing the HtmlRootUrlPath, this is the path under
355: * the webserver, what is the root for this instance.
356: * this will return '/' or something like '/mmbase/' or so...
357: *
358: * This information should be requested from the ServletRequest, but if for some reason you
359: * don't have one handy, this method can be used.
360:
361: * @return the HtmlRootUrlPath
362: */
363: public synchronized static String getHtmlRootUrlPath() {
364: if (!htmlRootUrlPathInitialized) {
365: log.info("Finding root url");
366: if (!initialized) {
367: throw new RuntimeException(
368: "The init method should be called first.");
369: }
370: if (sx == null) { // no serlvetContext -> no htmlRootUrlPath
371: htmlRootUrlPathInitialized = true;
372: return htmlRootUrlPath;
373: }
374: String initPath = sx
375: .getInitParameter("mmbase.htmlrooturlpath");
376: if (initPath != null) {
377: log
378: .debug("Found mmbase.htmlrooturlpath explicitely configured");
379: htmlRootUrlPath = initPath;
380: } else {
381: // init the htmlRootUrlPath
382: try {
383: log.debug("Autodetecting htmlrooturlpath ");
384: // fetch resource path for the root servletcontext root...
385: // check wether this is root
386: if (sx.equals(sx.getContext("/"))) {
387: htmlRootUrlPath = "/";
388: } else {
389: String url = sx.getResource("/").toString();
390: // MM: simply hope that it is the last part of that URL.
391: // I do not think it is garantueed. Used mmbase.htmlrooturlpath in web.xml if it doesn't work.
392: int length = url.length();
393: int lastSlash = url.substring(0, length - 1)
394: .lastIndexOf('/');
395: if (lastSlash > 0) {
396: htmlRootUrlPath = url.substring(lastSlash);
397: } else {
398: log
399: .warn("Could not determine htmlRootUrlPath. Using default "
400: + htmlRootUrlPath
401: + "(contextUrl :"
402: + url
403: + ")");
404: }
405: }
406: } catch (Exception e) {
407: log.error(e);
408: }
409: try {
410: if (!sx.equals(sx.getContext(htmlRootUrlPath))) {
411: log
412: .warn("Probably did not succeed in determining htmlRootUrlPath ('"
413: + htmlRootUrlPath
414: + "'). Consider using the mmbase.htmlrooturlpath context-param in web.xml");
415: }
416: } catch (Exception e2) {
417: log.error(e2);
418: }
419: }
420: htmlRootUrlPathInitialized = true;
421: }
422: return htmlRootUrlPath;
423: }
424:
425: /**
426: * @since MMBase-1.8.4
427: */
428: public static File getDataDir() {
429: return null;
430: }
431:
432: /**
433: * Returns whether this class has been initialized.
434: * This can be used to determine whether MMBase specific configuration data is accessible.
435: */
436: public static boolean isInitialized() {
437: return initialized;
438: }
439: }
|