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 java.lang.reflect.InvocationTargetException;
19  import java.util.function.BiConsumer;
20  import java.util.function.Consumer;
21  import java.util.function.Function;
22  import java.util.stream.Collector;
23  import javax.annotation.Nullable;
24  import javax.annotation.concurrent.GuardedBy;
25  import javax.annotation.concurrent.ThreadSafe;
26  import org.spf4j.log.Level;
27  
28  /**
29   *
30   * @author Zoltan Farkas
31   */
32  @ThreadSafe
33  final class LogCollectorHandler<A, T> implements LogHandler, LogCollection<T> {
34  
35    private final Level fromLevel;
36    private final Level toLevel;
37    private final boolean passThrough;
38    private final Object sync = new Object();
39    @GuardedBy("sync")
40    private A accObj;
41    private final BiConsumer<A, TestLogRecord> acc;
42    private final Function<A, T> finisher;
43    private final Consumer<LogCollectorHandler<A, T>> onClose;
44    private boolean isClosed;
45  
46    LogCollectorHandler(final Level fromLevel, final Level toLevel,
47            final boolean passThrough,
48            final Collector<TestLogRecord, A, T> collector, final Consumer<LogCollectorHandler<A, T>> onClose) {
49      this.fromLevel = fromLevel;
50      this.toLevel = toLevel;
51      this.passThrough = passThrough;
52      this.accObj = collector.supplier().get();
53      this.acc = collector.accumulator();
54      this.finisher = collector.finisher();
55      this.onClose = onClose;
56      this.isClosed = false;
57    }
58  
59    @Override
60    public LogHandler.Handling handles(final Level level) {
61      if (level.ordinal() >= fromLevel.ordinal() && level.ordinal() <= toLevel.ordinal()) {
62        return passThrough ? LogHandler.Handling.HANDLE_PASS : LogHandler.Handling.HANDLE_CONSUME;
63      } else {
64        return LogHandler.Handling.NONE;
65      }
66    }
67  
68    @Override
69    @Nullable
70    public TestLogRecord handle(final TestLogRecord record) {
71      synchronized (sync) {
72        if (!isClosed) {
73          acc.accept(accObj, record);
74        }
75      }
76      if (passThrough) {
77        return record;
78      } else {
79        return null;
80      }
81    }
82  
83    @Override
84    public T get() {
85      synchronized (sync) {
86        T result = finisher.apply(accObj);
87        if (result == accObj) {
88          try {
89            return (T) result.getClass().getMethod("clone").invoke(result);
90          } catch (NoSuchMethodException | SecurityException | IllegalAccessException  | InvocationTargetException ex) {
91            throw new RuntimeException(ex);
92          }
93        }
94        return result;
95      }
96    }
97  
98  
99    @Override
100   public void close() {
101     synchronized (sync) {
102       if (!isClosed) {
103         try {
104           onClose.accept(this);
105         } finally {
106           isClosed = true;
107         }
108       }
109     }
110   }
111 
112   @Override
113   public String toString() {
114     return "LogCollectorHandler{" + "accObj=" + accObj + ", fromLevel="
115             + fromLevel + ", toLevel=" + toLevel + ", passThrough=" + passThrough + '}';
116   }
117 
118 }