You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by ro...@apache.org on 2010/07/22 15:29:53 UTC

svn commit: r966643 - in /incubator/wink/trunk: wink-common/src/main/java/org/apache/wink/common/internal/i18n/ wink-common/src/main/java/org/apache/wink/common/internal/registry/ wink-common/src/main/java/org/apache/wink/common/internal/registry/metad...

Author: rott
Date: Thu Jul 22 13:29:52 2010
New Revision: 966643

URL: http://svn.apache.org/viewvc?rev=966643&view=rev
Log:
WINK-304: improve serviceability log message output, add tests

Added:
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/ProvidersRegistrySystemTest.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/IProvider.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider1.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider2.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider3.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider4.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/ServiceabilityTest.java
Modified:
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/i18n/MessageBundle.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ClassMetadata.java
    incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties
    incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLogHandler.java
    incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLoggerAdapter.java
    incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/RequestProcessor.java
    incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/application/ApplicationProcessor.java

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/i18n/MessageBundle.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/i18n/MessageBundle.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/i18n/MessageBundle.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/i18n/MessageBundle.java Thu Jul 22 13:29:52 2010
@@ -42,16 +42,22 @@ public class MessageBundle {
      * Gets a string message from the resource bundle for the given key
      * 
      * @param key The resource key
-     * @return The message
+     * @return The message, or key in the case of MissingResourceException
      */
-    public String getMessage(String key) throws MissingResourceException {
-        String msg = resourceBundle.getString(key);
+    public String getMessage(String key) {
+        try {
+            String msg = resourceBundle.getString(key);
 
-        if (msg == null) {
-            throw new MissingResourceException("Cannot find resource key \"" + key //$NON-NLS-1$
-                + "\" in base name " //$NON-NLS-1$
-                + className, className, key);
+            if (msg == null) {
+                throw new MissingResourceException("Cannot find resource key \"" + key //$NON-NLS-1$
+                        + "\" in base name " //$NON-NLS-1$
+                        + className, className, key);
+            }
+            return msg;
+        } catch (MissingResourceException e) {
+            System.err.println(e.getMessage());
+            e.printStackTrace(System.err);
         }
-        return msg;
+        return key;
     }
 }

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java Thu Jul 22 13:29:52 2010
@@ -745,10 +745,27 @@ public class ProvidersRegistry {
 
         @Override
         public String toString() {
-            return toString("  "); //$NON-NLS-1$
+            return toString("  ", false, true); //$NON-NLS-1$
         }
-
-        protected String toString(String indent) {
+        
+        /**
+         * 
+         * @param userOnly only print user-defined entities
+         * @param trace if calling toString as part of debugging, use trace=false, if as part of trace or any other reason, use trace=true
+         * @return
+         */
+        public String toString(boolean userOnly, boolean trace) {
+            return toString("  ", userOnly, trace);
+        }
+
+        /**
+         * 
+         * @param indent how far to indent output
+         * @param userOnly only log user-defined entities
+         * @param trace if calling toString as part of debugging, use trace=false, if as part of trace or any other reason, use trace=true (debug prints slightly less verbose)
+         * @return
+         */
+        protected String toString(String indent, boolean userOnly, boolean trace) {
             StringBuffer sb = new StringBuffer();
 
             sb.append("\nRawType: "); //$NON-NLS-1$
@@ -757,25 +774,39 @@ public class ProvidersRegistry {
             if (data.isEmpty()) {
                 sb.append("{empty}"); //$NON-NLS-1$
             } else {
-                sb.append("\n"); //$NON-NLS-1$
-            }
-
-            // The data Map can be huge. Separate entries
-            // to make it more understandable
-            for (MediaType k : data.keySet()) {
-                sb.append("MediaType key = "); //$NON-NLS-1$
-                sb.append(k);
-                sb.append("\n"); //$NON-NLS-1$
-                sb.append("ObjectFactory Set value = {\n"); //$NON-NLS-1$
-
-                // Separate each ObjectFactory entry in the Set
-                // into its own line
-                for (ObjectFactory<T> of : data.get(k)) {
-                    sb.append(indent);
-                    sb.append(of);
-                    sb.append("\n"); //$NON-NLS-1$
+                StringBuffer sb_map = new StringBuffer();
+                boolean userItemFound = !userOnly;
+                // The data Map can be huge. Separate entries
+                // to make it more understandable
+                for (MediaType k : data.keySet()) {
+                    sb_map.append("MediaType key = "); //$NON-NLS-1$
+                    sb_map.append(k);
+                    sb_map.append("\n"); //$NON-NLS-1$
+                    sb_map.append("ObjectFactory Set value = {\n"); //$NON-NLS-1$
+
+                    // Separate each ObjectFactory entry in the Set
+                    // into its own line
+                    for (ObjectFactory<T> of : data.get(k)) {
+                        // assuming everything in the org.apache.wink.* package space with "internal" in package name is system, not user
+                        String instanceClassName = of.getInstanceClass().getName();
+                        if ((userOnly && !(instanceClassName.startsWith("org.apache.wink.common.internal.") || instanceClassName.startsWith("org.apache.wink.server.internal."))) || !userOnly) { //$NON-NLS-1$ $NON-NLS-2$
+                            userItemFound = true;
+                            sb_map.append(indent);
+                            if (trace) { // trace, print full ObjectFactory.toString()
+                                sb_map.append(of);
+                            } else { // debug, print slightly less information
+                                sb_map.append(of.getInstanceClass());
+                            }
+                            sb_map.append("\n"); //$NON-NLS-1$
+                        }
+                    }
+                    sb_map.append("}\n"); //$NON-NLS-1$
+                }
+                if ((sb_map.length() > 0) && userItemFound) {
+                    sb.append("\n" + sb_map.toString()); //$NON-NLS-1$
+                } else {
+                    sb.append("{empty}"); //$NON-NLS-1$
                 }
-                sb.append("}\n"); //$NON-NLS-1$
             }
             return sb.toString();
         }
@@ -932,7 +963,23 @@ public class ProvidersRegistry {
 
         @Override
         public String toString() {
-            return String.format("Priority: %f, ObjectFactory: %s", priority, of); //$NON-NLS-1$
+            return String.format("Priority: %f, ObjectFactory: %s", priority, of.toString().replace("class ", "")); //$NON-NLS-1$
+        }
+    }
+    
+    /**
+     * 
+     * @param userOnly true = log user providers only, false = log all providers
+     */
+    public String getLogFormattedProvidersList(boolean userOnly) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(this.contextResolvers.toString(userOnly, false));
+        sb.append(this.messageBodyReaders.toString(userOnly, false));
+        sb.append(this.messageBodyWriters.toString(userOnly, false));
+        if (userOnly) {
+            return Messages.getMessage("followingProvidersUserDefined", sb.toString());
+        } else {
+            return Messages.getMessage("followingProviders", sb.toString());
         }
     }
 

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ClassMetadata.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ClassMetadata.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ClassMetadata.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ClassMetadata.java Thu Jul 22 13:29:52 2010
@@ -147,7 +147,7 @@ public class ClassMetadata extends Abstr
 
     @Override
     public String toString() {
-        return String.format("Class: %s", resourceClass); //$NON-NLS-1$
+        return String.format("Class: %s", resourceClass.toString().replace("class ", "")); //$NON-NLS-1$
     }
 
 }

Modified: incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties (original)
+++ incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties Thu Jul 22 13:29:52 2010
@@ -94,7 +94,7 @@ jaxbCreateDefaultJAXBElement=The system 
 # Failure Messages
 mediaTypeWrongFormat=The {0} is not a valid MediaType format. You must use the following format: type/subtype.
 unhandledExceptionToContainer=An unhandled exception occurred which will be propagated to the container.
-exceptionOccurredDuringInvocation=The following error occurred during the invocation of the handlers chain: {0}
+exceptionOccurredDuringInvocation=The following error occurred during the invocation of the handlers chain: {0} while processing {1} request sent to {2}
 
 # Contexts
 uriBadBaseURI=The following base URI is not valid: {0} 
@@ -213,6 +213,10 @@ entityRefsNotSupportedSunJDK5=Entity ref
 saxParseException=The system cannot parse the XML content into a {0} instance.  Verify that the XML content is valid.
 saxParserConfigurationException=The system cannot configure the SAX parser with the given configuration parameter.
 badXMLReaderInitialStart=The XMLStreamReader instance has already been partially processed.
+processingRequestTo=Processing {0} request to {1}, source content type is {2}, acceptable media types include {3}
+registeredResources=Registered resources: {0}
+followingProviders=The following JAX-RS providers are registered: {0}
+followingProvidersUserDefined=The following user-defined JAX-RS providers are registered: {0}
+applicationProcessed=The following application has been processed: {0}
 multipleHttpMethodAnnotations=Multiple http method annotations on method {0} in class {1}
 resourceMethodMoreThanOneEntityParam=The {0} method has more than one entity parameter. You must use only one entity parameter.
-processingRequestTo=Processing {0} request to {1}

Modified: incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLogHandler.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLogHandler.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLogHandler.java (original)
+++ incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLogHandler.java Thu Jul 22 13:29:52 2010
@@ -22,34 +22,58 @@ package org.apache.wink.logging;
 
 import java.util.ArrayList;
 import java.util.logging.Handler;
+import java.util.logging.Level;
 import java.util.logging.LogRecord;
 
 public class WinkLogHandler extends Handler {
+    
+    public enum LEVEL {
+        INFO, DEBUG, TRACE
+    }
 
     static private ArrayList<LogRecord> logRecords = new ArrayList<LogRecord>();
     static boolean storeLogsOn = false;
+    static LEVEL level;
     
     @Override
     public void close() throws SecurityException {
-        // TODO Auto-generated method stub
     }
 
     @Override
     public void flush() {
-        // TODO Auto-generated method stub
+    }
+    
+    public static Level getLogLevel() {
+        if (level != null) {
+            if (level.equals(LEVEL.INFO)) {
+                return Level.INFO;
+            } else if (level.equals(LEVEL.DEBUG)) {
+                return Level.FINE;
+            } else if (level.equals(LEVEL.TRACE)) {
+                return Level.FINEST;
+            }
+        }
+        return Level.OFF;
     }
 
     @Override
     public void publish(LogRecord record) {
         if (storeLogsOn) {
-            logRecords.add(record);
+            if (level.equals(LEVEL.INFO) && record.getLevel().equals(Level.INFO)) {
+                logRecords.add(record);
+            } else if (level.equals(LEVEL.DEBUG) && record.getLevel().equals(Level.FINE)) {
+                logRecords.add(record);
+            } else if (level.equals(LEVEL.TRACE) && record.getLevel().equals(Level.FINEST)) {
+                logRecords.add(record);
+            }
         }
     }
     
     /**
      * turns logging capture on
      */
-    public static void turnLoggingCaptureOn() {
+    public static void turnLoggingCaptureOn(LEVEL _level) {
+        level = _level;
         storeLogsOn = true;
     }
     
@@ -58,6 +82,7 @@ public class WinkLogHandler extends Hand
      */
     public static void turnLoggingCaptureOff() {
         storeLogsOn = false;
+        level = null;
     }
     
     /**

Modified: incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLoggerAdapter.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLoggerAdapter.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLoggerAdapter.java (original)
+++ incubator/wink/trunk/wink-component-test-support/src/main/java/org/apache/wink/logging/WinkLoggerAdapter.java Thu Jul 22 13:29:52 2010
@@ -31,16 +31,21 @@ import org.slf4j.spi.LocationAwareLogger
 public final class WinkLoggerAdapter extends MarkerIgnoringBase implements
         LocationAwareLogger {
 
-    final java.util.logging.Logger logger;
-
+    /*
+     * We create a new Logger instance for each call because we want the level controlled by WinkLogHandler.
+     * It's clunky, but the level is controllable by individual unittest methods, and we need to accommodate that.
+     */
+    
+    String loggerName;
+    WinkLogHandler winkLogHandler;
+    
     WinkLoggerAdapter(java.util.logging.Logger logger) {
-        this.logger = logger;
-        this.logger.setLevel(Level.FINEST);
-        this.logger.addHandler(new WinkLogHandler());
+        winkLogHandler = new WinkLogHandler();
+        loggerName = logger.getName();
     }
 
     public boolean isTraceEnabled() {
-        return logger.isLoggable(Level.FINEST);
+        return WinkLogHandler.getLogLevel().equals(Level.FINEST);
     }
 
     public void trace(String message) {
@@ -64,7 +69,7 @@ public final class WinkLoggerAdapter ext
     }
 
     public boolean isDebugEnabled() {
-        return logger.isLoggable(Level.FINE);
+        return WinkLogHandler.getLogLevel().equals(Level.FINE);
     }
 
     public void debug(String msg) {
@@ -88,7 +93,7 @@ public final class WinkLoggerAdapter ext
     }
 
     public boolean isInfoEnabled() {
-        return logger.isLoggable(Level.INFO);
+        return WinkLogHandler.getLogLevel().equals(Level.INFO);
     }
 
     public void info(String msg) {
@@ -112,7 +117,7 @@ public final class WinkLoggerAdapter ext
     }
 
     public boolean isWarnEnabled() {
-        return logger.isLoggable(Level.WARNING);
+        return WinkLogHandler.getLogLevel().equals(Level.WARNING);
     }
 
     public void warn(String msg) {
@@ -136,7 +141,7 @@ public final class WinkLoggerAdapter ext
     }
 
     public boolean isErrorEnabled() {
-        return logger.isLoggable(Level.SEVERE);
+        return WinkLogHandler.getLogLevel().equals(Level.SEVERE);
     }
 
     public void error(String msg) {
@@ -162,8 +167,14 @@ public final class WinkLoggerAdapter ext
     private void log(Level level, String msg, Throwable t) {
         LogRecord record = new LogRecord(level, msg);
         record.setThrown(t);
+        java.util.logging.Logger logger = java.util.logging.Logger.getLogger(loggerName);
+        logger.setLevel(WinkLogHandler.getLogLevel());
+        // all of the WinkLogHander internals are static, so despite having a new instance
+        // of Logger and WinkLogHandler, we'll get the expected log records
+        logger.addHandler(winkLogHandler);
         record.setLoggerName(logger.getName());
         logger.log(record);
+        logger.removeHandler(winkLogHandler);
     }
 
     public void log(Marker marker, String caller, int level, String message,

Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/RequestProcessor.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/RequestProcessor.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/RequestProcessor.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/RequestProcessor.java Thu Jul 22 13:29:52 2010
@@ -42,6 +42,8 @@ import org.apache.wink.server.internal.a
 import org.apache.wink.server.internal.handlers.SearchResult;
 import org.apache.wink.server.internal.handlers.ServerMessageContext;
 import org.apache.wink.server.internal.registry.ResourceInstance;
+import org.apache.wink.server.internal.registry.ResourceRecord;
+import org.apache.wink.server.internal.registry.ResourceRegistry;
 import org.apache.wink.server.internal.resources.HtmlServiceDocumentResource;
 import org.apache.wink.server.internal.resources.RootResource;
 import org.apache.wink.server.utils.RegistrationUtils;
@@ -56,18 +58,21 @@ public class RequestProcessor {
     private static final Logger           logger                           =
                                                                                LoggerFactory
                                                                                    .getLogger(RequestProcessor.class);
-    private static final String           PROPERTY_ROOT_RESOURCE_NONE      = "none";                                  //$NON-NLS-1$
-    private static final String           PROPERTY_ROOT_RESOURCE_ATOM      = "atom";                                  //$NON-NLS-1$
-    private static final String           PROPERTY_ROOT_RESOURCE_ATOM_HTML = "atom+html";                             //$NON-NLS-1$
+    private static final String           PROPERTY_ROOT_RESOURCE_NONE      = "none"; //$NON-NLS-1$
+    private static final String           PROPERTY_ROOT_RESOURCE_ATOM      = "atom"; //$NON-NLS-1$
+    private static final String           PROPERTY_ROOT_RESOURCE_ATOM_HTML = "atom+html"; //$NON-NLS-1$
     private static final String           PROPERTY_ROOT_RESOURCE_DEFAULT   =
                                                                                PROPERTY_ROOT_RESOURCE_ATOM_HTML;
-    private static final String           PROPERTY_ROOT_RESOURCE           = "wink.rootResource";                     //$NON-NLS-1$
+    private static final String           PROPERTY_ROOT_RESOURCE           = "wink.rootResource"; //$NON-NLS-1$
     private static final String           PROPERTY_ROOT_RESOURCE_CSS       =
-                                                                               "wink.serviceDocumentCssPath";         //$NON-NLS-1$
+                                                                               "wink.serviceDocumentCssPath"; //$NON-NLS-1$
     private static final String           PROPERTY_LOAD_WINK_APPLICATIONS  =
-                                                                               "wink.loadApplications";               //$NON-NLS-1$
+                                                                               "wink.loadApplications"; //$NON-NLS-1$
 
     private final DeploymentConfiguration configuration;
+    
+    private String requestString;  // save off the request string in case we need to log it
+    private String requestMethod;  // save off the request method in case we need to log it
 
     public RequestProcessor(DeploymentConfiguration configuration) {
         this.configuration = configuration;
@@ -134,14 +139,11 @@ public class RequestProcessor {
     public void handleRequest(HttpServletRequest request, HttpServletResponse response)
         throws ServletException {
         try {
+            requestMethod = request.getMethod();
+            requestString = request.getRequestURL().toString();
+            requestString += ((request.getQueryString() != null && request.getQueryString().length() > 0) ? ("?" + request.getQueryString()) : ""); //$NON-NLS-1$ $NON-NLS-2$
             if (logger.isDebugEnabled()) {
-                String requestString = request.getProtocol() + "://"; //$NON-NLS-1$
-                requestString += ((request.getLocalName() != null && request.getLocalName().length() > 0) ? request.getLocalName() : request.getLocalAddr());
-                requestString += ":"; //$NON-NLS-1$
-                requestString += request.getLocalPort();
-                requestString += request.getRequestURI();
-                requestString += ((request.getQueryString() != null && request.getQueryString().length() > 0) ? ("?" + request.getQueryString()) : ""); //$NON-NLS-1$ $NON-NLS-2$
-                logger.debug(Messages.getMessage("processingRequestTo", request.getMethod(), requestString)); //$NON-NLS-1$
+                logger.debug(Messages.getMessage("processingRequestTo", requestMethod, requestString, request.getContentType(), request.getHeader("Accept"))); //$NON-NLS-1$ $NON-NLS-2$
             }
             handleRequestWithoutFaultBarrier(request, response);
         } catch (Throwable t) {
@@ -176,12 +178,12 @@ public class RequestProcessor {
             // run the response handler chain
             configuration.getResponseHandlersChain().run(msgContext);
 
-            logger.trace("Attempting to release resource instance"); //$NON-NLS-1$
+            logger.trace("Attempting to release resource instance");
             isReleaseResourcesCalled = true;
             try {
                 releaseResources(msgContext);
             } catch (Exception e) {
-                logger.trace("Caught exception when releasing resource object", e); //$NON-NLS-1$
+                logger.trace("Caught exception when releasing resource object", e);
                 throw e;
             }
         } catch (Throwable t) {
@@ -202,7 +204,7 @@ public class RequestProcessor {
                     try {
                         releaseResources(originalContext);
                     } catch (Exception e2) {
-                        logger.trace("Caught exception when releasing resource object", e2); //$NON-NLS-1$
+                        logger.trace("Caught exception when releasing resource object", e2);
                     }
                 }
             } catch (Exception e) {
@@ -212,7 +214,7 @@ public class RequestProcessor {
                     try {
                         releaseResources(originalContext);
                     } catch (Exception e2) {
-                        logger.trace("Caught exception when releasing resource object", e2); //$NON-NLS-1$
+                        logger.trace("Caught exception when releasing resource object", e2);
                     }
                 }
                 throw e;
@@ -228,16 +230,14 @@ public class RequestProcessor {
         if (searchResult != null) {
             List<ResourceInstance> resourceInstances = searchResult.getData().getMatchedResources();
             for (ResourceInstance res : resourceInstances) {
-                logger.trace("Releasing resource instance"); //$NON-NLS-1$
+                logger.trace("Releasing resource instance");
                 res.releaseInstance(msgContext);
             }
         }
     }
 
     private void logException(Throwable t) {
-        String exceptionName = t.getClass().getSimpleName();
-        String messageFormat =
-            Messages.getMessage("exceptionOccurredDuringInvocation", exceptionName); //$NON-NLS-1$
+        String messageFormat;
         if (t instanceof WebApplicationException) {
             WebApplicationException wae = (WebApplicationException)t;
             int statusCode = wae.getResponse().getStatus();
@@ -248,32 +248,28 @@ public class RequestProcessor {
                 statusSep = " - "; //$NON-NLS-1$
                 statusMessage = status.toString();
             }
-            exceptionName =
-                String.format("%s (%d%s%s)", exceptionName, statusCode, statusSep, statusMessage); //$NON-NLS-1$
-            if (statusCode >= 500) {
-                if (logger.isDebugEnabled()) {
-                    logger.debug(messageFormat, t); //$NON-NLS-1$
-                } else {
-                    logger.info(messageFormat); //$NON-NLS-1$
-                }
-            } else {
-                // don't log the whole call stack for sub-500 return codes unless debugging
-                if (logger.isDebugEnabled()) {
-                    logger.debug(messageFormat, t); //$NON-NLS-1$
-                } else {
-                    logger.info(messageFormat); //$NON-NLS-1$
-                }
-            }
+            String exceptionName =
+                String.format("%s (%d%s%s)", t.getClass().getSimpleName(), statusCode, statusSep, statusMessage); //$NON-NLS-1$
+            messageFormat = Messages.getMessage("exceptionOccurredDuringInvocation", exceptionName, requestMethod, requestString); //$NON-NLS-1$
         } else {
-            if (logger.isDebugEnabled()) {
-                logger.debug(messageFormat, t); //$NON-NLS-1$
-            } else {
-                logger.info(messageFormat); //$NON-NLS-1$
+            messageFormat = Messages.getMessage("exceptionOccurredDuringInvocation", t.getClass().getSimpleName(), requestMethod, requestString); //$NON-NLS-1$
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug(messageFormat, t);
+            ResourceRegistry rr = this.configuration.getResourceRegistry();
+            List<ResourceRecord> resourceRecords = rr.getRecords();
+            StringBuffer sb = new StringBuffer();
+            for (ResourceRecord record : resourceRecords) {
+                sb.append("\n  " + record.toString()); //$NON-NLS-1$
             }
+            logger.debug(Messages.getMessage("registeredResources", (sb.toString().length() > 0) ? sb.toString() : "{}")); //$NON-NLS-1$ $NON-NLS-2$
+            logger.debug(this.configuration.getProvidersRegistry().getLogFormattedProvidersList(true));
+        } else {
+            logger.info(messageFormat);
         }
     }
 
-    private ServerMessageContext createMessageContext(HttpServletRequest request,
+    private ServerMessageContext createMessageContext(HttpServletRequest request,   
                                                       HttpServletResponse response) {
         ServerMessageContext messageContext =
             new ServerMessageContext(request, response, configuration);

Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/application/ApplicationProcessor.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/application/ApplicationProcessor.java?rev=966643&r1=966642&r2=966643&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/application/ApplicationProcessor.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/application/ApplicationProcessor.java Thu Jul 22 13:29:52 2010
@@ -19,6 +19,7 @@
  *******************************************************************************/
 package org.apache.wink.server.internal.application;
 
+import java.util.List;
 import java.util.Set;
 
 import javax.ws.rs.core.Application;
@@ -28,6 +29,7 @@ import org.apache.wink.common.internal.i
 import org.apache.wink.common.internal.registry.ProvidersRegistry;
 import org.apache.wink.common.internal.registry.metadata.ProviderMetadataCollector;
 import org.apache.wink.common.internal.registry.metadata.ResourceMetadataCollector;
+import org.apache.wink.server.internal.registry.ResourceRecord;
 import org.apache.wink.server.internal.registry.ResourceRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -89,6 +91,17 @@ public class ApplicationProcessor {
             processWinkApplication((WinkApplication)application);
         }
 
+        // always produce INFO output after completing application processing:
+        logger.info(Messages.getMessage("applicationProcessed", application.getClass().getName())); //$NON-NLS-1$
+        List<ResourceRecord> resourceRecords = resourceRegistry.getRecords();
+        StringBuffer sb = new StringBuffer();
+        for (ResourceRecord record : resourceRecords) {
+            sb.append("\n  " + record.toString()); //$NON-NLS-1$
+        }
+        logger.info(Messages.getMessage("registeredResources", (sb.length() > 0) ? sb.toString() : "{}")); //$NON-NLS-1$ $NON-NLS-2$
+        logger.info(providersRegistry.getLogFormattedProvidersList(true));
+        // done with INFO
+        
         logger.trace("Processing of Application completed."); //$NON-NLS-1$
     }
 
@@ -123,13 +136,17 @@ public class ApplicationProcessor {
                     }
                 }
             } catch (Exception e) {
-                logger.warn(Messages.getMessage("exceptionOccurredDuringInstanceProcessing", obj //$NON-NLS-1$
-                        .getClass().getCanonicalName()));
-                logger.warn(Messages.getMessage("listExceptionDuringInstanceProcessing"), e); //$NON-NLS-1$
+                if (logger.isWarnEnabled()) {
+                    logger.warn(Messages.getMessage("exceptionOccurredDuringInstanceProcessing", obj //$NON-NLS-1$
+                            .getClass().getCanonicalName()));
+                    logger.warn(Messages.getMessage("listExceptionDuringInstanceProcessing"), e); //$NON-NLS-1$
+                }
             } catch (NoClassDefFoundError e) {
-                logger.warn(Messages.getMessage("exceptionOccurredDuringInstanceProcessing", obj //$NON-NLS-1$
-                        .getClass().getCanonicalName()));
-                logger.warn(Messages.getMessage("listExceptionDuringInstanceProcessing"), e); //$NON-NLS-1$
+                if (logger.isWarnEnabled()) {
+                    logger.warn(Messages.getMessage("exceptionOccurredDuringInstanceProcessing", obj //$NON-NLS-1$
+                            .getClass().getCanonicalName()));
+                    logger.warn(Messages.getMessage("listExceptionDuringInstanceProcessing"), e); //$NON-NLS-1$
+                }
             }
         }
     }

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/ProvidersRegistrySystemTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/ProvidersRegistrySystemTest.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/ProvidersRegistrySystemTest.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/ProvidersRegistrySystemTest.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.wink.common.internal.application.ApplicationFileLoader;
+import org.apache.wink.common.internal.providers.entity.StringProvider;
+import org.apache.wink.common.internal.registry.ProvidersRegistry;
+import org.apache.wink.server.internal.DeploymentConfiguration;
+import org.apache.wink.server.internal.RequestProcessor;
+import org.apache.wink.server.internal.registry.providers.Provider1;
+import org.apache.wink.server.internal.registry.providers.Provider2;
+import org.apache.wink.server.internal.registry.providers.Provider3;
+import org.apache.wink.server.internal.registry.providers.Provider4;
+import org.apache.wink.server.internal.servlet.MockServletInvocationTest;
+import org.apache.wink.server.internal.servlet.RestServlet;
+import org.apache.wink.test.mock.MockRequestConstructor;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+public class ProvidersRegistrySystemTest extends MockServletInvocationTest {
+    
+    private static File winkprovidersFile = null;
+    private static File winkapplicationFile = null;
+    private static String rootPath = null;
+    private static final String backupExt = "_backup";
+
+    // store this instance so we can check that it was loaded from getSingletons after our Application has loaded
+    private static Provider1 provider1Singleton = new Provider1();
+    
+    @Override
+    protected void setUp() throws Exception {
+        
+        Field defaultFileField = ApplicationFileLoader.class.getDeclaredField("CORE_APPLICATION");
+        defaultFileField.setAccessible(true);
+        String filePath = (String)defaultFileField.get(null);
+        if (!filePath.startsWith("/")) {
+            filePath = "/" + filePath;
+        }
+        
+        // use the path where CORE_APPLICATION is found as the root for the WINK_APPLICATION file
+        String classPath = System.getProperty("java.class.path");
+        StringTokenizer tokenizer = new StringTokenizer(classPath, System.getProperty("path.separator"));
+        while (tokenizer.hasMoreElements()) {
+            String temp = tokenizer.nextToken();
+            if (temp.contains("test-classes")) {
+                rootPath = temp;
+                break;
+            }
+        }
+        
+        // save a backup of winkprovidersFile if it exists:
+        copyfile(rootPath + filePath, rootPath + filePath + backupExt);
+        
+        // create a custom wink-providers file with known entries for this test
+        ArrayList<String> lines = new ArrayList<String>();
+        lines.add(Provider1.class.getName());  // should be ignored due to it already being listed in getSingletons
+        lines.add(Provider2.class.getName());  // should be ignored due to it already being listed in getClasses
+        lines.add(Provider3.class.getName());  // accepted
+        lines.add(StringProvider.class.getName());  // accepted, need it to complete end to end test
+        winkprovidersFile = createFile(rootPath + filePath, lines.toArray(new String[0]));
+        
+        defaultFileField = ApplicationFileLoader.class.getDeclaredField("WINK_APPLICATION");
+        defaultFileField.setAccessible(true);
+        filePath = (String)defaultFileField.get(null);
+        if (!filePath.startsWith("/")) {
+            filePath = "/" + filePath;
+        }
+        
+        // create a custom wink-application file with known entries for this test
+        lines = new ArrayList<String>();
+        lines.add(Provider1.class.getName());  // should be ignored due to it already being listed in getSingletons
+        lines.add(Provider2.class.getName());  // should be ignored due to it already being listed in getClasses
+        lines.add(Provider3.class.getName());  // should be ignored due to it already being listed in wink-providers
+        lines.add(Provider4.class.getName());  // accepted
+        winkapplicationFile = createFile(rootPath + filePath, lines.toArray(new String[0]));
+        
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (!winkapplicationFile.delete()) {
+            fail("failed to delete file " + winkapplicationFile.getPath());
+        }
+        if (!winkprovidersFile.delete()) {
+            fail("failed to delete file " + winkprovidersFile.getPath());
+        }
+        // restore the backup:
+        copyfile(winkprovidersFile.getPath() + backupExt, winkprovidersFile.getPath());
+        super.tearDown();
+    }
+    
+    @Override
+    protected String getApplicationClassName() {
+        return MyApplication.class.getName();
+    }
+    
+    public static class MyApplication extends Application {
+
+        @Override
+        public Set<Class<?>> getClasses() {
+            HashSet<Class<?>> set = new LinkedHashSet<Class<?>>();
+            set.add(Provider1.class);  // Provider1 should be ignored due to it already being listed in getSingletons
+            set.add(Provider2.class);  // accepted
+            return set;
+        }
+        
+        @Override
+        public Set<Object> getSingletons() {
+            HashSet<Object> set = new LinkedHashSet<Object>();
+            set.add(provider1Singleton);
+            set.add(new Provider1());  // should be ignored due to provider1Singleton already being listed
+            set.add(new ECHOResource());
+            return set;
+        }
+    
+    }
+    
+    @Path("/test")
+    public static class ECHOResource {
+
+        @POST
+        @Consumes(MediaType.TEXT_PLAIN)
+        @Produces(MediaType.TEXT_PLAIN)
+        @Path("priority")
+        public String echoString(String string) {
+            return string;
+        }
+    }
+    
+    /**
+     * Test the order of loading and the prioritization of Providers based on that loading order.
+     * 
+     * NOTE:  this test depends on the MockServletInvocationTest continuing to use LinkedHashSet in its
+     * getClasses and getSingletons methods
+     * 
+     */
+    public void testProviderPrioritization() throws Exception {
+        
+        // make sure all the lists were read and processed by tracking the number of hits to the ctors
+        
+        Provider1 p1 = new Provider1();
+        assertEquals(5, p1.getNumCtorHits());
+        
+        Provider2 p2 = new Provider2();
+        assertEquals(3, p2.getNumCtorHits());
+        
+        Provider3 p3 = new Provider3();
+        assertEquals(2, p3.getNumCtorHits());
+        
+        Provider4 p4 = new Provider4();
+        assertEquals(2, p4.getNumCtorHits());
+        
+        // to actually inspect the list in the 'data' object in the MessageBodyReaders in the ProvidersRegistry would take a lot of
+        // reflection and hacking.  We'll at least confirm that only 5 (due to AssetProvider) are in the ProvidersRegistry.
+
+        RestServlet servlet = (RestServlet)this.getServlet();
+        ServletContext context = servlet.getServletContext();
+        RequestProcessor processor = (RequestProcessor) context.getAttribute(RequestProcessor.class.getName());
+        DeploymentConfiguration config = processor.getConfiguration();
+        ProvidersRegistry providersRegistry = config.getProvidersRegistry();
+        // to confirm that the ignores are indeed happening, I need to get the private field
+        // "messageBodyReaders" object, then it's superclass "data" object and inspect it:
+        Field field = providersRegistry.getClass().getDeclaredField("messageBodyReaders");
+        field.setAccessible(true);
+        Object messageBodyReaders = field.get(providersRegistry);
+        Field field2 = messageBodyReaders.getClass().getSuperclass().getDeclaredField("data");
+        field2.setAccessible(true);
+        HashMap data = (HashMap)field2.get(messageBodyReaders);
+        HashSet readers = (HashSet)data.get(MediaType.WILDCARD_TYPE);
+        
+        assertEquals(6, readers.size());
+        
+        // under the covers, the "list" is a treeset, so the iterator does not really tell us any info about the sort
+        Set<String> expectedSet = new HashSet<String>(6);
+        expectedSet.add("Priority: 0.500000, ObjectFactory: SingletonOF: " + org.apache.wink.server.internal.registry.providers.Provider1.class.getName());
+        expectedSet.add("Priority: 0.100000, ObjectFactory: ClassMetadataPrototypeOF Class: " + org.apache.wink.common.internal.providers.entity.AssetProvider.class.getName());
+        expectedSet.add("Priority: 0.100000, ObjectFactory: SingletonOF: " + org.apache.wink.server.internal.registry.providers.Provider3.class.getName());
+        expectedSet.add("Priority: 0.500000, ObjectFactory: SingletonOF: " + org.apache.wink.server.internal.registry.providers.Provider2.class.getName());
+        expectedSet.add("Priority: 0.100000, ObjectFactory: SingletonOF: " + org.apache.wink.server.internal.registry.providers.Provider4.class.getName());
+        expectedSet.add("Priority: 0.100000, ObjectFactory: SingletonOF: " + StringProvider.class.getName());
+        
+        // this is obviously not the best way to check this.  If toString() output is changed, or the TreeSet implementation is modified,
+        // this test code will also have to be modified.  Also, can't check order of the readers HashSet.  But we're compatible with other
+        // locales now.
+        int count = 0;
+        for (Iterator it = readers.iterator(); it.hasNext();) {
+            Object obj = it.next();
+            assertTrue(obj.toString(), expectedSet.contains(obj.toString()));
+            count++;
+        }
+        
+        // do a real transaction too to confirm that the listing in getClasses took the top spot
+        
+        MockHttpServletRequest request =
+            MockRequestConstructor.constructMockRequest("POST",
+                                                        "/test/priority",
+                                                        MediaType.TEXT_PLAIN,
+                                                        MediaType.TEXT_PLAIN,
+                                                        "".getBytes());
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(200, response.getStatus());
+        // make sure the first instance processed has top priority, and that it is indeed the first instance of Provider2 (because it was given
+        // higher priority due to getClasses being processed after getSingletons)
+        assertEquals(Provider2.class.getName() + "_" + p2.getFirstInstanceHashCode(), response.getContentAsString());
+        
+    }
+    
+    // utility method
+    private File createFile(String filePath, String[] lines) throws Exception {
+        
+        File propFile = new File(filePath);
+        if (!propFile.exists()) {
+            File dir = new File(filePath.substring(0, filePath.lastIndexOf("/")));
+            dir.mkdirs();
+            propFile.createNewFile();
+        }
+        FileWriter fileWriter = new FileWriter(propFile);
+        for (int i = 0; i < lines.length; i++) {
+            fileWriter.write(lines[i]);
+            fileWriter.write(System.getProperty("line.separator"));
+        }
+        fileWriter.flush();
+        fileWriter.close();
+        return propFile;
+    }
+    
+    private static void copyfile(String sourceFile, String destinationFile) throws Exception {
+        try {
+            File f1 = new File(sourceFile);
+            File f2 = new File(destinationFile);
+            InputStream in = new FileInputStream(f1);
+
+            OutputStream out = new FileOutputStream(f2);
+
+            byte[] buf = new byte[1024];
+            int len;
+            while ((len = in.read(buf)) > 0){
+                out.write(buf, 0, len);
+            }
+            in.close();
+            out.close();
+        } catch (Exception e) {
+            // ignore
+        }
+
+    }
+    
+}
\ No newline at end of file

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/IProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/IProvider.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/IProvider.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/IProvider.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry.providers;
+
+import javax.ws.rs.ext.MessageBodyReader;
+
+public interface IProvider extends MessageBodyReader<String> {
+
+    /**
+     * implementors must count the number of hits to their constructor(s)
+     * @return number of hits to the constructor
+     */
+    public int getNumCtorHits();
+    
+    /**
+     * implementors should track the hashcode of the first instance created
+     * @return first created instance's hashcode
+     */
+    public int getFirstInstanceHashCode();
+    
+}

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider1.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider1.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider1.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider1.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry.providers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Consumes
+@Produces
+public class Provider1 implements IProvider {
+
+    static private int ctorHits = 0;
+    static private int firstInstanceHashcode = 0;
+    
+    public Provider1() {
+        ctorHits++;
+        if (firstInstanceHashcode == 0) {
+            firstInstanceHashcode = hashCode();
+        }
+    }
+    
+    public boolean isReadable(Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public String readFrom(Class<String> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType,
+            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException {
+        return this.getClass().getName() + "_" + hashCode();
+    }
+
+    public int getNumCtorHits() {
+        return ctorHits;
+    }
+    
+    public int getFirstInstanceHashCode() {
+        return firstInstanceHashcode;
+    }
+    
+}
\ No newline at end of file

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider2.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider2.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider2.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider2.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry.providers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Consumes
+@Produces
+public class Provider2 implements IProvider {
+
+    private static int ctorHits = 0;
+    private static int firstInstanceHashcode = 0;
+    
+    public Provider2() {
+        ctorHits++;
+        if (firstInstanceHashcode == 0) {
+            firstInstanceHashcode = hashCode();
+        }
+    }
+
+    public boolean isReadable(Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public String readFrom(Class<String> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType,
+            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException {
+        return this.getClass().getName() + "_" + hashCode();
+    }
+    
+    public int getNumCtorHits() {
+        return ctorHits;
+    }
+    
+    public int getFirstInstanceHashCode() {
+        return firstInstanceHashcode;
+    }
+    
+}
\ No newline at end of file

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider3.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider3.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider3.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider3.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry.providers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Consumes
+@Produces
+public class Provider3 implements IProvider {
+
+    private static int ctorHits = 0;
+    private static int firstInstanceHashcode = 0;
+    
+    public Provider3() {
+        ctorHits++;
+        if (firstInstanceHashcode == 0) {
+            firstInstanceHashcode = hashCode();
+        }
+    }
+    
+    public boolean isReadable(Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public String readFrom(Class<String> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType,
+            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException {
+        return this.getClass().getName() + "_" + hashCode();
+    }
+    
+    public int getNumCtorHits() {
+        return ctorHits;
+    }
+
+    public int getFirstInstanceHashCode() {
+        return firstInstanceHashcode;
+    }
+    
+}
\ No newline at end of file

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider4.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider4.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider4.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/registry/providers/Provider4.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.wink.server.internal.registry.providers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Consumes
+@Produces
+public class Provider4 implements IProvider {
+
+    private static int ctorHits = 0;
+    private static int firstInstanceHashcode = 0;
+    
+    public Provider4() {
+        ctorHits++;
+        if (firstInstanceHashcode == 0) {
+            firstInstanceHashcode = hashCode();
+        }
+    }
+    
+    public boolean isReadable(Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public String readFrom(Class<String> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType,
+            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException {
+        return this.getClass().getName() + "_" + hashCode();
+    }
+    
+    public int getNumCtorHits() {
+        return ctorHits;
+    }
+
+    public int getFirstInstanceHashCode() {
+        return firstInstanceHashcode;
+    }
+    
+}
\ No newline at end of file

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/ServiceabilityTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/ServiceabilityTest.java?rev=966643&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/ServiceabilityTest.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/serviceability/ServiceabilityTest.java Thu Jul 22 13:29:52 2010
@@ -0,0 +1,277 @@
+/*
+ * 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.wink.server.serviceability;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.wink.common.internal.application.ApplicationValidator;
+import org.apache.wink.common.internal.lifecycle.LifecycleManagersRegistry;
+import org.apache.wink.common.internal.registry.ProvidersRegistry;
+import org.apache.wink.logging.WinkLogHandler;
+import org.apache.wink.server.internal.application.ApplicationProcessor;
+import org.apache.wink.server.internal.registry.ResourceRegistry;
+import org.apache.wink.server.internal.servlet.MockServletInvocationTest;
+import org.apache.wink.test.mock.MockRequestConstructor;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+/**
+ * 
+ * When running this test in Eclipse or another IDE, make sure project wink-component-test-support is first in the classpath
+ * so that SLF4J picks up the SLF4J bridge provided from it.  Otherwise, you'll get no log output to assert against.
+ *
+ */
+public class ServiceabilityTest extends MockServletInvocationTest {
+
+    @Override
+    protected Class<?>[] getClasses() {
+        return new Class<?>[]{MyResource.class, MyContextResolver.class, MyContextResolver1.class};
+    }
+
+    @Path("/root")
+    public static class MyResource {
+
+        @GET
+        @Produces(MediaType.TEXT_PLAIN)
+        public String getTEXT() {
+            return "some text";
+        }
+
+        @GET
+        @Produces(MediaType.TEXT_HTML)
+        public String getHTML() {
+            return "some html";
+        }
+        
+        @GET
+        @Path("2")
+        @Produces(MediaType.TEXT_PLAIN)
+        public String getTEXT2() {
+            return "some text 2";
+        }
+
+    }
+    
+    // intentionally forgetting @Provider annotation as part of test
+    public static class MyContextResolver implements ContextResolver {
+        public Object getContext(Class type) {
+            return null;
+        }
+    }
+    
+    @Provider
+    public static class MyContextResolver1 implements ContextResolver {
+        public Object getContext(Class type) {
+            return null;
+        }
+    }
+    
+    public static class MyApp extends Application {
+
+        @Override
+        public Set<Class<?>> getClasses() {
+            Set<Class<?>> classes = new HashSet<Class<?>>();
+            classes.add(MyAppResource.class);
+            return classes;
+        }
+        
+        @Path("/myapp")
+        public static class MyAppResource {
+            @GET
+            @Produces(MediaType.TEXT_PLAIN)
+            @Path("gettext")
+            public String getTEXT() {
+                return "some private text";
+            }
+        }
+        
+    }
+    
+    public static class MockAppValidator extends ApplicationValidator {
+
+        @Override
+        public boolean isValidProvider(Class<?> cls) {
+            return true;
+        }
+
+        @Override
+        public boolean isValidResource(Class<?> cls) {
+            return true;
+        }
+        
+    }
+    
+
+    @Override
+    protected void setUp() throws Exception {
+        WinkLogHandler.clearRecords();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        WinkLogHandler.clearRecords();
+        super.tearDown();
+    }
+    
+    public void testGoodAppStartupInfoLogOutput() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.INFO);
+        MockAppValidator mockAppValidator = new MockAppValidator();
+        ResourceRegistry mockResourceRegistry = new ResourceRegistry(new LifecycleManagersRegistry(), mockAppValidator);
+        ProvidersRegistry mockProvidersRegistry = new ProvidersRegistry(new LifecycleManagersRegistry(), mockAppValidator);
+        ApplicationProcessor appProcessor = new ApplicationProcessor(new MyApp(), mockResourceRegistry, mockProvidersRegistry, false);
+        appProcessor.process();
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(3, records.size());
+        assertEquals("The following application has been processed: org.apache.wink.server.serviceability.ServiceabilityTest$MyApp", records.get(0).getMessage());
+        assertEquals("Registered resources: \n" +
+                "  Path: myapp; ClassMetadata: Class: org.apache.wink.server.serviceability.ServiceabilityTest$MyApp$MyAppResource", records.get(1).getMessage());
+        assertEquals("The following user-defined JAX-RS providers are registered: \n" +
+                "RawType: interface javax.ws.rs.ext.ContextResolver\n" +
+                "Data Map: {empty}\n" +
+                "RawType: interface javax.ws.rs.ext.MessageBodyReader\n" +
+                "Data Map: {empty}\n" +
+                "RawType: interface javax.ws.rs.ext.MessageBodyWriter\n" +
+                "Data Map: {empty}", records.get(2).getMessage());
+    }
+    
+    public void testGoodURLLogOutput1() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.DEBUG);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root", MediaType.TEXT_PLAIN);
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(200, mockResponse.getStatus());
+        assertEquals("some text", mockResponse.getContentAsString());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(1, records.size());
+        assertEquals("Processing GET request to http://localhost:80/root, source content type is null, acceptable media types include text/plain", records.get(0).getMessage());
+    }
+    
+    public void testGoodURLLogOutput2() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.DEBUG);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root", MediaType.TEXT_HTML);
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(200, mockResponse.getStatus());
+        assertEquals("some html", mockResponse.getContentAsString());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(1, records.size());
+        assertEquals("Processing GET request to http://localhost:80/root, source content type is null, acceptable media types include text/html", records.get(0).getMessage());
+    }
+    
+    public void testGoodURLLogOutput3() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.DEBUG);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root", MediaType.TEXT_PLAIN);
+        mockRequest.setQueryString("param1=value1");
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(200, mockResponse.getStatus());
+        assertEquals("some text", mockResponse.getContentAsString());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(1, records.size());
+        assertEquals("Processing GET request to http://localhost:80/root?param1=value1, source content type is null, acceptable media types include text/plain", records.get(0).getMessage());
+    }
+    
+    public void testGoodURLLogOutput4() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.DEBUG);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root/2", MediaType.TEXT_PLAIN);
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(200, mockResponse.getStatus());
+        assertEquals("some text 2", mockResponse.getContentAsString());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(1, records.size());
+        assertEquals("Processing GET request to http://localhost:80/root/2, source content type is null, acceptable media types include text/plain", records.get(0).getMessage());
+    }
+    
+    public void testBadURLLogOutput1() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.INFO);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root/BAD", MediaType.TEXT_PLAIN);
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(404, mockResponse.getStatus());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(1, records.size());
+        assertEquals("The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) while processing GET request sent to http://localhost:80/root/BAD", records.get(0).getMessage());
+        assertNull(records.get(0).getThrown());  // when NOT in debug mode, exception should NOT show up in the debug trace
+    }
+    
+    public void testBadURLLogOutput2() throws Exception {
+        WinkLogHandler.turnLoggingCaptureOn(WinkLogHandler.LEVEL.DEBUG);
+        
+        MockHttpServletRequest mockRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/root/BAD", MediaType.TEXT_PLAIN);
+        MockHttpServletResponse mockResponse = invoke(mockRequest);
+        assertEquals(404, mockResponse.getStatus());
+        
+        WinkLogHandler.turnLoggingCaptureOff();
+        ArrayList<LogRecord> records = WinkLogHandler.getRecords();
+        
+        assertEquals(4, records.size());
+        assertEquals("Processing GET request to http://localhost:80/root/BAD, source content type is null, acceptable media types include text/plain", records.get(0).getMessage());
+        assertEquals("The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) while processing GET request sent to http://localhost:80/root/BAD", records.get(1).getMessage());
+        assertNotNull(records.get(1).getThrown());  // when in debug mode, exception should show up in the debug trace
+        assertEquals("Registered resources: \n" +
+                "  Path: root; ClassMetadata: Class: org.apache.wink.server.serviceability.ServiceabilityTest$MyResource\n" +
+                "  Path: ; ClassMetadata: Class: org.apache.wink.server.internal.resources.HtmlServiceDocumentResource", records.get(2).getMessage());
+        assertEquals("The following user-defined JAX-RS providers are registered: \n" +
+                "RawType: interface javax.ws.rs.ext.ContextResolver\nData Map: \n" +
+                "MediaType key = */*\n" +
+                "ObjectFactory Set value = {\n" +
+                "  class org.apache.wink.server.serviceability.ServiceabilityTest$MyContextResolver1\n" +
+                "}\n" +
+                "\nRawType: interface javax.ws.rs.ext.MessageBodyReader\nData Map: {empty}" +
+                "\nRawType: interface javax.ws.rs.ext.MessageBodyWriter\nData Map: {empty}", records.get(3).getMessage());
+    }
+
+}