org.richfaces.resource.AbstractBaseResource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of richfaces-core Show documentation
Show all versions of richfaces-core Show documentation
The RichFaces core framework.
The newest version!
/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.context.FacesContext;
import org.richfaces.application.Uptime;
import org.richfaces.log.Logger;
import org.richfaces.log.RichfacesLogger;
import org.richfaces.application.ServiceTracker;
/**
* @author Nick Belaevski
* @since 4.0
*/
public abstract class AbstractBaseResource extends Resource {
public static final String URL_PROTOCOL = "jsfresource";
private static final Logger LOGGER = RichfacesLogger.RESOURCE.getLogger();
private Date lastModified = null;
protected AbstractBaseResource() {
super();
}
protected int getContentLength(FacesContext context) {
return -1;
}
/**
* TODO optimize/review?
*
* @return Returns the lastModified.
*/
protected Date getLastModified(FacesContext context) {
if (lastModified == null) {
lastModified = getLastModifiedBySource();
}
// TODO - originally lastModified was set during resource creation.
// as resources can be managed beans this approach does not seem good
if (lastModified == null) {
lastModified = ServiceTracker.getService(Uptime.class).getStartTime();
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug(MessageFormat.format(
"Using resource handler start time as last modified date: {0,date,dd MMM yyyy HH:mm:ss zzz}",
lastModified));
}
}
return lastModified;
}
private Date getLastModifiedBySource() {
ClassLoader classLoader = getClassLoader();
if (classLoader == null) {
return null;
}
URL classResource = classLoader.getResource(getClass().getName().replace('.', '/') + ".class");
if (classResource != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(MessageFormat.format("Located source for the resource class: {0}", classResource));
}
try {
URLConnection connection = classResource.openConnection();
connection.setUseCaches(false);
long classLastModifiedDate = connection.getLastModified();
if (classLastModifiedDate > 0) {
lastModified = new Date(classLastModifiedDate);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(MessageFormat.format("Last source modification date is: {0,date}", lastModified));
}
}
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Source for the resource class has not been located");
}
}
return null;
}
protected ClassLoader getClassLoader() {
Class extends AbstractBaseResource> thisClass = getClass();
ClassLoader classLoader = thisClass.getClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
return classLoader;
}
private String getResourceVersion() {
if (this instanceof VersionedResource) {
return ((VersionedResource) this).getVersion();
}
return null;
}
@Override
public String getRequestPath() {
FacesContext context = FacesContext.getCurrentInstance();
ResourceCodec resourceCodec = ServiceTracker.getService(context, ResourceCodec.class);
String libraryName = getLibraryName();
String resourceName = getResourceName();
Object resourceData = ResourceUtils.saveResourceState(context, this);
String resourceVersion = getResourceVersion();
String resourceUri = resourceCodec.encodeResourceRequestPath(context, libraryName, resourceName, resourceData,
resourceVersion);
resourceUri = resourceCodec.encodeJSFMapping(context, resourceUri);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(MessageFormat.format("Request path for {0} resource is: {1}", String.valueOf(resourceName),
String.valueOf(resourceUri)));
}
return resourceUri;
}
boolean isResourceRequest() {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getResourceHandler().isResourceRequest(facesContext);
}
long getCurrentTime() {
return System.currentTimeMillis();
}
protected void addNoCacheResponseHeaders(FacesContext facesContext, Map headers) {
headers.put("Expires", "0");
headers.put("Cache-Control", "max-age=0, no-store, no-cache");
headers.put("Pragma", "no-cache");
}
protected void addCacheControlResponseHeaders(FacesContext facesContext, Map headers) {
addNoCacheResponseHeaders(facesContext, headers);
}
@Override
public Map getResponseHeaders() {
Map headers = new HashMap();
FacesContext facesContext = FacesContext.getCurrentInstance();
if (isResourceRequest()) {
int contentLength = getContentLength(facesContext);
if (contentLength >= 0) {
headers.put("Content-Length", String.valueOf(contentLength));
}
String contentType = getContentType();
if (contentType != null) {
headers.put("Content-Type", contentType);
}
Date lastModified = getLastModified(facesContext);
if (lastModified != null) {
headers.put("Last-Modified", ResourceUtils.formatHttpDate(lastModified));
}
headers.put("Date", ResourceUtils.formatHttpDate(getCurrentTime()));
addCacheControlResponseHeaders(facesContext, headers);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Created set of response headers");
// TODO - security - can we log header values?
for (Entry entry : headers.entrySet()) {
LOGGER.debug(MessageFormat.format("\t{0}={1}", entry.getKey(), entry.getValue()));
}
}
}
return headers;
}
@Override
public URL getURL() {
try {
return new URL(URL_PROTOCOL, null, -1, getResourceName(), new MyURLStreamHandler());
} catch (MalformedURLException e) {
throw new FacesException(e.getLocalizedMessage(), e);
}
}
@Override
public boolean userAgentNeedsUpdate(FacesContext context) {
return true;
}
private class MyURLConnection extends URLConnection {
MyURLConnection(URL u) {
super(u);
}
@Override
public void connect() throws IOException {
}
@Override
public int getContentLength() {
FacesContext facesContext = FacesContext.getCurrentInstance();
return AbstractBaseResource.this.getContentLength(facesContext);
}
@Override
public String getContentType() {
return AbstractBaseResource.this.getContentType();
}
@Override
public long getExpiration() {
return 0;
}
@Override
public long getLastModified() {
FacesContext facesContext = FacesContext.getCurrentInstance();
Date date = AbstractBaseResource.this.getLastModified(facesContext);
if (date != null) {
return date.getTime();
}
return 0;
}
@Override
public InputStream getInputStream() throws IOException {
return AbstractBaseResource.this.getInputStream();
}
}
private class MyURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return new MyURLConnection(u);
}
}
}