View Javadoc

1   /*
2    * $Id: ResourceVersionHandlerImpl.java,v 1.8 2010/03/19 14:53:48 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.version;
5   
6   import java.net.URL;
7   import java.util.HashMap;
8   import java.util.Map;
9   
10  import javax.faces.context.ExternalContext;
11  import javax.faces.context.FacesContext;
12  
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  import org.rcfaces.core.internal.Constants;
16  import org.rcfaces.core.internal.RcfacesContext;
17  import org.rcfaces.core.internal.contentAccessor.BasicContentAccessor;
18  import org.rcfaces.core.internal.contentAccessor.IContentAccessor;
19  import org.rcfaces.core.internal.contentAccessor.IContentPath;
20  import org.rcfaces.core.internal.contentAccessor.IContentVersionHandler;
21  import org.rcfaces.core.internal.contentAccessor.IGeneratedResourceInformation;
22  import org.rcfaces.core.internal.lang.StringAppender;
23  import org.rcfaces.core.internal.renderkit.AbstractProcessContext;
24  import org.rcfaces.core.internal.renderkit.IProcessContext;
25  import org.rcfaces.core.provider.AbstractProvider;
26  
27  /**
28   * 
29   * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
30   * @version $Revision: 1.8 $ $Date: 2010/03/19 14:53:48 $
31   */
32  public class ResourceVersionHandlerImpl extends AbstractProvider implements
33          IResourceVersionHandler, IContentVersionHandler {
34  
35      private static final String REVISION = "$Revision: 1.8 $";
36  
37      private static final Log LOG = LogFactory
38              .getLog(ResourceVersionHandlerImpl.class);
39  
40      private static final String APPLICATION_VERSION_URI_PARAMETER = Constants
41              .getPackagePrefix()
42              + ".APPLICATION_VERSION";
43  
44      private static final String HASHCODE_KEYWORD = "hashcode";
45  
46      private static final String NOW_KEYWORD = "now";
47  
48      private static final int HASHCODE_CACHE_INITIAL_SIZE = 128;
49  
50      private String prefixURI;
51  
52      private String version;
53  
54      private Map hashCodeByURL = null;
55  
56      public ResourceVersionHandlerImpl() {
57      }
58  
59      public String getId() {
60          return "ResourceVersionHandler";
61      }
62  
63      public void startup(FacesContext facesContext) {
64  
65          ExternalContext externalContext = facesContext.getExternalContext();
66  
67          String applicationVersionURI = ApplicationVersionServlet
68                  .getApplicationVersionURI(externalContext.getApplicationMap());
69          if (applicationVersionURI == null) {
70              LOG
71                      .debug("Can not find application version pattern ! (Servlet can be not defined)");
72              this.prefixURI = null;
73              this.version = null;
74              return;
75          }
76  
77          String version = externalContext
78                  .getInitParameter(APPLICATION_VERSION_URI_PARAMETER);
79          if (version == null || "none".equalsIgnoreCase(version)) {
80              this.prefixURI = null;
81              this.version = null;
82              LOG
83                      .info("Disable application version rewriting engine. (context parameter '"
84                              + APPLICATION_VERSION_URI_PARAMETER
85                              + "="
86                              + version
87                              + "')");
88              return;
89          }
90  
91          if (HASHCODE_KEYWORD.equalsIgnoreCase(version)) {
92              version = HASHCODE_KEYWORD;
93  
94              prefixURI = applicationVersionURI;
95              hashCodeByURL = new HashMap(HASHCODE_CACHE_INITIAL_SIZE);
96  
97              LOG.info("Use resource hashcode as the resource version.");
98  
99          } else {
100             if (NOW_KEYWORD.equalsIgnoreCase(version)) {
101                 version = "0." + System.currentTimeMillis();
102 
103                 LOG.info("Set resource version to a random value: '" + version
104                         + "'.");
105 
106             } else {
107                 LOG.info("Set resource version to specified value: '" + version
108                         + "'.");
109             }
110 
111             prefixURI = applicationVersionURI + "/" + version;
112             LOG.info("Set resource version url to '" + prefixURI + "'.");
113         }
114 
115         this.version = version;
116 
117         RcfacesContext rcfacesContext = RcfacesContext
118                 .getInstance(facesContext);
119         if (rcfacesContext.getResourceVersionHandler() == null) {
120             rcfacesContext.setResourceVersionHandler(this);
121         }
122 
123         if (rcfacesContext.getDefaultContentVersionHandler() == null) {
124             rcfacesContext.setDefaultContentVersionHandler(this);
125         }
126     }
127 
128     public boolean isEnabled() {
129         return prefixURI != null;
130     }
131 
132     public String getVersionTag(RcfacesContext rcfacesContext,
133             FacesContext facesContext, String relativeUrl,
134             IContentAccessor contentAccessor,
135             IGeneratedResourceInformation contentInformation) {
136 
137         if (prefixURI == null) {
138             return null;
139         }
140 
141         IProcessContext processContext = AbstractProcessContext
142                 .getProcessContext(facesContext);
143 
144         String absoluteURLWithoutPrefix = processContext.getAbsolutePath(
145                 relativeUrl, false);
146 
147         return getResourceVersion(facesContext, absoluteURLWithoutPrefix, null);
148     }
149 
150     public IContentAccessor getVersionedContentAccessor(
151             RcfacesContext rcfacesContext, FacesContext facesContext,
152             IContentAccessor contentAccessor,
153             IGeneratedResourceInformation[] contentInformation) {
154 
155         if (prefixURI == null) {
156             return null;
157         }
158 
159         String url = (String) contentAccessor.getContentRef();
160         int pathType = contentAccessor.getPathType();
161         switch (pathType) {
162 
163         case IContentPath.RELATIVE_PATH_TYPE:
164             IProcessContext processContext = AbstractProcessContext
165                     .getProcessContext(facesContext);
166 
167             url = processContext.getAbsolutePath(url, false);
168             break;
169 
170         case IContentPath.CONTEXT_PATH_TYPE:
171             break;
172 
173         default:
174             return null;
175         }
176 
177         if (hashCodeByURL == null) {
178             // Le prefixURI contient la version !
179             StringAppender sa = new StringAppender(prefixURI, 1
180                     + version.length() + url.length());
181             sa.append('/');
182             sa.append(version);
183             sa.append(url);
184 
185             return new BasicContentAccessor(facesContext, sa.toString(),
186                     contentAccessor, IContentPath.CONTEXT_PATH_TYPE);
187         }
188 
189         StringAppender sa = new StringAppender(prefixURI, 1
190                 + Constants.VERSIONED_URI_HASHCODE_MAX_SIZE + url.length() + 4); // 4
191         // =
192         // sécurité
193         // !
194 
195         String etag = getResourceVersion(facesContext, url, null);
196 
197         sa.append('/');
198         sa.append(etag);
199 
200         if (url.length() > 0 && url.charAt(0) != '/') {
201             sa.append('/');
202         }
203 
204         sa.append(url);
205 
206         return new BasicContentAccessor(facesContext, sa.toString(),
207                 contentAccessor, IContentPath.CONTEXT_PATH_TYPE);
208     }
209 
210     public String getResourceVersion(FacesContext facesContext,
211             String absolutePath, URL url) {
212         if (hashCodeByURL == null) {
213             return version;
214         }
215 
216         ResourceHashCode tag;
217         synchronized (hashCodeByURL) {
218             tag = (ResourceHashCode) hashCodeByURL.get(absolutePath);
219             if (tag == null) {
220                 tag = new ResourceHashCode(absolutePath, url);
221                 hashCodeByURL.put(absolutePath, tag);
222             }
223         }
224 
225         return tag.getHashCode(facesContext);
226     }
227 
228     /**
229      * 
230      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
231      * @version $Revision: 1.8 $ $Date: 2010/03/19 14:53:48 $
232      */
233     private static final class ResourceHashCode {
234 
235         private static final String REVISION = "$Revision: 1.8 $";
236 
237         private static final String NULL_HASH_CODE = "ERR";
238 
239         private final String absolutePath;
240 
241         private final URL url;
242 
243         private String etag;
244 
245         public ResourceHashCode(String absolutePath, URL url) {
246             this.absolutePath = absolutePath;
247             this.url = url;
248         }
249 
250         public synchronized String getHashCode(FacesContext facesContext) {
251             if (etag == null) {
252                 etag = HashCodeTools.computeURLFormat(facesContext,
253                         absolutePath, url,
254                         Constants.VERSIONED_URI_HASHCODE_MAX_SIZE);
255                 if (etag == null) {
256                     etag = NULL_HASH_CODE;
257                 }
258             }
259             return etag;
260         }
261 
262     }
263 }