2 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
23 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
25 * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
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.
36 * When distributing the software, include this License Header Notice in each
37 * file and include the License file at packager/legal/LICENSE.txt.
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.
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]"
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
61 package com.woorea.openstack.connector;
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;
71 import java.util.logging.Logger;
73 import javax.ws.rs.core.MultivaluedMap;
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;
88 public class JerseyLoggingFilter extends ClientFilter {
90 private static final Logger LOGGER = Logger.getLogger(LoggingFilter.class.getName());
92 private static final String NOTIFICATION_PREFIX = "* ";
94 private static final String REQUEST_PREFIX = "> ";
96 private static final String RESPONSE_PREFIX = "< ";
98 private static final String PASSWORD_PATTERN = "\"password\".*:.*\"(.*)\"";
100 private final class Adapter extends AbstractClientRequestAdapter {
101 private final StringBuilder b;
103 Adapter(ClientRequestAdapter cra, StringBuilder b) {
109 public OutputStream adapt(ClientRequest request, OutputStream out) throws IOException {
110 return new LoggingOutputStream(getAdapter().adapt(request, out), b);
115 private final class LoggingOutputStream extends OutputStream {
116 private final OutputStream out;
118 private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
120 private final StringBuilder b;
122 LoggingOutputStream(OutputStream out, StringBuilder b) {
128 public void write(byte[] b) throws IOException {
134 public void write(byte[] b, int off, int len) throws IOException {
135 baos.write(b, off, len);
136 out.write(b, off, len);
140 public void write(int b) throws IOException {
146 public void close() throws IOException {
147 printEntity(b, baos.toByteArray());
153 private final PrintStream loggingStream;
155 private final Logger logger;
157 private long _id = 0;
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
164 public JerseyLoggingFilter() {
169 * Create a logging filter logging the request and response to
172 * @param logger the logger to log requests and responses.
174 public JerseyLoggingFilter(Logger logger) {
175 this.loggingStream = null;
176 this.logger = logger;
180 * Create a logging filter logging the request and response to
183 * @param loggingStream the print stream to log requests and responses.
185 public JerseyLoggingFilter(PrintStream loggingStream) {
186 this.loggingStream = loggingStream;
190 private void log(StringBuilder b) {
191 if (logger != null) {
192 logger.info(b.toString());
194 loggingStream.print(b);
198 private StringBuilder prefixId(StringBuilder b, long id) {
199 b.append(Long.toString(id)).append(" ");
204 public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
205 long id = ++this._id;
207 logRequest(id, request);
209 ClientResponse response = getNext().handle(request);
211 logResponse(id, response);
216 private void logRequest(long id, ClientRequest request) {
217 StringBuilder b = new StringBuilder();
219 printRequestLine(b, id, request);
220 printRequestHeaders(b, id, request.getHeaders());
222 if (request.getEntity() != null) {
223 request.setAdapter(new Adapter(request.getAdapter(), b));
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");
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();
240 if(val.size() == 1) {
241 prefixId(b, id).append(REQUEST_PREFIX).append(header).append(": ").append(ClientRequest.getHeaderValue(val.get(0))).append("\n");
243 StringBuilder sb = new StringBuilder();
245 for(Object o : val) {
246 if(add) sb.append(',');
248 sb.append(ClientRequest.getHeaderValue(o));
250 prefixId(b, id).append(REQUEST_PREFIX).append(header).append(": ").append(sb.toString()).append("\n");
255 private void logResponse(long id, ClientResponse response) {
256 StringBuilder b = new StringBuilder();
258 printResponseLine(b, id, response);
259 printResponseHeaders(b, id, response.getHeaders());
261 ByteArrayOutputStream out = new ByteArrayOutputStream();
262 InputStream in = response.getEntityInputStream();
264 ReaderWriter.writeTo(in, out);
266 byte[] requestEntity = out.toByteArray();
267 printEntity(b, requestEntity);
268 response.setEntityInputStream(new ByteArrayInputStream(requestEntity));
269 } catch (IOException ex) {
270 throw new ClientHandlerException(ex);
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())).
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");
291 prefixId(b, id).append(RESPONSE_PREFIX).append("\n");
294 private void printEntity(StringBuilder b, byte[] entity) throws IOException {
295 if (entity.length == 0)
297 String entityString = new String(entity);
298 entityString = entityString.replaceAll(PASSWORD_PATTERN, "\"password\" : \"******\"");
299 b.append(entityString).append("\n");