View Javadoc
1   /*
2    * Copyright (C) 2003-2015 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 3 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.utils.image;
20  
21  import java.io.IOException;
22  import java.net.CookieHandler;
23  import java.net.CookieManager;
24  import java.net.HttpCookie;
25  import java.net.HttpURLConnection;
26  import java.net.URI;
27  import java.net.URISyntaxException;
28  
29  import org.apache.http.client.CookieStore;
30  import org.apache.http.cookie.Cookie;
31  import org.exoplatform.singleton.AccountSetting;
32  import org.exoplatform.utils.ExoConnectionUtils;
33  
34  import com.squareup.picasso.Picasso;
35  import com.squareup.picasso.UrlConnectionDownloader;
36  
37  import android.content.Context;
38  import android.net.Uri;
39  import android.util.Log;
40  
41  /**
42   * Created by The eXo Platform SAS<br/>
43   * A custom {@link Picasso} {@link UrlConnectionDownloader} that:
44   * <ul>
45   * <li>uses the cookies synchronized from {@link ExoConnectionUtils} to get
46   * permissions/restrictions about targeted resources</li>
47   * <li>sets the custom eXo/$version (Android) User-Agent header in the request
48   * </li>
49   * </ul>
50   * 
51   * @author Philippe Aristote paristote@exoplatform.com May 13, 2015
52   */
53  public class ExoPicassoDownloader extends UrlConnectionDownloader {
54  
55    private static final String TAG = "eXo___ExoPicassoDownloader___";
56  
57    // private static final String RESPONSE_SOURCE = "X-Android-Response-Source";
58  
59    public ExoPicassoDownloader(Context context) {
60      super(context);
61    }
62  
63    /**
64     * Creates a new CookieManager if none already exists and sets it as the
65     * default CookieHandler
66     * 
67     * @return the CookieManager newly created, or the existing one if it's
68     *         already the default CookieHandler
69     */
70    private CookieManager initCookieManager() {
71      CookieHandler handler = CookieHandler.getDefault();
72      CookieManager manager;
73      if (handler == null || !(handler instanceof CookieManager)) {
74        manager = new CookieManager();
75        CookieHandler.setDefault(manager);
76        // Sync cookies from ExoConnectionUtils only
77        // when the Cookies Manager is created
78        syncCookies(manager);
79      } else {
80        manager = (CookieManager) handler;
81      }
82      return manager;
83    }
84  
85    /**
86     * Syncs all cookies from ExoConnectionUtils cookieStore from Apache's
87     * HttpClient to HttpURLConnection.
88     * 
89     * @param manager the CookieManager in which to store the retrieved cookies
90     */
91    private void syncCookies(CookieManager manager) {
92      CookieStore store = ExoConnectionUtils.cookiesStore;
93      if (store == null)
94        return;
95  
96      for (Cookie cookie : store.getCookies()) {
97        HttpCookie c = new HttpCookie(cookie.getName(), cookie.getValue());
98        c.setDomain(cookie.getDomain());
99        c.setPath(cookie.getPath());
100       c.setVersion(cookie.getVersion());
101       String url = AccountSetting.getInstance().getDomainName() + "/" + cookie.getPath();
102       try {
103         manager.getCookieStore().add(new URI(url), c);
104       } catch (URISyntaxException e) {
105         Log.e(TAG, e.getMessage(), e);
106       }
107     }
108   }
109 
110   /**
111    * Creates a Http Connection which contains any existing cookie
112    * 
113    * @param path The URL to connect to
114    * @return the HttpURLConnection
115    * @throws IOException
116    */
117   private HttpURLConnection connection(Uri path) throws IOException {
118     HttpURLConnection connection = super.openConnection(path);
119     ExoConnectionUtils.setUserAgent(connection);
120     initCookieManager();
121     return connection;
122   }
123 
124   @Override
125   public Response load(Uri uri, int networkPolicy) throws IOException {
126     // TODO use networkPolicy as in com.squareup.picasso.UrlConnectionDownloader
127     // https://github.com/square/picasso/blob/picasso-parent-2.5.2/
128     // picasso/src/main/java/com/squareup/picasso/UrlConnectionDownloader.java
129     HttpURLConnection connection = connection(uri);
130     connection.setInstanceFollowRedirects(true);
131     connection.setUseCaches(true);
132 
133     int responseCode = connection.getResponseCode();
134     // Handle HTTP redirections that are not managed by HttpURLConnection
135     // automatically, e.g. HTTP -> HTTPS
136     // TODO consider using OkHttp instead
137     if (responseCode >= 300 && responseCode < 400) {
138       String location = connection.getHeaderField("Location");
139       connection.disconnect();
140       connection = connection(Uri.parse(location));
141       connection.setInstanceFollowRedirects(true);
142       connection.setUseCaches(true);
143       responseCode = connection.getResponseCode();
144     }
145     // Either the original or the new request have failed -> error
146     if (responseCode >= 300) {
147       connection.disconnect();
148       throw new ResponseException(responseCode + " " + connection.getResponseMessage(), networkPolicy, responseCode);
149     }
150 
151     long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
152     // boolean fromCache =
153     // parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));
154     boolean fromCache = false;
155 
156     return new Response(connection.getInputStream(), fromCache, contentLength);
157   }
158 
159 }