http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/common/src/flex/messaging/log/Logger.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/log/Logger.java b/common/src/flex/messaging/log/Logger.java new file mode 100644 index 0000000..8684a3e --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/log/Target.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/log/Target.java b/common/src/flex/messaging/log/Target.java new file mode 100644 index 0000000..7a39fb5 --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/BasicPrettyPrinter.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/BasicPrettyPrinter.java b/common/src/flex/messaging/util/BasicPrettyPrinter.java new file mode 100644 index 0000000..19fa547 --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/ExceptionUtil.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/ExceptionUtil.java b/common/src/flex/messaging/util/ExceptionUtil.java new file mode 100644 index 0000000..595077a --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/FileUtils.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/FileUtils.java b/common/src/flex/messaging/util/FileUtils.java new file mode 100644 index 0000000..31e8d30 --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/LocaleUtils.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/LocaleUtils.java b/common/src/flex/messaging/util/LocaleUtils.java new file mode 100644 index 0000000..5800433 --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/ObjectTrace.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/ObjectTrace.java b/common/src/flex/messaging/util/ObjectTrace.java new file mode 100644 index 0000000..646d72f --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/PrettyPrintable.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/PrettyPrintable.java b/common/src/flex/messaging/util/PrettyPrintable.java new file mode 100644 index 0000000..68fcc6e --- /dev/null +++ b/common/src/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/bf2e1dc9/common/src/flex/messaging/util/PrettyPrinter.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/PrettyPrinter.java b/common/src/flex/messaging/util/PrettyPrinter.java new file mode 100644 index 0000000..d0f9de0 --- /dev/null +++ b/common/src/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(); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/common/src/flex/messaging/util/PropertyStringResourceLoader.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/PropertyStringResourceLoader.java b/common/src/flex/messaging/util/PropertyStringResourceLoader.java new file mode 100644 index 0000000..21c2f59 --- /dev/null +++ b/common/src/flex/messaging/util/PropertyStringResourceLoader.java @@ -0,0 +1,378 @@ +/* + * 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.InputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.Locale; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; + +import flex.messaging.log.Log; +import flex.messaging.log.Logger; +import flex.messaging.log.LogCategories; + +/** + * Implementation of <code>ResourceLoader</code> that loads string resources + * from property files. + * <p> + * This class uses <code>MessageFormat</code> to perform substitutions + * within parameterized strings. + * </p> + * + * @see MessageFormat + * + */ +public class PropertyStringResourceLoader implements ResourceLoader +{ + // The property file bundle that contains localized error strings for BlazeDS. + public static final String PROPERTY_BUNDLE = "flex/messaging/errors"; + + // The property file bundle that contains localized error strings for BlazeDS + // code specific to vendors (eg. LoginCommands for specific application serves) + public static final String VENDORS_BUNDLE = "flex/messaging/vendors"; + + // The property file bundle that contains localized error strings for LCDS. + public static final String LCDS_PROPERTY_BUNDLE = "flex/data/errors"; + + // The category to write log entries under. + private static final String LOG_CATEGORY = LogCategories.RESOURCE; + + // The property bundle names to use in string lookups. + private String[] propertyBundles; + + // The default FDS locale. + private Locale defaultLocale; + + // The set of locales that have strings loaded. + private Set loadedLocales = new TreeSet(); + + // A map of all loaded strings. + private Map strings = new HashMap(); + + // The logger for this instance. + private Logger logger; + + /** + * Constructs a <code>PropertyStringResourceLoader</code> using the default + * property bundles specified by the <code>PROPERTY_BUNDLE</code> and + * <code>LCDS_PROPERTY_BUNDLE</code> fields. + */ + public PropertyStringResourceLoader() + { + this(new String[] {PROPERTY_BUNDLE, LCDS_PROPERTY_BUNDLE}); + } + + /** + * Constructs a <code>PropertyStringResourceLoader</code> that will use the + * specified property bundle to use for string lookups. + * + * @param propertyBundle The property bundles to use for lookups. + */ + public PropertyStringResourceLoader(String propertyBundle) + { + this(new String[] {propertyBundle}); + } + + /** + * Constructs a <code>PropertyStringResourceLoader</code> that will use the + * specified property bundles to use for string lookups. + * + * @param propertyBundles The list of the property bundles to use for lookups. + */ + public PropertyStringResourceLoader(String[] propertyBundles) + { + this.propertyBundles = propertyBundles; + logger = Log.getLogger(LOG_CATEGORY); + } + + // Implements flex.messaging.util.ResourceLoader.init; inherits javadoc specification. + public void init(Map properties) + {} + + // Implements flex.messaging.util.ResourceLoader.getString; inherits javadoc specification. + public String getString(String key) + { + return getString(key, null, null); + } + + // Implements flex.messaging.util.ResourceLoader.getString; inherits javadoc specification. + public String getString(String key, Object[] arguments) + { + return getString(key, null, arguments); + } + + // Implements flex.messaging.util.ResourceLoader.getString; inherits javadoc specification. + public String getString(String key, Locale locale) + { + return getString(key, locale, null); + } + + // Implements flex.messaging.util.ResourceLoader.getString; inherits javadoc specification. + public String getString(String key, Locale locale, Object[] arguments) + { + synchronized(strings) + { + if (defaultLocale == null) + { + defaultLocale = getDefaultLocale(); + } + } + String value = null; + String stringKey = null; + String localeKey = (locale != null) ? + generateLocaleKey(locale) : + generateLocaleKey(defaultLocale); + String originalStringKey = generateStringKey(key, localeKey); + int trimIndex = 0; + + /* + * Attempt to get a string for the target locale - fail back to less specific + * versions of the locale. + */ + while (true) + { + loadStrings(localeKey); + stringKey = generateStringKey(key, localeKey); + synchronized(strings) + { + value = (String) strings.get(stringKey); + if (value != null) + { + if (!stringKey.equals(originalStringKey)) + { + strings.put(originalStringKey, value); + } + return substituteArguments(value, arguments); + } + } + trimIndex = localeKey.lastIndexOf('_'); + if (trimIndex != -1) + { + localeKey = localeKey.substring(0, trimIndex); + } + else + { + break; + } + } + + /* + * Attempt to get the string in our default locale if it is + * different than the requested locale. + */ + if ((locale != null) && (!locale.equals(defaultLocale))) + { + localeKey = generateLocaleKey(defaultLocale); + stringKey = generateStringKey(key, localeKey); + synchronized(strings) + { + value = (String) strings.get(stringKey); + if (value != null) + { + strings.put(originalStringKey, value); + return substituteArguments(value, arguments); + } + } + } + + // As a last resort, try to get a non-locale-specific string. + loadStrings(""); + stringKey = generateStringKey(key, ""); + synchronized(strings) + { + value = (String) strings.get(stringKey); + if (value != null) + { + strings.put(originalStringKey, value); + return substituteArguments(value, arguments); + } + } + + // No string is available. Return a formatted missing string value. + return ("???" + key + "???"); + } + + /** + * Sets the default locale to be used when locating resources. The + * string will be converted into a Locale. + * + * @param locale The default locale to be used. + */ + public void setDefaultLocale(String locale) + { + defaultLocale = LocaleUtils.buildLocale(locale); + } + + /** + * Sets the default locale to be used when locating resources. + * + * @param locale The default locale to be used. + */ + public void setDefaultLocale(Locale locale) + { + defaultLocale = locale; + } + + /** + * The default locale to be used when locating resources. + * @return Locale the default Locale object + */ + public Locale getDefaultLocale() + { + if (defaultLocale == null) + defaultLocale = Locale.getDefault(); + + return defaultLocale; + } + + /** + * Loads localized strings for the specified locale from a property file. + * + * @param localeKey The locale to load strings for. + */ + protected synchronized void loadStrings(String localeKey) + { + if (loadedLocales.contains(localeKey)) + { + return; + } + + if (propertyBundles != null) + { + for (int i = 0; i < propertyBundles.length; i++) + { + String propertyBundle = propertyBundles[i]; + loadProperties(localeKey, propertyBundle); + } + } + } + + protected InputStream loadFile(String filename) + { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + InputStream stream = loader.getResourceAsStream(filename); + + // Try the properties file in our classloader too - just in case + if (stream == null) + { + stream = PropertyStringResourceLoader.class.getClassLoader().getResourceAsStream(filename); + } + + return stream; + } + + // Helper method for loadStrings. + protected void loadProperties(String localeKey, String propertyBundle) + { + // Build the path to the target property file. + String filename = propertyBundle; + if (localeKey.length() > 0) + { + filename += "_" + localeKey; + } + filename += ".properties"; + // Load the property file. + InputStream stream = loadFile(filename); + + Properties props = new Properties(); + if (stream != null) + { + try + { + props.load(stream); + } + catch (IOException ioe) + { + logger.warn("There was a problem reading the string resource property file '" + filename + "' stream.", ioe); + } + catch (IllegalArgumentException iae) + { + logger.warn("The string resource property file '" + filename + "' contains a malformed Unicode escape sequence.", iae); + } + finally + { + try + { + stream.close(); + } + catch (IOException ioe) + { + logger.warn("The string resource property file '" + filename + "' stream failed to close.", ioe); + } + } + } + else + { + logger.warn("The class loader could not locate the string resource property file '" + filename + "'. This may not be an issue if a property file is available for a less specific locale or the default locale."); + } + // Move strings into string cache. + if (props.size() > 0) + { + synchronized(strings) + { + Iterator iter = props.keySet().iterator(); + while (iter.hasNext()) + { + String key = (String) iter.next(); + strings.put(generateStringKey(key, localeKey), props.getProperty(key)); + } + } + } + } + + /** + * Generates a locale cache key. + * + * @param locale The locale to generate a cache key for. + * @return The generated cache key. + */ + private String generateLocaleKey(Locale locale) + { + return (locale == null) ? "" : locale.toString(); + } + + /** + * Generates a cache key for a string resource. + * + * @param key The string to generate a cache key for. + * @param locale The locale to retrieve the string for. + * @return The generated cache key for the string resource. + */ + private String generateStringKey(String key, String locale) + { + return (key + "-" + locale); + } + + /** + * Substitutes the specified arguments into a parameterized string. + * + * @param parameterized The string containing parameter tokens for substitution. + * @param arguments The arguments to substitute into the parameterized string. + * @return The resulting substituted string. + */ + private String substituteArguments(String parameterized, Object[] arguments) + { + return MessageFormat.format(parameterized, arguments).trim(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/common/src/flex/messaging/util/ResourceLoader.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/ResourceLoader.java b/common/src/flex/messaging/util/ResourceLoader.java new file mode 100644 index 0000000..e980f4b --- /dev/null +++ b/common/src/flex/messaging/util/ResourceLoader.java @@ -0,0 +1,104 @@ +/* + * 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; +import java.util.Map; + +/** + * The root interface for classes that provide access to localized resources. + * + * + */ +public interface ResourceLoader +{ + /** + * Initializes the <code>ResourceLoader</code> using the specified properties. + * + * @param properties The initialization properties. + */ + void init(Map properties); + + /** + * Sets the default locale to be used when locating resources. The + * string will be converted into a Locale. + * + * @param locale The default locale to be used. + */ + void setDefaultLocale(String locale); + + /** + * Sets the default locale to be used when locating resources. + * + * @param locale The default locale to be used. + */ + void setDefaultLocale(Locale locale); + + /** + * The default locale to be used when locating resources. + * + * @return The default locale. + */ + Locale getDefaultLocale(); + + /** + * Gets a string for the given key. + * + * @param key The key for the target string. + * @return The string for the given key. + */ + String getString(String key); + + /** + * Gets a parameterized string for the given key and substitutes + * the parameters using the passed array of arguments. + * + * @param key The key for the target string. + * @param arguments The arguments to substitute into the parameterized string. + * @return The substituted string for the given key. + * @exception IllegalArgumentException If the parameterized string is invalid, + * or if an argument in the <code>arguments</code> array + * is not of the type expected by the format element(s) + * that use it. + */ + String getString(String key, Object[] arguments); + + /** + * Gets a string for the given key and locale. + * + * @param key The key for the target string. + * @param locale The target locale for the string. + * @return The localized string for the given key. + */ + String getString(String key, Locale locale); + + /** + * Gets a parameterized string for the given key and locale and substitutes the + * parameters using the passed array of arguments. + * + * @param key The key for the target string. + * @param locale The target locale for the string. + * @param arguments The arguments to substitute into the parameterized string. + * @return The substituted localized string for the given key. + * @exception IllegalArgumentException If the parameterized string is invalid, + * or if an argument in the <code>arguments</code> array + * is not of the type expected by the format element(s) + * that use it. + */ + String getString(String key, Locale locale, Object[] arguments); + +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/common/src/flex/messaging/util/StringUtils.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/StringUtils.java b/common/src/flex/messaging/util/StringUtils.java new file mode 100644 index 0000000..5a33f2e --- /dev/null +++ b/common/src/flex/messaging/util/StringUtils.java @@ -0,0 +1,214 @@ +/* + * 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.StringReader; +import java.io.StringWriter; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +/** + * + */ +public class StringUtils +{ + /** + * The String to use for an OS specific line separator. + */ + public static final String NEWLINE = System.getProperty("line.separator"); + + public static String substitute(String str, String from, String to) + { + if (from == null || from.equals("") || to == null) + return str; + + int index = str.indexOf(from); + + if (index == -1) + return str; + + StringBuffer buf = new StringBuffer(str.length()); + int lastIndex = 0; + + while (index != -1) + { + buf.append(str.substring(lastIndex, index)); + buf.append(to); + lastIndex = index + from.length(); + index = str.indexOf(from, lastIndex); + } + + // add in last chunk + buf.append(str.substring(lastIndex)); + + return buf.toString(); + } + + public static boolean findMatchWithWildcard(char[] src, char[] pat) + { + if (src == null || pat == null) + return false; + + // we consider an empty pattern to be a don't-match-anything pattern + if (pat.length == 0) + return false; + + if (src.length == 0) + return (pat.length == 0 || (pat.length == 1 && (pat[0] == '*' || pat[0] == '?'))); + + boolean star = false; + + int srcLen = src.length; + int patLen = pat.length; + int srcIdx = 0; + int patIdx = 0; + + for (; srcIdx < srcLen; srcIdx++) + { + if (patIdx == patLen) + { + if (patLen < (srcLen - srcIdx)) + patIdx = 0; //Start the search again + else + return false; + } + + char s = src[srcIdx]; + char m = pat[patIdx]; + + switch (m) + { + case '*': + // star on the end + if (patIdx == pat.length - 1) + return true; + star = true; + ++patIdx; + break; + + case '?': + ++patIdx; + break; + + default: + if (s != m) + { + if (!star) + { + if (patLen < (srcLen - srcIdx)) + patIdx = 0; //Start the search again + else + return false; + } + } + else + { + star = false; + ++patIdx; + } + break; + } + } + + if (patIdx < patLen) + { + //read off the rest of the pattern and make sure it's all wildcard + for (; patIdx < patLen; patLen++) + { + if (pat[patIdx] != '*') + { + return false; + } + } + return true; + } + + + return !star; + } + + /** + * Returns a prettified version of the XML, with indentations and + * linefeeds. Returns the original string if there was an error. + * @param xml the xml string + * @return String the prettified xml string + */ + public static String prettifyXML(String xml) + { + String result = xml; + try + { + StringReader reader = new StringReader(xml); + StringWriter writer = new StringWriter(); + Transformer transformer = + TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.transform + (new StreamSource(reader), new StreamResult(writer)); + writer.close(); + + result = writer.toString(); + } + catch (TransformerFactoryConfigurationError error) + { + // Ignore. + } + catch (TransformerException error) + { + // Ignore. + } + catch (IOException error) + { + // Ignore. + } + return result; + } + + /** + * Returns a prettified version of the string, or the original + * string if the operation is not possible. + * @param string the string to check + * @return String the prettified string + */ + public static String prettifyString(String string) + { + String result = string; + if (string.startsWith("<?xml")) + { + result = prettifyXML(string); + } + return result; + } + + /** + * Returns true if a string is null or empty. + * @param string the String to check + * @return boolean true if the string is an empty string + */ + public static boolean isEmpty(String string) + { + return string == null || string.length() == 0; + } +} + http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/common/src/flex/messaging/util/UUIDUtils.java ---------------------------------------------------------------------- diff --git a/common/src/flex/messaging/util/UUIDUtils.java b/common/src/flex/messaging/util/UUIDUtils.java new file mode 100644 index 0000000..9fd3c57 --- /dev/null +++ b/common/src/flex/messaging/util/UUIDUtils.java @@ -0,0 +1,330 @@ +/* + * 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.Random; +import java.util.UUID; + +public class UUIDUtils +{ + private static Random _weakRand = new Random(); + + /** + * The spec indicates that our time value should be based on 100 nano + * second increments but our time granularity is in milliseconds. + * The spec also says we can approximate the time by doing an increment + * when we dole out new ids in the same millisecond. We can fit 10,000 + * 100 nanos into a single millisecond. + */ + private static final int MAX_IDS_PER_MILLI = 10000; + + /** + * Any given time-of-day value can only be used once; remember the last used + * value so we don't reuse them. + * <p>NOTE: this algorithm assumes the clock will not be turned back. + */ + private static long lastUsedTOD = 0; + /** Counter to use when we need more than one id in the same millisecond. */ + private static int numIdsThisMilli = 0; + + /** Hex digits, used for padding UUID strings with random characters. */ + private static final String alphaNum = "0123456789ABCDEF"; + + /** 4 bits per hex character. */ + private static final int BITS_PER_DIGIT = 4; + + private static final int BITS_PER_INT = 32; + private static final int BITS_PER_LONG = 64; + private static final int DIGITS_PER_INT = BITS_PER_INT / BITS_PER_DIGIT; + private static final int DIGITS_PER_LONG = BITS_PER_LONG / BITS_PER_DIGIT; + + /** + * @private + */ + private static char[] UPPER_DIGITS = new char[] { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + }; + + /** + * Private constructor to prevent instances from being created. + */ + private UUIDUtils() + { + } + + /** + * + * Use the createUUID function when you need a unique string that you will + * use as a persistent identifier in a distributed environment. To a very + * high degree of certainty, this function returns a unique value; no other + * invocation on the same or any other system should return the same value. + * + * @return a Universally Unique Identifier (UUID) + * Proper Format: `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' + * where `X' stands for a hexadecimal digit (0-9 or A-F). + */ + public static String createUUID() + { + return createUUID(false); + } + + public static String createUUID(boolean secure) throws Error + { + Random rand = _weakRand; + if (secure) + throw new Error("Secure UUIDs not implemented"); + + StringBuffer s = new StringBuffer(36); + + appendHexString(uniqueTOD(), false, 11, s); + + // Just use random padding characters, but ensure that the high bit + // is set to eliminate chances of collision with an IEEE 802 address. + s.append( alphaNum.charAt( rand.nextInt(16) | 8 ) ); + + // Add random padding characters. + appendRandomHexChars(32 - s.length(), rand, s); + + //insert dashes in proper position. so the format matches CF + s.insert(8,"-"); + s.insert(13,"-"); + s.insert(18,"-"); + s.insert(23,"-"); + + return s.toString(); + } + + /** + * Converts a 128-bit UID encoded as a byte[] to a String representation. + * The format matches that generated by createUID. If a suitable byte[] + * is not provided, null is returned. + * + * @param ba byte[] 16 bytes in length representing a 128-bit UID. + * + * @return String representation of the UID, or null if an invalid + * byte[] is provided. + */ + public static String fromByteArray(byte[] ba) + { + if (ba == null || ba.length != 16) + return null; + + StringBuffer result = new StringBuffer(36); + for (int i = 0; i < 16; i++) + { + if (i == 4 || i == 6 || i == 8 || i == 10) + result.append('-'); + + result.append(UPPER_DIGITS[(ba[i] & 0xF0) >>> 4]); + result.append(UPPER_DIGITS[(ba[i] & 0x0F)]); + } + return result.toString(); + } + + + /** + * A utility method to check whether a String value represents a + * correctly formatted UID value. UID values are expected to be + * in the format generated by createUID(), implying that only + * capitalized A-F characters in addition to 0-9 digits are + * supported. + * + * @param uid The value to test whether it is formatted as a UID. + * + * @return Returns true if the value is formatted as a UID. + */ + public static boolean isUID(String uid) + { + if (uid == null || uid.length() != 36) + return false; + + char[] chars = uid.toCharArray(); + for (int i = 0; i < 36; i++) + { + char c = chars[i]; + + // Check for correctly placed hyphens + if (i == 8 || i == 13 || i == 18 || i == 23) + { + if (c != '-') + return false; + } + // We allow capital alpha-numeric hex digits only + else if (c < 48 || c > 70 || (c > 57 && c < 65)) + { + return false; + } + } + + return true; + } + + /** + * Converts a UID formatted String to a byte[]. The UID must be in the + * format generated by createUID, otherwise null is returned. + * + * @param uid String representing a 128-bit UID. + * + * @return byte[] 16 bytes in length representing the 128-bits of the + * UID or null if the uid could not be converted. + */ + public static byte[] toByteArray(String uid) + { + if (!isUID(uid)) + return null; + + byte[] result = new byte[16]; + char[] chars = uid.toCharArray(); + int r = 0; + + for (int i = 0; i < chars.length; i++) + { + if (chars[i] == '-') + continue; + int h1 = Character.digit(chars[i], 16); + i++; + int h2 = Character.digit(chars[i], 16); + result[r++] = (byte)(((h1 << 4) | h2) & 0xFF); + } + return result; + } + + private static void appendRandomHexChars(int n, Random rand, StringBuffer result) + { + int digitsPerInt = DIGITS_PER_INT; + while (n > 0) + { + int digitsToUse = Math.min(n, digitsPerInt); + n -= digitsToUse; + appendHexString(rand.nextInt(), true, digitsToUse, result); + } + } + + private static void appendHexString + (long value, boolean prependZeroes, int nLeastSignificantDigits, + StringBuffer result) + { + int bitsPerDigit = BITS_PER_DIGIT; + + long mask = (1L << bitsPerDigit) - 1; + + if (nLeastSignificantDigits < DIGITS_PER_LONG) + { + // Clear the bits that we don't care about. + value &= (1L << (bitsPerDigit * nLeastSignificantDigits)) - 1; + } + + // Reorder the sequence so that the first set of bits will become the + // last set of bits. + int i = 0; + long reorderedValue = 0; + if (value == 0) + { + // One zero is dumped. + i++; + } + else + { + do + { + reorderedValue = (reorderedValue << bitsPerDigit) | (value & mask); + value >>>= bitsPerDigit; + i++; + } while (value != 0); + } + + if (prependZeroes) + { + for (int j = nLeastSignificantDigits - i; j > 0; j--) + { + result.append('0'); + } + } + + + // Dump the reordered sequence, with the most significant character + // first. + for (; i > 0; i--) + { + result.append(alphaNum.charAt((int) (reorderedValue & mask))); + reorderedValue >>>= bitsPerDigit; + } + } + + private static String createInsecureUUID() + { + StringBuffer s = new StringBuffer(36); + + appendHexString(uniqueTOD(), false, 11, s); + + // Just use random padding characters, but ensure that the high bit + // is set to eliminate chances of collision with an IEEE 802 address. + s.append( alphaNum.charAt( _weakRand.nextInt(16) | 8 ) ); + + // Add random padding characters. + appendRandomHexChars(32 - s.length(), _weakRand, s); + + //insert dashes in proper position. so the format matches CF + s.insert(8,"-"); + s.insert(13,"-"); + s.insert(18,"-"); + s.insert(23,"-"); + + return s.toString(); + } + + /** + * @return a time value, unique for calls to this method loaded by the same classloader. + */ + private static synchronized long uniqueTOD() + { + long currentTOD = System.currentTimeMillis(); + + // Clock was set back... do not hang in this case waiting to catch up. + // Instead, rely on the random number part to differentiate the ids. + if (currentTOD < lastUsedTOD) + lastUsedTOD = currentTOD; + + if (currentTOD == lastUsedTOD) + { + numIdsThisMilli++; + /* + * Fall back to the old technique of sleeping if we allocate + * too many ids in one time interval. + */ + if (numIdsThisMilli >= MAX_IDS_PER_MILLI) + { + while ( currentTOD == lastUsedTOD ) + { + try { Thread.sleep(1); } catch ( Exception interrupt ) { /* swallow, wake up */ } + currentTOD = System.currentTimeMillis(); + } + lastUsedTOD = currentTOD; + numIdsThisMilli = 0; + } + } + else + { + // We have a new TOD, reset the counter + lastUsedTOD = currentTOD; + numIdsThisMilli = 0; + } + + return lastUsedTOD * MAX_IDS_PER_MILLI + (long)numIdsThisMilli; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/AdobeInfo.xml ---------------------------------------------------------------------- diff --git a/core/AdobeInfo.xml b/core/AdobeInfo.xml new file mode 100755 index 0000000..19a7eaa --- /dev/null +++ b/core/AdobeInfo.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> + <manifest version="1.0"> + <versioninfo> + <build AdobeIPNumber="0000494"/> + </versioninfo> +</manifest> \ No newline at end of file
