View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http.impl.async;
29  
30  import java.io.IOException;
31  import java.net.SocketAddress;
32  import java.nio.ByteBuffer;
33  import java.nio.channels.ByteChannel;
34  import java.nio.channels.SelectionKey;
35  import java.util.concurrent.locks.Lock;
36  
37  import org.apache.hc.core5.http.Chars;
38  import org.apache.hc.core5.io.CloseMode;
39  import org.apache.hc.core5.reactor.Command;
40  import org.apache.hc.core5.reactor.IOEventHandler;
41  import org.apache.hc.core5.reactor.IOSession;
42  import org.apache.hc.core5.util.Args;
43  import org.apache.hc.core5.util.Timeout;
44  import org.slf4j.Logger;
45  
46  class LoggingIOSession implements IOSession {
47  
48      private final Logger log;
49      private final Logger wireLog;
50      private final IOSession session;
51  
52      public LoggingIOSession(final IOSession session, final Logger log, final Logger wireLog) {
53          super();
54          this.session = session;
55          this.log = log;
56          this.wireLog = wireLog;
57      }
58  
59      @Override
60      public String getId() {
61          return session.getId();
62      }
63  
64      @Override
65      public Lock getLock() {
66          return session.getLock();
67      }
68  
69      @Override
70      public boolean hasCommands() {
71          return session.hasCommands();
72      }
73  
74      @Override
75      public Command poll() {
76          return session.poll();
77      }
78  
79      @Override
80      public void enqueue(final Command command, final Command.Priority priority) {
81          session.enqueue(command, priority);
82          if (log.isDebugEnabled()) {
83              log.debug("{} Enqueued {} with priority {}", session, command.getClass().getSimpleName(), priority);
84          }
85      }
86  
87      @Override
88      public ByteChannel channel() {
89          return session.channel();
90      }
91  
92      @Override
93      public SocketAddress getLocalAddress() {
94          return session.getLocalAddress();
95      }
96  
97      @Override
98      public SocketAddress getRemoteAddress() {
99          return session.getRemoteAddress();
100     }
101 
102     @Override
103     public int getEventMask() {
104         return session.getEventMask();
105     }
106 
107     private static String formatOps(final int ops) {
108         final StringBuilder buffer = new StringBuilder(6);
109         buffer.append('[');
110         if ((ops & SelectionKey.OP_READ) > 0) {
111             buffer.append('r');
112         }
113         if ((ops & SelectionKey.OP_WRITE) > 0) {
114             buffer.append('w');
115         }
116         if ((ops & SelectionKey.OP_ACCEPT) > 0) {
117             buffer.append('a');
118         }
119         if ((ops & SelectionKey.OP_CONNECT) > 0) {
120             buffer.append('c');
121         }
122         buffer.append(']');
123         return buffer.toString();
124     }
125 
126     @Override
127     public void setEventMask(final int ops) {
128         session.setEventMask(ops);
129         if (log.isDebugEnabled()) {
130             log.debug("{} Event mask set {}", session, formatOps(ops));
131         }
132     }
133 
134     @Override
135     public void setEvent(final int op) {
136         session.setEvent(op);
137         if (log.isDebugEnabled()) {
138             log.debug("{} Event set {}", session, formatOps(op));
139         }
140     }
141 
142     @Override
143     public void clearEvent(final int op) {
144         session.clearEvent(op);
145         if (log.isDebugEnabled()) {
146             log.debug("{} Event cleared {}", session, formatOps(op));
147         }
148     }
149 
150     @Override
151     public boolean isOpen() {
152         return session.isOpen();
153     }
154 
155     @Override
156     public void close() {
157         if (log.isDebugEnabled()) {
158             log.debug("{} Close", session);
159         }
160         session.close();
161     }
162 
163     @Override
164     public Status getStatus() {
165         return session.getStatus();
166     }
167 
168     @Override
169     public void close(final CloseMode closeMode) {
170         if (log.isDebugEnabled()) {
171             log.debug("{} Close {}", session, closeMode);
172         }
173         session.close(closeMode);
174     }
175 
176     @Override
177     public Timeout getSocketTimeout() {
178         return session.getSocketTimeout();
179     }
180 
181     @Override
182     public void setSocketTimeout(final Timeout timeout) {
183         if (log.isDebugEnabled()) {
184             log.debug("{} Set timeout {}", session, timeout);
185         }
186         session.setSocketTimeout(timeout);
187     }
188 
189     @Override
190     public long getLastReadTime() {
191         return session.getLastReadTime();
192     }
193 
194     @Override
195     public long getLastWriteTime() {
196         return session.getLastWriteTime();
197     }
198 
199     @Override
200     public void updateReadTime() {
201         session.updateReadTime();
202     }
203 
204     @Override
205     public void updateWriteTime() {
206         session.updateWriteTime();
207     }
208 
209     @Override
210     public long getLastEventTime() {
211         return session.getLastEventTime();
212     }
213 
214     @Override
215     public IOEventHandler getHandler() {
216         return session.getHandler();
217     }
218 
219     @Override
220     public void upgrade(final IOEventHandler handler) {
221         Args.notNull(handler, "Protocol handler");
222         if (log.isDebugEnabled()) {
223             log.debug("{} protocol upgrade {}", session, handler.getClass());
224         }
225         session.upgrade(new IOEventHandler() {
226 
227             @Override
228             public void connected(final IOSession protocolSession) throws IOException {
229                 handler.connected(protocolSession);
230             }
231 
232             @Override
233             public void inputReady(final IOSession protocolSession, final ByteBuffer src) throws IOException {
234                 if (src != null && wireLog.isDebugEnabled()) {
235                     final ByteBuffer b = src.duplicate();
236                     logData(b, "<< ");
237                 }
238                 handler.inputReady(protocolSession, src);
239             }
240 
241             @Override
242             public void outputReady(final IOSession protocolSession) throws IOException {
243                 handler.outputReady(protocolSession);
244             }
245 
246             @Override
247             public void timeout(final IOSession protocolSession, final Timeout timeout) throws IOException {
248                 handler.timeout(protocolSession, timeout);
249             }
250 
251             @Override
252             public void exception(final IOSession protocolSession, final Exception cause) {
253                 handler.exception(protocolSession, cause);
254             }
255 
256             @Override
257             public void disconnected(final IOSession protocolSession) {
258                 handler.disconnected(protocolSession);
259             }
260 
261         });
262 
263     }
264 
265     private void logData(final ByteBuffer data, final String prefix) throws IOException {
266         final byte[] line = new byte[16];
267         final StringBuilder buf = new StringBuilder();
268         while (data.hasRemaining()) {
269             buf.setLength(0);
270             buf.append(session).append(" ").append(prefix);
271             final int chunk = Math.min(data.remaining(), line.length);
272             data.get(line, 0, chunk);
273 
274             for (int i = 0; i < chunk; i++) {
275                 final char ch = (char) line[i];
276                 if (ch > Chars.SP && ch <= Chars.DEL) {
277                     buf.append(ch);
278                 } else if (Character.isWhitespace(ch)) {
279                     buf.append(' ');
280                 } else {
281                     buf.append('.');
282                 }
283             }
284             for (int i = chunk; i < 17; i++) {
285                 buf.append(' ');
286             }
287 
288             for (int i = 0; i < chunk; i++) {
289                 buf.append(' ');
290                 final int b = line[i] & 0xff;
291                 final String s = Integer.toHexString(b);
292                 if (s.length() == 1) {
293                     buf.append("0");
294                 }
295                 buf.append(s);
296             }
297             wireLog.debug(buf.toString());
298         }
299     }
300 
301     @Override
302     public int read(final ByteBuffer dst) throws IOException {
303         final int bytesRead = session.read(dst);
304         if (log.isDebugEnabled()) {
305             log.debug("{} {} bytes read", session, bytesRead);
306         }
307         if (bytesRead > 0 && wireLog.isDebugEnabled()) {
308             final ByteBuffer b = dst.duplicate();
309             final int p = b.position();
310             b.limit(p);
311             b.position(p - bytesRead);
312             logData(b, "<< ");
313         }
314         return bytesRead;
315     }
316 
317     @Override
318     public int write(final ByteBuffer src) throws IOException {
319         final int byteWritten = session.write(src);
320         if (log.isDebugEnabled()) {
321             log.debug("{} {} bytes written", session, byteWritten);
322         }
323         if (byteWritten > 0 && wireLog.isDebugEnabled()) {
324             final ByteBuffer b = src.duplicate();
325             final int p = b.position();
326             b.limit(p);
327             b.position(p - byteWritten);
328             logData(b, ">> ");
329         }
330         return byteWritten;
331     }
332 
333     @Override
334     public String toString() {
335         return session.toString();
336     }
337 
338 }