From richfaces-svn-commits at lists.jboss.org Fri Nov 28 15:18:12 2008 Content-Type: multipart/mixed; boundary="===============0745291583826542359==" MIME-Version: 1.0 From: richfaces-svn-commits at lists.jboss.org To: richfaces-svn-commits at lists.jboss.org Subject: [richfaces-svn-commits] JBoss Rich Faces SVN: r11449 - trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached. Date: Fri, 28 Nov 2008 15:18:11 -0500 Message-ID: --===============0745291583826542359== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: nbelaevski Date: 2008-11-28 15:18:11 -0500 (Fri, 28 Nov 2008) New Revision: 11449 Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/CachedRe= sourceBuilder.java trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/DualLRUM= ap.java trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resource= Bean.java trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resource= BytesDataBean.java trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resource= DataBean.java Log: RF-3586 Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/C= achedResourceBuilder.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/CachedR= esourceBuilder.java 2008-11-28 19:06:24 UTC (rev 11448) +++ trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/CachedR= esourceBuilder.java 2008-11-28 20:18:11 UTC (rev 11449) @@ -24,6 +24,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.locks.ReentrantReadWriteLock; = import javax.faces.FacesException; import javax.faces.context.FacesContext; @@ -37,165 +39,241 @@ import org.apache.commons.logging.LogFactory; = /** - * @author shura + * This class is intended to generate predictable URIs for all resources h= andled by RichFaces. = + * It creates mapping between resource key/data value and generated random= string of known format = + * for all resource requests. By default {@link UUID#toString()} is used. = Mapping is maintained by LRU map + * having default capacity of {@value #DEFAULT_CAPACITY} so be aware that = stale entries can be removed and = + * application users will get errors then. = * = + * How to use: add to application classpath META-INF/services/org.ajax4jsf= .resource.InternetResourceBuilder + * file with the following content org.ajax4jsf.resource.cached.Cach= edResourceBuilder + * = + * Limitations: + * = + *
    + *
  1. Doesn't work in clustered environments
  2. + *
  3. All resource URIs become invalid after server restart that can cau= se cache issues
  4. + *
  5. + * Diagnostic of resource loading errors becomes somewhat harder. Varian= t of code where random key = + * is appended to resource name doesn't satisfy the requirement of no pa= th depth > 8 as requested = + * by users (see = RF-3586 for more info) + *
  6. + *
+ * = + * @author Alexander Smirnov + * @author Nick Belaevski */ public class CachedResourceBuilder extends ResourceBuilderImpl { = - private static final Log log =3D LogFactory - .getLog(CachedResourceBuilder.class); + private static final Log log =3D LogFactory.getLog(CachedResourceBuilder.= class); = - private static final int DEFAULT_CAPACITY =3D 10000; + protected static final int DEFAULT_CAPACITY =3D 10000; = - private long counter =3D 0; + private ReentrantReadWriteLock readWriteLock =3D new ReentrantReadWriteLo= ck(); + = + private DualLRUMap cache; = - private DualLRUMap cache; + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#decrypt(byte[]) + */ + protected byte[] decrypt(byte[] data) { + // dummy - data not send via internet. + return data; + } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#decrypt(byte[]) - */ - protected byte[] decrypt(byte[] data) { - // dummy - data not send via internet. - return data; - } + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#encrypt(byte[]) + */ + protected byte[] encrypt(byte[] data) { + // dummy - data not send via internet. + return data; + } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#encrypt(byte[]) - */ - protected byte[] encrypt(byte[] data) { - // dummy - data not send via internet. - return data; - } + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#getResourceDataForKey(j= ava.lang.String) + */ + public Object getResourceDataForKey(String key) { + ResourceBean bean =3D null; + try { + readWriteLock.readLock().lock(); + bean =3D (ResourceBean) cache.get(key); + } finally { + readWriteLock.readLock().unlock(); + } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#getResourceDataF= orKey(java.lang.String) - */ - public Object getResourceDataForKey(String key) { - ResourceBean bean =3D (ResourceBean) cache.get(key); - if (null =3D=3D bean) { - throw new ResourceNotFoundException("Resource for key " + key - + "not present in cache"); + if (null =3D=3D bean) { + throw new ResourceNotFoundException("Resource for key " + key + + "not present in cache"); + } + + return bean.getData(); } - return bean.getData(); - } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#getResourceForKe= y(java.lang.String) - */ - public InternetResource getResourceForKey(String key) - throws ResourceNotFoundException { - ResourceBean bean =3D (ResourceBean) cache.get(key); - if (null =3D=3D bean) { - throw new ResourceNotFoundException("Resource for key " + key - + "not present in cache"); + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#getResourceForKey(java.= lang.String) + */ + public InternetResource getResourceForKey(String key) + throws ResourceNotFoundException { + ResourceBean bean =3D null; + try { + readWriteLock.readLock().lock(); + bean =3D (ResourceBean) cache.get(key); + } finally { + readWriteLock.readLock().unlock(); + } + + if (null =3D=3D bean) { + throw new ResourceNotFoundException("Resource for key " + key + + "not present in cache"); + } + = + return super.getResourceForKey(bean.getKey()); } - return super.getResourceForKey(bean.getKey()); - } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#getUri(org.ajax4= jsf.resource.InternetResource, - * javax.faces.context.FacesContext, java.lang.Object) - */ - public String getUri(InternetResource resource, FacesContext facesCont= ext, - Object data) { - ResourceBean bean; - if (null =3D=3D data) { - bean =3D new ResourceBean(resource.getKey()); - } else { - if (data instanceof byte[]) { - // Special case for simple bytes array data. - bean =3D new ResourceBytesDataBean(resource.getKey(), - (byte[]) data); - } else { - bean =3D new ResourceDataBean(resource.getKey(), data); - } + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#getUri(org.ajax4jsf.res= ource.InternetResource, + * javax.faces.context.FacesContext, java.lang.Object) + */ + public String getUri(InternetResource resource, FacesContext facesContext, + Object data) { + ResourceBean bean; + if (null =3D=3D data) { + bean =3D new ResourceBean(resource.getKey()); + } else { + if (data instanceof byte[]) { + // Special case for simple bytes array data. + bean =3D new ResourceBytesDataBean(resource.getKey(), + (byte[]) data); + } else { + bean =3D new ResourceDataBean(resource.getKey(), data); + } + } + + String key =3D null; + = + try { + readWriteLock.readLock().lock(); + = + key =3D (String) cache.getKey(bean); + + if (key !=3D null) { + // Refresh LRU + cache.get(key); + } + } finally { + readWriteLock.readLock().unlock(); + } + + if (key =3D=3D null) { + try { + readWriteLock.writeLock().lock(); + + key =3D (String) cache.getKey(bean); + if (null =3D=3D key) { + key =3D createNextKey(); + while (cache.containsKey(key)) { + key =3D createNextKey(); + } + + cache.put(key, bean); + } else { + // Refresh LRU + cache.get(key); + } + = + } finally { + readWriteLock.writeLock().unlock(); + } + } + = + boolean isGlobal =3D !resource.isSessionAware(); + + String resourceURL =3D getFacesResourceURL(facesContext, key, isGlobal); + if (!isGlobal) { + resourceURL =3D facesContext.getExternalContext().encodeResourceURL( + resourceURL); + } + if (log.isDebugEnabled()) { + log.debug(Messages.getMessage(Messages.BUILD_RESOURCE_URI_INFO, + resource.getKey(), resourceURL)); + } + return resourceURL;// context.getExternalContext().encodeResourceURL(res= ourceURL); } - String key =3D (String) cache.getKey(bean); - if (null =3D=3D key) { - synchronized (this) { - counter++; - key =3D bean.hashCode() + "c" + counter; - } - cache.put(key, bean); - } else { - // Refresh LRU - cache.get(key); + + /* + * (non-Javadoc) + * = + * @see org.ajax4jsf.resource.ResourceBuilderImpl#init(javax.servlet.Serv= letContext, + * java.lang.String) + */ + public void init() throws FacesException { + super.init(); + = + Properties properties =3D getProperties("cache.properties"); + int capacity =3D getCapacity(properties); + if (capacity <=3D 0) { + capacity =3D DEFAULT_CAPACITY; + log.info("Using default capacity: " + DEFAULT_CAPACITY); + } + = + cache =3D new DualLRUMap(capacity); } + + /** + * Get properties file from classpath + * = + * @param name + * @return + */ + protected Properties getProperties(String name) { + Properties properties =3D new Properties(); + InputStream props =3D URLToStreamHelper.urlToStreamSafe(CachedResourceBu= ilder.class + .getResource(name)); + if (null !=3D props) { + try { + properties.load(props); + } catch (IOException e) { + // TODO Auto-generated catch block + log.warn(Messages.getMessage(Messages.READING_PROPERTIES_ERROR, + name), e); + } finally { + try { + props.close(); + } catch (IOException e) { + // Can be ignored + } + } + } + return properties; + + } = - boolean isGlobal =3D !resource.isSessionAware(); - = - String resourceURL =3D getFacesResourceURL(facesContext, key, isGlobal); - if (!isGlobal) { - resourceURL =3D facesContext.getExternalContext().encodeResourceURL( - resourceURL); + protected String createNextKey() { + return UUID.randomUUID().toString(); } - if (log.isDebugEnabled()) { - log.debug(Messages.getMessage(Messages.BUILD_RESOURCE_URI_INFO, - resource.getKey(), resourceURL)); - } - return resourceURL;// context.getExternalContext().encodeResourceURL(reso= urceURL); - } = - /* - * (non-Javadoc) - * = - * @see org.ajax4jsf.resource.ResourceBuilderImpl#init(javax.servl= et.ServletContext, - * java.lang.String) - */ - public void init() - throws FacesException { - super.init(); - // Create cache manager. - Properties properties =3D getProperties("cache.properties"); - int capacity =3D DEFAULT_CAPACITY; - String capacityString =3D properties.getProperty("cache.capacity"); - if (null !=3D capacityString) { - try { - capacity =3D Integer.parseInt(capacityString); - } catch (NumberFormatException e) { - log.warn("Error parsing value of parameters cache capacity, use default = value "+DEFAULT_CAPACITY, e); - } - } - cache =3D new DualLRUMap(capacity); - counter =3D getStartTime() - 1158760000000L; - } - - /** - * Get properties file from classpath - * = - * @param name - * @return - */ - protected Properties getProperties(String name) { - Properties properties =3D new Properties(); - InputStream props =3D URLToStreamHelper.urlToStreamSafe(CachedResourceBui= lder.class - .getResource(name)); - if (null !=3D props) { - try { - properties.load(props); - } catch (IOException e) { - // TODO Auto-generated catch block - log.warn(Messages.getMessage(Messages.READING_PROPERTIES_ERROR, - name), e); - } finally { - try { - props.close(); - } catch (IOException e) { - // Can be ignored + protected int getCapacity(Properties properties) { + // Create cache manager. + int capacity =3D 0; + String capacityString =3D properties.getProperty("cache.capacity"); + if (null !=3D capacityString) { + try { + capacity =3D Integer.parseInt(capacityString); + } catch (NumberFormatException e) { + log.warn("Error parsing value of parameters cache capacity", e); + } } - } + = + return capacity; } - return properties; - - } } Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/D= ualLRUMap.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/DualLRU= Map.java 2008-11-28 19:06:24 UTC (rev 11448) +++ trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/DualLRU= Map.java 2008-11-28 20:18:11 UTC (rev 11449) @@ -22,57 +22,48 @@ package org.ajax4jsf.resource.cached; = import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; = -import org.apache.commons.collections.LRUMap; +class DualLRUMap extends LinkedHashMap { + = + /** + * = + */ + private static final long serialVersionUID =3D -313747679711995782L; = -class DualLRUMap extends LRUMap { + private Map reverseMap; = - private Map reverseMap ; + private int capacity; + = + public DualLRUMap(int capacity) { + super(capacity, 0.75f, true); = - public DualLRUMap(int size) { - super(size); - reverseMap =3D new HashMap(size); + this.capacity =3D capacity; + = + this.reverseMap =3D new HashMap(capacity, 0.75f); } - - /* (non-Javadoc) - * @see org.apache.commons.collections.LRUMap#processRemovedLRU(java.lang= .Object, java.lang.Object) - */ - protected void processRemovedLRU(Object key, Object value) { - synchronized (this) { - super.processRemovedLRU(key, value); - reverseMap.remove(value); - } - } - - /* (non-Javadoc) - * @see org.apache.commons.collections.LRUMap#put(java.lang.Object, java.= lang.Object) - */ - public Object put(Object key, Object value) { - synchronized (this) { - reverseMap.put(value, key); - return super.put(key, value); = - } - } = - public Object getKey(Object value){ - synchronized (this) { - Object key =3D reverseMap.get(value); - if(!containsKey(key)){ - reverseMap.remove(value); - key =3D null; - } - return key; - } + public V put(K key, V value) { + V v =3D super.put(key, value); + = + reverseMap.put(value, key); + = + return v; + }; + = + public K getKey(Object key) { + return reverseMap.get(key); } + = + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + boolean remove =3D (size() > capacity); = - /* (non-Javadoc) - * @see org.apache.commons.collections.LRUMap#get(java.lang.Object) - */ - public Object get(Object key) { - synchronized (this) { - return super.get(key); + if (remove) { + reverseMap.remove(eldest.getValue()); } + = + return remove; } - = } \ No newline at end of file Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/R= esourceBean.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eBean.java 2008-11-28 19:06:24 UTC (rev 11448) +++ trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eBean.java 2008-11-28 20:18:11 UTC (rev 11449) @@ -27,8 +27,12 @@ * @author shura * */ -public class ResourceBean implements Serializable { +public class ResourceBean implements Serializable { = + /** + * = + */ + private static final long serialVersionUID =3D 2830008963777271324L; private String key; = /** @@ -51,10 +55,15 @@ * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { + if (this =3D=3D obj) { + return true; + } + = if (null !=3D obj && obj instanceof ResourceBean) { ResourceBean bean =3D (ResourceBean) obj; return key.equals(bean.getKey()) && bean.getData() =3D=3D null; - }; + } + = return false; } = Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/R= esourceBytesDataBean.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eBytesDataBean.java 2008-11-28 19:06:24 UTC (rev 11448) +++ trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eBytesDataBean.java 2008-11-28 20:18:11 UTC (rev 11449) @@ -29,6 +29,10 @@ */ public class ResourceBytesDataBean extends ResourceBean { = + /** + * = + */ + private static final long serialVersionUID =3D -3012554202964229624L; private byte[] data; = ResourceBytesDataBean(String key, byte[] data){ @@ -43,11 +47,16 @@ * @see com.exadel.vcp.resource.ResourceBean#equals(java.lang.Object) */ public boolean equals(Object obj) { + if (this =3D=3D obj) { + return true; + } + if (null !=3D obj && obj instanceof ResourceBytesDataBean) { ResourceBytesDataBean bean =3D (ResourceBytesDataBean) obj; byte[] beanData =3D (byte[]) bean.getData(); return getKey().equals(bean.getKey()) && Arrays.equals(data, beanData); - }; + } + = return false; } = @@ -55,11 +64,10 @@ * @see com.exadel.vcp.resource.ResourceBean#hashCode() */ public int hashCode() { - int hash =3D super.hashCode(); - for (int i =3D 0; i < data.length; i++) { - hash =3D hash*32+data[i]; - } - return hash; + final int prime =3D 31; + int result =3D super.hashCode(); + result =3D prime * result + Arrays.hashCode(data); + return result; } = } Modified: trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/R= esourceDataBean.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eDataBean.java 2008-11-28 19:06:24 UTC (rev 11448) +++ trunk/framework/impl/src/main/java/org/ajax4jsf/resource/cached/Resourc= eDataBean.java 2008-11-28 20:18:11 UTC (rev 11449) @@ -26,8 +26,13 @@ * @author shura * */ -public class ResourceDataBean extends ResourceBean{ +public class ResourceDataBean extends ResourceBean { = + /** + * = + */ + private static final long serialVersionUID =3D -6486715556040103424L; + private Object data; = public ResourceDataBean(String key, Object data){ @@ -39,10 +44,15 @@ * @see com.exadel.vcp.resource.ResourceBean#equals(java.lang.Object) */ public boolean equals(Object obj) { + if (this =3D=3D obj) { + return true; + } + = if (null !=3D obj && obj instanceof ResourceBean) { ResourceBean bean =3D (ResourceBean) obj; return getKey().equals(bean.getKey()) && data.equals(bean.getData()); - }; + } + = return false; } = @@ -57,8 +67,10 @@ * @see com.exadel.vcp.resource.ResourceBean#hashCode() */ public int hashCode() { - // TODO Auto-generated method stub - return super.hashCode()*32+data.hashCode(); + final int prime =3D 31; + int result =3D super.hashCode(); + result =3D result * prime + data.hashCode(); + return result; } = } --===============0745291583826542359==--