001    /**
002     * Copyright (C) 2009-2011 the original author or authors.
003     * See the notice.md file distributed with this work for additional
004     * information regarding copyright ownership.
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.fusesource.restygwt.client;
020    
021    import java.util.Map;
022    
023    import com.google.gwt.http.client.URL;
024    
025    /**
026     * 
027     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
028     */
029    public class Resource {
030    
031        public static final String CONTENT_TYPE_TEXT = "text/plain";
032        public static final String CONTENT_TYPE_JSON = "application/json";
033        public static final String CONTENT_TYPE_XML = "application/xml";
034        public static final String CONTENT_TYPE_RSS = "application/rss+xml";
035        public static final String CONTENT_TYPE_ATOM = "application/atom+xml";
036        public static final String HEADER_ACCEPT = "Accept";
037        public static final String HEADER_CONTENT_TYPE = "Content-Type";
038    
039        final String path;
040        final String query;
041        final Map<String, String> headers;
042        
043        public Resource(String uri) {
044            this (uri, (Map<String, String>) null);
045        }
046        
047        public Resource(String uri, String query) {
048                    this(uri, query, null);
049            }
050    
051        public Resource(final String uri, final Map<String, String> headers) {
052            int pos = uri.indexOf('?');
053            if (pos >= 0) {
054                this.path = uri.substring(0, pos);
055                this.query = uri.substring(pos + 1);
056            } else {
057                    // Strip off trailing "/" so we have a known format to work off of when concatenating paths
058                this.path = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
059                this.query = null;
060            }
061            this.headers = (headers != null) ? headers : defaultHeaders();
062        }
063    
064        public Resource(final String uri, final String query, final Map<String, String> headers) {
065            // Strip off trailing "/" so we have a known format to work off of when concatenating paths
066            this.path = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
067            this.query = query;
068            this.headers = (headers != null) ? headers : defaultHeaders();
069        }    
070    
071            public Method head() {
072            return new Method(this, "HEAD").headers(headers);
073        }
074    
075        public Method get() {
076            return new Method(this, "GET").headers(headers);
077        }
078    
079        public Method put() {
080            return new Method(this, "PUT").headers(headers);
081        }
082    
083        public Method post() {
084            return new Method(this, "POST").headers(headers);
085        }
086    
087        public Method delete() {
088            return new Method(this, "DELETE").headers(headers);
089        }
090    
091        public Method options() {
092            return new Method(this, "OPTIONS").headers(headers);
093        }
094    
095        public JsonpMethod jsonp() {
096            return new JsonpMethod(this);
097        }
098    
099        public String getPath() {
100            return path;
101        }
102    
103        public String getQuery() {
104            return query;
105        }
106    
107        public String getUri() {
108            if (query != null) {
109                return path + "?" + query;
110            }
111            return path;
112        }
113        
114        public Map<String, String> getHeaders() {
115                    return headers;
116            }
117    
118        protected Map<String, String> defaultHeaders() {
119            return null;
120        }
121    
122        // TODO: support fancier resolutions
123        public Resource resolve(String path) {
124    
125            // it might be an absolute path...
126            if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("file:")) {
127                return new Resource(path);
128            }
129    
130            // strip prefix / if needed...
131            if (path.startsWith("/")) {
132                path = path.substring(1);
133            }
134            return new Resource(this.path + "/" + path);
135        }
136    
137        public Resource addQueryParam(String key, String value) {
138            key = URL.encodeComponent(key);
139            value = URL.encodeComponent(value);
140            String q = query == null ? "" : query + "&";
141            return new Resource(path, q + key + "=" + value, headers);
142        }
143    
144        public Resource addQueryParams(String key, Iterable<String> values) {
145            key = URL.encodeComponent(key);
146            StringBuilder q = new StringBuilder(query == null ? "" : query + "&");
147            boolean ampersand = false;
148            for (String value : values) {
149              if (ampersand) {
150                q.append('&');
151              } else {
152                ampersand = true;
153              }
154              value = URL.encodeComponent(value);
155              q.append(key).append("=").append(value);
156            }
157    
158            return new Resource(path, q.toString(), headers);
159        }
160    
161    
162    }