http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/LineFormattedTarget.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/LineFormattedTarget.java b/common/src/main/java/flex/messaging/log/LineFormattedTarget.java new file mode 100644 index 0000000..1864bb0 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/LineFormattedTarget.java @@ -0,0 +1,286 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +import flex.messaging.config.ConfigMap; +import flex.messaging.util.ExceptionUtil; +import flex.messaging.util.StringUtils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * + */ +public class LineFormattedTarget extends AbstractTarget +{ + /** + * Indicates if the date should be added to the trace. + */ + protected boolean includeDate; + + /** + * Indicates if the time should be added to the trace. + */ + protected boolean includeTime; + + /** + * Indicates if the level for the event should added to the trace. + */ + protected boolean includeLevel; + + /** + * Indicates if the category for this target should added to the trace. + */ + protected boolean includeCategory; + + /** + * A prefix to prepend onto each logged message. + */ + protected String prefix = null; + + /** + * The formatter to write the date as part of the logging statement. + * Defaults to MM/dd/yyyy format. + */ + protected DateFormat dateFormater = new SimpleDateFormat("MM/dd/yyyy"); + + /** + * The formatter to write the time as part of the logging statement. + * Defaults to HH:mm:ss.SSS format. + */ + protected DateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Default constructor. + */ + public LineFormattedTarget() + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Initialize, validate, start, and stop methods. + // + //-------------------------------------------------------------------------- + + /** + * Initializes the target with id and properties. Subclasses can overwrite. + * + * @param id id for the target which is ignored. + * @param properties ConfigMap of properties for the target. + */ + public void initialize(String id, ConfigMap properties) + { + super.initialize(id, properties); + + includeTime = properties.getPropertyAsBoolean("includeTime", false); + includeDate = properties.getPropertyAsBoolean("includeDate", false); + includeCategory = properties.getPropertyAsBoolean("includeCategory", false); + includeLevel = properties.getPropertyAsBoolean("includeLevel", false); + prefix = properties.getPropertyAsString("prefix", null); + } + + //-------------------------------------------------------------------------- + // + // Public Getters and Setters for AbstractService properties + // + //-------------------------------------------------------------------------- + + /** + * Returns includeCategory property. + * + * @return <code>true</code> if category is included; <code>false</code> otherwise. + */ + public boolean isIncludeCategory() + { + return includeCategory; + } + + /** + * Sets includeCategory property. + * + * @param includeCategory the include category + */ + public void setIncludeCategory(boolean includeCategory) + { + this.includeCategory = includeCategory; + } + + /** + * Returns includeDate property. + * + * @return <code>true</code> if date is included; <code>false</code> otherwise. + */ + public boolean isIncludeDate() + { + return includeDate; + } + + /** + * Sets includeDate property. + * + * @param includeDate the include date + */ + public void setIncludeDate(boolean includeDate) + { + this.includeDate = includeDate; + } + + /** + * Returns includeLevel property. + * + * @return <code>true</code> if level is included; <code>false</code> otherwise. + */ + public boolean isIncludeLevel() + { + return includeLevel; + } + + /** + * Sets includeLevel property. + * + * @param includeLevel the include level + */ + public void setIncludeLevel(boolean includeLevel) + { + this.includeLevel = includeLevel; + } + + /** + * Returns includeTime property. + * + * @return <code>true</code> if time is included; <code>false</code> otherwise. + */ + public boolean isIncludeTime() + { + return includeTime; + } + + /** + * Sets includeTime property. + * + * @param includeTime the include time + */ + public void setIncludeTime(boolean includeTime) + { + this.includeTime = includeTime; + } + + /** + * Returns prefix property. + * + * @return The prefix for log messages. + */ + public String getPrefix() + { + return prefix; + } + + /** + * Sets prefix property. + * + * @param prefix the prefix string + */ + public void setPrefix(String prefix) + { + this.prefix = prefix; + } + + /** + * This method handles a <code>LogEvent</code> from an associated logger. + * A target uses this method to translate the event into the appropriate + * format for transmission, storage, or display. + * This method will be called only if the event's level is in range of the + * target's level. + * @param event the log event + */ + public void logEvent(LogEvent event) + { + String pre = ""; + if (prefix != null) + { + pre = prefix + " "; // any space is stripped from config + } + + String date = ""; + if (includeDate || includeTime) + { + StringBuffer buffer = new StringBuffer(); + Date d = new Date(); + if (includeDate) + { + buffer.append(dateFormater.format(d)); + buffer.append(" "); + } + if (includeTime) + { + buffer.append(timeFormatter.format(d)); + buffer.append(" "); + } + date = buffer.toString(); + } + + String cat = includeCategory ? + ("[" + event.logger.getCategory() + "] ") : ""; + String level = ""; + if (includeLevel) + { + StringBuffer buffer = new StringBuffer(); + buffer.append("["); + buffer.append(LogEvent.getLevelString(event.level)); + buffer.append("]"); + buffer.append(" "); + level = buffer.toString(); + } + StringBuffer result = new StringBuffer(pre); + result.append(date).append(level).append(cat).append(event.message); + + if (event.throwable != null) + result.append(StringUtils.NEWLINE).append(ExceptionUtil.toString(event.throwable)); + + internalLog(result.toString()); + } + + //-------------------------------------------------------------------------- + // + // Protected/private methods. + // + //-------------------------------------------------------------------------- + + /** + * Descendants of this class should override this method to direct the + * specified message to the desired output. + * + * @param message String containing preprocessed log message which may + * include time, date, category, etc. based on property settings, + * such as <code>includeDate</code>, <code>includeCategory</code>, + * etc. + */ + protected void internalLog(String message) + { + // override this method to perform the redirection to the desired output + } +}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/Log.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/Log.java b/common/src/main/java/flex/messaging/log/Log.java new file mode 100644 index 0000000..570911a --- /dev/null +++ b/common/src/main/java/flex/messaging/log/Log.java @@ -0,0 +1,708 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +import flex.messaging.LocalizedException; +import flex.messaging.config.ConfigMap; +import flex.messaging.util.PrettyPrinter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.HashSet; + +/** + * + */ +public class Log +{ + + public static final String INVALID_CHARS = "[]~$^&\\/(){}<>+=`!#%?,:;\'\"@"; + + // Errors + private static final int INVALID_TARGET = 10013; + private static final int INVALID_CATEGORY = 10014; + private static final int INVALID_CATEGORY_CHARS = 10015; + + private static Log log; + private static PrettyPrinter prettyPrinter; + private static String prettyPrinterClass = "flex.messaging.util.BasicPrettyPrinter"; + + private static final HashSet excludedProperties = new HashSet(); + public static final String VALUE_SUPRESSED = "** [Value Suppressed] **"; + + private volatile short targetLevel; + private final Map loggers; + private final List targets; + private final Map targetMap; + private static final Object staticLock = new Object(); + + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Private constructor. + */ + private Log() + { + targetLevel = LogEvent.NONE; + loggers = new HashMap(); + targets = new ArrayList(); + targetMap = new LinkedHashMap(); + } + + + /** + * Creates the log on first access, returns already created log on + * subsequent calls. + * + * @return log. + */ + public static Log createLog() + { + synchronized (staticLock) + { + if (log == null) + log = new Log(); + + return log; + } + } + + //-------------------------------------------------------------------------- + // + // Initialize, validate, start, and stop methods. + // + //-------------------------------------------------------------------------- + + /** + * Initializes Log with id and properties. + * + * @param id Id for the Log which is ignored, though is used by the ManageableComponent superclass + * @param properties ConfigMap of properties for the Log. + */ + public static synchronized void initialize(String id, ConfigMap properties) + { + String value = properties.getPropertyAsString("pretty-printer", null); + if (value != null) + prettyPrinterClass = value; + + // Create a HashSet with the properties that we want to exclude from the + // list of properties given by 'getPropertiesAsList' + ConfigMap excludeMap = properties.getPropertyAsMap("exclude-properties", null); + if (excludeMap != null) + { + if (excludeMap.getPropertyAsList("property", null) != null) + excludedProperties.addAll(excludeMap.getPropertyAsList("property", null)); + } + } + + //-------------------------------------------------------------------------- + // + // Public Getters and Setters for Log properties + // + //-------------------------------------------------------------------------- + + /** + * Indicates whether a fatal level log event will be processed by a log target. + * @return boolean true if it is Fatal level + */ + public static boolean isFatal() + { + return log == null ? false : log.targetLevel <= LogEvent.FATAL; + } + + /** + * Indicates whether an error level log event will be processed by a log target. + * @return boolean true if it is Error level + */ + public static boolean isError() + { + return log == null ? false : log.targetLevel <= LogEvent.ERROR; + } + + /** + * Indicates whether a warn level log event will be processed by a log target. + * @return boolean true if it is Warn level + */ + public static boolean isWarn() + { + return log == null ? false : log.targetLevel <= LogEvent.WARN; + } + + /** + * Indicates whether an info level log event will be processed by a log target. + * @return boolean true if it is Info level + */ + public static boolean isInfo() + { + return log == null ? false : log.targetLevel <= LogEvent.INFO; + } + + /** + * Indicates whether a debug level log event will be processed by a log target. + * @return boolean true if it is debug level + */ + public static boolean isDebug() + { + return log == null ? false : log.targetLevel <= LogEvent.DEBUG; + } + + /** + * Indicates whether a log property should be excluded. + * @param property the property to check + * @return boolean true if the property should be excluded + */ + public static boolean isExcludedProperty(String property) + { + return !excludedProperties.isEmpty() && excludedProperties.contains(property); + } + + + /** + * Given a category, returns the logger associated with the category. + * + * @param category Categogry for the logger. + * @return Logger associated with the category. + */ + public static Logger getLogger(String category) + { + if (log != null) + return getLogger(log, category); + + // Return a dummy logger? + return new Logger(category); + } + + /** + * @param log base logger. + * @param category category to log to. + * @return Logger instance for the given category. + */ + public static Logger getLogger(Log log, String category) + { + checkCategory(category); + + synchronized (staticLock) + { + Logger result = (Logger) log.loggers.get(category); + if (result == null) + { + result = new Logger(category); + + // Check to see if there are any targets for this logger. + for (Iterator iter = log.targets.iterator(); iter.hasNext();) + { + Target target = (Target) iter.next(); + if (categoryMatchInFilterList(category, target.getFilters())) + target.addLogger(result); + } + + log.loggers.put(category, result); + } + return result; + } + } + + /** + * Returns an unmodifiable snapshot of the targets registered with this Log when the + * method is invoked. + * @return List the list of targets + */ + public static List getTargets() + { + if (log != null) + { + List currentTargets; + // Snapshot the current target list (shallow copy) and return it. + synchronized (staticLock) + { + currentTargets = Collections.unmodifiableList(new ArrayList(log.targets)); + } + return currentTargets; + } + return null; + } + + /** + * Return the Log's map of targets keyed on their human-readable ids (e.g. ConsoleTarget0, ConsoleTarget1, etc.) + * @return Map the target map + */ + public static Map getTargetMap() + { + if (log != null) + { + Map currentTargets; + synchronized (staticLock) + { + currentTargets = new LinkedHashMap(log.targetMap); + } + return currentTargets; + } + return null; + } + + /** + * Returns the target associated with the unique ID searchId. Returns null if no + * such target exists. + * @param searchId the search ID + * @return Target the associated target + */ + public static Target getTarget(String searchId) + { + if (log != null) + { + synchronized (staticLock) + { + return (Target) log.targetMap.get(searchId); + } + } + + return null; + } + + /** + * Return the categories for all of the loggers + * @return String[] the categories for all of the loggers + */ + public String[] getLoggers() + { + String[] currentCategories; + if (log != null) + { + synchronized (staticLock) + { + Object[] currentCategoryObjects = loggers.keySet().toArray(); + currentCategories = new String[currentCategoryObjects.length]; + for (int i = 0; i < currentCategoryObjects.length; i++) + { + currentCategories[i] = (String)(currentCategoryObjects[i]); + } + } + } + else + { + currentCategories = new String[0]; + } + + return currentCategories; + } + + /** + * Adds a target to the log. + * + * @param target Target to be added. + */ + public static void addTarget(Target target) + { + if (log != null) + { + if (target != null) + { + synchronized (staticLock) + { + List filters = target.getFilters(); + + // need to find what filters this target matches and set the specified + // target as a listener for that logger. + Iterator it = log.loggers.keySet().iterator(); + while (it.hasNext()) + { + String key = (String) it.next(); + if (categoryMatchInFilterList(key, filters)) + target.addLogger((Logger) log.loggers.get(key)); + } + // if we found a match all is good, otherwise we need to + // put the target in a waiting queue in the event that a logger + // is created that this target cares about. + if (!log.targets.contains(target)) + log.targets.add(target); + + if (!log.targetMap.containsValue(target)) + { + String name = target.getClass().getName(); + + if (name.indexOf(".") > -1) + { + String[] classes = name.split("\\."); + name = classes[classes.length - 1]; + } + + log.targetMap.put(new String(name + log.targetMap.size()), target); + } + + // update our global target log level if this target is more verbose. + short targetLevel = target.getLevel(); + if (log.targetLevel == LogEvent.NONE) + log.targetLevel = targetLevel; + else if (targetLevel < log.targetLevel) + { + log.targetLevel = targetLevel; + } + } + } + else + { + // Invalid target specified. Target must not be null. + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_TARGET); + throw ex; + } + } + } + + /** + * Removes a target from the log. + * + * @param target The target to be removed. + */ + public static void removeTarget(Target target) + { + if (log != null) + { + if (target != null) + { + synchronized (staticLock) + { + // Remove the target from any associated loggers. + List filters = target.getFilters(); + Iterator it = log.loggers.keySet().iterator(); + while (it.hasNext()) + { + String key = (String) it.next(); + if (categoryMatchInFilterList(key, filters)) + target.removeLogger((Logger) log.loggers.get(key)); + } + // Remove the target from the Log set. + log.targets.remove(target); + resetTargetLevel(); + } + } + else + { + // Invalid target specified. Target must not be null. + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_TARGET); + throw ex; + } + } + } + + //-------------------------------------------------------------------------- + // + // Other Public APIs + // + //-------------------------------------------------------------------------- + + /** + * This method removes all of the current loggers and targets from the cache. + * and resets target level. + */ + public static synchronized void reset() + { + flush(); + } + + /** + * + */ + public static void flush() + { + if (log != null) + { + log.loggers.clear(); + log.targets.clear(); + log.targetLevel = LogEvent.NONE; + } + } + + /** + * @param l string representation of the log level. + * @return a short value representing the log level. + */ + public static short readLevel(String l) + { + short lvl = LogEvent.ERROR; + if ((l != null) && (l.length() > 0)) + { + l = l.trim().toLowerCase(); + char c = l.charAt(0); + switch (c) + { + case 'n': + lvl = LogEvent.NONE; + break; + case 'e': + lvl = LogEvent.ERROR; + break; + case 'w': + lvl = LogEvent.WARN; + break; + case 'i': + lvl = LogEvent.INFO; + break; + case 'd': + lvl = LogEvent.DEBUG; + break; + case 'a': + lvl = LogEvent.ALL; + break; + default: + lvl = LogEvent.ERROR; + } + } + + return lvl; + } + + /** + * + * This method checks the specified string value for illegal characters. + * + * @param value to check for illegal characters. + * The following characters are not valid: + * []~$^&\/(){}<>+=`!#%?,:;'"&#64; + * @return <code>true</code> if there are any illegal characters found, + * <code>false</code> otherwise + */ + public static boolean hasIllegalCharacters(String value) + { + char[] chars = value.toCharArray(); + for (int i = 0; i < chars.length; i++) + { + char c = chars[i]; + if (INVALID_CHARS.indexOf(c) != -1) + { + return true; + } + } + + return false; + } + + /** + * Returns the PrettyPrinter used by the Log. + * + * @return the PrettyPrinter used by the Log. + */ + public static PrettyPrinter getPrettyPrinter() + { + if (prettyPrinter == null || + !prettyPrinter.getClass().getName().equals(prettyPrinterClass)) + { + try + { + Class c = Class.forName(prettyPrinterClass); + prettyPrinter = (PrettyPrinter)c.newInstance(); + } + catch (Throwable t) + { + throw new RuntimeException("Error creating instance of default pretty printer.", t); + } + } + return (PrettyPrinter)prettyPrinter.copy(); + } + + /** + * Returns the current target level for the Log. + * + * @return the current target level for the Log. + */ + public static short getTargetLevel() + { + return log == null ? LogEvent.NONE : log.targetLevel; + } + + /** + * + * Sets the pretty printer class name used by the log. + * + * @param value Name of the pretty printer class. + */ + public static void setPrettyPrinterClass(String value) + { + prettyPrinterClass = value; + } + + //-------------------------------------------------------------------------- + // + // Protected/private methods. + // + //-------------------------------------------------------------------------- + + /* package */ static void resetTargetLevel() + { + if (log != null) + { + synchronized (staticLock) + { + short maxTargetLevel = LogEvent.NONE; + for (Iterator iter = log.targets.iterator(); iter.hasNext();) + { + short targetLevel = ((Target) iter.next()).getLevel(); + if (maxTargetLevel == LogEvent.NONE || targetLevel < maxTargetLevel) + maxTargetLevel = targetLevel; + } + log.targetLevel = maxTargetLevel; + } + } + } + + /* package */ static void processTargetFilterAdd(Target target, String filter) + { + if (log != null) + { + synchronized (staticLock) + { + List filters = new ArrayList(); + filters.add(filter); + + // Find the loggers this target matches and add the + // target as a listener for log events from these loggers. + Iterator it = log.loggers.keySet().iterator(); + while (it.hasNext()) + { + String key = (String) it.next(); + if (categoryMatchInFilterList(key, filters)) + target.addLogger((Logger) log.loggers.get(key)); + } + } + } + } + + /* package */ static void processTargetFilterRemove(Target target, String filter) + { + if (log != null) + { + synchronized (staticLock) + { + // Remove the target from any matching loggers. + List filters = new ArrayList(); + filters.add(filter); + Iterator it = log.loggers.keySet().iterator(); + while (it.hasNext()) + { + String key = (String) it.next(); + if (categoryMatchInFilterList(key, filters)) + target.removeLogger((Logger) log.loggers.get(key)); + } + } + } + } + + /** + * This method checks that the specified category matches any of the filter + * expressions provided in the filters array. + * + * @param category to match against + * @param filters - list of strings to check category against. + * @return <code>true</code> if the specified category matches any of the + * filter expressions found in the filters list, <code>false</code> + * otherwise. + */ + private static boolean categoryMatchInFilterList(String category, List filters) + { + if (filters == null) + return false; + + for (int i = 0; i < filters.size(); i++) + { + String filter = (String) filters.get(i); + // match category to filter based on the presence of a wildcard + if (checkFilterToCategory(filter,category)) + return true; + } + return false; + } + + /** + * Check whether the category match with the filter. + * @param filter The filter string to check against a specific category + * @param category The category which the filter could match + * @return whether the filter matches a specific category + */ + public static boolean checkFilterToCategory(String filter, String category) + { + int index = -1; + index = filter.indexOf("*"); + + if (index == 0) // match all + { + return true; + } + else if (index < 0) // match full category to filter + { + if (category.equals(filter)) + { + return true; + } + } + else // match partial category to filter + { + if ((category.length() >= index) && category.substring(0, index).equals(filter.substring(0, index))) + { + return true; + } + } + + return false; + } + + /** + * This method will ensure that a valid category string has been specified. + * If the category is not valid an exception will be thrown. + * + * Categories can not contain any blanks or any of the following characters: + * []`*~,!#$%^&()]{}+=\|'";?><./&#64; or be less than 1 character in length. + */ + private static void checkCategory(String category) + { + if (category == null || category.length() == 0) + { + // Categories must be at least one character in length. + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_CATEGORY); + throw ex; + } + + if (hasIllegalCharacters(category) || (category.indexOf("*") != -1)) + { + // Categories can not contain any of the following characters: 'INVALID_CHARS' + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_CATEGORY_CHARS, new Object[]{INVALID_CHARS}); + throw ex; + } + } + + /** + * Clean up static member variables. + */ + public static void clear() + { + log = null; + prettyPrinter = null; + } + +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/LogCategories.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/LogCategories.java b/common/src/main/java/flex/messaging/log/LogCategories.java new file mode 100644 index 0000000..2cb6094 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/LogCategories.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +/** + * + * + * This class contains all the log categories used in our classes. When adding + * a new log category, make sure the sample configuration file is updated + * as well. + * + */ +public interface LogCategories +{ + String CLIENT_FLEXCLIENT = "Client.FlexClient"; + String CLIENT_FLEXCLIENT_ADAPTIVE = "Client.FlexClient.Adaptive"; + String CLIENT_MESSAGECLIENT = "Client.MessageClient"; + + String CONFIGURATION = "Configuration"; + String CONFIGURATION_SPRING = "Configuration.Spring"; + + String ENDPOINT_GENERAL = "Endpoint.General"; + String ENDPOINT_AMF = "Endpoint.AMF"; + String ENDPOINT_NIO_AMF = "Endpoint.NIOAMF"; + String ENDPOINT_FLEXSESSION = "Endpoint.FlexSession"; + String ENDPOINT_GATEWAY = "Endpoint.Gateway"; + String ENDPOINT_HTTP = "Endpoint.HTTP"; + String ENDPOINT_NIO_HTTP = "Endpoint.NIOHTTP"; + String ENDPOINT_RTMP = "Endpoint.RTMP"; + String ENDPOINT_STREAMING_AMF = "Endpoint.StreamingAMF"; + String ENDPOINT_STREAMING_NIO_AMF = "Endpoint.StreamingNIOAMF"; + String ENDPOINT_STREAMING_HTTP = "Endpoint.StreamingHTTP"; + String ENDPOINT_STREAMING_NIO_HTTP = "Endpoint.StreamingNIOHTTP"; + String ENDPOINT_WEBSOCKET_NIO_AMF = "Endpoint.WebSocketNIOAMF"; + String ENDPOINT_TYPE = "Endpoint.Type"; + + String EXECUTOR = "Executor"; + + String MANAGEMENT_GENERAL = "Management.General"; + String MANAGEMENT_MBEANSERVER = "Management.MBeanServer"; + + String MESSAGE_GENERAL = "Message.General"; + String MESSAGE_COMMAND = "Message.Command"; + String MESSAGE_DATA = "Message.Data"; + String MESSAGE_FILTER = "Message.Filter"; + String MESSAGE_REMOTING = "Message.Remoting"; + String MESSAGE_RPC = "Message.RPC"; + String MESSAGE_SELECTOR = "Message.Selector"; + String MESSAGE_TIMING = "Message.Timing"; + + String PROTOCOL_AMFSOCKET = "Protocol.AMFSocket"; + String PROTOCOL_HTTP = "Protocol.HTTP"; + String PROTOCOL_RTMP = "Protocol.RTMP"; + String PROTOCOL_RTMPT = "Protocol.RTMPT"; + + String RESOURCE = "Resource"; + + String SERVICE_GENERAL = "Service.General"; + String SERVICE_CLUSTER = "Service.Cluster"; + String SERVICE_COLLABORATION = "Service.Collaboration"; + String SERVICE_DATA = "Service.Data"; // Not a category but used by TargetSettings to replace DataService + String SERVICE_DATA_GENERAL = "Service.Data.General"; + String SERVICE_DATA_HIBERNATE = "Service.Data.Hibernate"; + String SERVICE_DATA_SQL = "Service.Data.SQL"; + String SERVICE_DATA_TRANSACTION = "Service.Data.Transaction"; + String SERVICE_ADVANCED_MESSAGING = "Service.AdvancedMessaging"; + String SERVICE_NOTIFICATION = "Service.Notification"; + String SERVICE_GATEWAY = "Service.Gateway"; + String SERVICE_GATEWAY_CONNECTOR = "Service.Gateway.Connector"; + String SERVICE_HTTP = "Service.HTTP"; + String SERVICE_MESSAGE = "Service.Message"; + String SERVICE_MESSAGE_JMS = "Service.Message.JMS"; + String SERVICE_REMOTING = "Service.Remoting"; + + String SECURITY = "Security"; + + String SOCKET_SERVER_GENERAL = "SocketServer.General"; + String SOCKET_SERVER_BYTE_BUFFER_MANAGEMENT = "SocketServer.ByteBufferManagement"; + + String SSL = "SSL"; + + String STARTUP_MESSAGEBROKER = "Startup.MessageBroker"; + String STARTUP_SERVICE = "Startup.Service"; + String STARTUP_DESTINATION = "Startup.Destination"; + + String TIMEOUT = "Timeout"; + + String TRANSPORT_RELIABLE = "Transport.Reliable"; + String TRANSPORT_THROTTLE = "Transport.Throttle"; + String TRANSPORT_THROTTLE_BUFFER = "Transport.Throttle.Buffer"; + String TRANSPORT_THROTTLE_CONFLATE = "Transport.Throttle.Conflate"; + + String WSRP_GENERAL = "WSRP.General"; + + String RDS = "RDS"; + + String FBSERVICES_INTROSPECTION = "FBServices.Introspection"; +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/LogEvent.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/LogEvent.java b/common/src/main/java/flex/messaging/log/LogEvent.java new file mode 100644 index 0000000..7492352 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/LogEvent.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +/** + * + */ +public class LogEvent +{ + public static final short NONE = 2000; + public static final short FATAL = 1000; + public static final short ERROR = 8; + public static final short WARN = 6; + public static final short INFO = 4; + public static final short DEBUG = 2; + public static final short ALL = 0; + + /** + * Provides access to the level for this log event. + * Valid values are: + * <ul> + * <li><code>LogEvent.DEBUG</code> designates informational + * level messages that are fine grained and most helpful when + * debugging an application.</li> + * + * <li><code>LogEvent.INFO</code> designates informational messages + * that highlight the progress of the application at + * coarse-grained level.</li> + * + * <li><code>LogEvent.WARN</code> designates events that could be + * harmful to the application operation.</li> + * + * <li><code>LogEvent.ERROR</code> designates error events that might + * still allow the application to continue running.</li> + * + * <li><code>LogEvent.FATAL</code> designates events that are very + * harmful and will eventually lead to application failure.</li> + * + * </ul> + */ + public short level; + + /** + * Provides access to the message that was logged. + */ + public String message; + + /** + * Logger instance that raised the log event. + */ + public Logger logger; + + /** + * Related exception, if applicable. + */ + public Throwable throwable; + + /** + * Constructor. + * + * @param lgr Logger instance that raised the log event. + * @param msg Message that was logged. + * @param lvl The level for the log event. + * @param t Related exception, if applicable. + */ + public LogEvent(Logger lgr, String msg, short lvl, Throwable t) + { + logger = lgr; + message = msg; + level = lvl; + throwable = t; + } + + /** + * Returns a string value representing the level specified. + * + * @param value the level a string is desired for. + * @return the level specified in english + */ + public static String getLevelString(short value) + { + switch (value) + { + case NONE: + return ("NONE"); + case FATAL: + return ("FATAL"); + case ERROR: + return ("ERROR"); + case WARN: + return ("WARN"); + case INFO: + return ("INFO"); + case DEBUG: + return ("DEBUG"); + case ALL: + return ("ALL"); + default: + return ("UNKNOWN"); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/Logger.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/Logger.java b/common/src/main/java/flex/messaging/log/Logger.java new file mode 100644 index 0000000..8684a3e --- /dev/null +++ b/common/src/main/java/flex/messaging/log/Logger.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +import flex.messaging.util.PrettyPrinter; +import flex.messaging.util.StringUtils; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * The <code>Logger</code> class is used to log out information. It provides named + * methods to log information out at the desired level. Each <code>Logger</code> + * will log information out for a log category that is settable. + * + * + */ +public class Logger +{ + /** + * The category this logger send messages for. + */ + private volatile String category; + + /** + * The list of targets that this logger will dispatch log events to. + */ + private final ArrayList targets; + + /** + * Constructs a <code>Logger</code> instance that will log + * information out to the specified category. + * + * @param category The category to log information for. + */ + public Logger(String category) + { + this.category = category; + targets = new ArrayList(); + } + + /** + * Returns the category this <code>Logger</code> logs information for. + * + * @return The category this <code>Logger</code> logs information for. + */ + public String getCategory() + { + return category; + } + + /** + * Determines whether the <code>Logger</code> has at least one target. + * + * @return True if the <code>Logger</code> has one or more targets. + */ + public boolean hasTarget() + { + synchronized (targets) + { + return !targets.isEmpty(); + } + } + /** + * Adds a <code>Target</code> that will format and output log events + * generated by this <code>Logger</code>. + * + * @param target The <code>Target</code> to add. + */ + void addTarget(Target target) + { + synchronized (targets) + { + if (!targets.contains(target)) + targets.add(target); + } + } + + /** + * Removes a <code>Target</code> from this <code>Logger</code>. + * + * @param target The <code>Target</code> to remove. + */ + void removeTarget(Target target) + { + synchronized (targets) + { + targets.remove(target); + } + } + + /* + * DEBUG + */ + /** + * Logs out a debug message. + * + * @param message The message to log. + */ + public void debug(String message) + { + log(LogEvent.DEBUG, message, null, null); + } + + /** + * Logs out a debug message associated with a <code>Throwable</code>. + * + * @param message The message to log. + * @param t The associated <code>Throwable</code>. + */ + public void debug(String message, Throwable t) + { + log(LogEvent.DEBUG, message, null, t); + } + + /** + * Logs out a debug message supporting positional parameter substitutions. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + */ + public void debug(String message, Object[] parameters) + { + log(LogEvent.DEBUG, message, parameters, null); + } + + /** + * Logs out a debug message supporting positional parameter substitutions and an + * associated <code>Throwable</code>. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + * @param t The associated <code>Throwable</code>. + */ + public void debug(String message, Object[] parameters, Throwable t) + { + log(LogEvent.DEBUG, message, parameters, t); + } + + /* + * INFO + */ + /** + * Logs out an info message. + * + * @param message The message to log. + */ + public void info(String message) + { + log(LogEvent.INFO, message, null, null); + } + + /** + * Logs out an info message associated with a <code>Throwable</code>. + * + * @param message The message to log. + * @param t The associated <code>Throwable</code>. + */ + public void info(String message, Throwable t) + { + log(LogEvent.INFO, message, null, t); + } + + /** + * Logs out an info message supporting positional parameter substitutions. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + */ + public void info(String message, Object[] parameters) + { + log(LogEvent.INFO, message, parameters, null); + } + + /** + * Logs out an info message supporting positional parameter substitutions and an + * associated <code>Throwable</code>. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + * @param t The associated <code>Throwable</code>. + */ + public void info(String message, Object[] parameters, Throwable t) + { + log(LogEvent.INFO, message, parameters, t); + } + + /* + * WARN + */ + /** + * Logs out a warn message. + * + * @param message The message to log. + */ + public void warn(String message) + { + log(LogEvent.WARN, message, null, null); + } + + /** + * Logs out a warn message associated with a <code>Throwable</code>. + * + * @param message The message to log. + * @param t The associated <code>Throwable</code>. + */ + public void warn(String message, Throwable t) + { + log(LogEvent.WARN, message, null, t); + } + + /** + * Logs out a warn message supporting positional parameter substitutions. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + */ + public void warn(String message, Object[] parameters) + { + log(LogEvent.WARN, message, parameters, null); + } + + /** + * Logs out a warn message supporting positional parameter substitutions and an + * associated <code>Throwable</code>. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + * @param t The associated <code>Throwable</code>. + */ + public void warn(String message, Object[] parameters, Throwable t) + { + log(LogEvent.WARN, message, parameters, t); + } + + /* + * ERROR + */ + /** + * Logs out an error message. + * + * @param message The message to log. + */ + public void error(String message) + { + log(LogEvent.ERROR, message, null, null); + } + + /** + * Logs out an error message associated with a <code>Throwable</code>. + * + * @param message The message to log. + * @param t The associated <code>Throwable</code>. + */ + public void error(String message, Throwable t) + { + log(LogEvent.ERROR, message, null, t); + } + + /** + * Logs out an error message supporting positional parameter substitutions. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + */ + public void error(String message, Object[] parameters) + { + log(LogEvent.ERROR, message, parameters, null); + } + + /** + * Logs out an error message supporting positional parameter substitutions and an + * associated <code>Throwable</code>. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + * @param t The associated <code>Throwable</code>. + */ + public void error(String message, Object[] parameters, Throwable t) + { + log(LogEvent.ERROR, message, parameters, t); + } + + /* + * FATAL + */ + /** + * Logs out a fatal message. + * + * @param message The message to log. + */ + public void fatal(String message) + { + log(LogEvent.FATAL, message, null, null); + } + + /** + * Logs out a fatal message associated with a <code>Throwable</code>. + * + * @param message The message to log. + * @param t The associated <code>Throwable</code>. + */ + public void fatal(String message, Throwable t) + { + log(LogEvent.FATAL, message, null, t); + } + + /** + * Logs out a fatal message supporting positional parameter substitutions. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + */ + public void fatal(String message, Object[] parameters) + { + log(LogEvent.FATAL, message, parameters, null); + } + + /** + * Logs out a fatal message supporting positional parameter substitutions and an + * associated <code>Throwable</code>. + * + * @param message The message to log. + * @param parameters Parameters to substitute into the message. + * @param t The associated <code>Throwable</code>. + */ + public void fatal(String message, Object[] parameters, Throwable t) + { + log(LogEvent.FATAL, message, parameters, t); + } + + /** + * + * The methods named according to log level delegate to this method to log. + * + * @param level The log level. + * @param message The message to log. + * @param parameters Substitution parameters (may be null). + * @param t The associated <code>Throwable</code> (may be null). + */ + public void log(short level, String message, Object[] parameters, Throwable t) + { + log(level, message, parameters, t, true); + } + + /** + * + * Logs a passed message if its level verifies as high enough. + * + * @param level The log level. + * @param message The message to log. + * @param parameters Substitution parameters (may be null). + * @param t The associated <code>Throwable</code>. + * @param verifyLevel <code>true</code> to verify the log level; otherwise log without verifying the level. + */ + public void log(short level, String message, Object[] parameters, Throwable t, boolean verifyLevel) + { + if (targets.size() > 0 && (!verifyLevel || (level >= Log.getTargetLevel()))) + { + if (parameters != null) + { + PrettyPrinter prettyPrinter = Log.getPrettyPrinter(); + + // replace all of the parameters in the msg string + for(int i = 0; i < parameters.length; i++) + { + String replacement = parameters[i] != null ? prettyPrinter.prettify(parameters[i]) : "null"; + + //this guy runs into problems if the replacement has a \ or $ in it + //message = message.replaceAll("\\{" + i + "\\}", replacement); + message = StringUtils.substitute(message, "{" + i + "}", replacement); + } + } + LogEvent event = new LogEvent(this, message, level, t); + Target tgt; + synchronized (targets) + { + for (Iterator iter = targets.iterator(); iter.hasNext();) + { + tgt = (Target) iter.next(); + if (!verifyLevel || (level >= tgt.getLevel())) + tgt.logEvent(event); + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/Target.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/Target.java b/common/src/main/java/flex/messaging/log/Target.java new file mode 100644 index 0000000..7a39fb5 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/Target.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.log; + +import java.util.List; + +import flex.messaging.config.ConfigMap; + +/** + * All logger target implementations within the logging framework must + * implement this interface. <code>Target</code> implementations receive log events + * and output information from these events to the appropriate output + * destination which may be a console, log file or some other custom + * destination. + */ +public interface Target +{ + /** + * Initializes the target with id and properties. + * + * @param id id for the target. + * @param properties ConfigMap of properties for the target. + */ + void initialize(String id, ConfigMap properties); + + /** + * Returns the category filters defined for the <code>Target</code>. + * + * @return The category filters defined for the <code>Target</code>. + */ + List getFilters(); + + /** + * Sets the category filters that the <code>Target</code> will process + * log events for. + * + * @param value The category filters that the <code>Target</code> will process + */ + void setFilters(List value); + + /** + * Adds the category filteer that the <code>Target</code> will process + * log events for. + * + * @param value The new category filter to add to the <code>Target</code>'s list of filters. + */ + void addFilter(String value); + + /** + * Removes a category filter from the list of filters the <code>Target</code> will + * process log events for. + * + * @param value The category filter to remove from the <code>Target</code>'s list of filters. + */ + void removeFilter(String value); + + /** + * Returns the log level that the <code>Target</code> will process log + * events for. Log events at this level, or at a higher priority level + * will be processed. + * + * @return The log level that the <code>Target</code> will process log events for. + */ + short getLevel(); + + /** + * Sets the log level that the <code>Target</code> will process log events + * for. Log events at this level, or at a higher priority level will be + * processed. + * + * @param value The log level that the <code>Target</code> will process log events for. + */ + void setLevel(short value); + + /** + * Adds a <code>Logger</code> whose category matches the filters list for + * the <code>Target</code>. The <code>Logger</code> will dispatch log events + * to this <code>Target</code> to be output. + * + * @param logger The <code>Logger</code> to add. + */ + void addLogger(Logger logger); + + /** + * Removes a <code>Logger</code> from the <code>Target</code>. + * + * @param logger The <code>Logger</code> to remove. + */ + void removeLogger(Logger logger); + + /** + * Logs a log event out to the <code>Target</code>s output destination, + * which may be the console or a log file. + * + * @param event The <code>LogEvent</code> containing the information to output. + */ + void logEvent(LogEvent event); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/BasicPrettyPrinter.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/BasicPrettyPrinter.java b/common/src/main/java/flex/messaging/util/BasicPrettyPrinter.java new file mode 100644 index 0000000..19fa547 --- /dev/null +++ b/common/src/main/java/flex/messaging/util/BasicPrettyPrinter.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +/** + * Prettifies the representation of an Object as a String. Complex + * types are not traversed. + * + * + */ +public class BasicPrettyPrinter implements PrettyPrinter +{ + protected ObjectTrace trace; + + public BasicPrettyPrinter() + { + } + + /** + * Prettifies the representation of an Object as a String. + * <ul> + * <li>Simple types are simply toString'ed.</li> + * <li>XML strings are formatted with line feeds and indentations.</li> + * <li>Complex types report their class names.</li> + * <li>Collections, Maps and native Arrays also report their size/length.</li> + * </ul> + * @return A prettified version of an Object as a String. + */ + public String prettify(Object o) + { + try + { + trace = new ObjectTrace(); + internalPrettify(o); + return trace.toString(); + } + catch (Throwable t) + { + return trace.toString(); + } + finally + { + trace = null; + } + } + + protected void internalPrettify(Object o) + { + if (o == null) + { + trace.writeNull(); + } + else if (o instanceof String) + { + String string = (String)o; + if (string.startsWith("<?xml")) + { + trace.write(StringUtils.prettifyXML(string)); + } + else + { + trace.write(string); + } + } + else if (o instanceof Number || o instanceof Boolean || o instanceof Date + || o instanceof Calendar || o instanceof Character) + { + trace.write(o); + } + else + { + prettifyComplexType(o); + } + } + + protected void prettifyComplexType(Object o) + { + StringBuffer header = new StringBuffer(); + + if (o instanceof PrettyPrintable) + { + PrettyPrintable pp = (PrettyPrintable)o; + header.append(pp.toStringHeader()); + } + + Class c = o.getClass(); + String className = c.getName(); + + if (o instanceof Collection) + { + header.append(className).append(" (Collection size:").append(((Collection)o).size()).append(")"); + } + else if (o instanceof Map) + { + header.append(className).append(" (Map size:").append(((Map)o).size()).append(")"); + } + else if (c.isArray() && c.getComponentType() != null) + { + Class componentType = c.getComponentType(); + className = componentType.getName(); + header.append(className).append("[] (Array length:").append(Array.getLength(o)).append(")"); + } + else + { + header.append(className); + } + + trace.startObject(header.toString()); + trace.endObject(); + } + + /** + * If the definition of toString is not from java.lang.Object or any class in the + * java.util.* package then we consider it a custom implementation in which case + * we'll use it instead of introspecting the class. + * + * @param c The class to check for a custom toString definition. + * @return Whether this class declares a custom toString() method. + */ + protected boolean hasCustomToStringMethod(Class c) + { + try + { + Method toStringMethod = c.getMethod("toString", (Class[])null); + Class declaringClass = toStringMethod.getDeclaringClass(); + if (declaringClass != Object.class + && !declaringClass.getName().startsWith("java.util")) + { + return true; + } + } + catch (Throwable t) + { + } + + return false; + } + + public Object copy() + { + return new BasicPrettyPrinter(); + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/ExceptionUtil.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/ExceptionUtil.java b/common/src/main/java/flex/messaging/util/ExceptionUtil.java new file mode 100644 index 0000000..595077a --- /dev/null +++ b/common/src/main/java/flex/messaging/util/ExceptionUtil.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * + */ +public class ExceptionUtil +{ + /** + * List of no-arg methods that are known to return a wrapped throwable. + **/ + public static String[] unwrapMethods = { "getRootCause", "getTargetException", + "getTargetError", "getException", + "getCausedByException", "getLinkedException" }; + + /** + * Get the wrapped Exception object from the Throwable object. + * @param t the Throwable object + * @return Throwable the wrapped exception object if any + */ + public static Throwable wrappedException(Throwable t) + { + // Handle these statically since they are core to Java + return (t instanceof InvocationTargetException)? + ((InvocationTargetException)t).getTargetException() : getRootCauseWithReflection(t); + } + + /** + * Get to the base exception (if any). + * @param t the Throwable object + * @return the base Exception object + */ + public static Throwable baseException(Throwable t) + { + Throwable wrapped = wrappedException(t); + return wrapped != null? baseException(wrapped) : t; + } + + /** + * Return the stack trace in a String. + * @param t the Throwable object + * @return String the String presentation of the Throwable object + */ + public static String toString(Throwable t) + { + StringWriter strWrt = new StringWriter(); + t.printStackTrace(new PrintWriter(strWrt)); + + return strWrt.toString(); + } + + /** + * Return the stack trace up to the first line that starts with prefix. + * + * <p>Example: ExceptionUtil.getStackTraceUpTo(exception, "jrunx.");</p> + * @param t the Throwable object + * @param prefix the prefix message that we are looking for + * @return String the String of stack trace lines till the prefix message is located + */ + public static String getStackTraceUpTo(Throwable t, String prefix) + { + StringTokenizer tokens = new StringTokenizer(toString(t), "\n\r"); + StringBuffer trace = new StringBuffer(); + boolean done = false; + + String lookingFor = "at " + prefix; + while (!done && tokens.hasMoreElements()) + { + String token = tokens.nextToken(); + if (token.indexOf(lookingFor) == -1) + trace.append(token); + else + done = true; + trace.append(StringUtils.NEWLINE); + } + + return trace.toString(); + } + + /** + * return the top n lines of this stack trace. + * + * <p>Example: ExceptionUtil.getStackTraceLines(exception, 10);</p> + * @param t the Throwable object + * @param numLines number of lines we should trace down + * @return String the String of stack trace lines + */ + public static String getStackTraceLines(Throwable t, int numLines) + { + StringTokenizer tokens = new StringTokenizer(toString(t), "\n\r"); + + StringBuffer trace = new StringBuffer(); + + for (int i=0; i<numLines; i++) + { + String token = tokens.nextToken(); + trace.append(token); + trace.append(StringUtils.NEWLINE); + } + + return trace.toString(); + } + + /** + * Return the "nth" method call from the stack trace of "t", where 0 is + * the top. + * @param t the Throwable object + * @param nth the line number of the message should we skip + * @return String the callAt String + */ + public static String getCallAt(Throwable t, int nth) + { + StringTokenizer tokens = new StringTokenizer(toString(t), "\n\r"); + try + { + // Skip the first line - the exception message + for(int i = 0; i <= nth; ++i) + tokens.nextToken(); + + // get the method name from the next token + String token = tokens.nextToken(); + int index1 = token.indexOf(' '); + int index2 = token.indexOf('('); + StringBuffer call = new StringBuffer(); + call.append(token.substring(index1 < 0 ? 0 : index1 + 1, index2 < 0 ? call.length() : index2)); + + int index3 = token.indexOf(':', index2 < 0 ? 0 : index2); + if(index3 >= 0) + { + int index4 = token.indexOf(')', index3); + call.append(token.substring(index3, index4 < 0 ? token.length() : index4)); + } + return call.toString(); + } + catch(NoSuchElementException e) {} + + return "unknown"; + } + + + /** + * Utility method for converting an exception into a string. This + * method unwinds all wrapped exceptions + * @param t The throwable exception + * @return The printable exception + */ + public static String exceptionToString(Throwable t) + { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + + //print out the exception stack. + printExceptionStack(t, out, 0); + return sw.toString(); + } + + /** + * Utility method for converting an exception and all chained root causes into a + * string. Unlike <code>exceptionToString(Throwable)</code> which prints the chain + * from most nested root cause down to the top-level exception, this method prints + * from the top-level exception down to the most nested root cause. + * + * @param t The throwable exception. + * @return The printable exception. + */ + public static String exceptionFollowedByRootCausesToString(Throwable t) + { + StringBuffer output = new StringBuffer(); + Throwable root = t; + while (root != null) + { + output.append((root == t) ? ((root instanceof Exception) ? " Exception: " : " Error: ") : " Root cause: "); + output.append(ExceptionUtil.toString(root)); + // Do not recurse if the root cause has already been printed; this will have happened if the root cause has + // been assigned to the current Throwable via initCause() or as a constructor argument. + Throwable cause = root.getCause(); + root = ExceptionUtil.wrappedException(root); + if (cause == root) + break; + } + return output.toString(); + } + + /** + * Recursively prints out a stack of wrapped exceptions. + * + * @param th the Throwable object + * @param out the output writer to print to + * @param depth the number of levels the stack should be printed + */ + protected static void printExceptionStack(Throwable th, PrintWriter out, int depth){ + //only print the stack depth if the depth is greater than 0 + boolean printStackDepth = depth>0; + + Throwable wrappedException = ExceptionUtil.wrappedException(th); + if (wrappedException != null) + { + printStackDepth = true; + printExceptionStack(wrappedException, out, depth + 1); + } + + if(printStackDepth){ + out.write("[" + depth + "]"); + } + + th.printStackTrace(out); + } + + private static Throwable getRootCauseWithReflection(Throwable t) + { + for(int i = 0; i < unwrapMethods.length; i++) + { + Method m = null; + + try + { + m = t.getClass().getMethod(unwrapMethods[i], (Class[])null); + return (Throwable) m.invoke(t, (Object[])null); + } + catch(Exception nsme) + { + // ignore + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/FileUtils.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/FileUtils.java b/common/src/main/java/flex/messaging/util/FileUtils.java new file mode 100644 index 0000000..31e8d30 --- /dev/null +++ b/common/src/main/java/flex/messaging/util/FileUtils.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package flex.messaging.util; + +import java.io.IOException; +import java.io.InputStream; + +/** + * + */ +public class FileUtils +{ + public static final String UTF_8 = "UTF-8"; + public static final String UTF_16 = "UTF-16"; + + /** + * Sets a mark in the InputStream for 3 bytes to check for a BOM. If the BOM + * stands for UTF-8 encoded content then the stream will not be reset, otherwise + * for UTF-16 with a BOM or any other encoding situation the stream is reset to the + * mark (as for UTF-16 the parser will handle the BOM). + * + * @param in InputStream containing BOM and must support mark(). + * @param default_encoding The default character set encoding. null or "" => system default + * @return The file character set encoding. + * @throws IOException an IOException, if something went wrong. + */ + public static final String consumeBOM(InputStream in, String default_encoding) throws IOException + { + in.mark(3); + + // Determine file encoding... + // ASCII - no header (use the supplied encoding) + // UTF8 - EF BB BF + // UTF16 - FF FE or FE FF (decoder chooses endian-ness) + if (in.read() == 0xef && in.read() == 0xbb && in.read() == 0xbf) + { + // UTF-8 reader does not consume BOM, so do not reset + if (System.getProperty("flex.platform.CLR") != null) + { + return "UTF8"; + } + else + { + return UTF_8; + } + } + else + { + in.reset(); + int b0 = in.read(); + int b1 = in.read(); + if (b0 == 0xff && b1 == 0xfe || b0 == 0xfe && b1 == 0xff) + { + in.reset(); + // UTF-16 reader will consume BOM + if (System.getProperty("flex.platform.CLR") != null) + { + return "UTF16"; + } + else + { + return UTF_16; + } + } + else + { + // no BOM found + in.reset(); + if (default_encoding != null && default_encoding.length() != 0) + { + return default_encoding; + } + else + { + return System.getProperty("file.encoding"); + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/LocaleUtils.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/LocaleUtils.java b/common/src/main/java/flex/messaging/util/LocaleUtils.java new file mode 100644 index 0000000..5800433 --- /dev/null +++ b/common/src/main/java/flex/messaging/util/LocaleUtils.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +import java.util.Locale; + +/** + * + */ +public class LocaleUtils +{ + /** + * Builds a <code>Locale</code> instance from the passed string. If the string + * is <code>null</code> this method will return the default locale for the JVM. + * + * @param locale The locale as a string. + * @return The Locale instance built from the passed string. + */ + public static Locale buildLocale(String locale) + { + if (locale == null) + { + return Locale.getDefault(); + } + else + { + int index = locale.indexOf('_'); + if (index == -1) + { + return new Locale(locale); + } + String language = locale.substring(0, index); + String rest = locale.substring(index + 1); + index = rest.indexOf('_'); + if (index == -1) + { + return new Locale(language, rest); + } + String country = rest.substring(0, index); + rest = rest.substring(index + 1); + return new Locale(language, country, rest); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/ObjectTrace.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/ObjectTrace.java b/common/src/main/java/flex/messaging/util/ObjectTrace.java new file mode 100644 index 0000000..646d72f --- /dev/null +++ b/common/src/main/java/flex/messaging/util/ObjectTrace.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +import flex.messaging.log.Log; + +/** + * Simple utility to trace an Object graph out to a StringBuffer. + * + * Note that new lines are NOT added after the individual values + * in complex type properties. + * + * + */ +public class ObjectTrace +{ + + + /* This boolean is used for suppressing debug output for selected properties. + * The logger will check this before printing a property. + */ + public boolean nextElementExclude; + + public ObjectTrace() + { + buffer = new StringBuffer(4096); + } + + public ObjectTrace(int bufferSize) + { + buffer = new StringBuffer(bufferSize); + } + + public String toString() + { + return buffer.toString(); + } + + public void write(Object o) + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append(String.valueOf(o)); + } + + public void writeNull() + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append("null"); + } + + public void writeRef(int ref) + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append("(Ref #").append(ref).append(")"); + } + + public void writeString(String s) + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append("\"").append(s).append("\""); + } + + public void startArray(String header) + { + if (header != null && header.length() > 0) + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append(header).append(newLine); + } + + m_indent++; + m_nested++; + } + + public void arrayElement(int index) + { + buffer.append(indentString()).append("[").append(index).append("] = "); + } + + public void endArray() + { + m_indent--; + m_nested--; + } + + public void startObject(String header) + { + if (header != null && header.length() > 0) + { + if (m_nested <= 0) + buffer.append(indentString()); + + buffer.append(header).append(newLine); + } + + m_indent++; + m_nested++; + } + + public void namedElement(String name) + { + if (Log.isExcludedProperty(name)) + { + nextElementExclude = true; + } + + buffer.append(indentString()).append(name).append(" = "); + } + + public void endObject() + { + m_indent--; + m_nested--; + } + + public void newLine() + { + boolean alreadyPadded = false; + int length = buffer.length(); + + if (length > 3) + { + String tail = buffer.substring(length - 3, length - 1); //Get last two chars in buffer + alreadyPadded = tail.equals(newLine); + } + + if (!alreadyPadded) + buffer.append(newLine); + } + + /** + * Uses the static member, m_indent to create a string of spaces of + * the appropriate indentation. + * + * @return the ident string. + */ + protected String indentString() + { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < m_indent; ++i) + { + sb.append(" "); + } + return sb.toString(); + } + + protected StringBuffer buffer; + protected int m_indent; + protected int m_nested; + public static String newLine = StringUtils.NEWLINE; +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/PrettyPrintable.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/PrettyPrintable.java b/common/src/main/java/flex/messaging/util/PrettyPrintable.java new file mode 100644 index 0000000..68fcc6e --- /dev/null +++ b/common/src/main/java/flex/messaging/util/PrettyPrintable.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +/** + * Allows an Object to customize how it is pretty printed in + * logging/debugging output. + * + * + */ +public interface PrettyPrintable +{ + String toStringHeader(); + + String toStringCustomProperty(String name); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/util/PrettyPrinter.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/util/PrettyPrinter.java b/common/src/main/java/flex/messaging/util/PrettyPrinter.java new file mode 100644 index 0000000..d0f9de0 --- /dev/null +++ b/common/src/main/java/flex/messaging/util/PrettyPrinter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.util; + +/** + * Implementations convert Object graphs to Strings for + * logging and debugging. + * + * + */ +public interface PrettyPrinter +{ + String prettify(Object o); + + Object copy(); +}