View Javadoc

1   /**
2    * Licensed to jclouds, Inc. (jclouds) under one or more
3    * contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  jclouds licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.jclouds.logging.internal;
20  
21  import static com.google.common.base.Preconditions.checkNotNull;
22  import static com.google.common.io.Closeables.closeQuietly;
23  import static org.jclouds.io.Payloads.newPayload;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.io.FileNotFoundException;
29  import java.io.IOException;
30  import java.io.InputStream;
31  
32  import javax.annotation.Resource;
33  
34  import org.jclouds.io.MutableContentMetadata;
35  import org.jclouds.io.Payload;
36  import org.jclouds.io.PayloadEnclosing;
37  import org.jclouds.logging.Logger;
38  
39  import com.google.common.io.ByteStreams;
40  import com.google.common.io.FileBackedOutputStream;
41  
42  /**
43   * Logs data to the wire LOG, similar to {@code org.apache.HttpWire.impl.conn.Wire}
44   * 
45   * @author Adrian Cole
46   */
47  public abstract class Wire {
48  
49     @Resource
50     protected Logger logger = Logger.NULL;
51  
52     protected abstract Logger getWireLog();
53  
54     private void wire(String header, InputStream instream) {
55        StringBuilder buffer = new StringBuilder();
56        int ch;
57        try {
58           while ((ch = instream.read()) != -1) {
59              if (ch == 13) {
60                 buffer.append("[\\r]");
61              } else if (ch == 10) {
62                 buffer.append("[\\n]\"");
63                 buffer.insert(0, "\"");
64                 buffer.insert(0, header);
65                 getWireLog().debug(buffer.toString());
66                 buffer.setLength(0);
67              } else if ((ch < 32) || (ch > 127)) {
68                 buffer.append("[0x");
69                 buffer.append(Integer.toHexString(ch));
70                 buffer.append("]");
71              } else {
72                 buffer.append((char) ch);
73              }
74           }
75           if (buffer.length() > 0) {
76              buffer.append('\"');
77              buffer.insert(0, '\"');
78              buffer.insert(0, header);
79              getWireLog().debug(buffer.toString());
80           }
81        } catch (IOException e) {
82           logger.error(e, "Error tapping line");
83        }
84     }
85  
86     public boolean enabled() {
87        return getWireLog().isDebugEnabled();
88     }
89  
90     public InputStream copy(final String header, InputStream instream) {
91        int limit = 256 * 1024;
92        FileBackedOutputStream out = null;
93        try {
94           out = new FileBackedOutputStream(limit);
95           long bytesRead = ByteStreams.copy(instream, out);
96           if (bytesRead >= limit)
97              logger.debug("over limit %d/%d: wrote temp file", bytesRead, limit);
98           wire(header, out.getSupplier().getInput());
99           return out.getSupplier().getInput();
100       } catch (IOException e) {
101          throw new RuntimeException("Error tapping line", e);
102       } finally {
103          closeQuietly(out);
104          closeQuietly(instream);
105       }
106    }
107 
108    public InputStream input(InputStream instream) {
109       return copy("<< ", checkNotNull(instream, "input"));
110    }
111 
112    public void input(PayloadEnclosing request) {
113       Payload oldContent = request.getPayload();
114       Payload wiredPayload = newPayload(input(oldContent.getInput()));
115       copyPayloadMetadata(oldContent, wiredPayload);
116       request.setPayload(wiredPayload);
117    }
118 
119    public void output(PayloadEnclosing request) {
120       Payload oldContent = request.getPayload();
121       Payload wiredPayload;
122       try {
123          wiredPayload = newPayload(output(oldContent.getRawContent()));
124       } catch (UnsupportedOperationException e) {
125          wiredPayload = newPayload(output(oldContent.getInput()));
126       }
127       copyPayloadMetadata(oldContent, wiredPayload);
128       request.setPayload(wiredPayload);
129    }
130 
131    private void copyPayloadMetadata(Payload oldContent, Payload wiredPayload) {
132       MutableContentMetadata oldMd = oldContent.getContentMetadata();
133       MutableContentMetadata wiredMd = wiredPayload.getContentMetadata();
134       if (oldMd.getContentLength() != null)
135          wiredMd.setContentLength(oldMd.getContentLength());
136       wiredMd.setContentType(oldMd.getContentType());
137       wiredMd.setContentMD5(oldMd.getContentMD5());
138       wiredMd.setContentDisposition(oldMd.getContentDisposition());
139       wiredMd.setContentEncoding(oldMd.getContentEncoding());
140       wiredMd.setContentLanguage(oldMd.getContentLanguage());
141    }
142 
143    @SuppressWarnings("unchecked")
144    public <T> T output(T data) {
145       checkNotNull(data, "data");
146       if (data instanceof InputStream) {
147          return (T) copy(">> ", (InputStream) data);
148       } else if (data instanceof byte[]) {
149          output((byte[]) data);
150          return data;
151       } else if (data instanceof String) {
152          output((String) data);
153          return data;
154       } else if (data instanceof File) {
155          output(((File) data));
156          return data;
157       }
158       throw new UnsupportedOperationException("Content not supported " + data.getClass());
159    }
160 
161    private void output(final File out) {
162       checkNotNull(out, "output");
163       InputStream in = null;
164       try {
165          in = new FileInputStream(out);
166          wire(">> ", in);
167       } catch (FileNotFoundException e) {
168          logger.error(e, "Error tapping file: %s", out);
169       } finally {
170          closeQuietly(in);
171       }
172    }
173 
174    private void output(byte[] b) {
175       wire(">> ", new ByteArrayInputStream(checkNotNull(b, "output")));
176    }
177 
178    private void output(final String s) {
179       output(checkNotNull(s, "output").getBytes());
180    }
181 
182 }