View Javadoc
1   /*
2    * Copyright 2018 SPF4J.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.spf4j.test.log;
17  
18  import com.google.common.collect.ImmutableList;
19  import java.util.ArrayList;
20  import java.util.Comparator;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.SortedMap;
25  import java.util.TreeMap;
26  import java.util.function.ToIntFunction;
27  import javax.annotation.Nullable;
28  import javax.annotation.ParametersAreNonnullByDefault;
29  import javax.annotation.concurrent.Immutable;
30  import org.spf4j.log.Level;
31  
32  /**
33   * @author Zoltan Farkas
34   */
35  @Immutable
36  @ParametersAreNonnullByDefault
37  final class LogConfigImpl implements LogConfig {
38  
39    static final Comparator<String> REV_STR_COMPARATOR = ((Comparator<String>) String::compareTo).reversed();
40  
41    private static final int DEFAULT_HANDLER_COUNT = Integer.getInteger("spf4j.test.log.defaultNrOfHandlers", 4);
42  
43    private final ImmutableList<LogHandler> rootHandler;
44  
45    private final SortedMap<String, List<LogHandler>> logHandlers;
46  
47    LogConfigImpl(final ImmutableList<LogHandler> rootHandler, final Map<String, List<LogHandler>> catHandlers) {
48      this.rootHandler = rootHandler;
49      logHandlers = new TreeMap<>(REV_STR_COMPARATOR);
50      logHandlers.putAll(catHandlers);
51    }
52  
53    @Override
54    public LogConfigImpl add(final String category, final LogHandler handler,
55            final ToIntFunction<List<LogHandler>> whereTo) {
56      ImmutableList<LogHandler> rh;
57      Map<String, List<LogHandler>> ch;
58      if (category.isEmpty()) {
59        List<LogHandler> existing = rootHandler;
60        List<LogHandler> handlers = new ArrayList<>(existing.size() + 1);
61        handlers.addAll(existing);
62        handlers.add(whereTo.applyAsInt(handlers), handler);
63        rh = ImmutableList.<LogHandler>builder().addAll(handlers).build();
64        ch = logHandlers;
65      } else {
66        rh = rootHandler;
67        ch = new HashMap<>(logHandlers);
68        List<LogHandler> hndlrs = ch.get(category);
69        if (hndlrs == null) {
70          hndlrs = new ArrayList<>(2);
71          ch.put(category, hndlrs);
72          hndlrs.add(handler);
73        } else {
74          List<LogHandler> exHandlers = hndlrs;
75          hndlrs = new ArrayList<>(exHandlers.size() + 1);
76          hndlrs.addAll(exHandlers);
77          hndlrs.add(whereTo.applyAsInt(hndlrs), handler);
78          ch.put(category, hndlrs);
79        }
80      }
81      return new LogConfigImpl(rh, ch);
82    }
83  
84  
85    @Override
86    public LogConfigImpl remove(final String category, final LogHandler handler) {
87      ImmutableList<LogHandler> rh;
88      Map<String, List<LogHandler>> ch;
89      if (category.isEmpty()) {
90        rh = rootHandler.stream().filter((h) ->  h != handler).collect(ImmutableList.toImmutableList());
91        ch = logHandlers;
92      } else {
93        rh = rootHandler;
94        ch = new HashMap<>(logHandlers);
95        List<LogHandler> hndlrs = ch.get(category);
96        if (hndlrs != null) {
97          hndlrs = new ArrayList<>(hndlrs);
98          hndlrs.remove(handler);
99          if (hndlrs.isEmpty()) {
100           ch.remove(category);
101         } else {
102           ch.put(category, hndlrs);
103         }
104       }
105     }
106     return new LogConfigImpl(rh, ch);
107   }
108 
109   @Override
110   @Nullable
111   public LogConsumer getLogConsumer(final String category, final Level level) {
112     ArrayList<LogHandler> res = new ArrayList<>(DEFAULT_HANDLER_COUNT);
113     if (category.isEmpty() || logHandlers.isEmpty()) {
114       addAll(level, rootHandler, res);
115       return CompositeLogHandler.from(res);
116     }
117     for (Map.Entry<String, List<LogHandler>> entry : logHandlers.tailMap(category).entrySet()) {
118       String key = entry.getKey();
119       if (category.startsWith(key)) {
120         if (addAll(level, entry.getValue(), res)) {
121           return CompositeLogHandler.from(res);
122         }
123       } else if (key.charAt(0) != category.charAt(0)) {
124         break;
125       }
126     }
127     addAll(level, rootHandler, res);
128     return CompositeLogHandler.from(res);
129   }
130 
131   private static boolean addAll(final Level level, final List<LogHandler> from, final List<LogHandler> to) {
132     for (LogHandler handler : from) {
133       LogHandler.Handling handling = handler.handles(level);
134       switch (handling) {
135         case HANDLE_CONSUME:
136           if (!(handler instanceof ConsumeAllLogs)) {
137             to.add(handler);
138           }
139           return true;
140         case HANDLE_PASS:
141           to.add(handler);
142           break;
143         case NONE:
144           break;
145         default:
146           throw new UnsupportedOperationException("Not known " + handling);
147       }
148     }
149     return false;
150   }
151 
152   @Override
153   public String toString() {
154     return "LogConfigImpl{" + "rootHandler=" + rootHandler + ", logHandlers=" + logHandlers + '}';
155   }
156 
157 }