View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.blobstore.functions;
20  
21  import static com.google.common.base.Preconditions.checkArgument;
22  import static com.google.common.base.Preconditions.checkNotNull;
23  import static com.google.common.base.Preconditions.checkState;
24  import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
25  import static org.jclouds.blobstore.util.BlobStoreUtils.getNameFor;
26  
27  import java.net.URI;
28  import java.util.Map.Entry;
29  
30  import javax.inject.Inject;
31  import javax.inject.Named;
32  import javax.inject.Provider;
33  import javax.ws.rs.core.HttpHeaders;
34  
35  import org.jclouds.blobstore.domain.MutableBlobMetadata;
36  import org.jclouds.date.DateService;
37  import org.jclouds.http.HttpException;
38  import org.jclouds.http.HttpRequest;
39  import org.jclouds.http.HttpResponse;
40  import org.jclouds.http.HttpUtils;
41  import org.jclouds.rest.InvocationContext;
42  import org.jclouds.rest.internal.GeneratedHttpRequest;
43  
44  import com.google.common.annotations.VisibleForTesting;
45  import com.google.common.base.Function;
46  
47  /**
48   * @author Adrian Cole
49   */
50  public class ParseSystemAndUserMetadataFromHeaders implements Function<HttpResponse, MutableBlobMetadata>,
51           InvocationContext<ParseSystemAndUserMetadataFromHeaders> {
52     private final String metadataPrefix;
53     private final DateService dateParser;
54     private final Provider<MutableBlobMetadata> metadataFactory;
55  
56     private String name;
57     private URI endpoint;
58  
59     @Inject
60     public ParseSystemAndUserMetadataFromHeaders(Provider<MutableBlobMetadata> metadataFactory, DateService dateParser,
61              @Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
62        this.metadataFactory = checkNotNull(metadataFactory, "metadataFactory");
63        this.dateParser = checkNotNull(dateParser, "dateParser");
64        this.metadataPrefix = checkNotNull(metadataPrefix, "metadataPrefix");
65     }
66  
67     public MutableBlobMetadata apply(HttpResponse from) {
68        checkNotNull(from, "request");
69        checkState(name != null, "name must be initialized by now");
70  
71        MutableBlobMetadata to = metadataFactory.get();
72        to.setName(name);
73        to.setUri(endpoint);
74        if (from.getPayload() != null)
75           HttpUtils.copy(from.getPayload().getContentMetadata(), to.getContentMetadata());
76        addETagTo(from, to);
77        parseLastModifiedOrThrowException(from, to);
78        addUserMetadataTo(from, to);
79        return to;
80     }
81  
82     @VisibleForTesting
83     void addUserMetadataTo(HttpResponse from, MutableBlobMetadata metadata) {
84        for (Entry<String, String> header : from.getHeaders().entries()) {
85           if (header.getKey() != null && header.getKey().startsWith(metadataPrefix))
86              metadata.getUserMetadata().put((header.getKey().substring(metadataPrefix.length())).toLowerCase(),
87                       header.getValue());
88        }
89     }
90  
91     @VisibleForTesting
92     void parseLastModifiedOrThrowException(HttpResponse from, MutableBlobMetadata metadata) throws HttpException {
93        String lastModified = from.getFirstHeaderOrNull(HttpHeaders.LAST_MODIFIED);
94        if (lastModified == null) {
95           // scaleup-storage uses the wrong case for the last modified header
96           if ((lastModified = from.getFirstHeaderOrNull("Last-modified")) == null)
97              throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: " + from);
98        }
99  
100       // Walrus
101       if (lastModified.startsWith("20")) {
102          metadata.setLastModified(dateParser.iso8601DateParse(lastModified.replace("+0000", "Z")));
103       } else {
104          metadata.setLastModified(dateParser.rfc822DateParse(lastModified));
105       }
106 
107       if (metadata.getLastModified() == null)
108          throw new HttpException("could not parse: " + HttpHeaders.LAST_MODIFIED + ": " + lastModified);
109    }
110 
111    protected void addETagTo(HttpResponse from, MutableBlobMetadata metadata) {
112       String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
113       if (metadata.getETag() == null && eTag != null) {
114          metadata.setETag(eTag);
115       }
116    }
117 
118    public ParseSystemAndUserMetadataFromHeaders setContext(HttpRequest request) {
119       this.endpoint = request.getEndpoint();
120       checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
121       return setName(getNameFor(GeneratedHttpRequest.class.cast(request)));
122    }
123 
124    public ParseSystemAndUserMetadataFromHeaders setName(String name) {
125       this.name = checkNotNull(name, "name");
126       return this;
127    }
128 }