43323f8727ad736eba4b5c5efbbedfc1063dadcc
[so/libs.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Intellectual Property. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 /**
23  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
24  *
25  * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
26  *
27  * The contents of this file are subject to the terms of either the GNU
28  * General Public License Version 2 only ("GPL") or the Common Development
29  * and Distribution License("CDDL") (collectively, the "License").  You
30  * may not use this file except in compliance with the License.  You can
31  * obtain a copy of the License at
32  * http://glassfish.java.net/public/CDDL+GPL_1_1.html
33  * or packager/legal/LICENSE.txt.  See the License for the specific
34  * language governing permissions and limitations under the License.
35  *
36  * When distributing the software, include this License Header Notice in each
37  * file and include the License file at packager/legal/LICENSE.txt.
38  *
39  * GPL Classpath Exception:
40  * Oracle designates this particular file as subject to the "Classpath"
41  * exception as provided by Oracle in the GPL Version 2 section of the License
42  * file that accompanied this code.
43  *
44  * Modifications:
45  * If applicable, add the following below the License Header, with the fields
46  * enclosed by brackets [] replaced by your own identifying information:
47  * "Portions Copyright [year] [name of copyright owner]"
48  *
49  * Contributor(s):
50  * If you wish your version of this file to be governed by only the CDDL or
51  * only the GPL Version 2, indicate your decision by adding "[Contributor]
52  * elects to include this software in this distribution under the [CDDL or GPL
53  * Version 2] license."  If you don't indicate a single choice of license, a
54  * recipient has the option to distribute your version of this file under
55  * either the CDDL, the GPL Version 2 or to extend the choice of license to
56  * its licensees as provided above.  However, if you add GPL Version 2 code
57  * and therefore, elected the GPL Version 2 license, then the option applies
58  * only if the new code is made subject to such option by the copyright
59  * holder.
60  */
61 package com.woorea.openstack.connector;
62
63 import java.io.ByteArrayInputStream;
64 import java.io.ByteArrayOutputStream;
65 import java.io.IOException;
66 import java.io.InputStream;
67 import java.io.OutputStream;
68 import java.io.PrintStream;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.logging.Logger;
72
73 import javax.ws.rs.core.MultivaluedMap;
74
75 import com.sun.jersey.api.client.AbstractClientRequestAdapter;
76 import com.sun.jersey.api.client.ClientHandlerException;
77 import com.sun.jersey.api.client.ClientRequest;
78 import com.sun.jersey.api.client.ClientRequestAdapter;
79 import com.sun.jersey.api.client.ClientResponse;
80 import com.sun.jersey.api.client.filter.ClientFilter;
81 import com.sun.jersey.api.client.filter.LoggingFilter;
82 import com.sun.jersey.core.util.ReaderWriter;
83
84 /**
85  * A logging filter.
86  * 
87  */
88 public class JerseyLoggingFilter extends ClientFilter {
89
90     private static final Logger LOGGER = Logger.getLogger(LoggingFilter.class.getName());
91
92     private static final String NOTIFICATION_PREFIX = "* ";
93     
94     private static final String REQUEST_PREFIX = "> ";
95     
96     private static final String RESPONSE_PREFIX = "< ";
97
98     private static final String PASSWORD_PATTERN = "\"password\".*:.*\"(.*)\"";
99     
100     private final class Adapter extends AbstractClientRequestAdapter {
101         private final StringBuilder b;
102
103         Adapter(ClientRequestAdapter cra, StringBuilder b) {
104             super(cra);
105             this.b = b;
106         }
107
108         @Override
109         public OutputStream adapt(ClientRequest request, OutputStream out) throws IOException {
110             return new LoggingOutputStream(getAdapter().adapt(request, out), b);
111         }
112         
113     }
114
115     private final class LoggingOutputStream extends OutputStream {
116         private final OutputStream out;
117         
118         private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
119         
120         private final StringBuilder b;
121
122         LoggingOutputStream(OutputStream out, StringBuilder b) {
123             this.out = out;
124             this.b = b;
125         }
126         
127         @Override
128         public void write(byte[] b)  throws IOException {
129             baos.write(b);
130             out.write(b);
131         }
132     
133         @Override
134         public void write(byte[] b, int off, int len)  throws IOException {
135             baos.write(b, off, len);
136             out.write(b, off, len);
137         }
138
139         @Override
140         public void write(int b) throws IOException {
141             baos.write(b);
142             out.write(b);
143         }
144
145         @Override
146         public void close() throws IOException {
147             printEntity(b, baos.toByteArray());
148             log(b);
149             out.close();
150         }
151     }
152
153     private final PrintStream loggingStream;
154
155     private final Logger logger;
156
157     private long _id = 0;
158
159     /**
160      * Create a logging filter logging the request and response to
161      * a default JDK logger, named as the fully qualified class name of this
162      * class.
163      */
164     public JerseyLoggingFilter() {
165         this(LOGGER);
166     }
167
168     /**
169      * Create a logging filter logging the request and response to
170      * a JDK logger.
171      * 
172      * @param logger the logger to log requests and responses.
173      */
174     public JerseyLoggingFilter(Logger logger) {
175         this.loggingStream = null;
176         this.logger = logger;
177     }
178
179     /**
180      * Create a logging filter logging the request and response to
181      * print stream.
182      *
183      * @param loggingStream the print stream to log requests and responses.
184      */
185     public JerseyLoggingFilter(PrintStream loggingStream) {
186         this.loggingStream = loggingStream;
187         this.logger = null;
188     }
189
190     private void log(StringBuilder b) {
191         if (logger != null) {
192             logger.info(b.toString());
193         } else {
194             loggingStream.print(b);
195         }
196     }
197
198     private StringBuilder prefixId(StringBuilder b, long id) {
199         b.append(Long.toString(id)).append(" ");
200         return b;
201     }
202
203     @Override
204     public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
205         long id = ++this._id;
206
207         logRequest(id, request);
208
209         ClientResponse response = getNext().handle(request);
210
211         logResponse(id, response);
212
213         return response;
214     }
215
216     private void logRequest(long id, ClientRequest request) {
217         StringBuilder b = new StringBuilder();
218         
219         printRequestLine(b, id, request);
220         printRequestHeaders(b, id, request.getHeaders());
221
222         if (request.getEntity() != null) {
223             request.setAdapter(new Adapter(request.getAdapter(), b));
224         } else {
225             log(b);
226         }
227     }
228
229     private void printRequestLine(StringBuilder b, long id, ClientRequest request) {
230         prefixId(b, id).append(NOTIFICATION_PREFIX).append("Client out-bound request").append("\n");
231         prefixId(b, id).append(REQUEST_PREFIX).append(request.getMethod()).append(" ").
232                 append(request.getURI().toASCIIString()).append("\n");
233     }
234
235     private void printRequestHeaders(StringBuilder b, long id, MultivaluedMap<String, Object> headers) {
236         for (Map.Entry<String, List<Object>> e : headers.entrySet()) {
237             List<Object> val = e.getValue();
238             String header = e.getKey();
239
240             if(val.size() == 1) {
241                 prefixId(b, id).append(REQUEST_PREFIX).append(header).append(": ").append(ClientRequest.getHeaderValue(val.get(0))).append("\n");
242             } else {
243                 StringBuilder sb = new StringBuilder();
244                 boolean add = false;
245                 for(Object o : val) {
246                     if(add) sb.append(',');
247                     add = true;
248                     sb.append(ClientRequest.getHeaderValue(o));
249                 }
250                 prefixId(b, id).append(REQUEST_PREFIX).append(header).append(": ").append(sb.toString()).append("\n");
251             }
252         }
253     }
254
255     private void logResponse(long id, ClientResponse response) {
256         StringBuilder b = new StringBuilder();
257
258         printResponseLine(b, id, response);
259         printResponseHeaders(b, id, response.getHeaders());
260
261         ByteArrayOutputStream out = new ByteArrayOutputStream();
262         InputStream in = response.getEntityInputStream();
263         try {
264             ReaderWriter.writeTo(in, out);
265
266             byte[] requestEntity = out.toByteArray();
267             printEntity(b, requestEntity);
268             response.setEntityInputStream(new ByteArrayInputStream(requestEntity));
269         } catch (IOException ex) {
270             throw new ClientHandlerException(ex);
271         }
272         log(b);
273     }
274
275     private void printResponseLine(StringBuilder b, long id, ClientResponse response) {
276         prefixId(b, id).append(NOTIFICATION_PREFIX).
277                 append("Client in-bound response").append("\n");
278         prefixId(b, id).append(RESPONSE_PREFIX).
279                 append(Integer.toString(response.getStatus())).
280                 append("\n");
281     }
282     
283     private void printResponseHeaders(StringBuilder b, long id, MultivaluedMap<String, String> headers) {
284         for (Map.Entry<String, List<String>> e : headers.entrySet()) {
285             String header = e.getKey();
286             for (String value : e.getValue()) {
287                 prefixId(b, id).append(RESPONSE_PREFIX).append(header).append(": ").
288                         append(value).append("\n");
289             }
290         }
291         prefixId(b, id).append(RESPONSE_PREFIX).append("\n");
292     }
293
294     private void printEntity(StringBuilder b, byte[] entity) throws IOException {
295         if (entity.length == 0)
296             return;
297         String entityString = new String(entity);
298         entityString = entityString.replaceAll(PASSWORD_PATTERN, "\"password\" : \"******\"");
299         b.append(entityString).append("\n");
300     }
301 }