1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.sink.impl;
20
21 import java.lang.reflect.InvocationHandler;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Proxy;
25 import java.util.LinkedList;
26 import java.util.Queue;
27
28 import org.apache.maven.doxia.sink.Sink;
29
30
31
32
33 public class BufferingSinkProxyFactory implements SinkWrapperFactory {
34
35 private static final class MethodWithArguments {
36 private final Method method;
37 private final Object[] args;
38
39 MethodWithArguments(Method method, Object[] args) {
40 super();
41 this.method = method;
42 this.args = args;
43 }
44
45 void invoke(Object object) {
46 try {
47 method.invoke(object, args);
48 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
49 throw new IllegalStateException("Could not call buffered method " + method, e);
50 }
51 }
52 }
53
54 public interface BufferingSink extends Sink {
55
56 Sink getBufferedSink();
57 }
58
59 private static final class BufferingSinkProxy implements InvocationHandler {
60 private final Queue<MethodWithArguments> bufferedInvocations;
61 private final Sink delegate;
62 private static final Method FLUSH_METHOD;
63 private static final Method GET_BUFFERED_SINK_METHOD;
64
65 static {
66 try {
67 FLUSH_METHOD = Sink.class.getMethod("flush");
68 GET_BUFFERED_SINK_METHOD = BufferingSink.class.getMethod("getBufferedSink");
69 } catch (NoSuchMethodException | SecurityException e) {
70 throw new IllegalStateException("Could not find flush method in Sink!", e);
71 }
72 }
73
74 BufferingSinkProxy(Sink delegate) {
75 bufferedInvocations = new LinkedList<>();
76 this.delegate = delegate;
77 }
78
79 @Override
80 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
81 if (method.equals(FLUSH_METHOD)) {
82 bufferedInvocations.forEach(i -> i.invoke(delegate));
83 bufferedInvocations.clear();
84 } else if (method.equals(GET_BUFFERED_SINK_METHOD)) {
85 return delegate;
86 } else {
87 bufferedInvocations.add(new MethodWithArguments(method, args));
88 }
89 return null;
90 }
91 }
92
93 @Override
94 public Sink createWrapper(Sink delegate) {
95 BufferingSinkProxy proxy = new BufferingSinkProxy(delegate);
96 return (Sink) Proxy.newProxyInstance(
97 delegate.getClass().getClassLoader(), new Class<?>[] {BufferingSink.class}, proxy);
98 }
99
100 public static BufferingSink castAsBufferingSink(Sink sink) {
101 if (sink instanceof BufferingSink) {
102 return (BufferingSink) sink;
103 } else {
104 throw new IllegalArgumentException("The given sink is not a BufferingSink but a " + sink.getClass());
105 }
106 }
107
108 @Override
109 public int getPriority() {
110 return 0;
111 }
112 }