Author: gvanmatre Date: Tue Jun 27 21:04:20 2006 New Revision: 417663 URL: http://svn.apache.org/viewvc?rev=417663&view=rev Log: Fix for issue SHALE-201 reported by Ryan Wynn.
Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/Clay.java struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/AbstractCommand.java struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/CreateComponentCommand.java struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/config/SymbolsTestCase.java Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/Clay.java URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/Clay.java?rev=417663&r1=417662&r2=417663&view=diff ============================================================================== --- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/Clay.java (original) +++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/Clay.java Tue Jun 27 21:04:20 2006 @@ -302,6 +302,8 @@ Map symbolTable = new TreeMap(); symbolTable.putAll(getSymbols()); clayContext.setSymbols(symbolTable); + //evaluate nested symbols + AbstractCommand.realizeSymbols(clayContext); //resolve the literal "@managed-bean-name" String expr = AbstractCommand.replaceMnemonic(clayContext, getShapeValidator()); @@ -338,6 +340,9 @@ symbolTable.putAll(getDisplayElementRoot().getSymbols()); symbolTable.putAll(getSymbols()); clayContext.setSymbols(symbolTable); + + //evaluate nested symbols + AbstractCommand.realizeSymbols(clayContext); clayContext.setRootElement(getDisplayElementRoot()); clayContext.setParent(this); Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/AbstractCommand.java URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/AbstractCommand.java?rev=417663&r1=417662&r2=417663&view=diff ============================================================================== --- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/AbstractCommand.java (original) +++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/AbstractCommand.java Tue Jun 27 21:04:20 2006 @@ -19,8 +19,13 @@ package org.apache.shale.clay.component.chain; import java.net.URL; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; import org.apache.commons.chain.Catalog; import org.apache.commons.chain.CatalogFactory; @@ -87,6 +92,150 @@ public static String replaceMnemonic(ClayContext context) { return replaceMnemonic(context, context.getAttribute().getValue()); } + + /** + * <p>Evaluates nested symbols. These are symbols that have references to other + * symbols as their values. The nested symbols evaluation is sensitive to dependencies. + * The current scoped symbol table is found in the [EMAIL PROTECTED] ClayContext}.</p> + */ + public static void realizeSymbols(ClayContext context) { + Map symbols = context.getSymbols(); + if (symbols == null || symbols.isEmpty()) + return; + + Iterator si = symbols.entrySet().iterator(); + + Map dependenciesMap = new TreeMap(); + TreeSet allNestedSymbols = new TreeSet(); + + while (si.hasNext()) { + Map.Entry e = (Map.Entry) si.next(); + SymbolBean symbol = (SymbolBean) e.getValue(); + if (symbol.getValue() != null) { + List symbolDependencies = findSymbols(context, symbol.getValue()); + if (!symbolDependencies.isEmpty()) { + dependenciesMap.put(symbol.getName(), symbolDependencies); + allNestedSymbols.addAll(symbolDependencies); + allNestedSymbols.add(symbol.getName()); + } + } + } + + List allNestedSymbolsOrdered = getOrderedByDependencies(allNestedSymbols, dependenciesMap); + for (int i = 0; i < allNestedSymbolsOrdered.size(); i++) { + String symbolName = (String) allNestedSymbolsOrdered.get(i); + SymbolBean sourceSymbol = (SymbolBean) symbols.get(symbolName); + if (sourceSymbol != null && sourceSymbol.getValue() != null) { + String value = replaceMnemonic(context, sourceSymbol.getValue()); + SymbolBean targetSymbol = new SymbolBean(); + targetSymbol.setDescription(sourceSymbol.getDescription()); + targetSymbol.setName(sourceSymbol.getName()); + targetSymbol.setValue(value); + + symbols.put(targetSymbol.getName(), targetSymbol); + } + } + + + } + + /** + * <p>Orders the symbols by their dependencies. Each symbol + * can have multiple dependencies.</p> + * + * @param allNestedSymbols Set of symbol names + * @param dependenciesMap List of dependencies for each symbol + * @return ordered list of symbol names ordered by dependencies + */ + private static List getOrderedByDependencies(Set allNestedSymbols, Map dependenciesMap) { + + List tmpList = new ArrayList(allNestedSymbols); + + ordered: for (int i = 0; i < tmpList.size(); i++) { + boolean swap = false; + for (int j = 0; j < tmpList.size(); j++) { + String symbolName = (String) tmpList.get(j); + List symbolDependencies = (List) dependenciesMap.get(symbolName); + if (symbolDependencies != null && symbolDependencies.size() > 0) { + int max = -1; + for (int n = 0; n < symbolDependencies.size(); n++) + max = Math.max(max, tmpList.indexOf(symbolDependencies.get(n))); + if (max > j) { + String tmp = (String) tmpList.get(j); + tmpList.remove(j); + tmpList.add(max, tmp); + swap = true; + j = max; + } + } + + } + if (!swap) + break ordered; + } + + return tmpList; + + } + + /** + * <p>Returns a List of symbols found within the <code>symbolToken</code>. + * The comprehensive symbol table is found in the [EMAIL PROTECTED] ClayContext}.</p> + */ + private static List findSymbols(ClayContext context, String symbolToken) { + + List targetList = new ArrayList(); + + StringBuffer buff = new StringBuffer(symbolToken); + Map symbols = context.getSymbols(); + Iterator si = symbols.entrySet().iterator(); + boolean wasSymbolFound = false; + int i = buff.indexOf("@"); + replace: while (i > -1 && si.hasNext()) { + Map.Entry e = (Map.Entry) si.next(); + SymbolBean symbol = (SymbolBean) e.getValue(); + String key = symbol.getName(); + i = (wasSymbolFound ? buff.indexOf("@") : i); + if (i == -1) + break replace; + + next: while (i > -1 && i <= (buff.length() - key.length())) { + + int n = -1; + indexOf: for (int s = i; s <= (buff.length() - key.length()); s++) { + for (int c = 0; c < key.length(); c++) { + char skey = Character.toLowerCase(key.charAt(c)); + char tkey = Character.toLowerCase(buff.charAt(s + c)); + if (skey != tkey) + continue indexOf; + } + // match found + n = s; + break indexOf; + } + + if (n > -1) { + if (!targetList.contains(key)) + targetList.add(key); + i = n + key.length(); + wasSymbolFound = true; + } else { + break next; + } + } + + e = null; + key = null; + } + symbols = null; + si = null; + + + return targetList; + } + + + /** * <p> Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/CreateComponentCommand.java URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/CreateComponentCommand.java?rev=417663&r1=417662&r2=417663&view=diff ============================================================================== --- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/CreateComponentCommand.java (original) +++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/component/chain/CreateComponentCommand.java Tue Jun 27 21:04:20 2006 @@ -127,6 +127,10 @@ // push to context clayContext.setSymbols(symbolTable); + // evaluate nested symbols; symbols having symbols as values + realizeSymbols(clayContext); + + String id = null; if ((id = displayElement.getId()) == null) id = createUniqueId(facesContext); @@ -218,6 +222,9 @@ // push to context clayContext.setSymbols(symbolTable); + + // evaluate nested symbols + realizeSymbols(clayContext); } Modified: struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/config/SymbolsTestCase.java URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/config/SymbolsTestCase.java?rev=417663&r1=417662&r2=417663&view=diff ============================================================================== --- struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/config/SymbolsTestCase.java (original) +++ struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/config/SymbolsTestCase.java Tue Jun 27 21:04:20 2006 @@ -16,6 +16,8 @@ package org.apache.shale.clay.config; import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; import javax.faces.component.UIComponent; @@ -23,6 +25,7 @@ import junit.framework.TestSuite; import org.apache.commons.chain.Command; +import org.apache.shale.clay.component.chain.AbstractCommand; import org.apache.shale.clay.component.chain.ClayContext; import org.apache.shale.clay.component.chain.CreateComponentCommand; import org.apache.shale.clay.component.chain.PropertyValueCommand; @@ -46,6 +49,93 @@ } + public void testNestedSymbolReplacement() { + + + Map symbols = new TreeMap(); + + ClayContext clayContext = new ClayContext(); + clayContext.setFacesContext(facesContext); + clayContext.setSymbols(symbols); + + SymbolBean symbol = this.createSymbol("@a", "@b"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@b", "@c"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@c", "@d"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@d", "test"); + symbols.put(symbol.getName(), symbol); + + AbstractCommand.realizeSymbols(clayContext); + + symbol = (SymbolBean) symbols.get("@a"); + assertNotNull(symbol); + assertEquals("test", symbol.getValue()); + + symbol = (SymbolBean) symbols.get("@b"); + assertNotNull(symbol); + assertEquals("test", symbol.getValue()); + + symbol = (SymbolBean) symbols.get("@c"); + assertNotNull(symbol); + assertEquals("test", symbol.getValue()); + + symbol = (SymbolBean) symbols.get("@d"); + assertNotNull(symbol); + assertEquals("test", symbol.getValue()); + + + symbols.clear(); + + symbol = this.createSymbol("@a", "@b"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@b", "@a"); + symbols.put(symbol.getName(), symbol); + + AbstractCommand.realizeSymbols(clayContext); + + symbol = (SymbolBean) symbols.get("@a"); + assertNotNull(symbol); + assertEquals("@a", symbol.getValue()); + + symbol = (SymbolBean) symbols.get("@b"); + assertNotNull(symbol); + assertEquals("@a", symbol.getValue()); + + + + symbols.clear(); + + symbol = this.createSymbol("@foo", "@[EMAIL PROTECTED]"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@xbeanx", "@a"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@xpropertyx", "@b"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@a", "foo"); + symbols.put(symbol.getName(), symbol); + + symbol = this.createSymbol("@b", "bar"); + symbols.put(symbol.getName(), symbol); + + AbstractCommand.realizeSymbols(clayContext); + + symbol = (SymbolBean) symbols.get("@foo"); + assertNotNull(symbol); + assertEquals("foo.bar", symbol.getValue()); + + } + + + public void testGenericPropertyCommand () throws Exception { javax.faces.component.html.HtmlOutputText child = (javax.faces.component.html.HtmlOutputText) facesContext.getApplication().createComponent("javax.faces.HtmlOutputText");