Author: tomekr
Date: Wed Oct  7 12:52:09 2015
New Revision: 1707283

URL: http://svn.apache.org/viewvc?rev=1707283&view=rev
Log:
SLING-4544 Performance: MessageFormat shouldn't be used for logging in 
SlingRequestProgressTracker

Added:
    
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/FastMessageFormat.java
    
sling/trunk/bundles/engine/src/test/java/org/apache/sling/engine/impl/request/FastMessageFormatTest.java
Modified:
    
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/SlingRequestProgressTracker.java

Added: 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/FastMessageFormat.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/FastMessageFormat.java?rev=1707283&view=auto
==============================================================================
--- 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/FastMessageFormat.java
 (added)
+++ 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/FastMessageFormat.java
 Wed Oct  7 12:52:09 2015
@@ -0,0 +1,101 @@
+/*
+ * 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 org.apache.sling.engine.impl.request;
+
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.util.Date;
+
+/**
+ * Fast MessageFormat implementation which is not thread-safe. It is based on 
the assumptions that
+ * <ul>
+ *     <li>most formats do not contain format types and styles</li>
+ *     <li>do not use escaping</li>
+ *     <li>format elements are in order</li>
+ * </ul>
+ *
+ * If one of these assumptions fails, then it falls back to the original 
{@link MessageFormat}.<br>
+ * To increase the benefit of this implementation, every instance should be 
reused as often as possible.
+ */
+public class FastMessageFormat {
+
+    // Reusable formats instances. Cannot be static because these classes are 
not thread safe.
+    private NumberFormat numberFormat;
+    private DateFormat dateFormat;
+
+    private NumberFormat getNumberFormat() {
+        if (numberFormat == null) {
+            numberFormat = NumberFormat.getNumberInstance();
+        }
+        return numberFormat;
+    }
+
+    private DateFormat getDateFormat() {
+        if (dateFormat == null) {
+            dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, 
DateFormat.SHORT);
+        }
+        return dateFormat;
+    }
+
+    /**
+     * Use this method exactly like {@link MessageFormat#format(String, 
Object...)}.
+     *
+     * @see MessageFormat#format(String, Object...)
+     */
+    public String format(String pattern, Object... arguments) {
+        if (arguments == null || arguments.length == 0) {
+            return pattern;
+        } else {
+            if (pattern.indexOf('\'') != -1) {
+                // Escaping is not supported, fall back
+                return MessageFormat.format(pattern, arguments);
+            } else {
+                StringBuilder message = new StringBuilder();
+                int previousEnd = 0;
+                for (int i = 0; i < arguments.length; i++) {
+                    String placeholder = '{' + String.valueOf(i);
+                    int placeholderIndex = pattern.indexOf(placeholder);
+                    // -1 or before previous placeholder || format element 
with type/style
+                    if (placeholderIndex < previousEnd
+                            || pattern.charAt(placeholderIndex + 
placeholder.length()) != '}') {
+                        // Type, style and random order are not supported, 
fall back
+                        return MessageFormat.format(pattern, arguments);
+                    } else {
+                        // Format argument if necessary
+                        Object argument = arguments[i];
+                        if (argument instanceof Number) {
+                            argument = getNumberFormat().format(argument);
+                        } else if (argument instanceof Date) {
+                            argument = getDateFormat().format(argument);
+                        }
+
+                        // Append previous part of the string and formatted 
argument
+                        message.append(pattern.substring(previousEnd, 
placeholderIndex));
+                        message.append(argument);
+                        previousEnd = placeholderIndex + placeholder.length() 
+ 1;
+                    }
+                }
+                message.append(pattern.substring(previousEnd, 
pattern.length()));
+                return message.toString();
+            }
+        }
+    }
+
+}

Modified: 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/SlingRequestProgressTracker.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/SlingRequestProgressTracker.java?rev=1707283&r1=1707282&r2=1707283&view=diff
==============================================================================
--- 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/SlingRequestProgressTracker.java
 (original)
+++ 
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/SlingRequestProgressTracker.java
 Wed Oct  7 12:52:09 2015
@@ -19,7 +19,6 @@
 package org.apache.sling.engine.impl.request;
 
 import java.io.PrintWriter;
