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"); 


Reply via email to