ResourceRequestData data = resourceCodec.decodeResource(context, resourcePath);
assert (data != null);
Cache cache = ServiceTracker.getService(context, Cache.class);
Resource resource = lookupInCache(cache, data.getResourceKey());
if (resource == null) {
resource = resourceFactory.createResource(context, data);
}
if (resource == null) {
sendResourceNotFound(context);
return;
}
if (resource instanceof CacheableResource) {
CacheableResource cacheableResource = (CacheableResource) resource;
if (cacheableResource.isCacheable(context)) {
// TODO - we could move this part of code to ConcurrentMap so that
// only single thread does resource put
CachedResourceImpl cachedResource = new CachedResourceImpl();
cachedResource.initialize(resource);
// someone may provided this resource for us
// while we were reading it, check once again
resource = lookupInCache(cache, data.getResourceKey());
if (resource == null) {
// don't cache it on Development stage
if (!ProjectStage.Development.equals(context.getApplication().getProjectStage())) {
Date cacheExpirationDate = cachedResource.getExpired(context);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(new MessageFormat(
"Storing {0} resource in cache until {1,date,dd MMM yyyy HH:mm:ss zzz}", Locale.US)
.format(new Object[] { data.getResourceKey(), cacheExpirationDate }));
}
cache.put(data.getResourceKey(), cachedResource, cacheExpirationDate);
}
resource = cachedResource;
}
}
}
if (resource.userAgentNeedsUpdate(context)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("User agent needs resource update, encoding resource");
}
ExternalContext externalContext = context.getExternalContext();
Map<String, String> headers = resource.getResponseHeaders();
for (Entry<String, String> headerEntry : headers.entrySet()) {
String headerName = headerEntry.getKey();
String headerValue = headerEntry.getValue();
// TODO should external context handles this itself?
if ("content-length".equals(headerName.toLowerCase(Locale.US))) {
try {
externalContext.setResponseContentLength(Integer.parseInt(headerValue));
} catch (NumberFormatException e) {
// TODO: handle exception
}
} else {
externalContext.setResponseHeader(headerName, headerValue);
}
}
// TODO null content type?
String contentType = resource.getContentType();
if (contentType != null) {
externalContext.setResponseContentType(contentType);
}
if (resource instanceof ContentProducerResource) {
ContentProducerResource contentProducerResource = (ContentProducerResource) resource;
contentProducerResource.encode(context);
} else {
// TODO setup output buffer size according to configuration parameter
InputStream is = resource.getInputStream();
OutputStream os = externalContext.getResponseOutputStream();
try {
ResourceUtils.copyStreamContent(is, os);
} finally {