-import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -129,6 +128,8 @@ public class SlingRequestProgressTracker
      */
     private final Map<String, Long> namedTimerEntries = new HashMap<String, 
Long>();
 
+    private final FastMessageFormat messageFormat = new FastMessageFormat();
+
     /**
      * Creates a new request progress tracker.
      */
@@ -210,7 +211,7 @@ public class SlingRequestProgressTracker
 
     /** Creates an entry with the given entry tag and message */
     public void log(String format, Object... args) {
-        String message = MessageFormat.format(format, args);
+        String message = messageFormat.format(format, args);
         entries.add(new TrackingEntry(LOG_PREFIX + message));
     }
 
@@ -250,7 +251,7 @@ public class SlingRequestProgressTracker
      */
     public void logTimer(String name, String format, Object... args) {
         if (namedTimerEntries.containsKey(name)) {
-            logTimerInternal(name, MessageFormat.format(format, args), 
namedTimerEntries.get(name));
+            logTimerInternal(name, messageFormat.format(format, args), 
namedTimerEntries.get(name));
         }
     }
 

Added: 
sling/trunk/bundles/engine/src/test/java/org/apache/sling/engine/impl/request/FastMessageFormatTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/test/java/org/apache/sling/engine/impl/request/FastMessageFormatTest.java?rev=1707283&view=auto
==============================================================================
--- 
sling/trunk/bundles/engine/src/test/java/org/apache/sling/engine/impl/request/FastMessageFormatTest.java
 (added)
+++ 
sling/trunk/bundles/engine/src/test/java/org/apache/sling/engine/impl/request/FastMessageFormatTest.java
 Wed Oct  7 12:52:09 2015
@@ -0,0 +1,82 @@
+/*
+ * 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 org.apache.sling.engine.impl.request;
+
+import org.junit.Test;
+
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+
+import static org.junit.Assert.assertEquals;
+
+public class FastMessageFormatTest {
+
+    @Test
+    public void testFormat() {
+        FormatTest[] tests = {
+                // Data types
+                new FormatTest("{0}", 1),
+                new FormatTest("{0}", Integer.MAX_VALUE),
+                new FormatTest("{0}", Long.MAX_VALUE),
+                new FormatTest("{0}", Math.PI),
+                new FormatTest("{0}", 123456.123456),
+                new FormatTest("{0}", Float.MAX_VALUE),
+                new FormatTest("{0}", new Date()),
+                new FormatTest("{0}", Calendar.getInstance()),
+                new FormatTest("{0}", true),
+                new FormatTest("{0}", false),
+                new FormatTest("{0}", new int[] {1,2,3}),
+                new FormatTest("{0}", (Object) new Integer[] {1,2,3}),
+                new FormatTest("{0}", Arrays.asList(1, 2, 3)),
+                new FormatTest("{0}", "text"),
+
+                // Patterns
+                new FormatTest("{0}{0}", 1, 2),
+                new FormatTest("a{0}b{1}c", 1, 2),
+                new FormatTest("a{0}b{1}c{2}d", 1, 2, 3),
+                new FormatTest("a{0}bb{1}ccc{2}dddd", 10, 20, 30),
+                new FormatTest("c{1}b{0}a", 1, 2),
+                new FormatTest("c{1}b{0}a{1}c", 1, 2),
+
+                // Type/style
+                new FormatTest("c{0,number,#.##}b{0}a{1}c", 1, 2),
+                new FormatTest("{0,number,#.##}", 1.2345),
+
+                // Escaping
+                new FormatTest("'{0}'", 1)
+        };
+
+        FastMessageFormat fastMessageFormat = new FastMessageFormat();
+        for (FormatTest test : tests) {
+            String expected = MessageFormat.format(test.pattern, test.args);
+            String actual = fastMessageFormat.format(test.pattern, test.args);
+            assertEquals(expected, actual);
+        }
+    }
+
+    private static class FormatTest {
+        final String pattern;
+        final Object[] args;
+        public FormatTest(String pattern, Object... args) {
+            this.pattern = pattern;
+            this.args = args;
+        }
+    }
+
+}


Reply via email to