1
2
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
30
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
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);
191
192
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
231
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 }