57ab36504b290982d080f050071b568119d7d268
[pithos-web-client] / src / gr / grnet / pithos / web / client / rest / GetCommand.java
1 /*
2  * Copyright 2011 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35 package gr.grnet.pithos.web.client.rest;
36
37 import gr.grnet.pithos.web.client.Pithos;
38 import gr.grnet.pithos.web.client.rest.resource.FileResource;
39 import gr.grnet.pithos.web.client.rest.resource.FolderResource;
40 import gr.grnet.pithos.web.client.rest.resource.GroupResource;
41 import gr.grnet.pithos.web.client.rest.resource.GroupUserResource;
42 import gr.grnet.pithos.web.client.rest.resource.GroupsResource;
43 import gr.grnet.pithos.web.client.rest.resource.OtherUserResource;
44 import gr.grnet.pithos.web.client.rest.resource.OthersResource;
45 import gr.grnet.pithos.web.client.rest.resource.RestResource;
46 import gr.grnet.pithos.web.client.rest.resource.SearchResource;
47 import gr.grnet.pithos.web.client.rest.resource.SharedResource;
48 import gr.grnet.pithos.web.client.rest.resource.TagsResource;
49 import gr.grnet.pithos.web.client.rest.resource.TrashResource;
50 import gr.grnet.pithos.web.client.rest.resource.UploadStatusResource;
51 import gr.grnet.pithos.web.client.rest.resource.UserResource;
52 import gr.grnet.pithos.web.client.rest.resource.UserSearchResource;
53
54 import java.util.HashMap;
55 import java.util.Map;
56
57 import com.google.gwt.core.client.GWT;
58 import com.google.gwt.http.client.Request;
59 import com.google.gwt.http.client.RequestBuilder;
60 import com.google.gwt.http.client.Response;
61
62 public abstract class GetCommand<T extends RestResource> extends RestCommand{
63
64         boolean complete = false;
65         T result = null;
66         Throwable exception = null;
67         Class<T> aclass;
68         private final String path;
69         private String username;
70         private boolean requestSent = false;
71         T cached;
72         
73         private static final long MAX_CACHE_AGE = 1000;
74         
75         private static class RequestData {
76                 public String path;
77                 public String username;
78                 
79                 public RequestData(String _path, String _username) {
80                         path = _path;
81                         username = _username;
82                 }
83
84                 @Override
85                 public int hashCode() {
86                         final int prime = 31;
87                         int result = 1;
88                         result = prime * result + ((path == null) ? 0 : path.hashCode());
89                         result = prime * result + ((username == null) ? 0 : username.hashCode());
90                         return result;
91                 }
92
93                 @Override
94                 public boolean equals(Object obj) {
95                         if (this == obj)
96                                 return true;
97                         if (obj == null)
98                                 return false;
99                         if (getClass() != obj.getClass())
100                                 return false;
101                         RequestData other = (RequestData) obj;
102                         if (path == null) {
103                                 if (other.path != null)
104                                         return false;
105                         } else if (!path.equals(other.path))
106                                 return false;
107                         if (username == null) {
108                                 if (other.username != null)
109                                         return false;
110                         } else if (!username.equals(other.username))
111                                 return false;
112                         return true;
113                 }
114         }
115         
116         private static class ResponseData {
117                 public long timestamp;
118                 public Object result;
119                 public ResponseData(long _timestamp, Object _result) {
120                         timestamp = _timestamp;
121                         result = _result;
122                 }
123         }
124         
125         private static Map<RequestData, ResponseData> cache = new HashMap<RequestData, ResponseData>();
126         
127
128         public GetCommand(Class<T> theclass, String pathToGet, T theCached){
129                 this(theclass, pathToGet, true, theCached);
130         }
131
132         public GetCommand(Class<T> theclass, String pathToGet, boolean showLoading, T theCached){
133                 setShowLoadingIndicator(showLoading);
134                 if(isShowLoadingIndicator())
135                         Pithos.get().showLoadingIndicator("Getting ",pathToGet);
136                 this.aclass = theclass;
137                 if(pathToGet.indexOf("?") != -1)
138                         path = pathToGet;
139                 else
140                         path =fixPath(pathToGet);
141                 this.cached = theCached;
142         }
143
144         public GetCommand(Class<T> theclass, String aUsername , String pathToGet, T theCached){
145                 this(theclass, aUsername, pathToGet, true, theCached);
146         }
147
148         public GetCommand(Class<T> theclass, String aUsername , String pathToGet, boolean showLoading, T theCached){
149                 setShowLoadingIndicator(showLoading);
150                 if(isShowLoadingIndicator())
151                         Pithos.get().showLoadingIndicator("Getting ",pathToGet);
152                 this.aclass = theclass;
153                 path = fixPath(pathToGet);
154                 this.username = aUsername;
155                 this.cached = theCached;
156         }
157
158         private void sendRequest(){
159                 if(requestSent)
160                         return;
161                 requestSent=true;
162                 RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
163                 if(cached!=null && cached.getLastModifiedSince() != null)
164                         builder.setHeader("If-Modified-Since", cached.getLastModifiedSince());
165                 try {
166                         if(username == null)
167                                 handleHeaders(builder, path);
168                         else
169                                 handleHeaders(username, builder, path);
170                         builder.sendRequest("", new RestCallback(path) {
171
172                                 @Override
173                                 public Object deserialize(Response response) {
174                                         return deserializeResponse(path, response);
175                                 }
176
177                                 @Override
178                                 public void handleError(Request request, Throwable _exception) {
179                                         result = null;
180                                         complete = true;
181                                         exception = _exception;
182                                         if(_exception instanceof RestException)
183                                                 if(((RestException)_exception).getHttpStatusCode() == 304 && cached != null){
184                                                         GWT.log("Using cache:"+cached.getUri(), null);
185                                                         handleSuccess(cached);
186                                                         return;
187                                                 }
188                                         
189                                 }
190
191                                 @Override
192                                 public void handleSuccess(Object object) {
193                                         result = (T) object;
194                                         complete = true;
195                                 }
196
197                         });
198                 } catch (Exception ex) {
199                         complete = true;
200                         exception = ex;
201                 }
202         }
203         public boolean isComplete() {
204                 return complete;
205         }
206
207         public T getResult(){
208                 return result;
209         }
210
211         @Override
212         public boolean execute() {
213                 boolean com = isComplete();
214                 RequestData key = new RequestData(path, username);
215                 if (!com) {
216                         if (cache.containsKey(key)) {
217                                 ResponseData resp = cache.get(key);
218                                 if (resp==null) {
219                                         return true;
220                                 }
221                                 
222                                 // Cache hit
223                                 if (System.currentTimeMillis()-resp.timestamp>MAX_CACHE_AGE) {
224                                         // Cache stale, remove
225                                         cache.put(key,null);
226                                 }
227                                 else {
228                                         // Use cache data
229                                         if(isShowLoadingIndicator())
230                                                 Pithos.get().hideLoadingIndicator();
231                                         if (resp.result instanceof Throwable) {
232                                                 // Error to be handled
233                                                 Throwable ex = (Throwable) resp.result;
234                                                 onError(ex);
235                                                 return false;
236                                         }
237                                         result = (T) resp.result;
238                                         if (result != null) {
239                                                 onComplete();
240                                         }
241                                         complete = true;
242                                         return false;
243                                 }
244                         }
245                 
246                         if(!requestSent) {
247                                 cache.put(key,null);
248                                 sendRequest();
249                         }
250                 }
251                 
252                 if(com){
253                         if(isShowLoadingIndicator())
254                                 Pithos.get().hideLoadingIndicator();
255                         if(getResult() != null) {
256                                 // Add to cache
257                                 cache.put(key, new ResponseData(System.currentTimeMillis(), getResult()));
258                                 onComplete();
259                         }
260                         else {
261                                 cache.put(key, new ResponseData(System.currentTimeMillis(), exception));
262                                 onError(exception);
263                         }
264                         return false;
265                 }
266                 return true;
267         }
268
269         public Object deserializeResponse(String aPath, Response response) {
270                 RestResource result1 = null;
271                 if(aclass.equals(FolderResource.class)){
272                         result1 = new FolderResource(aPath);
273                         result1.createFromJSON(response.getText());
274                 }
275                 else if(aclass.equals(FileResource.class)){
276                         result1 = new FileResource(aPath);
277                         result1.createFromJSON(response.getHeader("X-Pithos-Metadata"));
278                 }
279                 else if(aclass.equals(GroupsResource.class)){
280                         result1 = new GroupsResource(aPath);
281                         result1.createFromJSON(response.getText());
282                 }
283                 else if(aclass.equals(TrashResource.class)){
284                         result1 = new TrashResource(aPath);
285                         result1.createFromJSON(response.getText());
286                 }
287                 else if(aclass.equals(SharedResource.class)){
288                         result1 = new SharedResource(aPath);
289                         result1.createFromJSON(response.getText());
290                 }
291                 else if(aclass.equals(OthersResource.class)){
292                         result1 = new OthersResource(aPath);
293                         result1.createFromJSON(response.getText());
294                 }
295                 else if(aclass.equals(OtherUserResource.class)){
296                         result1 = new OtherUserResource(aPath);
297                         result1.createFromJSON(response.getText());
298                 }
299                 else if(aclass.equals(GroupResource.class)){
300                         result1 = new GroupResource(aPath);
301                         result1.createFromJSON(response.getText());
302                 }
303                 else if(aclass.equals(GroupUserResource.class)){
304                         result1 = new GroupUserResource(aPath);
305                         result1.createFromJSON(response.getText());
306                 }
307                 else if(aclass.equals(UserResource.class)){
308                         result1 = new UserResource(aPath);
309                         result1.createFromJSON(response.getText());
310                 }
311                 else if(aclass.equals(TagsResource.class)){
312                         result1 = new TagsResource(aPath);
313                         result1.createFromJSON(response.getText());
314                 }
315                 else if(aclass.equals(SearchResource.class)){
316                         result1 = new SearchResource(aPath);
317                         result1.createFromJSON(response.getText());
318                 }
319                 else if(aclass.equals(UserSearchResource.class)){
320                         result1 = new UserSearchResource(aPath);
321                         result1.createFromJSON(response.getText());
322                 }
323                 else if(aclass.equals(UploadStatusResource.class)){
324                         result1 = new UploadStatusResource(aPath);
325                         result1.createFromJSON(response.getText());
326                 }
327                 return result1;
328         }
329
330         public T getCached() {
331                 return cached;
332         }
333
334         public void setCached(T theCached) {
335                 this.cached = theCached;
336         }
337         
338         public boolean usedCachedVersion(){
339                 if(exception !=null && exception instanceof RestException)
340                         if(((RestException)exception).getHttpStatusCode() == 304){
341                                 return true;
342                         }
343                 return false;
344         }
345 }