ffdeb8390f148bb52d42527a871f5eaff79262a6
[so/libs.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * 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, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package com.woorea.openstack.connector;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.atomic.AtomicLong;
30 import java.util.logging.Logger;
31
32 import com.sun.jersey.api.client.AbstractClientRequestAdapter;
33 import com.sun.jersey.api.client.ClientHandlerException;
34 import com.sun.jersey.api.client.ClientRequest;
35 import com.sun.jersey.api.client.ClientRequestAdapter;
36 import com.sun.jersey.api.client.ClientResponse;
37 import com.sun.jersey.api.client.filter.ClientFilter;
38 import com.sun.jersey.core.util.ReaderWriter;
39
40 /**
41  * A Jersey client filter that writes the request and response to a specified logger.
42  */
43 public class JerseyLoggingFilter extends ClientFilter {
44
45     private final AtomicLong counter = new AtomicLong(0);
46     private final Logger logger;
47
48     /**
49      * Constructor
50      * @param logger the logger to which the request and response are written.
51      */
52     public JerseyLoggingFilter(Logger logger) {
53         this.logger = logger;
54     }
55
56     @Override
57     public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
58         long id = counter.incrementAndGet();
59         logRequest(id, request);
60         ClientResponse response = getNext().handle(request);
61         logResponse(id, response);
62         return response;
63     }
64
65     /**
66      * Logs a request.
67      * @param id the request id (counter)
68      * @param request the request
69      */
70     private void logRequest(long id, ClientRequest request) {
71         StringBuilder builder = new StringBuilder();
72
73         builder.append(String.valueOf(id));
74         builder.append(" * Client out-bound request\n");
75
76         builder.append(String.valueOf(id));
77         builder.append(" > ");
78         builder.append(request.getMethod());
79         builder.append(" ");
80         builder.append(request.getURI().toASCIIString());
81         builder.append("\n");
82
83         // Request headers
84
85         for (Map.Entry<String, List<Object>> entry : request.getHeaders().entrySet()) {
86             String header = entry.getKey();
87             List<Object> values = entry.getValue();
88
89             if (values.size() == 1) {
90                 builder.append(String.valueOf(id));
91                 builder.append(" > ");
92                 builder.append(header);
93                 builder.append(": ");
94                 builder.append(ClientRequest.getHeaderValue(values.get(0)));
95                 builder.append("\n");
96             } else {
97                 StringBuilder buf = new StringBuilder();
98                 boolean first = true;
99
100                 for(Object value : values) {
101                     if (first) {
102                         first = false;
103                     } else {
104                         buf.append(",");
105                     }
106
107                     buf.append(ClientRequest.getHeaderValue(value));
108                 }
109
110                 builder.append(String.valueOf(id));
111                 builder.append(" > ");
112                 builder.append(header);
113                 builder.append(": ");
114                 builder.append(buf.toString());
115                 builder.append("\n");
116             }
117         }
118
119         // Request body
120
121         if (request.getEntity() != null) {
122             request.setAdapter(new JerseyLoggingAdapter(request.getAdapter(), builder));
123         } else {
124             logger.info(builder.toString());
125         }
126     }
127
128     /**
129      * Logs a response.
130      * @param id the request id (counter)
131      * @param response the response
132      */
133     private void logResponse(long id, ClientResponse response) {
134         StringBuilder builder = new StringBuilder();
135
136         builder.append(String.valueOf(id));
137         builder.append(" * Client in-bound response\n");
138
139         builder.append(String.valueOf(id));
140         builder.append(" < ");
141         builder.append(String.valueOf(response.getStatus()));
142         builder.append("\n");
143
144         // Response headers
145
146         for (Map.Entry<String, List<String>> entry : response.getHeaders().entrySet()) {
147             String header = entry.getKey();
148             for (String value : entry.getValue()) {
149                 builder.append(String.valueOf(id));
150                 builder.append(" < ");
151                 builder.append(header);
152                 builder.append(": ");
153                 builder.append(value).append("\n");
154             }
155         }
156
157         // Response body
158
159         ByteArrayOutputStream out = new ByteArrayOutputStream();
160         InputStream in = response.getEntityInputStream();
161         try {
162             ReaderWriter.writeTo(in, out);
163
164             byte[] requestEntity = out.toByteArray();
165             appendToBuffer(builder, requestEntity);
166             response.setEntityInputStream(new ByteArrayInputStream(requestEntity));
167         } catch (IOException ex) {
168             throw new ClientHandlerException(ex);
169         }
170
171         logger.info(builder.toString());
172     }
173
174     /**
175      * Appends bytes to the builder. If the bytes contain the password pattern,
176      * the password is obliterated.
177      * @param builder the builder
178      * @param bytes the bytes to append
179      */
180     private void appendToBuffer(StringBuilder builder, byte[] bytes) {
181         if (bytes.length != 0) {
182             String s = new String(bytes);
183             builder.append(s.replaceAll("\"password\".*:.*\"(.*)\"", "\"password\" : \"******\""));
184             builder.append("\n");
185         }
186     }
187
188     private class JerseyLoggingAdapter extends AbstractClientRequestAdapter {
189         private final StringBuilder builder;
190
191         JerseyLoggingAdapter(ClientRequestAdapter adapter, StringBuilder builder) {
192             super(adapter);
193             this.builder = builder;
194         }
195
196         @Override
197         public OutputStream adapt(ClientRequest request, OutputStream out) throws IOException {
198             return new JerseyLoggingOutputStream(getAdapter().adapt(request, out), builder);
199         }
200     }
201
202     private class JerseyLoggingOutputStream extends OutputStream {
203         private final OutputStream stream;
204         private final StringBuilder builder;
205         private final ByteArrayOutputStream logStream = new ByteArrayOutputStream();
206
207         JerseyLoggingOutputStream(OutputStream stream, StringBuilder builder) {
208             this.stream = stream;
209             this.builder = builder;
210         }
211
212         @Override
213         public void write(int value) throws IOException {
214             logStream.write(value);
215             stream.write(value);
216         }
217
218         @Override
219         public void close() throws IOException {
220             appendToBuffer(builder, logStream.toByteArray());
221             logger.info(builder.toString());
222             stream.close();
223         }
224     }
225 }