Author: nbelaevski
Date: 2008-04-24 20:24:48 -0400 (Thu, 24 Apr 2008)
New Revision: 8145
Added:
trunk/framework/impl/src/main/java/org/richfaces/skin/AbstractChainableSkinImpl.java
trunk/framework/impl/src/main/java/org/richfaces/skin/BaseSkinImpl.java
trunk/framework/impl/src/main/java/org/richfaces/skin/BasicSkinImpl.java
Modified:
trunk/framework/impl/src/main/java/org/richfaces/skin/SkinFactoryImpl.java
trunk/framework/impl/src/main/java/org/richfaces/skin/SkinImpl.java
Log:
Skin inheritance implemented
Added:
trunk/framework/impl/src/main/java/org/richfaces/skin/AbstractChainableSkinImpl.java
===================================================================
--- trunk/framework/impl/src/main/java/org/richfaces/skin/AbstractChainableSkinImpl.java
(rev 0)
+++
trunk/framework/impl/src/main/java/org/richfaces/skin/AbstractChainableSkinImpl.java 2008-04-25
00:24:48 UTC (rev 8145)
@@ -0,0 +1,140 @@
+/**
+ * License Agreement.
+ *
+ * JBoss RichFaces - Ajax4jsf Component Library
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.richfaces.skin;
+
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.Messages;
+
+/**
+ * @author nick belaevski
+ * @since 3.2
+ */
+
+public abstract class AbstractChainableSkinImpl extends BasicSkinImpl {
+
+ protected SkinFactoryImpl factory;
+
+ AbstractChainableSkinImpl(Map properties, SkinFactoryImpl factory) {
+ super(properties);
+ this.factory = factory;
+ }
+
+ protected Skin getBaseSkin(FacesContext context) {
+ Object object = getSkinParams().get(Skin.baseSkin);
+ boolean base = isBase();
+ Skin skin = null;
+
+ if (object != null) {
+ skin = factory.getSkinByName(context, object, base);
+ }
+
+ if (skin == null) {
+ if (base) {
+ skin = factory.getDefaultSkin(context);
+ } else {
+ skin = factory.getBaseSkin(context);
+ }
+ }
+
+ return skin;
+ }
+
+ protected Object resolveSkinParameter(FacesContext context, String name, int[]
singleInt) {
+ Object object = super.resolveSkinParameter(context, name);
+ if (object == null) {
+ Skin baseSkin = getBaseSkin(context);
+ if (baseSkin != null) {
+ if (baseSkin instanceof AbstractChainableSkinImpl) {
+ AbstractChainableSkinImpl skinImpl = (AbstractChainableSkinImpl) baseSkin;
+
+ if (singleInt[0]++ > 1000) {
+ throw new FacesException(Messages.getMessage(
+ Messages.SKIN_CYCLIC_REFERENCE, name));
+ }
+
+ object = skinImpl.resolveSkinParameter(context, name, singleInt);
+ } else {
+ object = baseSkin.getParameter(context, name);
+ }
+ }
+ }
+
+ return getValueReference(context, object);
+ }
+
+ protected boolean containsProperty(FacesContext context, String name, int[]
singleInt) {
+ boolean contains = super.containsProperty(name);
+ if (!contains) {
+ Skin baseSkin = getBaseSkin(context);
+ if (baseSkin != null) {
+ if (baseSkin instanceof AbstractChainableSkinImpl) {
+ AbstractChainableSkinImpl skinImpl = (AbstractChainableSkinImpl) baseSkin;
+
+ if (singleInt[0]++ > 1000) {
+ throw new FacesException(Messages.getMessage(
+ Messages.SKIN_CYCLIC_REFERENCE, name));
+ }
+
+ contains = skinImpl.containsProperty(context, name, singleInt);
+ } else {
+ contains = baseSkin.containsProperty(name);
+ }
+ }
+ }
+
+ return contains;
+ }
+
+ protected Object resolveSkinParameter(FacesContext context, String name) {
+ int[] singleInt = new int[] {0};
+ Object resolvedParameter = resolveSkinParameter(context, name, singleInt);
+
+ while (resolvedParameter instanceof String) {
+ String string = (String) resolvedParameter;
+ if (string.length() > 0 && string.charAt(0) == '&') {
+ singleInt[0]++;
+ resolvedParameter = resolveSkinParameter(context, string.substring(1), singleInt);
+ if (resolvedParameter == null) {
+ throw new FacesException(Messages.getMessage(
+ Messages.SKIN_ILLEGAL_REFERENCE, name));
+ }
+ } else {
+ break;
+ }
+ }
+
+ return resolvedParameter;
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.skin.Skin#containsProperty(java.lang.String)
+ */
+ public boolean containsProperty(String name) {
+ return containsProperty(FacesContext.getCurrentInstance(), name, new int[] {0});
+ }
+
+ protected abstract boolean isBase();
+}
Added: trunk/framework/impl/src/main/java/org/richfaces/skin/BaseSkinImpl.java
===================================================================
--- trunk/framework/impl/src/main/java/org/richfaces/skin/BaseSkinImpl.java
(rev 0)
+++ trunk/framework/impl/src/main/java/org/richfaces/skin/BaseSkinImpl.java 2008-04-25
00:24:48 UTC (rev 8145)
@@ -0,0 +1,42 @@
+/**
+ * License Agreement.
+ *
+ * JBoss RichFaces - Ajax4jsf Component Library
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.richfaces.skin;
+
+import java.util.Map;
+
+/**
+ * @author nick belaevski
+ * @since 3.2
+ */
+
+public class BaseSkinImpl extends AbstractChainableSkinImpl {
+
+ BaseSkinImpl(Map properties, SkinFactoryImpl factory) {
+ super(properties, factory);
+ }
+
+ @Override
+ protected boolean isBase() {
+ return true;
+ }
+
+}
Added: trunk/framework/impl/src/main/java/org/richfaces/skin/BasicSkinImpl.java
===================================================================
--- trunk/framework/impl/src/main/java/org/richfaces/skin/BasicSkinImpl.java
(rev 0)
+++ trunk/framework/impl/src/main/java/org/richfaces/skin/BasicSkinImpl.java 2008-04-25
00:24:48 UTC (rev 8145)
@@ -0,0 +1,157 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.richfaces.skin;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.el.ValueExpression;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ * Singleton ( in respect as collection of different skins ) for produce
+ * instances properties for all used skins.
+ *
+ * @author shura (latest modification by $Author: alexsmirnov $)
+ * @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:59:41 $
+ *
+ */
+public class BasicSkinImpl implements Skin {
+
+ public static final String RENDER_KIT_PARAMETER = "render.kit";
+
+ public static final String REQUEST_HASH_CODES_MAP_PARAMETER =
"org.ajax4jsf.skin.HASH_CODES_MAP";
+
+ private Map<String, Object> skinParams = new HashMap<String, Object>();
+
+ /**
+ * Skin can instantiate only by factory method.
+ *
+ * @param skinName
+ */
+ BasicSkinImpl(Map properties) {
+ this.skinParams = properties;
+ }
+
+ protected Map<String, Object> getSkinParams() {
+ return skinParams;
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.skin.Skin#getRenderKitId(javax.faces.context.FacesContext)
+ */
+ public String getRenderKitId(FacesContext context) {
+ return (String) getValueReference(context, resolveSkinParameter(context,
RENDER_KIT_PARAMETER));
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.skin.Skin#getParameter(javax.faces.context.FacesContext,
java.lang.String)
+ */
+ public Object getParameter(FacesContext context, String name) {
+ return getValueReference(context, resolveSkinParameter(context, name));
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.skin.Skin#getParameter(javax.faces.context.FacesContext,
java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public Object getParameter(FacesContext context, String name, Object defaultValue)
{
+ Object value = getValueReference(context, resolveSkinParameter(context, name));
+ if(null == value){
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ protected Object resolveSkinParameter(FacesContext context, String name) {
+ return skinParams.get(name);
+ }
+
+ protected Skin getBaseSkin(FacesContext context) {
+ return null;
+ }
+
+ /**
+ * Calculate concrete value for property - if it stored as @see ValueBinding ,
+ * return interpreted value.
+ * @param context
+ * @param property
+ * @return
+ */
+ protected Object getValueReference(FacesContext context, Object property) {
+ if (property instanceof ValueExpression) {
+ ValueExpression value = (ValueExpression) property;
+ return value.getValue(context.getELContext());
+ }
+ return property;
+ }
+
+
+ public String toString() {
+ return this.getClass().getSimpleName() + ": " + skinParams.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.skin.Skin#hashCode(javax.faces.context.FacesContext)
+ */
+ public int hashCode(FacesContext context) {
+ ExternalContext externalContext = context.getExternalContext();
+ Map<String, Object> requestMap = externalContext.getRequestMap();
+ ConcurrentMap<Skin, Integer> map;
+ synchronized (requestMap) {
+ map = (ConcurrentMap<Skin, Integer>)
requestMap.get(REQUEST_HASH_CODES_MAP_PARAMETER);
+ if (map == null) {
+ map = new ConcurrentHashMap<Skin, Integer>();
+ requestMap.put(REQUEST_HASH_CODES_MAP_PARAMETER, map);
+ }
+ }
+
+ Integer requestCode = (Integer) map.get(this);
+ if(null == requestCode){
+ int hash = 0;
+ for (Iterator iter = skinParams.keySet().iterator(); iter.hasNext();) {
+ String key = (String) iter.next();
+ Object parameter = getParameter(context,key);
+ hash = 31*hash + key.hashCode();
+ hash = 31*hash + (parameter != null ? parameter.hashCode() : 0);
+ }
+
+ Skin baseSkin = getBaseSkin(context);
+ if (baseSkin != null) {
+ hash = 31*hash + baseSkin.hashCode(context);
+ }
+
+ requestCode = new Integer(hash);
+ // store hash for this skin as request-skope parameter - not calculate on next calls
for same request
+ map.putIfAbsent(this, requestCode);
+ }
+ return requestCode.intValue();
+ }
+
+ public boolean containsProperty(String name) {
+ return skinParams.containsKey(name);
+ }
+
+}
Modified: trunk/framework/impl/src/main/java/org/richfaces/skin/SkinFactoryImpl.java
===================================================================
--- trunk/framework/impl/src/main/java/org/richfaces/skin/SkinFactoryImpl.java 2008-04-24
21:44:19 UTC (rev 8144)
+++ trunk/framework/impl/src/main/java/org/richfaces/skin/SkinFactoryImpl.java 2008-04-25
00:24:48 UTC (rev 8145)
@@ -31,6 +31,8 @@
import java.util.Properties;
import java.util.Map.Entry;
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
@@ -87,6 +89,9 @@
private static final String[] DEFAULT_CONFIGURATION_PATHS = {
"META-INF/skins/DEFAULT.configuration.properties" };
private Map skins = Collections.synchronizedMap(new HashMap());
+ private Map baseSkins = Collections.synchronizedMap(new HashMap());
+ private Map sourceProperties = Collections.synchronizedMap(new HashMap());
+
private Properties defaultSkinProperties = null;
private String skinName = null;
private ValueBinding skinBinding = null;
@@ -98,7 +103,7 @@
private static final String A4J_SKIN_PARAMETER = "org.ajax4jsf.SKIN";
- protected Skin getSkinByName(Object currentSkinOrName) {
+ protected Skin getSkinByName(FacesContext facesContext, Object currentSkinOrName,
boolean isBase) {
if (null == currentSkinOrName) {
throw new SkinNotFoundException(Messages
.getMessage(Messages.NULL_SKIN_NAME_ERROR));
@@ -108,7 +113,9 @@
return (Skin) currentSkinOrName;
}
String currentSkinName = currentSkinOrName.toString();
- Skin currentSkin = (Skin) skins.get(currentSkinName);
+
+ Map skinsMap = (isBase ? baseSkins : skins);
+ Skin currentSkin = (Skin) skinsMap.get(currentSkinName);
// LAZY creation for skins, since, in case of EL expressions
// for skin name, we don't can know all names of existing skins.
if (currentSkin == null) {
@@ -116,27 +123,27 @@
log.debug(Messages.getMessage(Messages.CREATE_SKIN_INFO,
currentSkinName));
}
- currentSkin = buildSkin(currentSkinName, getDefaultSkinProperties());
- skins.put(currentSkinName, currentSkin);
+ currentSkin = buildSkin(facesContext, currentSkinName, isBase);
+ skinsMap.put(currentSkinName, currentSkin);
}
return currentSkin;
}
public Skin getDefaultSkin(FacesContext context) {
- return getSkinByName(DEFAULT_SKIN_NAME);
+ return getSkinByName(context, DEFAULT_SKIN_NAME, false);
}
public Skin getSkin(FacesContext context) {
// TODO - cache skin for current thread ? or for current Faces Lifecycle
// Phase ?
Object currentSkinOrName = getSkinOrName(context, false);
- return getSkinByName(currentSkinOrName);
+ return getSkinByName(context, currentSkinOrName, false);
}
public Skin getBaseSkin(FacesContext context) {
Object currentSkinOrName = getSkinOrName(context, true);
- return getSkinByName(currentSkinOrName);
+ return getSkinByName(context, currentSkinOrName, true);
}
protected Properties getDefaultSkinProperties() {
@@ -249,31 +256,20 @@
}
}
- private void processProperties(Map<Object, Object> properties) {
+ private void processProperties(FacesContext context, Map<Object, Object>
properties) {
+ ELContext elContext = context.getELContext();
// replace all EL-expressions by prepared ValueBinding ?
ApplicationFactory factory = (ApplicationFactory) FactoryFinder
.getFactory(FactoryFinder.APPLICATION_FACTORY);
Application app = factory.getApplication();
for (Entry<Object, Object> entry : properties.entrySet()) {
- String propertyName = (String) entry.getKey();
Object propertyObject = entry.getValue();
if (propertyObject instanceof String) {
String property = (String) propertyObject;
- int count = 0;
- while (property.startsWith("&")) {
- property = (String) properties.get(property.substring(1));
- if (null == property) {
- throw new FacesException(Messages.getMessage(
- Messages.SKIN_ILLEGAL_REFERENCE, propertyName));
- }
- if (count++ > 1000) {
- throw new FacesException(Messages.getMessage(
- Messages.SKIN_CYCLIC_REFERENCE, propertyName));
- }
- }
if (ELUtils.isValueReference(property)) {
- entry.setValue(app.createValueBinding(property));
+ ExpressionFactory expressionFactory = app.getExpressionFactory();
+ entry.setValue(expressionFactory.createValueExpression(elContext, property,
Object.class));
} else {
entry.setValue(property);
}
@@ -287,47 +283,32 @@
* append in content to default properties. First, get it from
* META-INF/skins/ , next - from root package. for any place search order
* determined by {@link java.lang.ClassLoader } realisation.
- *
* @param name
* name for builded skin.
* @param defaultProperties
+ *
* @return skin instance for current name
* @throws SkinNotFoundException -
* if no skin properies found for name.
*/
- protected Skin buildSkin(String name, Properties defaultProperties)
+ protected Skin buildSkin(FacesContext context, String name, boolean isBase)
throws SkinNotFoundException {
- String baseSkinName = name;
- int counter = 0;
-
- Map<Object, Object> result = new HashMap<Object, Object>();
- do {
- Map<Object, Object> skinParams = loadProperties(baseSkinName, SKINS_PATHS);
- for (Entry<Object, Object> entry : skinParams.entrySet()) {
- Object key = entry.getKey();
- if (!result.containsKey(key)) {
- result.put(key, entry.getValue());
- }
- }
-
- baseSkinName = (String) skinParams.get(Skin.baseSkin);
-
- if (counter++ > 1000) {
- throw new IllegalStateException("Cyclic base skin!");
- }
-
- } while (baseSkinName != null);
-
- for (Entry<Object, Object> entry : defaultProperties.entrySet()) {
- if (!result.containsKey(entry.getKey())) {
- result.put(entry.getKey(), entry.getValue());
- }
+ Map<Object, Object> skinParams = (Map<Object, Object>)
sourceProperties.get(name);
+ if (skinParams == null) {
+ skinParams = loadProperties(name, SKINS_PATHS);
+ processProperties(context, skinParams);
+ skinParams = Collections.unmodifiableMap(skinParams);
+ sourceProperties.put(name, skinParams);
}
- processProperties(result);
-
- return new SkinImpl(result);
+ if (DEFAULT_SKIN_NAME.equals(name)) {
+ return new BasicSkinImpl(skinParams);
+ } else if (isBase) {
+ return new BaseSkinImpl(skinParams, this);
+ } else {
+ return new SkinImpl(skinParams, this);
+ }
}
/**
Modified: trunk/framework/impl/src/main/java/org/richfaces/skin/SkinImpl.java
===================================================================
--- trunk/framework/impl/src/main/java/org/richfaces/skin/SkinImpl.java 2008-04-24
21:44:19 UTC (rev 8144)
+++ trunk/framework/impl/src/main/java/org/richfaces/skin/SkinImpl.java 2008-04-25
00:24:48 UTC (rev 8145)
@@ -21,131 +21,20 @@
package org.richfaces.skin;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import javax.faces.context.ExternalContext;
-import javax.faces.context.FacesContext;
-import javax.faces.el.ValueBinding;
/**
- * Singleton ( in respect as collection of different skins ) for produce
- * instances properties for all used skins.
- *
- * @author shura (latest modification by $Author: alexsmirnov $)
- * @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:59:41 $
- *
+ * @author nick belaevski
+ * @since 3.2
*/
-public class SkinImpl implements Skin {
+public class SkinImpl extends AbstractChainableSkinImpl {
+ SkinImpl(Map properties, SkinFactoryImpl factory) {
+ super(properties, factory);
+ }
- public static final String RENDER_KIT_PARAMETER = "render.kit";
-
- public static final String REQUEST_HASH_CODES_MAP_PARAMETER =
"org.ajax4jsf.skin.HASH_CODES_MAP";
-
- private Map skinParams = new HashMap();
-
-
- /**
- * Skin can instantiate only by factory method.
- *
- * @param skinName
- */
- SkinImpl(Map properties) {
- skinParams = properties;
- }
-
-
- /* (non-Javadoc)
- * @see org.richfaces.skin.Skin#getRenderKitId(javax.faces.context.FacesContext)
- */
- public String getRenderKitId(FacesContext context) {
- return (String) getValueReference(context,skinParams.get(RENDER_KIT_PARAMETER));
- }
-
- /* (non-Javadoc)
- * @see org.richfaces.skin.Skin#getParameter(javax.faces.context.FacesContext,
java.lang.String)
- */
- public Object getParameter(FacesContext context, String name) {
- return getValueReference(context,skinParams.get(name));
- }
-
- /* (non-Javadoc)
- * @see org.richfaces.skin.Skin#getParameter(javax.faces.context.FacesContext,
java.lang.String, java.lang.String, java.lang.Object)
- */
- public Object getParameter(FacesContext context, String name, Object defaultValue) {
- Object value = getValueReference(context, skinParams.get(name));
- if(null == value){
- value = defaultValue;
- }
- return value;
- }
-
-
- /**
- * Calculate concrete value for property - if it stored as @see ValueBinding ,
- * return interpreted value.
- * @param context
- * @param property
- * @return
- */
- private Object getValueReference(FacesContext context, Object property) {
- if (property instanceof ValueBinding) {
- ValueBinding value = (ValueBinding) property;
- return value.getValue(context);
- }
- return property;
- }
-
-
- public String toString() {
- return skinParams.toString();
- }
-
-
- /* (non-Javadoc)
- * @see org.richfaces.skin.Skin#containsProperty(java.lang.String)
- */
- public boolean containsProperty(String name) {
- // TODO Auto-generated method stub
- return skinParams.containsKey(name);
- }
-
-
- /* (non-Javadoc)
- * @see org.richfaces.skin.Skin#hashCode(javax.faces.context.FacesContext)
- */
- public int hashCode(FacesContext context) {
- ExternalContext externalContext = context.getExternalContext();
- Map<String, Object> requestMap = externalContext.getRequestMap();
- ConcurrentMap<Skin, Integer> map;
- synchronized (requestMap) {
- map = (ConcurrentMap<Skin, Integer>)
requestMap.get(REQUEST_HASH_CODES_MAP_PARAMETER);
- if (map == null) {
- map = new ConcurrentHashMap<Skin, Integer>();
- requestMap.put(REQUEST_HASH_CODES_MAP_PARAMETER, map);
- }
- }
-
- Integer requestCode = (Integer) map.get(this);
- if(null == requestCode){
- int hash = 0;
- for (Iterator iter = skinParams.keySet().iterator(); iter.hasNext();) {
- String key = (String) iter.next();
- Object parameter = getParameter(context,key);
- hash = 31*hash + key.hashCode();
- hash = 31*hash + (parameter != null ? parameter.hashCode() : 0);
- }
- requestCode = new Integer(hash);
- // store hash for this skin as request-skope parameter - not calculate on next calls
for same request
- map.putIfAbsent(this, requestCode);
- }
- return requestCode.intValue();
- }
-
-
-
+ protected boolean isBase() {
+ return false;
+ }
}