This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch jbFixRestNpe
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/jbFixRestNpe by this push:
     new 8361e5498 Rest bean refactoring.
8361e5498 is described below

commit 8361e5498ee84509face84a4e4e87e3cc776b2cf
Author: JamesBognar <[email protected]>
AuthorDate: Sun Jul 10 12:10:05 2022 -0400

    Rest bean refactoring.
---
 .../org/apache/juneau/rest/ResourceSupplier.java   |  40 ++++++
 .../java/org/apache/juneau/rest/RestContext.java   | 141 +++++----------------
 .../java/org/apache/juneau/rest/RestOpContext.java |   2 +-
 .../org/apache/juneau/rest/annotation/Rest.java    |   4 -
 .../juneau/rest/annotation/RestAnnotation.java     |   2 -
 .../juneau/rest/debug/BasicDebugEnablement.java    | 128 +++++++++++--------
 .../apache/juneau/rest/debug/DebugEnablement.java  |  94 +++++++++++++-
 .../org/apache/juneau/rest/logger/CallLogger.java  |   2 -
 8 files changed, 239 insertions(+), 174 deletions(-)

diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResourceSupplier.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResourceSupplier.java
new file mode 100644
index 000000000..63c836ebb
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResourceSupplier.java
@@ -0,0 +1,40 @@
+// 
***************************************************************************************************************************
+// * 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.juneau.rest;
+
+import java.util.function.*;
+
+/**
+ * A supplier of a REST resource bean.
+ *
+ * <p>
+ * Pretty much just a normal supplier, but wrapped in a concrete class so that 
it can be retrieved by class name.
+ */
+public class ResourceSupplier implements Supplier<Object> {
+
+       private final Supplier<?> supplier;
+
+       /**
+        * Constructor.
+        *
+        * @param supplier The supplier of the bean.
+        */
+       public ResourceSupplier(Supplier<?> supplier) {
+               this.supplier = supplier;
+       }
+
+       @Override
+       public Object get() {
+               return supplier.get();
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 74bc6a91b..7726c50f2 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -211,7 +211,7 @@ public class RestContext extends Context {
 
                private boolean initialized;
 
-               Supplier<?> resource;
+               ResourceSupplier resource;
                ServletContext servletContext;
 
                final ServletConfig inner;
@@ -238,7 +238,7 @@ public class RestContext extends Context {
                private HeaderList.Builder defaultRequestHeaders, 
defaultResponseHeaders;
                private NamedAttributeList.Builder defaultRequestAttributes;
                private RestOpArgList.Builder restOpArgs;
-               private DebugEnablement.Builder debugEnablement;
+               private BeanCreator<DebugEnablement> debugEnablement;
                private MethodList startCallMethods, endCallMethods, 
postInitMethods, postInitChildFirstMethods, destroyMethods, preCallMethods, 
postCallMethods;
                private RestOperations.Builder restOperations;
                private RestChildren.Builder restChildren;
@@ -324,13 +324,14 @@ public class RestContext extends Context {
                                return this;
                        initialized = true;
 
-                       this.resource = resource;
+                       this.resource = new ResourceSupplier(resource);
                        Supplier<?> r = this.resource;
                        Class<?> rc = resourceClass;
 
                        beanStore = createBeanStore(rc, r)
                                .build()
                                .addBean(Builder.class, this)
+                               .addBean(ResourceSupplier.class, this.resource)
                                .addBean(ServletConfig.class, inner != null ? 
inner : this)
                                .addBean(ServletContext.class, (inner != null ? 
inner : this).getServletContext());
 
@@ -3359,7 +3360,7 @@ public class RestContext extends Context {
                
//-----------------------------------------------------------------------------------------------------------------
 
                /**
-                * Returns the debug enablement sub-builder.
+                * Returns the debug enablement bean creator.
                 *
                 * <p>
                 * Enables the following:
@@ -3372,149 +3373,74 @@ public class RestContext extends Context {
                 *
                 * @return The debug enablement sub-builder.
                 */
-               public DebugEnablement.Builder debugEnablement() {
+               public BeanCreator<DebugEnablement> debugEnablement() {
                        if (debugEnablement == null)
-                               debugEnablement = 
createDebugEnablement(beanStore(), resource());
+                               debugEnablement = createDebugEnablement();
                        return debugEnablement;
                }
 
                /**
-                * Applies an operation to the debug enablement sub-builder.
+                * Specifies the debug enablement class to use for this REST 
context.
                 *
-                * <p>
-                * Typically used to allow you to execute operations without 
breaking the fluent flow of the context builder.
-                *
-                * <h5 class='section'>Example:</h5>
-                * <p class='bjava'>
-                *      RestContext <jv>context</jv> = RestContext
-                *              .<jsm>create</jsm>(<jv>resourceClass</jv>, 
<jv>parentContext</jv>, <jv>servletConfig</jv>)
-                *              .debugEnablement(<jv>x</jv> -&gt; 
<jv>x</jv>.defaultEnable(<jsf>ALWAYS</jsf>))
-                *              .build();
-                * </p>
-                *
-                * @param operation The operation to apply.
-                * @return This object.
-                */
-               public Builder 
debugEnablement(Consumer<DebugEnablement.Builder> operation) {
-                       operation.accept(debugEnablement());
-                       return this;
-               }
-
-               /**
-                * Sets the debug default value.
-                *
-                * <p>
-                * The default debug value is the enablement value if not 
otherwise overridden at the class or method level.
-                *
-                * @param value The debug default value.
+                * @param value The new value for this setting.
                 * @return This object.
                 */
-               @FluentSetter
-               public Builder debugDefault(Enablement value) {
-                       defaultSettings().set("RestContext.debugDefault", 
value);
+               public Builder debugEnablement(Class<? extends DebugEnablement> 
value) {
+                       debugEnablement().type(value);
                        return this;
                }
 
                /**
-                * Specifies the debug level on this REST resource.
+                * Specifies the debug enablement class to use for this REST 
context.
                 *
-                * @param value The value for this setting.
+                * @param value The new value for this setting.
                 * @return This object.
                 */
-               public Builder debug(Enablement value) {
-                       debugEnablement().enable(value, this.resourceClass);
+               public Builder debugEnablement(DebugEnablement value) {
+                       debugEnablement().impl(value);
                        return this;
                }
 
                /**
-                * Debug mode on specified classes/methods.
-                *
-                * Enables the following:
-                * <ul class='spaced-list'>
-                *      <li>
-                *              HTTP request/response bodies are cached in 
memory for logging purposes.
-                *      <li>
-                *              Request/response messages are automatically 
logged.
-                * </ul>
+                * Sets the debug default value.
                 *
-                * <ul class='seealso'>
-                *      <li class='ja'>{@link Rest#debugOn}
-                * </ul>
+                * <p>
+                * The default debug value is the enablement value if not 
otherwise overridden at the class or method level.
                 *
-                * @param value The new value for this setting.
+                * @param value The debug default value.
                 * @return This object.
                 */
                @FluentSetter
-               public Builder debugOn(String value) {
-                       for (Map.Entry<String,String> e : splitMap(value != 
null ? value : "", true).entrySet()) {
-                               String k = e.getKey(), v = e.getValue();
-                               if (v.isEmpty())
-                                       v = "ALWAYS";
-                               if (! k.isEmpty())
-                                       
debugEnablement().enable(Enablement.fromString(v), k);
-                       }
+               public Builder debugDefault(Enablement value) {
+                       defaultSettings().set("RestContext.debugDefault", 
value);
                        return this;
                }
 
                /**
-                * Instantiates the debug enablement sub-builder.
+                * Instantiates the debug enablement bean creator.
                 *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new debug enablement sub-builder.
+                * @return A new debug enablement bean creator.
                 */
-               protected DebugEnablement.Builder 
createDebugEnablement(BeanStore beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<DebugEnablement.Builder> v = Value.of(
-                               DebugEnablement
-                                       .create(beanStore)
-                       );
-
-                       // Default debug enablement if not overridden at 
class/method level.
-                       Enablement debugDefault = 
defaultSettings.get(Enablement.class, 
"RestContext.debugDefault").orElse(isDebug() ? Enablement.ALWAYS : 
Enablement.NEVER);
-                       v.get().defaultEnable(debugDefault);
-
-                       // Gather @RestOp(debug) settings.
-                       Consumer<MethodInfo> consumer = x -> {
-                               Value<String> debug = Value.empty();
-                               
x.getAnnotationList(REST_OP_GROUP).forEachValue(String.class, "debug", 
NOT_EMPTY, y -> debug.set(y));
-                               if (debug.isPresent())
-                                       
v.get().enable(Enablement.fromString(debug.get()), x.getFullName());
-                       };
-                       ClassInfo.ofProxy(resource.get()).forEachPublicMethod(x 
-> true, consumer);
-
-                       // Replace with bean from bean store.
-                       rootBeanStore
-                               .getBean(DebugEnablement.class)
-                               .ifPresent(x -> v.get().impl(x));
+               protected BeanCreator<DebugEnablement> createDebugEnablement() {
 
-                       // Replace with this bean.
-                       resourceAs(DebugEnablement.class)
-                               .ifPresent(x -> v.get().impl(x));
+                       BeanCreator<DebugEnablement> creator = 
beanStore.createBean(DebugEnablement.class).type(BasicDebugEnablement.class);
 
-                       // Specify the implementation class if its set as a 
default.
+                       // Specify the bean type if its set as a default.
                        defaultClasses()
                                .get(DebugEnablement.class)
-                               .ifPresent(x -> v.get().type(x));
+                               .ifPresent(x -> creator.type(x));
 
-                       // Replace with builder from:  public [static] 
DebugEnablement.Builder createDebugEnablement(<args>)
-                       beanStore
-                               
.createMethodFinder(DebugEnablement.Builder.class)
-                               .addBean(DebugEnablement.Builder.class, v.get())
-                               .find("createDebugEnablement")
-                               .run(x -> v.set(x));
+                       rootBeanStore
+                               .getBean(DebugEnablement.class)
+                               .ifPresent(x -> creator.impl(x));
 
                        // Replace with bean from:  public [static] 
DebugEnablement createDebugEnablement(<args>)
                        beanStore
                                .createMethodFinder(DebugEnablement.class)
-                               .addBean(DebugEnablement.Builder.class, v.get())
                                .find("createDebugEnablement")
-                               .run(x -> v.get().impl(x));
+                               .run(x -> creator.impl(x));
 
-                       return v.get();
+                       return creator;
                }
 
                
//-----------------------------------------------------------------------------------------------------------------
@@ -5871,6 +5797,7 @@ public class RestContext extends Context {
                                .addBean(BeanStore.class, beanStore)
                                .addBean(RestContext.class, this)
                                .addBean(Object.class, resource.get())
+                               .addBean(DefaultSettingsMap.class, 
defaultSettings)
                                .addBean(Builder.class, builder)
                                .addBean(AnnotationWorkList.class, 
builder.getApplied());
 
@@ -5915,7 +5842,7 @@ public class RestContext extends Context {
                        defaultResponseHeaders = bs.add(HeaderList.class, 
builder.defaultResponseHeaders().build(), "RestContext.defaultResponseHeaders");
                        defaultRequestAttributes = 
bs.add(NamedAttributeList.class, builder.defaultRequestAttributes().build(), 
"RestContext.defaultRequestAttributes");
                        restOpArgs = builder.restOpArgs().build().asArray();
-                       debugEnablement = builder.debugEnablement().build();
+                       debugEnablement = bs.add(DebugEnablement.class, 
builder.debugEnablement().orElse(null));
                        startCallMethods = 
builder.startCallMethods().stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
                        endCallMethods = 
builder.endCallMethods().stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
                        postInitMethods = 
builder.postInitMethods().stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
index 8875054ed..b301c738a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
@@ -2238,7 +2238,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                        if (builder.debug == null)
                                debug = context.getDebugEnablement();
                        else
-                               debug = 
DebugEnablement.create(context.getRootBeanStore()).enable(builder.debug, 
"*").build();
+                               debug = 
DebugEnablement.create(context.getBeanStore()).enable(builder.debug, 
"*").build();
 
                        mi = MethodInfo.of(method).accessible();
                        Object r = context.getResource();
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index 2d4216476..9550d8c21 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
@@ -523,10 +523,6 @@ public @interface Rest {
         *              These debug settings can be overridden at runtime by 
directly calling {@link RestRequest#setDebug()}.
         * </ul>
         *
-        * <ul class='seealso'>
-        *      <li class='jm'>{@link 
org.apache.juneau.rest.RestContext.Builder#debugOn(String)}
-        * </ul>
-        *
         * @return The annotation value.
         */
        String debugOn() default "";
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
index f02087f22..e939d7c81 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
@@ -1109,8 +1109,6 @@ public class RestAnnotation {
                        string(a.allowedMethodHeaders()).ifPresent(x -> 
b.allowedMethodHeaders(x));
                        string(a.allowedMethodParams()).ifPresent(x -> 
b.allowedMethodParams(x));
                        bool(a.renderResponseStackTraces()).ifPresent(x -> 
b.renderResponseStackTraces(x));
-                       
string(a.debug()).map(Enablement::fromString).ifPresent(x -> b.debug(x));
-                       string(a.debugOn()).ifPresent(x -> b.debugOn(x));
                }
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/BasicDebugEnablement.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/BasicDebugEnablement.java
index acd47cf8d..86a8c4bf8 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/BasicDebugEnablement.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/BasicDebugEnablement.java
@@ -12,82 +12,104 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.debug;
 
-import static org.apache.juneau.internal.ObjectUtils.*;
-import static org.apache.juneau.Enablement.*;
-import static org.apache.juneau.collections.JsonMap.*;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.rest.annotation.RestOpAnnotation.*;
 
-import java.lang.reflect.*;
-import java.util.function.*;
-
-import javax.servlet.http.*;
+import java.util.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.cp.*;
+import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.*;
-import org.apache.juneau.utils.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.svl.*;
 
 /**
  * Default implementation of the {@link DebugEnablement} interface.
+ * 
+ * <p>
+ * Enables debug mode based on the following annotations:
+ * <ul>
+ *     <li class='ja'>{@link Rest#debug()}
+ *     <li class='ja'>{@link RestOp#debug()}
+ *     <li class='ja'>{@link Rest#debugOn()}
+ * </ul>
  *
  * <ul class='seealso'>
  *     <li class='link'>{@doc jrs.LoggingAndDebugging}
  *     <li class='extlink'>{@source}
  * </ul>
  */
-public class BasicDebugEnablement implements DebugEnablement {
-
-       private final Enablement defaultEnablement;
-       private final ReflectionMap<Enablement> enablementMap;
-       private final Predicate<HttpServletRequest> conditionalPredicate;
+public class BasicDebugEnablement extends DebugEnablement {
 
        /**
         * Constructor.
         *
-        * @param builder The builder containing the settings for this bean.
+        * @param beanStore The bean store containing injectable beans for this 
enablement.
         */
-       public BasicDebugEnablement(DebugEnablement.Builder builder) {
-               this.defaultEnablement = 
firstNonNull(builder.defaultEnablement, NEVER);
-               this.enablementMap = builder.mapBuilder.build();
-               this.conditionalPredicate = firstNonNull(builder.conditional, x 
-> "true".equalsIgnoreCase(x.getHeader("Debug")));
+       public BasicDebugEnablement(BeanStore beanStore) {
+               super(beanStore);
        }
 
        @Override
-       public boolean isDebug(RestOpContext context, HttpServletRequest req) {
-               Method m = context.getJavaMethod();
-               Enablement e = 
enablementMap.find(m).orElse(enablementMap.find(m.getDeclaringClass()).orElse(defaultEnablement));
-               return e == ALWAYS || (e == CONDITIONAL && 
isConditionallyEnabled(req));
-       }
+       protected Builder init(BeanStore beanStore) {
+               Builder b = super.init(beanStore);
 
-       @Override
-       public boolean isDebug(RestContext context, HttpServletRequest req) {
-               Class<?> c = context.getResourceClass();
-               Enablement e = enablementMap.find(c).orElse(defaultEnablement);
-               return e == ALWAYS || (e == CONDITIONAL && 
isConditionallyEnabled(req));
-       }
+               DefaultSettingsMap defaultSettings = 
beanStore.getBean(DefaultSettingsMap.class).get();
+               RestContext.Builder builder = 
beanStore.getBean(RestContext.Builder.class).get();
+               ResourceSupplier resource = 
beanStore.getBean(ResourceSupplier.class).get();
+               VarResolver varResolver = 
beanStore.getBean(VarResolver.class).get();
 
-       /**
-        * Returns <jk>true</jk> if debugging is conditionally enabled on the 
specified request.
-        *
-        * <p>
-        * This method only gets called when the enablement value resolves to 
{@link Enablement#CONDITIONAL CONDITIONAL}.
-        *
-        * <p>
-        * Subclasses can override this method to provide their own 
implementation.
-        * The default implementation is provided by {@link 
DebugEnablement.Builder#conditional(Predicate)}
-        * which has a default predicate of <c><jv>x</jv> -&gt; 
<js>"true"</js>.equalsIgnoreCase(<jv>x</jv>.getHeader(<js>"Debug"</js>)</c>.
-        *
-        * @param req The incoming HTTP request.
-        * @return <jk>true</jk> if debugging is conditionally enabled on the 
specified request.
-        */
-       protected boolean isConditionallyEnabled(HttpServletRequest req) {
-               return conditionalPredicate.test(req);
-       }
+               // Default debug enablement if not overridden at class/method 
level.
+               Enablement debugDefault = defaultSettings.get(Enablement.class, 
"RestContext.debugDefault").orElse(builder.isDebug() ? Enablement.ALWAYS : 
Enablement.NEVER);
+               b.defaultEnable(debugDefault);
+
+               ClassInfo ci = ClassInfo.ofProxy(resource.get());
+
+               // Gather @Rest(debug) settings.
+               ci.forEachAnnotation(
+                       Rest.class,
+                       x -> true,
+                       x -> {
+                               String x2 = varResolver.resolve(x.debug());
+                               if (! x2.isEmpty())
+                                       b.enable(Enablement.fromString(x2), 
ci.getFullName());
+                       }
+               );
+
+               // Gather @RestOp(debug) settings.
+               ci.forEachPublicMethod(
+                       x -> true,
+                       x -> {
+                               x.getAnnotationList(REST_OP_GROUP).forEachValue(
+                                       String.class,
+                                       "debug",
+                                       y -> true,
+                                       y -> {
+                                               String y2 = 
varResolver.resolve(y);
+                                               if (! y2.isEmpty())
+                                                       
b.enable(Enablement.fromString(y2), x.getFullName());
+                                       }
+                               );
+                       }
+               );
+
+               // Gather @Rest(debugOn) settings.
+               ci.forEachAnnotation(
+                       Rest.class,
+                       x -> true,
+                       x -> {
+                               String x2 = varResolver.resolve(x.debugOn());
+                               for (Map.Entry<String,String> e : splitMap(x2, 
true).entrySet()) {
+                                       String k = e.getKey(), v = e.getValue();
+                                       if (v.isEmpty())
+                                               v = "ALWAYS";
+                                       if (! k.isEmpty())
+                                               
b.enable(Enablement.fromString(v), k);
+                               }
+                       }
+               );
 
-       @Override /* Object */
-       public String toString() {
-               return filteredMap()
-                       .append("defaultEnablement", defaultEnablement)
-                       .append("enablementMap", enablementMap)
-                       .append("conditionalPredicate", conditionalPredicate)
-                       .asString();
+               return b;
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
index 3eb452965..a3cfa5bad 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
@@ -13,8 +13,11 @@
 package org.apache.juneau.rest.debug;
 
 import static org.apache.juneau.Enablement.*;
+import static org.apache.juneau.collections.JsonMap.*;
+import static org.apache.juneau.internal.ObjectUtils.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
 
+import java.lang.reflect.Method;
 import java.util.function.*;
 
 import javax.servlet.http.*;
@@ -34,7 +37,7 @@ import org.apache.juneau.utils.*;
  *     <li class='extlink'>{@source}
  * </ul>
  */
-public interface DebugEnablement {
+public abstract class DebugEnablement {
 
        
//-----------------------------------------------------------------------------------------------------------------
        // Static
@@ -43,7 +46,11 @@ public interface DebugEnablement {
        /**
         * Represents no DebugEnablement.
         */
-       public abstract class Void implements DebugEnablement {};
+       public abstract class Void extends DebugEnablement {
+               Void(BeanStore beanStore) {
+                       super(beanStore);
+               }
+       };
 
        /**
         * Static creator.
@@ -62,7 +69,7 @@ public interface DebugEnablement {
        /**
         * Builder class.
         */
-       public class Builder {
+       public static class Builder {
 
                ReflectionMap.Builder<Enablement> mapBuilder;
                Enablement defaultEnablement = NEVER;
@@ -214,6 +221,48 @@ public interface DebugEnablement {
        // Instance
        
//-----------------------------------------------------------------------------------------------------------------
 
+       private final Enablement defaultEnablement;
+       private final ReflectionMap<Enablement> enablementMap;
+       private final Predicate<HttpServletRequest> conditionalPredicate;
+
+       /**
+        * Constructor.
+        * <p>
+        * Subclasses typically override the {@link #init(BeanStore)} method 
when using this constructor.
+        *
+        * @param beanStore The bean store containing injectable beans for this 
enablement.
+        */
+       public DebugEnablement(BeanStore beanStore) {
+               Builder builder = init(beanStore);
+               this.defaultEnablement = 
firstNonNull(builder.defaultEnablement, NEVER);
+               this.enablementMap = builder.mapBuilder.build();
+               this.conditionalPredicate = firstNonNull(builder.conditional, x 
-> "true".equalsIgnoreCase(x.getHeader("Debug")));
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param builder The builder for this enablement.
+        */
+       public DebugEnablement(Builder builder) {
+               this.defaultEnablement = 
firstNonNull(builder.defaultEnablement, NEVER);
+               this.enablementMap = builder.mapBuilder.build();
+               this.conditionalPredicate = firstNonNull(builder.conditional, x 
-> "true".equalsIgnoreCase(x.getHeader("Debug")));
+
+       }
+
+       /**
+        * Initializer.
+        * <p>
+        * Subclasses should override this method to make modifications to the 
builder used to create this logger.
+        *
+        * @param beanStore The bean store containing injectable beans for this 
logger.
+        * @return A new builder object.
+        */
+       protected Builder init(BeanStore beanStore) {
+               return new Builder(beanStore);
+       }
+
        /**
         * Returns <jk>true</jk> if debug is enabled on the specified class and 
request.
         *
@@ -225,7 +274,11 @@ public interface DebugEnablement {
         * @param req The HTTP request.
         * @return <jk>true</jk> if debug is enabled on the specified method 
and request.
         */
-       public boolean isDebug(RestContext context, HttpServletRequest req);
+       public boolean isDebug(RestContext context, HttpServletRequest req) {
+               Class<?> c = context.getResourceClass();
+               Enablement e = enablementMap.find(c).orElse(defaultEnablement);
+               return e == ALWAYS || (e == CONDITIONAL && 
isConditionallyEnabled(req));
+       }
 
        /**
         * Returns <jk>true</jk> if debug is enabled on the specified method 
and request.
@@ -238,5 +291,36 @@ public interface DebugEnablement {
         * @param req The HTTP request.
         * @return <jk>true</jk> if debug is enabled on the specified method 
and request.
         */
-       public boolean isDebug(RestOpContext context, HttpServletRequest req);
+       public boolean isDebug(RestOpContext context, HttpServletRequest req) {
+               Method m = context.getJavaMethod();
+               Enablement e = 
enablementMap.find(m).orElse(enablementMap.find(m.getDeclaringClass()).orElse(defaultEnablement));
+               return e == ALWAYS || (e == CONDITIONAL && 
isConditionallyEnabled(req));
+       }
+
+       /**
+        * Returns <jk>true</jk> if debugging is conditionally enabled on the 
specified request.
+        *
+        * <p>
+        * This method only gets called when the enablement value resolves to 
{@link Enablement#CONDITIONAL CONDITIONAL}.
+        *
+        * <p>
+        * Subclasses can override this method to provide their own 
implementation.
+        * The default implementation is provided by {@link 
DebugEnablement.Builder#conditional(Predicate)}
+        * which has a default predicate of <c><jv>x</jv> -&gt; 
<js>"true"</js>.equalsIgnoreCase(<jv>x</jv>.getHeader(<js>"Debug"</js>)</c>.
+        *
+        * @param req The incoming HTTP request.
+        * @return <jk>true</jk> if debugging is conditionally enabled on the 
specified request.
+        */
+       protected boolean isConditionallyEnabled(HttpServletRequest req) {
+               return conditionalPredicate.test(req);
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return filteredMap()
+                       .append("defaultEnablement", defaultEnablement)
+                       .append("enablementMap", enablementMap)
+                       .append("conditionalPredicate", conditionalPredicate)
+                       .asString();
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
index ffe38a9f8..7a471c8f8 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
@@ -84,7 +84,6 @@ import org.apache.juneau.rest.util.*;
  * <ul class='seealso'>
  *     <li class='jm'>{@link 
org.apache.juneau.rest.RestContext.Builder#callLogger()}
  *     <li class='jm'>{@link 
org.apache.juneau.rest.RestContext.Builder#debugEnablement()}
- *     <li class='jm'>{@link 
org.apache.juneau.rest.RestContext.Builder#debugOn(String)}
  *     <li class='ja'>{@link Rest#debug}
  *     <li class='ja'>{@link RestOp#debug}
  *     <li class='link'>{@doc jrs.LoggingAndDebugging}
@@ -714,7 +713,6 @@ public class CallLogger {
         * @param req The HTTP request being logged.
         * @return <jk>true</jk> if debug is enabled on this request.
         * @see org.apache.juneau.rest.RestContext.Builder#debugEnablement()
-        * @see org.apache.juneau.rest.RestContext.Builder#debugOn(String)
         * @see Rest#debug()
         * @see RestOp#debug()
         */

Reply via email to