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.io.payloads;
20  
21  import static com.google.common.base.Throwables.propagate;
22  import static com.google.common.collect.Lists.newArrayList;
23  import static com.google.common.io.ByteStreams.join;
24  import static com.google.common.io.ByteStreams.newInputStreamSupplier;
25  
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.util.Map.Entry;
29  
30  import com.google.common.io.InputSupplier;
31  
32  /**
33   * 
34   * @author Adrian Cole
35   */
36  public class MultipartForm extends BasePayload<Iterable<? extends Part>> {
37     public static final String BOUNDARY = "--JCLOUDS--";
38     private static final String rn = "\r\n";
39     private static final String dd = "--";
40  
41     private boolean isRepeatable;
42     private final InputSupplier<? extends InputStream> chain;
43  
44     @SuppressWarnings("unchecked")
45     public MultipartForm(String boundary, Iterable<? extends Part> content) {
46        super(content);
47        getContentMetadata().setContentType("multipart/form-data; boundary=" + boundary);
48        getContentMetadata().setContentLength(0l);
49        String boundaryrn = boundary + rn;
50        isRepeatable = true;
51        InputSupplier<? extends InputStream> chain = join();
52        for (Part part : content) {
53           if (!part.isRepeatable())
54              isRepeatable = false;
55           getContentMetadata().setContentLength(
56                    getContentMetadata().getContentLength() + part.getContentMetadata().getContentLength());
57           chain = join(chain, addLengthAndReturnHeaders(boundaryrn, part), part, addLengthAndReturnRn());
58        }
59        chain = join(chain, addLengthAndReturnFooter(boundary));
60        this.chain = chain;
61     }
62  
63     public MultipartForm(String boundary, Part... parts) {
64        this(boundary, newArrayList(parts));
65     }
66  
67     public MultipartForm(Part... parts) {
68        this(BOUNDARY, parts);
69     }
70  
71     private InputSupplier<? extends InputStream> addLengthAndReturnRn() {
72        getContentMetadata().setContentLength(getContentMetadata().getContentLength() + rn.length());
73        return newInputStreamSupplier(rn.getBytes());
74     }
75  
76     private InputSupplier<? extends InputStream> addLengthAndReturnHeaders(String boundaryrn, Part part) {
77        StringBuilder builder = new StringBuilder(dd).append(boundaryrn);
78        for (Entry<String, String> entry : part.getHeaders().entries()) {
79           String header = String.format("%s: %s%s", entry.getKey(), entry.getValue(), rn);
80           builder.append(header);
81        }
82        builder.append(rn);
83        getContentMetadata().setContentLength(getContentMetadata().getContentLength() + builder.length());
84        return newInputStreamSupplier(builder.toString().getBytes());
85     }
86  
87     private InputSupplier<? extends InputStream> addLengthAndReturnFooter(String boundary) {
88        String end = dd + boundary + dd + rn;
89        getContentMetadata().setContentLength(getContentMetadata().getContentLength() + end.length());
90        return newInputStreamSupplier(end.getBytes());
91     }
92  
93     @Override
94     public InputStream getInput() {
95        try {
96           return chain.getInput();
97        } catch (IOException e) {
98           propagate(e);
99           return null;
100       }
101    }
102 
103    @Override
104    public boolean isRepeatable() {
105       return isRepeatable;
106    }
107 
108    @Override
109    public void release() {
110       for (Part part : content)
111          part.release();
112    }
113 
114 }