Author: dkulp
Date: Wed Jan 6 17:36:07 2010
New Revision: 896560
URL: http://svn.apache.org/viewvc?rev=896560&view=rev
Log:
[CXF-2596] Add a FaultLogger to allow custom handling of fault logging
Patch from Tomas Majak applied. Thanks!
Added:
cxf/trunk/api/src/main/java/org/apache/cxf/logging/
cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java (with
props)
Modified:
cxf/trunk/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
cxf/trunk/api/src/test/java/org/apache/cxf/phase/PhaseInterceptorChainTest.java
Added: cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java?rev=896560&view=auto
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java (added)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java Wed Jan
6 17:36:07 2010
@@ -0,0 +1,44 @@
+/**
+ * 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.cxf.logging;
+
+import org.apache.cxf.message.Message;
+
+/**
+ * Implement this interface to customize logging behavior for Exceptions
+ * thrown by the application implementing the service call.
+ * Implementations of this class must be registered in configuration of CXF
+ * to be invoked.
+ *
+ * Implementing this interface can also be used for listening to exceptions
+ * that occur in the service, as long as they are not caught in the
application.
+ */
+public interface FaultLogger {
+ /**
+ * Handle logging for the occured exception.
+ * @param exception The exception
+ * @param description A description of where in the service interfaces
+ * the exception occurred.
+ * @param message the message processed while the exception occured.
+ * @return <code>true</code> if CXF should use default logging for this
+ * exception, <code>false</code> if CXF not should do any logging.
+ */
+ boolean log(Exception exception, String description, Message message);
+}
Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/logging/FaultLogger.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified:
cxf/trunk/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java?rev=896560&r1=896559&r2=896560&view=diff
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
(original)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
Wed Jan 6 17:36:07 2010
@@ -35,6 +35,7 @@
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.InterceptorChain;
+import org.apache.cxf.logging.FaultLogger;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.FaultMode;
import org.apache.cxf.message.Message;
@@ -82,6 +83,7 @@
private Message pausedMessage;
private MessageObserver faultObserver;
private PhaseInterceptorIterator iterator;
+ private final boolean isFineLogging;
// currently one chain for one request/response, use below as signal
// to avoid duplicate fault processing on nested calling of
@@ -91,6 +93,8 @@
private PhaseInterceptorChain(PhaseInterceptorChain src) {
+ isFineLogging = LOG.isLoggable(Level.FINE);
+
//only used for clone
state = State.EXECUTING;
@@ -127,7 +131,8 @@
public PhaseInterceptorChain(SortedSet<Phase> ps) {
state = State.EXECUTING;
-
+ isFineLogging = LOG.isLoggable(Level.FINE);
+
int numPhases = ps.size();
phases = new Phase[numPhases];
nameMap = new HashMap<String, Integer>();
@@ -194,7 +199,7 @@
+ ((phaseName == null) ? ": Phase declaration is missing."
: ": Phase " + phaseName + " specified does not exist."));
} else {
- if (LOG.isLoggable(Level.FINE)) {
+ if (isFineLogging) {
LOG.fine("Adding interceptor " + i + " to phase " + phaseName);
}
@@ -223,7 +228,6 @@
@SuppressWarnings("unchecked")
public synchronized boolean doIntercept(Message message) {
updateIterator();
- boolean isFineLogging = LOG.isLoggable(Level.FINE);
pausedMessage = message;
Message oldMessage = CURRENT_MESSAGE.get();
@@ -264,37 +268,17 @@
description.append("\' ");
}
}
-
- FaultMode mode = message.get(FaultMode.class);
- if (mode == FaultMode.CHECKED_APPLICATION_FAULT) {
- if (LOG.isLoggable(Level.FINE)) {
- LogUtils.log(LOG, Level.FINE,
- "Application " + description
- + "has thrown exception,
unwinding now", ex);
- } else if (LOG.isLoggable(Level.INFO)) {
- Throwable t = ex;
- if (ex instanceof Fault
- && ex.getCause() != null) {
- t = ex.getCause();
- }
-
- LogUtils.log(LOG, Level.INFO,
- "Application " + description
- + "has thrown exception,
unwinding now: "
- + t.getClass().getName()
- + ": " + ex.getMessage());
- }
- } else if (LOG.isLoggable(Level.WARNING)) {
- if (mode == FaultMode.UNCHECKED_APPLICATION_FAULT)
{
- LogUtils.log(LOG, Level.WARNING,
- "Application " + description
- + "has thrown exception,
unwinding now", ex);
- } else {
- LogUtils.log(LOG, Level.WARNING,
- "Interceptor for " + description
- + "has thrown exception,
unwinding now", ex);
- }
+
+ FaultLogger flogger = (FaultLogger)
+
message.getContextualProperty(FaultLogger.class.getName());
+ boolean useDefaultLogging = true;
+ if (flogger != null) {
+ useDefaultLogging = flogger.log(ex,
description.toString(), message);
+ }
+ if (useDefaultLogging) {
+ doDefaultLogging(message, ex, description);
}
+
message.setContent(Exception.class, ex);
boolean isOneWay = false;
@@ -320,7 +304,40 @@
CURRENT_MESSAGE.set(oldMessage);
}
}
-
+
+ private void doDefaultLogging(Message message, RuntimeException ex,
StringBuilder description) {
+ FaultMode mode = message.get(FaultMode.class);
+ if (mode == FaultMode.CHECKED_APPLICATION_FAULT) {
+ if (isFineLogging) {
+ LogUtils.log(LOG, Level.FINE,
+ "Application " + description
+ + "has thrown exception, unwinding now", ex);
+ } else if (LOG.isLoggable(Level.INFO)) {
+ Throwable t = ex;
+ if (ex instanceof Fault
+ && ex.getCause() != null) {
+ t = ex.getCause();
+ }
+
+ LogUtils.log(LOG, Level.INFO,
+ "Application " + description
+ + "has thrown exception, unwinding now: "
+ + t.getClass().getName()
+ + ": " + ex.getMessage());
+ }
+ } else if (LOG.isLoggable(Level.WARNING)) {
+ if (mode == FaultMode.UNCHECKED_APPLICATION_FAULT) {
+ LogUtils.log(LOG, Level.WARNING,
+ "Application " + description
+ + "has thrown exception, unwinding now", ex);
+ } else {
+ LogUtils.log(LOG, Level.WARNING,
+ "Interceptor for " + description
+ + "has thrown exception, unwinding now", ex);
+ }
+ }
+ }
+
/**
* Intercept a message, invoking each phase's handlers in turn,
* starting after the specified interceptor.
@@ -374,7 +391,6 @@
@SuppressWarnings("unchecked")
private void unwind(Message message) {
- boolean isFineLogging = LOG.isLoggable(Level.FINE);
while (iterator.hasPrevious()) {
Interceptor currentInterceptor = iterator.previous();
if (isFineLogging) {
@@ -604,7 +620,7 @@
}
private void outputChainToLog(boolean modified) {
- if (LOG.isLoggable(Level.FINE)) {
+ if (isFineLogging) {
if (modified) {
LOG.fine(toString(" was modified"));
} else {
Modified:
cxf/trunk/api/src/test/java/org/apache/cxf/phase/PhaseInterceptorChainTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/api/src/test/java/org/apache/cxf/phase/PhaseInterceptorChainTest.java?rev=896560&r1=896559&r2=896560&view=diff
==============================================================================
---
cxf/trunk/api/src/test/java/org/apache/cxf/phase/PhaseInterceptorChainTest.java
(original)
+++
cxf/trunk/api/src/test/java/org/apache/cxf/phase/PhaseInterceptorChainTest.java
Wed Jan 6 17:36:07 2010
@@ -30,6 +30,8 @@
import org.apache.cxf.continuations.SuspendedInvocationException;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.InterceptorChain;
+import org.apache.cxf.logging.FaultLogger;
+import org.apache.cxf.message.FaultMode;
import org.apache.cxf.message.Message;
import org.easymock.classextension.EasyMock;
import org.easymock.classextension.IMocksControl;
@@ -214,6 +216,36 @@
}
@Test
+ public void testSingleInterceptorFailWithCustomLogger() throws Exception {
+ AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
+ setUpPhaseInterceptorInvocations(p, true, true);
+ setUpCustomLogger(true, true, false);
+ control.replay();
+ chain.add(p);
+ chain.doIntercept(message);
+ }
+
+ @Test
+ public void testSingleInterceptorFailWithCustomLoggerAndDefaultLogging()
throws Exception {
+ AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
+ setUpPhaseInterceptorInvocations(p, true, true);
+ setUpCustomLogger(true, true, true);
+ control.replay();
+ chain.add(p);
+ chain.doIntercept(message);
+ }
+
+ @Test
+ public void testSingleInterceptorFailWithoutCustomLogger() throws
Exception {
+ AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
+ setUpPhaseInterceptorInvocations(p, true, true);
+ setUpCustomLogger(false, true, false);
+ control.replay();
+ chain.add(p);
+ chain.doIntercept(message);
+ }
+
+ @Test
public void testTwoInterceptorsInSamePhasePass() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, false);
@@ -412,6 +444,33 @@
}
}
+ private void setUpCustomLogger(boolean useCustomLogger,
+ boolean expectFault,
+ boolean returnFromCustomLogger) {
+ if (useCustomLogger) {
+ FaultLogger customLogger = control.createMock(FaultLogger.class);
+ message.getContextualProperty(FaultLogger.class.getName());
+ EasyMock.expectLastCall().andReturn(customLogger);
+ if (expectFault) {
+ customLogger.log(EasyMock.isA(Exception.class),
+ EasyMock.isA(String.class),
+ EasyMock.isA(Message.class));
+ EasyMock.expectLastCall().andReturn(returnFromCustomLogger);
+ if (returnFromCustomLogger) {
+ //default logging should also be invoked
+ //not too beautiful way to verify that defaultLogging was
invoked.
+ message.get(FaultMode.class);
+
EasyMock.expectLastCall().andReturn(FaultMode.RUNTIME_FAULT);
+ }
+ }
+ } else {
+ message.getContextualProperty(FaultLogger.class.getName());
+ EasyMock.expectLastCall().andReturn(null);
+ }
+
+ }
+
+
public class InsertingPhaseInterceptor extends
AbstractPhaseInterceptor<Message> {
int invoked;