Repository: tapestry-5
Updated Branches:
  refs/heads/master 48d1f6409 -> fa691e262


Extract ExceptionReportWriter from ExceptionReporterImpl

Do a better job formatting the output, and display session attributes if 
present.


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ede56bc6
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ede56bc6
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ede56bc6

Branch: refs/heads/master
Commit: ede56bc6fb85694b969a1ffd348960e72a04f936
Parents: 48d1f64
Author: Howard M. Lewis Ship <hls...@apache.org>
Authored: Wed Dec 31 16:45:37 2014 -0800
Committer: Howard M. Lewis Ship <hls...@apache.org>
Committed: Wed Dec 31 16:45:37 2014 -0800

----------------------------------------------------------------------
 .../exceptions/ExceptionReportWriterImpl.java   | 313 +++++++++++++++++++
 .../exceptions/ExceptionReporterImpl.java       | 251 +--------------
 .../tapestry5/modules/TapestryModule.java       |  15 +-
 .../services/ExceptionReportWriter.java         |  38 +++
 .../tapestry5/services/ExceptionReporter.java   |   4 +-
 5 files changed, 369 insertions(+), 252 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ede56bc6/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReportWriterImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReportWriterImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReportWriterImpl.java
new file mode 100644
index 0000000..51909b8
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReportWriterImpl.java
@@ -0,0 +1,313 @@
+// Licensed 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.tapestry5.internal.services.exceptions;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.func.Mapper;
+import org.apache.tapestry5.func.Reducer;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.ExceptionAnalysis;
+import org.apache.tapestry5.ioc.services.ExceptionAnalyzer;
+import org.apache.tapestry5.ioc.services.ExceptionInfo;
+import org.apache.tapestry5.services.ExceptionReportWriter;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.RequestGlobals;
+import org.apache.tapestry5.services.Session;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ExceptionReportWriterImpl implements ExceptionReportWriter
+{
+    private static final Reducer<Integer, Integer> MAX = new Reducer<Integer, 
Integer>()
+    {
+        @Override
+        public Integer reduce(Integer accumulator, Integer element)
+        {
+            return Math.max(accumulator, element);
+        }
+    };
+
+    private static final Mapper<String, Integer> STRING_TO_LENGTH = new 
Mapper<String, Integer>()
+    {
+        @Override
+        public Integer map(String element)
+        {
+            return element.length();
+        }
+    };
+
+    private final static Mapper<ExceptionInfo, Flow<String>> 
EXCEPTION_INFO_TO_PROPERTY_NAMES =
+            new Mapper<ExceptionInfo, Flow<String>>()
+            {
+                @Override
+                public Flow<String> map(ExceptionInfo element)
+                {
+                    return F.flow(element.getPropertyNames());
+                }
+            };
+
+    /**
+     * A little closure that understands how to write a key/value pair 
represening a property.
+     */
+    interface PropertyWriter
+    {
+        void write(String name, Object value);
+    }
+
+    @Inject
+    private ExceptionAnalyzer analyzer;
+
+    @Inject
+    private RequestGlobals requestGlobals;
+
+    @Inject
+    @Symbol(SymbolConstants.CONTEXT_PATH)
+    private String contextPath;
+
+    @Override
+    public void writeReport(PrintWriter writer, Throwable exception)
+    {
+        writeReport(writer, analyzer.analyze(exception));
+    }
+
+    private PropertyWriter newPropertyWriter(final PrintWriter writer, 
Iterable<String> names)
+    {
+        final int maxPropertyNameLength = 
F.flow(names).map(STRING_TO_LENGTH).reduce(MAX, 0);
+
+        final String propertyNameFormat = "  %" + maxPropertyNameLength + "s: 
%s%n";
+
+        return new PropertyWriter()
+        {
+            @SuppressWarnings("rawtypes")
+            @Override
+            public void write(String name, Object value)
+            {
+                if (value.getClass().isArray())
+                {
+                    write(name, toList(value));
+                    return;
+                }
+
+                if (value instanceof Iterable)
+                {
+                    boolean first = true;
+                    Iterable iterable = (Iterable) value;
+                    Iterator i = iterable.iterator();
+                    while (i.hasNext())
+                    {
+                        if (first)
+                        {
+                            writer.printf(propertyNameFormat, name, i.next());
+                            first = false;
+                        } else
+                        {
+                            for (int j = 0; j < maxPropertyNameLength + 4; j++)
+                                writer.write(' ');
+
+                            writer.println(i.next());
+                        }
+                    }
+                    return;
+                }
+
+                writer.printf(propertyNameFormat, name, value);
+            }
+
+            @SuppressWarnings({"rawtypes", "unchecked"})
+            private List toList(Object array)
+            {
+                int count = Array.getLength(array);
+                List result = new ArrayList(count);
+                for (int i = 0; i < count; i++)
+                {
+                    result.add(Array.get(array, i));
+                }
+                return result;
+            }
+        };
+    }
+
+    @Override
+    public void writeReport(final PrintWriter writer, ExceptionAnalysis 
analysis)
+    {
+        writer.printf("EXCEPTION STACK:%n%n");
+
+        // Figure out what all the property names are so that we can set the 
width of the column that lists
+        // property names.
+        Flow<String> propertyNames = F.flow(analysis.getExceptionInfos())
+                .mapcat(EXCEPTION_INFO_TO_PROPERTY_NAMES).append("Exception", 
"Message");
+
+        PropertyWriter pw = newPropertyWriter(writer, propertyNames);
+
+        boolean first = true;
+
+        for (ExceptionInfo info : analysis.getExceptionInfos())
+        {
+            if (first)
+            {
+                writer.println();
+                first = false;
+            }
+
+            pw.write("Exception", info.getClassName());
+            pw.write("Message", info.getMessage());
+
+            for (String name : info.getPropertyNames())
+            {
+                pw.write(name, info.getProperty(name));
+            }
+            if (!info.getStackTrace().isEmpty())
+            {
+                writer.printf("%n  Stack trace:%n%n");
+                for (StackTraceElement e : info.getStackTrace())
+                {
+                    writer.printf("  - %s%n", e.toString());
+                }
+            }
+            writer.println();
+        }
+
+        Request request = requestGlobals.getRequest();
+
+        if (request != null)
+        {
+            // New PropertyWriter based on the lengths of parameter names and 
header names, and a sample of
+            // the literal keys.
+
+            pw = newPropertyWriter(writer,
+                    F.flow(request.getParameterNames())
+                            .concat(request.getHeaderNames())
+                            .append("serverName", "removeHost"));
+
+            writer.printf("REQUEST:%n%nBasic Information:%n%n");
+
+            List<String> flags = CollectionFactory.newList();
+            if (request.isXHR())
+            {
+                flags.add("XHR");
+            }
+            if (request.isRequestedSessionIdValid())
+            {
+                flags.add("requestedSessionIdValid");
+            }
+            if (request.isSecure())
+            {
+                flags.add("secure");
+            }
+            pw.write("contextPath", contextPath);
+
+            if (!flags.isEmpty())
+            {
+                pw.write("flags", InternalUtils.joinSorted(flags));
+            }
+            pw.write("method", request.getMethod());
+            pw.write("path", request.getPath());
+            pw.write("locale", request.getLocale());
+            pw.write("serverName", request.getServerName());
+            pw.write("remoteHost", request.getRemoteHost());
+
+            writer.printf("%nHeaders:%n%n");
+
+            for (String name : request.getHeaderNames())
+            {
+                pw.write(name, request.getHeader(name));
+            }
+            if (!request.getParameterNames().isEmpty())
+            {
+                writer.print("%nParameters:%n");
+                for (String name : request.getParameterNames())
+                {
+                    // TODO: Support multi-value parameters
+                    pw.write(name, request.getParameters(name));
+                }
+            }
+
+            Session session = request.getSession(false);
+
+            if (session != null)
+            {
+                pw = newPropertyWriter(writer, session.getAttributeNames());
+
+                writer.printf("%nSESSION:%n%n");
+
+                for (String name : session.getAttributeNames())
+                {
+                    pw.write(name, session.getAttribute(name));
+                }
+            }
+        }
+
+        writer.printf("%nSYSTEM INFORMATION:");
+
+        Runtime runtime = Runtime.getRuntime();
+
+        writer.printf("%n%nMemory:%n  %,15d bytes free%n  %,15d bytes total%n  
%,15d bytes max%n",
+                runtime.freeMemory(),
+                runtime.totalMemory(),
+                runtime.maxMemory());
+
+        Thread[] threads = TapestryInternalUtils.getAllThreads();
+
+        int maxThreadNameLength = 0;
+
+        for (Thread t : threads)
+        {
+            maxThreadNameLength = Math.max(maxThreadNameLength, 
t.getName().length());
+        }
+
+        String format = "%n%s %" + maxThreadNameLength + "s %s";
+
+        writer.printf("%n%,d Threads:", threads.length);
+
+        for (Thread t : threads)
+        {
+            writer.printf(format,
+                    Thread.currentThread() == t ? "*" : " ",
+                    t.getName(),
+                    t.getState().name());
+
+            if (t.isDaemon())
+            {
+                writer.write(", daemon");
+            }
+
+            if (!t.isAlive())
+            {
+                writer.write(", NOT alive");
+            }
+
+            if (t.isInterrupted())
+            {
+                writer.write(", interrupted");
+            }
+
+            if (t.getPriority() != Thread.NORM_PRIORITY)
+            {
+                writer.printf(", priority %d", t.getPriority());
+            }
+        }
+
+        // Finish the final line.
+        writer.println();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ede56bc6/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReporterImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReporterImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReporterImpl.java
index 77a7161..af276d0 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReporterImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/exceptions/ExceptionReporterImpl.java
@@ -13,74 +13,40 @@
 package org.apache.tapestry5.internal.services.exceptions;
 
 import org.apache.tapestry5.SymbolConstants;
-import org.apache.tapestry5.func.F;
-import org.apache.tapestry5.func.Flow;
-import org.apache.tapestry5.func.Mapper;
-import org.apache.tapestry5.func.Reducer;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.annotations.Symbol;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.ExceptionAnalysis;
-import org.apache.tapestry5.ioc.services.ExceptionAnalyzer;
-import org.apache.tapestry5.ioc.services.ExceptionInfo;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.services.ExceptionReportWriter;
 import org.apache.tapestry5.services.ExceptionReporter;
-import org.apache.tapestry5.services.Request;
-import org.apache.tapestry5.services.RequestGlobals;
 import org.slf4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Array;
-import java.util.*;
+import java.util.Date;
 import java.util.concurrent.atomic.AtomicInteger;
 
 @SuppressWarnings("ResultOfMethodCallIgnored")
 public class ExceptionReporterImpl implements ExceptionReporter
 {
-    private static final Reducer<Integer, Integer> MAX = new Reducer<Integer, 
Integer>()
-    {
-        @Override
-        public Integer reduce(Integer accumulator, Integer element)
-        {
-            return Math.max(accumulator, element);
-        }
-    };
-
-    private static final Mapper<String, Integer> STRING_TO_LENGTH = new 
Mapper<String, Integer>()
-    {
-        @Override
-        public Integer map(String element)
-        {
-            return element.length();
-        }
-    };
 
     @Inject
     @Symbol(SymbolConstants.EXCEPTION_REPORTS_DIR)
     private File logDir;
 
     @Inject
-    @Symbol(SymbolConstants.CONTEXT_PATH)
-    private String contextPath;
-
-    @Inject
     @Symbol(SymbolConstants.RESTRICTIVE_ENVIRONMENT)
     private boolean restrictive;
 
-    @Inject
-    private ExceptionAnalyzer analyzer;
-
     private final AtomicInteger uid = new AtomicInteger();
 
     @Inject
     private Logger logger;
 
+
     @Inject
-    private RequestGlobals requestGlobals;
+    private ExceptionReportWriter exceptionReportWriter;
 
     @Override
     public void reportException(Throwable exception)
@@ -134,221 +100,18 @@ public class ExceptionReporterImpl implements 
ExceptionReporter
     private void writeExceptionToFile(Throwable exception, File log) throws 
IOException
     {
         log.createNewFile();
-        ExceptionAnalysis analysis = analyzer.analyze(exception);
+
         PrintWriter writer = null;
+
         try
         {
             writer = new PrintWriter(log);
-            writeException(writer, analysis);
+            exceptionReportWriter.writeReport(writer, exception);
         } finally
         {
             InternalUtils.close(writer);
         }
     }
 
-    interface PropertyWriter
-    {
-        void write(String name, Object value);
-    }
-
-    private final static Mapper<ExceptionInfo, Flow<String>> 
EXCEPTION_INFO_TO_PROPERTY_NAMES =
-            new Mapper<ExceptionInfo, Flow<String>>()
-            {
-                @Override
-                public Flow<String> map(ExceptionInfo element)
-                {
-                    return F.flow(element.getPropertyNames());
-                }
-            };
-
-    private void writeException(final PrintWriter writer, ExceptionAnalysis 
analysis)
-    {
-        final Formatter f = new Formatter(writer);
-        writer.print("EXCEPTION STACK:\n\n");
-        Request request = requestGlobals.getRequest();
-
-        // Figure out what all the property names are so that we can set the 
width of the column that lists
-        // property names.
-        Flow<String> propertyNames = F.flow(analysis.getExceptionInfos())
-                .mapcat(EXCEPTION_INFO_TO_PROPERTY_NAMES).append("Exception 
type", "Message");
-
-        if (request != null)
-        {
-            propertyNames = 
propertyNames.concat(request.getParameterNames()).concat(request.getHeaderNames());
-        }
-
-        final int maxPropertyNameLength = 
propertyNames.map(STRING_TO_LENGTH).reduce(MAX, 0);
-
-        final String propertyNameFormat = "  %" + maxPropertyNameLength + "s: 
%s\n";
-
-        PropertyWriter pw = new PropertyWriter()
-        {
-            @SuppressWarnings("rawtypes")
-            @Override
-            public void write(String name, Object value)
-            {
-                if (value.getClass().isArray())
-                {
-                    write(name, toList(value));
-                    return;
-                }
-
-                if (value instanceof Iterable)
-                {
-                    boolean first = true;
-                    Iterable iterable = (Iterable) value;
-                    Iterator i = iterable.iterator();
-                    while (i.hasNext())
-                    {
-                        if (first)
-                        {
-                            f.format(propertyNameFormat, name, i.next());
-                            first = false;
-                        } else
-                        {
-                            for (int j = 0; j < maxPropertyNameLength + 4; j++)
-                                writer.write(' ');
-
-                            writer.println(i.next());
-                        }
-                    }
-                    return;
-                }
-
-                // TODO: Handling of arrays & collections
-                f.format(propertyNameFormat, name, value);
-            }
-
-            @SuppressWarnings({"rawtypes", "unchecked"})
-            private List toList(Object array)
-            {
-                int count = Array.getLength(array);
-                List result = new ArrayList(count);
-                for (int i = 0; i < count; i++)
-                {
-                    result.add(Array.get(array, i));
-                }
-                return result;
-            }
-        };
-
-        boolean first = true;
-
-        for (ExceptionInfo info : analysis.getExceptionInfos())
-        {
-            if (first)
-            {
-                writer.println();
-                first = false;
-            }
-            pw.write("Exception type", info.getClassName());
-            pw.write("Message", info.getMessage());
-            for (String name : info.getPropertyNames())
-            {
-                pw.write(name, info.getProperty(name));
-            }
-            if (!info.getStackTrace().isEmpty())
-            {
-                writer.write("\n  Stack trace:\n");
-                for (StackTraceElement e : info.getStackTrace())
-                {
-                    f.format("  - %s\n", e.toString());
-                }
-            }
-            writer.println();
-        }
-
-        if (request != null)
-        {
-            writer.print("REQUEST:\n\nBasic Information:\n");
-            List<String> flags = CollectionFactory.newList();
-            if (request.isXHR())
-            {
-                flags.add("XHR");
-            }
-            if (request.isRequestedSessionIdValid())
-            {
-                flags.add("requestedSessionIdValid");
-            }
-            if (request.isSecure())
-            {
-                flags.add("secure");
-            }
-            pw.write("contextPath", contextPath);
-            if (!flags.isEmpty())
-            {
-                pw.write("flags", InternalUtils.joinSorted(flags));
-            }
-            pw.write("method", request.getMethod());
-            pw.write("path", request.getPath());
-            pw.write("locale", request.getLocale());
-            pw.write("serverName", request.getServerName());
-            pw.write("remoteHost", request.getRemoteHost());
-            writer.print("\nHeaders:\n");
-            for (String name : request.getHeaderNames())
-            {
-                pw.write(name, request.getHeader(name));
-            }
-            if (!request.getParameterNames().isEmpty())
-            {
-                writer.print("\nParameters:\n");
-                for (String name : request.getParameterNames())
-                {
-                    // TODO: Support multi-value parameters
-                    pw.write(name, request.getParameters(name));
-                }
-            }
-            // TODO: Session if it exists
-        }
-
-        writer.print("\nSYSTEM INFORMATION:");
-
-        Runtime runtime = Runtime.getRuntime();
-
-        f.format("\n\nMemory:\n  %,15d bytes free\n  %,15d bytes total\n  
%,15d bytes max\n",
-                runtime.freeMemory(),
-                runtime.totalMemory(),
-                runtime.maxMemory());
-
-        Thread[] threads = TapestryInternalUtils.getAllThreads();
-
-        int maxThreadNameLength = 0;
-
-        for (Thread t : threads)
-        {
-            maxThreadNameLength = Math.max(maxThreadNameLength, 
t.getName().length());
-        }
-
-        String format = "\n%s %" + maxThreadNameLength + "s %s";
-
-        f.format("\n%,d Threads:", threads.length);
-
-        for (Thread t : threads)
-        {
-            f.format(format,
-                    Thread.currentThread() == t ? "*" : " ",
-                    t.getName(),
-                    t.getState().name());
-            if (t.isDaemon())
-            {
-                writer.write(", daemon");
-            }
-            if (!t.isAlive())
-            {
-                writer.write(", NOT alive");
-            }
-            if (t.isInterrupted())
-            {
-                writer.write(", interrupted");
-            }
-            if (t.getPriority() != Thread.NORM_PRIORITY)
-            {
-                f.format(", priority %d", t.getPriority());
-            }
-        }
-        writer.println();
-
-        f.close();
-    }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ede56bc6/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index d215095..119ca58 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -38,6 +38,7 @@ import org.apache.tapestry5.internal.services.*;
 import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateFilter;
 import org.apache.tapestry5.internal.services.ajax.AjaxResponseRendererImpl;
 import 
org.apache.tapestry5.internal.services.ajax.MultiZoneUpdateEventResultProcessor;
+import 
org.apache.tapestry5.internal.services.exceptions.ExceptionReportWriterImpl;
 import org.apache.tapestry5.internal.services.exceptions.ExceptionReporterImpl;
 import 
org.apache.tapestry5.internal.services.linktransform.LinkTransformerImpl;
 import 
org.apache.tapestry5.internal.services.linktransform.LinkTransformerInterceptor;
@@ -377,6 +378,7 @@ public final class TapestryModule
         binder.bind(DateUtilities.class, DateUtilitiesImpl.class);
         binder.bind(PartialTemplateRenderer.class, 
PartialTemplateRendererImpl.class);
         binder.bind(ExceptionReporter.class, ExceptionReporterImpl.class);
+        binder.bind(ExceptionReportWriter.class, 
ExceptionReportWriterImpl.class);
         binder.bind(ComponentOverride.class, 
ComponentOverrideImpl.class).eagerLoad();
         binder.bind(Html5Support.class, Html5SupportImpl.class);
     }
@@ -2721,7 +2723,7 @@ public final class TapestryModule
         configuration.addInstance("Maven", 
MavenComponentLibraryInfoSource.class);
         configuration.add("TapestryCore", new 
TapestryCoreComponentLibraryInfoSource());
     }
-    
+
     private static final class TapestryCoreComponentLibraryInfoSource 
implements
             ComponentLibraryInfoSource
     {
@@ -2731,9 +2733,9 @@ public final class TapestryModule
             ComponentLibraryInfo info = null;
             if (libraryMapping.libraryName.equals("core"))
             {
-            
+
                 info = new ComponentLibraryInfo();
-                
+
                 // the information above will probably not change in the 
future, or change very 
                 // infrequently, so I see no problem in hardwiring them here.
                 info.setArtifactId("tapestry-core");
@@ -2747,18 +2749,17 @@ public final class TapestryModule
                 
info.setIssueTrackerUrl("https://issues.apache.org/jira/browse/TAP5";);
                 info.setHomepageUrl("http://tapestry.apache.org";);
                 info.setLibraryMapping(libraryMapping);
-                
+
                 final InputStream inputStream = 
TapestryModule.class.getResourceAsStream(
                         
"/META-INF/gradle/org.apache.tapestry/tapestry-core/project.properties");
-                
+
                 if (inputStream != null)
                 {
                     Properties properties = new Properties();
                     try
                     {
                         properties.load(inputStream);
-                    }
-                    catch (IOException e)
+                    } catch (IOException e)
                     {
                         throw new RuntimeException(e);
                     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ede56bc6/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReportWriter.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReportWriter.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReportWriter.java
new file mode 100644
index 0000000..1f834b0
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReportWriter.java
@@ -0,0 +1,38 @@
+// Licensed 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.tapestry5.services;
+
+import org.apache.tapestry5.ioc.services.ExceptionAnalysis;
+
+import java.io.PrintWriter;
+
+/**
+ * Used by the default {@link org.apache.tapestry5.services.ExceptionReporter} 
implementation to convert an exception into
+ * a stream of text that can be stored to a file. Other applications include 
sending the text via e-mail or other messaging
+ * service.
+ *
+ * @since 5.4
+ */
+public interface ExceptionReportWriter
+{
+    /**
+     * Analyzes the exception (using the {@link 
org.apache.tapestry5.ioc.services.ExceptionAnalyzer} service)
+     * and then writes the result to the writer.
+     */
+    void writeReport(PrintWriter writer, Throwable exception);
+
+    /**
+     * Writes the analyzed exception to the writer.
+     */
+    void writeReport(PrintWriter writer, ExceptionAnalysis exception);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ede56bc6/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReporter.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReporter.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReporter.java
index 582f849..070aa84 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReporter.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/ExceptionReporter.java
@@ -25,13 +25,15 @@ package org.apache.tapestry5.services;
  *
  * @see org.apache.tapestry5.SymbolConstants#EXCEPTION_REPORTS_DIR
  * @see org.apache.tapestry5.services.RequestExceptionHandler
+ * @see org.apache.tapestry5.services.ExceptionReportWriter
  */
 public interface ExceptionReporter
 {
     /**
      * Used to communicate to the page what exception is to be reported.
      *
-     * @param exception runtime exception thrown during processing of the 
request
+     * @param exception
+     *         runtime exception thrown during processing of the request
      */
     void reportException(Throwable exception);
 }
\ No newline at end of file

Reply via email to