6d98005db765e6b2352947918df1286fd7f0bd55
[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 }