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.io; |
20 | |
21 | import static com.google.common.base.Preconditions.checkNotNull; |
22 | import static com.google.common.base.Preconditions.checkState; |
23 | import static com.google.common.io.ByteStreams.toByteArray; |
24 | |
25 | import java.io.File; |
26 | import java.io.IOException; |
27 | import java.io.InputStream; |
28 | import java.security.MessageDigest; |
29 | import java.security.NoSuchAlgorithmException; |
30 | import java.util.Comparator; |
31 | import java.util.Map; |
32 | |
33 | import org.jclouds.javax.annotation.Nullable; |
34 | |
35 | import org.jclouds.crypto.CryptoStreams; |
36 | import org.jclouds.io.payloads.ByteArrayPayload; |
37 | import org.jclouds.io.payloads.FilePayload; |
38 | import org.jclouds.io.payloads.InputStreamPayload; |
39 | import org.jclouds.io.payloads.StringPayload; |
40 | import org.jclouds.io.payloads.UrlEncodedFormPayload; |
41 | |
42 | import com.google.common.base.Throwables; |
43 | import com.google.common.collect.Multimap; |
44 | |
45 | /** |
46 | * |
47 | * @author Adrian Cole |
48 | */ |
49 | public class Payloads { |
50 | private Payloads() { |
51 | } |
52 | |
53 | public static Payload newPayload(Object data) { |
54 | checkNotNull(data, "data"); |
55 | if (data instanceof Payload) { |
56 | return (Payload) data; |
57 | } else if (data instanceof InputStream) { |
58 | return newInputStreamPayload((InputStream) data); |
59 | } else if (data instanceof byte[]) { |
60 | return newByteArrayPayload((byte[]) data); |
61 | } else if (data instanceof String) { |
62 | return newStringPayload((String) data); |
63 | } else if (data instanceof File) { |
64 | return newFilePayload((File) data); |
65 | } else { |
66 | throw new UnsupportedOperationException("unsupported payload type: " + data.getClass()); |
67 | } |
68 | } |
69 | |
70 | public static InputStreamPayload newInputStreamPayload(InputStream data) { |
71 | return new InputStreamPayload(checkNotNull(data, "data")); |
72 | } |
73 | |
74 | public static ByteArrayPayload newByteArrayPayload(byte[] data) { |
75 | return new ByteArrayPayload(checkNotNull(data, "data")); |
76 | } |
77 | |
78 | public static StringPayload newStringPayload(String data) { |
79 | return new StringPayload(checkNotNull(data, "data")); |
80 | } |
81 | |
82 | public static FilePayload newFilePayload(File data) { |
83 | return new FilePayload(checkNotNull(data, "data")); |
84 | } |
85 | |
86 | public static UrlEncodedFormPayload newUrlEncodedFormPayload(Multimap<String, String> formParams, char... skips) { |
87 | return new UrlEncodedFormPayload(formParams, skips); |
88 | } |
89 | |
90 | public static UrlEncodedFormPayload newUrlEncodedFormPayload(Multimap<String, String> formParams, |
91 | @Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) { |
92 | return new UrlEncodedFormPayload(formParams, sorter, skips); |
93 | } |
94 | |
95 | /** |
96 | * Calculates and sets {@link Payload#setContentMD5} on the payload. |
97 | * |
98 | * <p/> |
99 | * note that this will rebuffer in memory if the payload is not repeatable. |
100 | * |
101 | * @param payload |
102 | * payload to calculate |
103 | * @param md5 |
104 | * digester to calculate payloads with. |
105 | * @return new Payload with md5 set. |
106 | * @throws IOException |
107 | */ |
108 | public static Payload calculateMD5(Payload payload, MessageDigest md5) throws IOException { |
109 | checkNotNull(payload, "payload"); |
110 | if (!payload.isRepeatable()) { |
111 | MutableContentMetadata oldContentMetadata = payload.getContentMetadata(); |
112 | Payload oldPayload = payload; |
113 | try { |
114 | payload = newByteArrayPayload(toByteArray(payload)); |
115 | } finally { |
116 | oldPayload.release(); |
117 | } |
118 | oldContentMetadata.setContentLength(payload.getContentMetadata().getContentLength()); |
119 | oldContentMetadata.setContentMD5(payload.getContentMetadata().getContentMD5()); |
120 | payload.setContentMetadata(oldContentMetadata); |
121 | } |
122 | payload.getContentMetadata().setContentMD5(CryptoStreams.digest(payload, md5)); |
123 | return payload; |
124 | } |
125 | |
126 | /** |
127 | * Uses default md5 generator. |
128 | * |
129 | * @see #calculateMD5(Payload, MessageDigest) |
130 | */ |
131 | public static Payload calculateMD5(Payload payload) throws IOException { |
132 | try { |
133 | return calculateMD5(payload, MessageDigest.getInstance("MD5")); |
134 | } catch (NoSuchAlgorithmException e) { |
135 | Throwables.propagate(e); |
136 | return null; |
137 | } |
138 | } |
139 | |
140 | /** |
141 | * Calculates the md5 on a payload, replacing as necessary. |
142 | * |
143 | * @see #calculateMD5(Payload, MessageDigest) |
144 | */ |
145 | public static <T extends PayloadEnclosing> T calculateMD5(T payloadEnclosing, MessageDigest md5) throws IOException { |
146 | checkState(payloadEnclosing != null, "payloadEnclosing"); |
147 | Payload newPayload = calculateMD5(payloadEnclosing.getPayload(), md5); |
148 | if (newPayload != payloadEnclosing.getPayload()) |
149 | payloadEnclosing.setPayload(newPayload); |
150 | return payloadEnclosing; |
151 | } |
152 | |
153 | /** |
154 | * Calculates the md5 on a payload, replacing as necessary. |
155 | * <p/> |
156 | * uses default md5 generator. |
157 | * |
158 | * @see #calculateMD5(Payload, MessageDigest) |
159 | */ |
160 | public static <T extends PayloadEnclosing> T calculateMD5(T payloadEnclosing) throws IOException { |
161 | try { |
162 | return calculateMD5(payloadEnclosing, MessageDigest.getInstance("MD5")); |
163 | } catch (NoSuchAlgorithmException e) { |
164 | Throwables.propagate(e); |
165 | return null; |
166 | } |
167 | } |
168 | } |