001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.debug;
018
019import static org.apache.juneau.commons.utils.CollectionUtils.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022import static org.apache.juneau.rest.annotation.RestOpAnnotation.*;
023
024import java.util.*;
025import org.apache.juneau.*;
026import org.apache.juneau.cp.*;
027import org.apache.juneau.commons.reflect.*;
028import org.apache.juneau.commons.utils.*;
029import org.apache.juneau.rest.*;
030import org.apache.juneau.rest.annotation.*;
031import org.apache.juneau.rest.util.*;
032import org.apache.juneau.svl.*;
033
034/**
035 * Default implementation of the {@link DebugEnablement} interface.
036 *
037 * <p>
038 * Enables debug mode based on the following annotations:
039 * <ul>
040 *    <li class='ja'>{@link Rest#debug()}
041 *    <li class='ja'>{@link RestOp#debug()}
042 *    <li class='ja'>{@link Rest#debugOn()}
043 * </ul>
044 *
045 * <h5 class='section'>See Also:</h5><ul>
046 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerLoggingAndDebugging">Logging / Debugging</a>
047 * </ul>
048 */
049public class BasicDebugEnablement extends DebugEnablement {
050
051   private static final AnnotationProvider AP = AnnotationProvider.INSTANCE;
052
053   /**
054    * Constructor.
055    *
056    * @param beanStore The bean store containing injectable beans for this enablement.
057    */
058   public BasicDebugEnablement(BeanStore beanStore) {
059      super(beanStore);
060   }
061
062   @Override
063   protected Builder init(BeanStore beanStore) {
064      var b = super.init(beanStore);
065
066      var defaultSettings = beanStore.getBean(DefaultSettingsMap.class).get();
067      var builder = beanStore.getBean(RestContext.Builder.class).get();
068      var resource = beanStore.getBean(ResourceSupplier.class).get();
069      var varResolver = beanStore.getBean(VarResolver.class).get();
070      var ap = AP;
071
072      // Default debug enablement if not overridden at class/method level.
073      var debugDefault = defaultSettings.get(Enablement.class, "RestContext.debugDefault").orElse(builder.isDebug() ? Enablement.ALWAYS : Enablement.NEVER);
074      b.defaultEnable(debugDefault);
075
076      var ci = ClassInfo.ofProxy(resource.get());
077
078      // Gather @Rest(debug) settings.
079      // @formatter:off
080      rstream(ap.find(Rest.class, ci)).map(AnnotationInfo::inner).forEach(x -> {
081         var x2 = varResolver.resolve(x.debug());
082         if (! x2.isEmpty())
083            b.enable(Enablement.fromString(x2), ci.getNameFull());
084      });
085      // @formatter:on
086
087      // Gather @RestOp(debug) settings.
088      // @formatter:off
089      ci.getPublicMethods().stream()
090         .forEach(x ->
091            rstream(ap.find(x))
092               .filter(REST_OP_GROUP)
093               .flatMap(ai -> ai.getValue(String.class, "debug").stream())
094               .filter(Utils::ne)
095               .map(varResolver::resolve)
096               .map(Enablement::fromString)
097               .filter(Objects::nonNull)
098               .forEach(e -> b.enable(e, x.getFullName()))
099         );
100      // @formatter:on
101
102      // Gather @Rest(debugOn) settings.
103      // @formatter:off
104      rstream(ap.find(Rest.class, ci)).map(AnnotationInfo::inner).forEach(x -> {
105         var x2 = varResolver.resolve(x.debugOn());
106         for (var e : splitMap(x2, true).entrySet()) {
107            var k = e.getKey();
108            var v = e.getValue();
109            if (v.isEmpty())
110               v = "ALWAYS";
111            if (! k.isEmpty())
112               opt(Enablement.fromString(v)).ifPresent(en -> b.enable(en, k));
113         }
114      });
115      // @formatter:on
116
117      return b;
118   }
119}