001: /*
002: * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005: package com.sun.portal.ubt;
006:
007: import com.sun.portal.ubt.monitor.FileMonitor;
008: import com.sun.portal.ubt.monitor.FileChangeListener;
009: import com.sun.portal.log.common.PortalLogger;
010: import com.sun.portal.util.ResourceLoader;
011:
012: import java.util.Properties;
013: import java.util.Enumeration;
014: import java.util.Vector;
015: import java.util.regex.Pattern;
016: import java.util.logging.*;
017: import java.io.*;
018: import java.beans.PropertyChangeSupport;
019: import java.beans.PropertyChangeListener;
020:
021: /**
022: * This class manages UBT log configurations.
023: */
024: public class UBTLogManager implements UBTLogManagerMBean,
025: FileChangeListener {
026: /**
027: * Portal ID property name
028: */
029: public static final String PORTAL_ID_PROPERTY = ResourceLoader.PORTAL_ID;
030: /**
031: * Instance ID property name
032: */
033: public static final String PORTAL_INSTANCE_ID_PROPERTY = ResourceLoader.INSTANCE_ID;
034: /**
035: * Portal instance ID token name supported by this managed. This token can appear in the
036: * File handler pattern.
037: */
038: public static final String PORTAL_INSTANCE_ID_TOKEN = "%instance";
039: /**
040: * UBT configuration file name property.
041: */
042: public static final String CONFIG_FILE_NAME_PROPERTY = "com.sun.portal.ubt.config.file";
043: /**
044: * UBT configuration file name.
045: */
046: public static final String CONFIG_FILE_VALUE_DEFAULT = "UBTConfig.properties";
047: /**
048: * UBT enable key name.
049: */
050: public static final String UBT_ENABLE_KEY = "com.sun.portal.ubt.enable";
051: /**
052: * Default value of UBT enablement.
053: */
054: public static final boolean UBT_ENABLE_VALUE_DEFAULT = false;
055: /**
056: * Name of the UBT root logger.
057: */
058: public static final String UBT_ROOT_LOGGER = "com.sun.portal.ubt";
059: /**
060: * Key name of the UBT root logger handler.
061: */
062: public static final String UBT_ROOT_LOG_HANDLER_KEY = UBT_ROOT_LOGGER
063: + ".handler";
064: /**
065: * Default handler name.
066: */
067: public static final String UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT = "java.util.logging.FileHandler";
068: /**
069: * Key name of the UBT root logger level.
070: */
071: public static final String UBT_ROOT_LOG_LEVEL_KEY = UBT_ROOT_LOGGER
072: + ".level";
073: /**
074: * Default value of the UBT root logger level.
075: */
076: public static final String UBT_ROOT_LOG_LEVEL_VALUE_DEFAULT = "INFO";
077: /**
078: * Key to specify if UserID need to be logged as part of UBT.
079: */
080: public static final String UBT_LOG_USER_ID_KEY = "com.sun.portal.ubt.loguserid";
081: /**
082: * Default value of the log UserID key.
083: */
084: public static final boolean UBT_LOG_USER_ID_VALUE_DEFAULT = true;
085: /**
086: * Key name of the configuration file update check periodicity
087: */
088: public static final String UBT_CONFIG_CHECK_PERIOD_KEY = "ubt.config.check.period";
089: /**
090: * Default value of the configuration file update check periodicity
091: */
092: public static final long UBT_CONFIG_CHECK_PERIOD_VALUE_DEFAULT = 1800;
093:
094: /**
095: * UBT Session ID attribute
096: */
097: public static final String UBT_SESSION_ID_ATTRIBUTE = "UBTSessionID";
098:
099: private PropertyChangeSupport changes = new PropertyChangeSupport(
100: UBTLogManager.class);
101: private static Logger logger = PortalLogger
102: .getLogger(UBTLogManager.class);
103:
104: private Properties configProps = new Properties();
105: private String configFileName = System
106: .getProperty(CONFIG_FILE_NAME_PROPERTY);
107:
108: private static UBTLogManager instance = null;
109: private static Object syncObject = new Object();
110:
111: private UBTLogManager() {
112: try {
113: String fs = File.separator;
114: Properties etcprops = ResourceLoader.getInstance()
115: .getProperties("PSConfig.properties");
116: configFileName = etcprops.getProperty("ps.data.location",
117: "")
118: + fs
119: + "portals"
120: + fs
121: + ResourceLoader
122: .getInstance(System.getProperties())
123: .getPortalId()
124: + fs
125: + "config"
126: + fs
127: + CONFIG_FILE_VALUE_DEFAULT;
128: System.setProperty(CONFIG_FILE_NAME_PROPERTY,
129: configFileName);
130: } catch (IOException e) {
131: logger.log(Level.WARNING, "PSUB_CSPU0023", e);
132: }
133: }
134:
135: /**
136: * Get the singlton class instance.
137: * @return UBTLogManager instance
138: */
139: public static UBTLogManager getInstance() {
140: if (instance == null) {
141: synchronized (syncObject) {
142: if (instance == null) {
143: instance = new UBTLogManager();
144: }
145: instance.loadConfiguration();
146: //This is done only when system comes up
147: instance.setLogFields();
148:
149: }
150: }
151: return instance;
152: }
153:
154: private void setLogFields() {
155: Vector v = UBTLogField.fields;
156: for (int i = 0; i < v.size(); i++) {
157: this .addLogField((UBTLogField) v.get(i));
158: }
159: }
160:
161: private void configureConfigMonitor() {
162: long periodicity = UBTLogManager.UBT_CONFIG_CHECK_PERIOD_VALUE_DEFAULT;
163: String val = getProperty(UBTLogManager.UBT_CONFIG_CHECK_PERIOD_KEY);
164: try {
165: if (val != null) {
166: periodicity = Long.parseLong(val);
167: }
168: } catch (Exception e) {
169: //not a proper long value, drop through
170: }
171: if (periodicity <= 0)
172: periodicity = UBTLogManager.UBT_CONFIG_CHECK_PERIOD_VALUE_DEFAULT;
173: try {
174: FileMonitor.getInstance().addFileChangeListener(this ,
175: configFileName, periodicity);
176: } catch (Exception e) {
177: logger.log(Level.INFO, "PSUB_CSPU0003", e);
178: }
179: }
180:
181: private void resetUBTRootLogger() {
182: Logger root = Logger.getLogger(UBT_ROOT_LOGGER);
183: //remove all handlers if there from root logger
184: //this step is required for reloadConfig
185: try {
186: Handler[] handlers = root.getHandlers();
187: if (handlers != null) {
188: for (int i = 0; i < handlers.length; i++) {
189: root.removeHandler(handlers[i]);
190: handlers[i].close();
191: }
192: }
193: } catch (Exception e) {
194: //some error we faced may be while closing
195: logger.log(Level.INFO, "PSUB_CSPU0004", e);
196: }
197: }
198:
199: private void configureUBTRootLogger() {
200: Logger root = Logger.getLogger(UBT_ROOT_LOGGER); //creates the root logger as well
201: root.setUseParentHandlers(false); //so that UBT logs are not routed around!
202: try {
203: // Check if there is a property defining the
204: // handler's level.
205: String levs = getProperty(UBT_ROOT_LOG_LEVEL_KEY);
206: if (levs != null) {
207: root.setLevel(Level.parse(levs));
208: } else {
209: root.setLevel(Level
210: .parse(UBT_ROOT_LOG_LEVEL_VALUE_DEFAULT));
211: }
212: } catch (Exception ex) {
213: System.err.println("Can't set level for "
214: + UBT_ROOT_LOG_LEVEL_KEY);
215: // Probably a bad level. Drop through.
216: }
217: resetUBTRootLogger();
218: String names[] = parseClassNames(getProperty(UBT_ROOT_LOG_HANDLER_KEY));
219: for (int i = 0; i < names.length; i++) {
220: String word = names[i];
221: Handler handler = null;
222: if (word.trim().equals(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT)) {
223: handler = this .getDefaultHandler();
224: } else {
225: try {
226: Class clz = Class.class.getClassLoader() == null ?
227: // check if this class is loaded by bootstrap classloader,
228: // some implementation may retun null
229: // in that case get the system classloader and load the class
230: // else use it.
231: // this check is added to avoid any problems in having the generic classes
232: // in the server classpath
233: ClassLoader.getSystemClassLoader().loadClass(word)
234: : Class.class.getClassLoader().loadClass(
235: word);
236: handler = (Handler) clz.newInstance();
237: } catch (Exception ex) {
238: if (logger.isLoggable(Level.INFO)) {
239: LogRecord record = new LogRecord(Level.INFO,
240: "PSUB_CSPU0005");
241: record.setParameters(new Object[] { word });
242: record.setThrown(ex);
243: record.setLoggerName(logger.getName());
244: logger.log(record);
245: }
246: }
247: }
248: if (handler != null) {
249: //set handler's level
250: Level level = getLevelProperty(word + ".level", root
251: .getLevel());
252: handler.setLevel(level);
253: //set handler's filter
254: Filter filter = getFilterProperty(word + ".filter",
255: null);
256: handler.setFilter(filter);
257: //set handler's formatter
258: Formatter formatter = getFormatter(word + ".formatter",
259: new UBTELFFormatter());
260: handler.setFormatter(formatter);
261: //add handler to the root logger
262: root.addHandler(handler);
263: } else {
264: logger.log(Level.INFO, "PSUB_CSPU0006", word);
265: }
266: }
267: //add the default file handler with all the properties set
268: if (root.getHandlers().length == 0) {
269: addDefaultHandlerToRoot();
270: }
271:
272: }
273:
274: private Handler getDefaultHandler() {
275: Handler fileHandler = null;
276: //pattern is essential to be mentioned in the properties file
277: //otherwise FileHandler is configured using LogManager properties
278: //which in this pattern's case is NOT appropriate
279: String pattern = getFilePattern();
280: pattern = replaceSupportedTokens(pattern);
281: //if limit is not specified or specified wrongly, no limit is set on the handler
282: //in this case count is not taken into account
283: //other wise count is 2 by default - WSARC recommendation (so that the important
284: //UBT logs are not lost once the max limit is reached
285: int limit = 0;
286: int count = 2;
287: try {
288: limit = Integer
289: .parseInt(getProperty(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
290: + ".limit"));
291: count = Integer
292: .parseInt(getProperty(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
293: + ".count"));
294: } catch (Exception e) {
295: logger.log(Level.INFO, "PSUB_CSPU0007", e);
296: }
297: //append is set to true by default, this is againt the fileHandler default, but something that is
298: //considered important in UBT
299: boolean append = Boolean.valueOf(
300: getProperty(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
301: + ".append", "true")).booleanValue();
302: try {
303: if (limit != 0) {
304: fileHandler = new FileHandler(pattern, limit, count,
305: append);
306: } else {
307: // in this case limit is unlimited, with count set to 1
308: fileHandler = new FileHandler(pattern, append);
309: }
310: } catch (IOException e) {
311: logger.log(Level.INFO, "PSUB_CSPU0008", e);
312: } catch (SecurityException e) {
313: logger.log(Level.INFO, "PSUB_CSPU0009", e);
314: } catch (Exception e) {
315: logger.log(Level.INFO, "PSUB_CSPU0010", e);
316: }
317: return fileHandler;
318: }
319:
320: private String replaceSupportedTokens(String srcString) {
321: String dest = srcString;
322: if (dest != null && dest.indexOf(PORTAL_INSTANCE_ID_TOKEN) >= 0) {
323: String instanceID = System.getProperty(
324: PORTAL_INSTANCE_ID_PROPERTY, "");
325: dest = Pattern.compile(PORTAL_INSTANCE_ID_TOKEN).matcher(
326: srcString).replaceAll(instanceID);
327: }
328: return dest;
329: }
330:
331: private void addDefaultHandlerToRoot() {
332: //add file handler
333: // If you change default handler to be something else,
334: //appropriately change the UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
335: Logger root = Logger.getLogger(UBT_ROOT_LOGGER);
336: Handler fileHandler = getDefaultHandler();
337: if (fileHandler != null) {
338: fileHandler.setLevel(getLevelProperty(
339: UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT + ".level",
340: Logger.getLogger(UBTLogManager.UBT_ROOT_LOGGER)
341: .getLevel()));
342: fileHandler.setFilter(getFilterProperty(
343: UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT + ".filter",
344: null));
345: fileHandler.setFormatter(getFormatter(
346: UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT + ".formatter",
347: new UBTELFFormatter()));
348: root.addHandler(fileHandler);
349: } else {
350: logger.log(Level.INFO, "PSUB_CSPU0011");
351: }
352: }
353:
354: /**
355: * Package private method to get file pattern
356: * If the property is not defined, a resource file
357: * is loaded for default value of the pattern
358: */
359: String getFilePattern() {
360: String val = getProperty(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
361: + ".pattern");
362: if (val == null) {
363: try {
364: String res = "com/sun/portal/ubt/resources/filePattern.properties";
365: InputStream it = this .getClass().getClassLoader()
366: .getResourceAsStream(res);
367: Properties prop = new Properties();
368: try {
369: prop.load(it);
370:
371: } catch (IOException e) {
372: logger.log(Level.INFO, "PSUB_CSPU0012", e);
373: }
374: val = prop
375: .getProperty(UBT_ROOT_LOG_HANDLER_VALUE_DEFAULT
376: + ".pattern");
377: } catch (Exception e) {
378: logger.log(Level.INFO, "PSUB_CSPU0013", e);
379: }
380: }
381: return val;
382: }
383:
384: /**
385: * Package private method to get a Level property.
386: * If the property is not defined or cannot be parsed
387: * we return the given default value.
388: */
389: Level getLevelProperty(String name, Level defaultValue) {
390: String val = getProperty(name);
391: if (val == null) {
392: return defaultValue;
393: }
394: try {
395: return Level.parse(val.trim());
396: } catch (Exception ex) {
397: return defaultValue;
398: }
399: }
400:
401: /**
402: * Package private method to get an event's level.
403: * We return Level instance named by the "event.<eventName>.level"
404: * property. If the property is not defined or has problems
405: * we return the defaultValue.
406: */
407: Level getEventLevel(String eventName, Level defaultValue) {
408: Level level = defaultValue;
409: String val = getProperty("ubt.event." + eventName + ".level");
410: try {
411: if (val != null) {
412: level = Level.parse(val);
413: }
414: } catch (Exception e) {
415: //something went wrong
416: //Drop through
417: }
418: return level;
419: }
420:
421: /**
422: * Package private method to get an event's logger name.
423: * We return Level instance named by the "event.<logger>"
424: * property. If the property is not defined or has problems
425: * we return the defaultValue.
426: */
427: String getEventLoggerName(String eventName, String defaultValue) {
428: String logger = defaultValue;
429: String val = getProperty("ubt.event." + eventName + ".logger");
430: if (val != null) {
431: logger = val;
432: }
433: return logger;
434: }
435:
436: /**
437: * Package private method to get a filter property.
438: * We return an instance of the class named by the "name"
439: * property. If the property is not defined or has problems
440: * we return the defaultValue.
441: */
442: Filter getFilterProperty(String name, Filter defaultValue) {
443: String val = getProperty(name);
444: try {
445: if (val != null) {
446: Class clz = Class.class.getClassLoader() == null ? ClassLoader
447: .getSystemClassLoader().loadClass(val)
448: : Class.class.getClassLoader().loadClass(val);
449: return (Filter) clz.newInstance();
450: }
451: } catch (Exception ex) {
452: // We got one of a variety of exceptions in creating the
453: // class or creating an instance.
454: // Drop through.
455: }
456: // We got an exception. Return the defaultValue.
457: return defaultValue;
458: }
459:
460: /**
461: * Package private method to get a formatter property.
462: * We return an instance of the class named by the "name"
463: * property. If the property is not defined or has problems
464: * we return the defaultValue.
465: */
466: Formatter getFormatter(String name, Formatter defaultValue) {
467: String val = getProperty(name);
468: try {
469: if (val != null) {
470: Class clz = Class.class.getClassLoader() == null ? ClassLoader
471: .getSystemClassLoader().loadClass(val)
472: : Class.class.getClassLoader().loadClass(val);
473: return (Formatter) clz.newInstance();
474: }
475: } catch (Exception ex) {
476: // We got one of a variety of exceptions in creating the
477: // class or creating an instance.
478: // Drop through.
479: }
480: // We got an exception. Return the defaultValue.
481: return defaultValue;
482: }
483:
484: // get a list of whitespace or comma separated classnames from a property.
485: private String[] parseClassNames(String names) {
486: String hands = names;
487: if (hands == null) {
488: return new String[0];
489: }
490: hands = hands.trim();
491: int ix = 0;
492: Vector result = new Vector();
493: while (ix < hands.length()) {
494: int end = ix;
495: while (end < hands.length()) {
496: if (Character.isWhitespace(hands.charAt(end))) {
497: break;
498: }
499: if (hands.charAt(end) == ',') {
500: break;
501: }
502: end++;
503: }
504: String word = hands.substring(ix, end);
505: ix = end + 1;
506: word = word.trim();
507: if (word.length() == 0) {
508: continue;
509: }
510: result.add(word);
511: }
512: return (String[]) result.toArray(new String[result.size()]);
513: }
514:
515: /**
516: * Is UBT enabled.
517: * @return true if enabled else false.
518: */
519: public boolean isUBTEnabled() {
520: String value = getProperty(UBT_ENABLE_KEY);
521: if (value == null)
522: return UBT_ENABLE_VALUE_DEFAULT;
523: else
524: return Boolean.valueOf(value.trim()).booleanValue();
525: }
526:
527: /**
528: * Get any property specified in the UBT configuration.
529: * @param name of the property
530: * @return value of the property.
531: */
532: public String getProperty(String name) {
533: return configProps.getProperty(name);
534: }
535:
536: /**
537: * Get any property in the UBT configuration, if not available, return the default value.
538: * @param name of the propert
539: * @param defaultVal Default value of the property if not found
540: * @return Value of the property
541: */
542: public String getProperty(String name, String defaultVal) {
543: return configProps.getProperty(name, defaultVal);
544: }
545:
546: private void readConfigFile() {
547: if (configFileName != null) {
548: InputStream in = null;
549: try {
550: in = new FileInputStream(configFileName);
551: readConfiguration(new BufferedInputStream(in));
552: } catch (FileNotFoundException e) {
553: logger.log(Level.INFO, "PSUB_CSPU0014", e);
554: } catch (IOException e) {
555: logger.log(Level.INFO, "PSUB_CSPU0015", e);
556: } finally {
557: if (in != null) {
558: try {
559: in.close();
560: } catch (IOException e) {
561: logger.log(Level.FINE, "PSUB_CSPU0016", e);
562: }
563: }
564: }
565: } else {
566: //try to load it from ResourceLoader
567: InputStream in = null;
568: try {
569: in = ResourceLoader.getInstance(System.getProperties())
570: .getResourceAsStream(CONFIG_FILE_VALUE_DEFAULT);
571: readConfiguration(new BufferedInputStream(in));
572: } catch (FileNotFoundException e) {
573: logger.log(Level.INFO, "PSUB_CSPU0014", e);
574: } catch (IOException e) {
575: logger.log(Level.INFO, "PSUB_CSPU0015", e);
576: } finally {
577: if (in != null) {
578: try {
579: in.close();
580: } catch (IOException e) {
581: logger.log(Level.FINE, "PSUB_CSPU0016", e);
582: }
583: }
584: }
585:
586: }
587: }
588:
589: private void loadConfiguration() {
590: readConfigFile();
591: if (isUBTEnabled()) {
592: configureUBTRootLogger();
593: } else {
594: resetUBTRootLogger();
595: }
596: configureConfigMonitor();
597: }
598:
599: /**
600: * Method to reload configuration and apply them in the system.
601: */
602: public void reloadConfiguration() {
603: loadConfiguration();
604: changes.firePropertyChange(null, null, null);
605: }
606:
607: /**
608: * Add Listener to reload event of configuration
609: * @param l listener
610: */
611: public void addReloadListener(PropertyChangeListener l) {
612: changes.addPropertyChangeListener(l);
613: }
614:
615: /**
616: * Remove reload listener.
617: * @param l listener
618: */
619: public void removeReloadListener(PropertyChangeListener l) {
620: changes.removePropertyChangeListener(l);
621: }
622:
623: private void readConfiguration(InputStream in) {
624: try {
625: configProps = new Properties();
626: configProps.load(in);
627: } catch (IOException e) {
628: logger.log(Level.FINE, "PSUB_CSPU0017", e);
629: }
630: }
631:
632: private Vector INFO_LOG_FIELDS = new Vector();
633: private Vector FINE_LOG_FIELDS = new Vector();
634: private Vector FINER_LOG_FIELDS = new Vector();
635: private Vector FINEST_LOG_FIELDS = new Vector();
636:
637: /**
638: * Add a log field.
639: * @param field log field
640: */
641: protected void addLogField(UBTLogField field) {
642: Level level = field.getLevel();
643: if (level.equals(Level.INFO)) {
644: INFO_LOG_FIELDS.add(field.getName());
645: } else if (level.equals(Level.FINE)) {
646: FINE_LOG_FIELDS.add(field.getName());
647: } else if (level.equals(Level.FINER)) {
648: FINER_LOG_FIELDS.add(field.getName());
649: } else if (level.equals(Level.FINEST)) {
650: FINEST_LOG_FIELDS.add(field.getName());
651: }
652: }
653:
654: /**
655: * Get log fields associated with a level. This method is usually used by
656: * a UBT log formatter.
657: * @param level Level
658: * @return Vector of the log fields.
659: */
660: public Vector getLogFields(Level level) {
661: Vector temp = new Vector(0);
662: switch (level.intValue()) {
663: case 800:
664: temp.addAll(INFO_LOG_FIELDS);
665: break;
666: case 500:
667: temp.addAll(INFO_LOG_FIELDS);
668: temp.addAll(FINE_LOG_FIELDS);
669: break;
670: case 400:
671: temp.addAll(INFO_LOG_FIELDS);
672: temp.addAll(FINE_LOG_FIELDS);
673: temp.addAll(FINER_LOG_FIELDS);
674: break;
675: case 300:
676: temp.addAll(INFO_LOG_FIELDS);
677: temp.addAll(FINE_LOG_FIELDS);
678: temp.addAll(FINER_LOG_FIELDS);
679: temp.addAll(FINEST_LOG_FIELDS);
680: break;
681: default:
682: break;
683: }
684: return temp;
685: }
686:
687: /**
688: * Get the enumeration of the registered UBT loggers.
689: * @return Enumeration of logger names.
690: */
691: public Enumeration getRegisteredUBTLoggers() {
692: Vector logVector = new Vector();
693: Enumeration logEnum = LogManager.getLogManager()
694: .getLoggerNames();
695: while (logEnum.hasMoreElements()) {
696: String next = (String) logEnum.nextElement();
697: if (next.startsWith(UBT_ROOT_LOGGER))
698: logVector.add(next);
699: }
700: return logVector.elements();
701: }
702:
703: /**
704: * Log a UBT event.
705: * Every UBT instrumenation should call this method to log the event eventually to a data sink.
706: * @param record UBT log record.
707: */
708: public void logEvent(UBTLogRecord record) {
709: Logger.getLogger(record.getLoggerName()).log(record);
710: }
711:
712: /**
713: * Method to be called if the configuration file is changed.
714: * @param fileName Name of the file. Dummy.
715: */
716: public void fileChanged(String fileName) {
717: synchronized (syncObject) {
718: reloadConfiguration();
719: }
720: }
721: }
|