You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jo...@apache.org on 2009/02/08 08:40:41 UTC

svn commit: r742013 - in /ofbiz/trunk/framework: base/config/ base/src/org/ofbiz/base/util/template/ entity/src/org/ofbiz/entity/ webapp/src/org/ofbiz/webapp/control/ widget/src/org/ofbiz/widget/screen/

Author: jonesde
Date: Sun Feb  8 07:40:40 2009
New Revision: 742013

URL: http://svn.apache.org/viewvc?rev=742013&view=rev
Log:
Implemented StringModel extension and BeansWrapper extension to load it in order to encode strings for HTML use; this is only done throught the HtmlWidget class that is part of the screen widget, so won't interfere with other FTL uses; note that there is other experimental code in here for wrapping the GenericValue object for html encoding, but that option wasn't very complete so went this way instead; this option behaves better and is more transparent than that escape x as x?html option for FTL files; there are also a few cleanups of typos and things in here; note that this means we have a different Configuration object and so a different template cache, and so we have different cache settings and such; after applying this I found a few places that encoded things they shouldn't but for the most part it is pretty good; will be committing some changes in applications in a bit to resolve a couple of these issues in ecommerce; all should watch out for funny things showing up as 
 HTML text instead of being interpreted by the browser as HTML, meaning it was encoded; in extreme cases just comment out lines 71-73 of HtmlWidget.java to turn off this encoding

Added:
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java   (with props)
Modified:
    ofbiz/trunk/framework/base/config/cache.properties
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java

Modified: ofbiz/trunk/framework/base/config/cache.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/cache.properties?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/config/cache.properties (original)
+++ ofbiz/trunk/framework/base/config/cache.properties Sun Feb  8 07:40:40 2009
@@ -91,8 +91,9 @@
 widget.tree.locationResource.expireTime=10000
 widget.tree.webappResource.expireTime=10000
 
-template.ftl.general.expireTime=10000
 template.ftl.location.expireTime=10000
+template.ftl.general.expireTime=10000
+widget.screen.template.ftl.general.expireTime=10000
 
 ModelDataFile.expireTime=10000
 

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java Sun Feb  8 07:40:40 2009
@@ -62,7 +62,6 @@
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
-//import com.clarkware.profiler.Profiler;
 
 /** FreeMarkerWorker - Freemarker Template Engine Utilities.
  *
@@ -73,17 +72,19 @@
     
     // use soft references for this so that things from Content records don't kill all of our memory, or maybe not for performance reasons... hmmm, leave to config file...
     public static UtilCache<String, Template> cachedTemplates = new UtilCache<String, Template>("template.ftl.general", 0, 0, false);
-    protected static Configuration defaultOfbizConfig = new Configuration();
+    protected static BeansWrapper defaultOfbizWrapper = BeansWrapper.getDefaultInstance();
+    protected static Configuration defaultOfbizConfig = makeConfiguration(defaultOfbizWrapper);
 
-    static {
-        BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
-        defaultOfbizConfig.setObjectWrapper(wrapper);
-        defaultOfbizConfig.setSharedVariable("Static", wrapper.getStaticModels());
-        defaultOfbizConfig.setLocalizedLookup(false);
-        defaultOfbizConfig.setTemplateLoader(new FlexibleTemplateLoader());
+    public static Configuration makeConfiguration(BeansWrapper wrapper) {
+        Configuration newConfig = new Configuration();
+        
+        newConfig.setObjectWrapper(wrapper);
+        newConfig.setSharedVariable("Static", wrapper.getStaticModels());
+        newConfig.setLocalizedLookup(false);
+        newConfig.setTemplateLoader(new FlexibleTemplateLoader());
         try {
-            defaultOfbizConfig.setSetting("datetime_format", "yyyy-MM-dd HH:mm:ss.SSS");
-            defaultOfbizConfig.setSetting("number_format", "0.##########");
+            newConfig.setSetting("datetime_format", "yyyy-MM-dd HH:mm:ss.SSS");
+            newConfig.setSetting("number_format", "0.##########");
         } catch (TemplateException e) {
             Debug.logError("Unable to set date/time and number formats in FreeMarker: " + e, module);
         }
@@ -103,23 +104,25 @@
             if (props == null || props.isEmpty()) {
                 Debug.logError("Unable to locate properties file " + propertyURL, module);
             } else {
-                loadTransforms(loader, props);
+                loadTransforms(loader, props, newConfig);
             }
         }
+        
+        return newConfig;
     }
     
     /**
      * Protected helper method.
      */
-    protected static void loadTransforms(ClassLoader loader, Properties props) {
+    protected static void loadTransforms(ClassLoader loader, Properties props, Configuration config) {
         for (Iterator<Object> i = props.keySet().iterator(); i.hasNext();) {
-            String key = (String)i.next();
+            String key = (String) i.next();
             String className = props.getProperty(key);
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Adding FTL Transform " + key + " with class " + className, module);
             }
             try {
-                defaultOfbizConfig.setSharedVariable(key, loader.loadClass(className).newInstance());
+                config.setSharedVariable(key, loader.loadClass(className).newInstance());
             } catch (Exception e) {
                 Debug.logError(e, "Could not pre-initialize dynamically loaded class: " + className + ": " + e, module);
             }
@@ -195,7 +198,7 @@
         // FIXME: the casting from Appendable to Writer is a temporary fix that could cause a
         //        run time error if in the future we will pass a different class to the method
         //        (such as a StringBuffer).
-        Environment env = template.createProcessingEnvironment(context, (Writer)outWriter);
+        Environment env = template.createProcessingEnvironment(context, (Writer) outWriter);
         applyUserSettings(env, context);
         env.process();
         return env;
@@ -261,16 +264,20 @@
      * @param templateLocation Location of the template - file path or URL
      */
     public static Template getTemplate(String templateLocation) throws TemplateException, IOException {
-        Template template = (Template) cachedTemplates.get(templateLocation);
+        return getTemplate(templateLocation, cachedTemplates, defaultOfbizConfig);
+    }
+    
+    public static Template getTemplate(String templateLocation, UtilCache<String, Template> cache, Configuration config) throws TemplateException, IOException {
+        Template template = (Template) cache.get(templateLocation);
         if (template == null) {
-            synchronized (cachedTemplates) {
-                template = (Template) cachedTemplates.get(templateLocation);
+            synchronized (cache) {
+                template = (Template) cache.get(templateLocation);
                 if (template == null) {
                     // only make the reader if we need it, and then close it right after!
                     Reader templateReader = makeReader(templateLocation);
-                    template = new Template(templateLocation, templateReader, defaultOfbizConfig);
+                    template = new Template(templateLocation, templateReader, config);
                     templateReader.close();
-                    cachedTemplates.put(templateLocation, template);
+                    cache.put(templateLocation, template);
                 }
             }
         }

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java Sun Feb  8 07:40:40 2009
@@ -142,21 +142,21 @@
     /** Creates new GenericEntity */
     protected void init(ModelEntity modelEntity) {
         if (modelEntity == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
         }
         this.modelEntity = modelEntity;
         this.entityName = modelEntity.getEntityName();
         
         // check some things
         if (this.entityName == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity parameter");
         }
     }
 
     /** Creates new GenericEntity from existing Map */
     protected void init(ModelEntity modelEntity, Map<String, ? extends Object> fields) {
         if (modelEntity == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
         }
         this.modelEntity = modelEntity;
         this.entityName = modelEntity.getEntityName();
@@ -164,14 +164,14 @@
         
         // check some things
         if (this.entityName == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity parameter");
         }
     }
 
     /** Creates new GenericEntity from existing Map */
     protected void init(ModelEntity modelEntity, Object singlePkValue) {
         if (modelEntity == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
         }
         if (modelEntity.getPksSize() != 1) {
             throw new IllegalArgumentException("Cannot create a GenericEntity with more than one primary key field");
@@ -182,25 +182,22 @@
         
         // check some things
         if (this.entityName == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity parameter");
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity parameter");
         }
     }
 
     /** Copy Constructor: Creates new GenericEntity from existing GenericEntity */
     protected void init(GenericEntity value) {
-        if (value.modelEntity == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity from another GenericEntity with a null modelEntity in the value parameter");
+        // check some things
+        if (value.entityName == null) {
+            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity parameter");
         }
-        this.entityName = value.modelEntity.getEntityName();
+        this.entityName = value.getEntityName();
+        // NOTE: could call getModelEntity to insure we have a value, just in case the value passed in has been serialized, but might as well leave it null to keep the object light if it isn't there
         this.modelEntity = value.modelEntity;
         if (value.fields != null) this.fields.putAll(value.fields);
         this.delegatorName = value.delegatorName;
         this.internalDelegator = value.internalDelegator;
-        
-        // check some things
-        if (this.entityName == null) {
-            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity parameter");
-        }
     }
 
     public void reset() {

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java Sun Feb  8 07:40:40 2009
@@ -24,8 +24,8 @@
 import java.util.List;
 import java.util.Map;
 
-import javolution.lang.Reusable;
 import javolution.context.ObjectFactory;
+import javolution.lang.Reusable;
 import javolution.util.FastMap;
 
 import org.ofbiz.base.util.Debug;
@@ -33,7 +33,6 @@
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.condition.EntityCondition;
 import org.ofbiz.entity.condition.EntityFieldMap;
-import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.model.ModelEntity;
 import org.ofbiz.entity.model.ModelKeyMap;
 import org.ofbiz.entity.model.ModelRelation;
@@ -44,6 +43,7 @@
  * Generic Entity Value Object - Handles persistence for any defined entity.
  *
  */
+@SuppressWarnings("serial")
 public class GenericValue extends GenericEntity implements Reusable {
 
     public static final GenericValue NULL_VALUE = new NullGenericValue();

Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java?rev=742013&view=auto
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java (added)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java Sun Feb  8 07:40:40 2009
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+
+package org.ofbiz.entity;
+
+
+import javolution.context.ObjectFactory;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.StringUtil;
+
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.ext.beans.MapModel;
+import freemarker.ext.beans.StringModel;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+
+
+/**
+ * Generic Entity Value Object - Handles persistence for any defined entity.
+ * WARNING: This object is experimental!
+ *
+ */
+@SuppressWarnings("serial")
+public class GenericValueHtmlWrapper extends GenericValue {
+    protected static final ObjectFactory<GenericValueHtmlWrapper> genericValueHtmlWrapperFactory = new ObjectFactory<GenericValueHtmlWrapper>() {
+        protected GenericValueHtmlWrapper create() {
+            return new GenericValueHtmlWrapper();
+        }
+    };
+    
+    /** Creates new GenericValueHtmlWrapper from existing GenericValue */
+    public static GenericValueHtmlWrapper create(GenericValue value) {
+        GenericValueHtmlWrapper newValue = genericValueHtmlWrapperFactory.object();
+        try {
+            newValue.init(value);
+        } catch (RuntimeException e) {
+            Debug.logError(e, "Error in init for clone of value: " + value, module);
+            throw e;
+        }
+        return newValue;
+    }
+
+    /* NOTE: this is NOT used because there are certain FTL files that call services and things, and this messes those up, so only overriding the Map.get(Object) method to get use of this as a Map 
+     * Override the basic get method, which all other get methods call so we only need to do this one (though most important for the Map.get(Object) and the getString() methods 
+    public Object get(String name) {
+        Object value = super.get(name);
+        if (value instanceof String) {
+            return StringUtil.htmlEncoder.encode((String) value);
+        } else {
+            return value;
+        }
+    }*/
+
+    public Object get(Object name) {
+        Object value = super.get(name);
+        if (value instanceof String) {
+            return StringUtil.htmlEncoder.encode((String) value);
+        } else {
+            return value;
+        }
+    }
+    
+    // another experimental object, this one specifically for FTL
+    public static class GenericValueHtmlWrapperForFtl extends MapModel {
+        public GenericValueHtmlWrapperForFtl(GenericValue gv, BeansWrapper wrapper) {
+            super(gv, wrapper);
+        }
+        
+        public TemplateModel get(String key) {
+            TemplateModel tm = null;
+            try {
+                tm = super.get(key);
+            } catch (TemplateModelException e) {
+                Debug.logError(e, "Error getting Map with key [" + key + "]: " + e.toString(), module);
+            }
+            if (tm instanceof StringModel) {
+                String original = ((StringModel) tm).getAsString();
+                if (original != null) {
+                    String encoded = StringUtil.htmlEncoder.encode(original);
+                    if (!original.equals(encoded)) {
+                        return new StringModel(encoded, this.wrapper);
+                    }
+                }
+            }
+            return tm;
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java Sun Feb  8 07:40:40 2009
@@ -950,7 +950,9 @@
     public boolean trackStats(HttpServletRequest request) {
         if (!"false".equalsIgnoreCase(context.getInitParameter("track-serverhit"))) {
             String uriString = RequestHandler.getRequestUri(request.getPathInfo());
-            return controllerConfig.requestMapMap.get(uriString).trackServerHit;
+            ConfigXMLReader.RequestMap requestMap = controllerConfig.requestMapMap.get(uriString);
+            if (requestMap == null) return false;
+            return requestMap.trackServerHit;
         } else {
             return false;
         }
@@ -959,7 +961,9 @@
     public boolean trackVisit(HttpServletRequest request) {
         if (!"false".equalsIgnoreCase(context.getInitParameter("track-visit"))) {
             String uriString = RequestHandler.getRequestUri(request.getPathInfo());
-            return controllerConfig.requestMapMap.get(uriString).trackVisit;
+            ConfigXMLReader.RequestMap requestMap = controllerConfig.requestMapMap.get(uriString);
+            if (requestMap == null) return false;
+            return requestMap.trackVisit;
         } else {
             return false;
         }

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java?rev=742013&r1=742012&r2=742013&view=diff
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java Sun Feb  8 07:40:40 2009
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -29,9 +28,11 @@
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
+import org.ofbiz.base.util.StringUtil;
 import org.ofbiz.base.util.UtilGenerics;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.base.util.collections.MapStack;
 import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.base.util.template.FreeMarkerWorker;
@@ -39,7 +40,13 @@
 import org.ofbiz.widget.html.HtmlWidgetRenderer;
 import org.w3c.dom.Element;
 
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.ext.beans.StringModel;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
 import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
 
 /**
  * Widget Library - Screen model HTML class.
@@ -47,6 +54,37 @@
 @SuppressWarnings("serial")
 public class HtmlWidget extends ModelScreenWidget {
     public static final String module = HtmlWidget.class.getName();
+
+    public static UtilCache<String, Template> specialTemplateCache = new UtilCache<String, Template>("widget.screen.template.ftl.general", 0, 0, false);
+    protected static BeansWrapper specialBeansWrapper = new ExtendedWrapper();
+    protected static Configuration specialConfig = FreeMarkerWorker.makeConfiguration(specialBeansWrapper);
+
+    // not sure if this is the best way to get FTL to use my fancy MapModel derivative, but should work at least...
+    public static class ExtendedWrapper extends BeansWrapper {
+        public TemplateModel wrap(Object object) throws TemplateModelException {
+            /* NOTE: don't use this and the StringHtmlWrapperForFtl or things will be double-encoded
+            if (object instanceof GenericValue) {
+                return new GenericValueHtmlWrapperForFtl((GenericValue) object, this);
+            }*/ 
+            // This StringHtmlWrapperForFtl option seems to be the best option
+            // and handles most things without causing too many problems
+            if (object instanceof String) {
+                return new StringHtmlWrapperForFtl((String) object, this);
+            }
+            return super.wrap(object);
+        }
+    }
+
+    public static class StringHtmlWrapperForFtl extends StringModel {
+        public StringHtmlWrapperForFtl(String str, BeansWrapper wrapper) {
+            super(str, wrapper);
+        }
+        public String getAsString() {
+            return StringUtil.htmlEncoder.encode(super.getAsString());
+        }
+    }
+    
+    // End Static, begin class section
     
     protected List<ModelScreenWidget> subWidgets = new ArrayList<ModelScreenWidget>();
     
@@ -87,6 +125,64 @@
             throw new IllegalArgumentException("Template location is empty");
         }
         
+
+        /*
+        // ======================================================================= 
+        // Go through the context and find GenericValue objects and wrap them
+        
+        // NOTE PROBLEM: there are still problems with this as it gets some things
+        // but does not get non-entity data including lots of strings
+        // directly in the context or things prepared or derived right in
+        // the FTL file, like the results of service calls, etc; we could
+        // do something more aggressive to encode and wrap EVERYTHING in
+        // the context, but I've been thinking that even this is too much
+        // overhead and that would be crazy
+        
+        // NOTE ALTERNATIVE1: considering instead to use the FTL features to wrap
+        // everything in an <#escape x as x?html>...</#escape>, but that could 
+        // cause problems with ${} expansions that have HTML in them, including:
+        // included screens (using ${screens.render(...)}), content that should 
+        // have HTML in it (lots of general, product, category, etc content), etc
+        
+        // NOTE ALTERNATIVE2: kind of like the "#escape X as x?html" option,
+        // implement an FTL *Model class and load it through a ObjectWrapper
+        // FINAL NOTE: after testing all of these alternatives, this one seems
+        // to behave the best, so going with that for now. 
+        
+        // isolate the scope so these wrapper objects go away after rendering is done 
+        MapStack<String> contextMs;
+        if (!(context instanceof MapStack)) {
+            contextMs = MapStack.create(context);
+            context = contextMs;
+        } else {
+            contextMs = UtilGenerics.cast(context);
+        }
+
+        contextMs.push();
+        for(Map.Entry<String, Object> mapEntry: contextMs.entrySet()) {
+            Object value = mapEntry.getValue();
+            if (value instanceof GenericValue) {
+                contextMs.put(mapEntry.getKey(), GenericValueHtmlWrapper.create((GenericValue) value));
+            } else if (value instanceof List) {
+                if (((List) value).size() > 0 && ((List) value).get(0) instanceof GenericValue) {
+                    List<GenericValue> theList = (List<GenericValue>) value;
+                    List<GenericValueHtmlWrapper> newList = FastList.newInstance();
+                    for (GenericValue gv: theList) {
+                        newList.add(GenericValueHtmlWrapper.create(gv));
+                    }
+                    contextMs.put(mapEntry.getKey(), newList);
+                }
+            }
+            // TODO and NOTE: should get most stuff, but we could support Maps 
+            // and Lists in Maps and such; that's tricky because we have to go 
+            // through the entire Map and not just one entry, and we would 
+            // have to shallow copy the whole Map too
+            
+        }
+        // this line goes at the end of the method, but moved up here to be part of the big comment about this
+        contextMs.pop();
+         */
+        
         if (location.endsWith(".ftl")) {
             try {
                 Map<String, ? extends Object> parameters = UtilGenerics.checkMap(context.get("parameters"));
@@ -94,7 +190,11 @@
                 if (insertWidgetBoundaryComments) {
                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("Begin", "Template", location));
                 }
-                FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
+                
+                //FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
+                Template template = FreeMarkerWorker.getTemplate(location, specialTemplateCache, specialConfig);
+                FreeMarkerWorker.renderTemplate(template, context, writer);
+                
                 if (insertWidgetBoundaryComments) {
                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("End", "Template", location));
                 }



Re: svn commit: r742013 - in /ofbiz/trunk/framework: base/config/ base/src/org/ofbiz/base/util/template/ entity/src/org/ofbiz/entity/ webapp/src/org/ofbiz/webapp/control/ widget/src/org/ofbiz/widget/screen/

Posted by Jacques Le Roux <ja...@les7arts.com>.
I thought that I should have takeen into account case unsensitive (but anyway, as I said maybe there is a better/more general 
solution)

Jacques

From: "David E Jones" <da...@hotwaxmedia.com>
>
> I'm looking into this now.
>
> -David
>
>
> On Feb 8, 2009, at 9:21 AM, Jacques Le Roux wrote:
>
>> This causes an issue when rendering a javascript variable build in  groovy
>> Commenting out lines 71-73 of HtmlWidget.java solves the problem.
>> Please see Giant Widget with variant explosion in ecommerce when  viewing details for an example.
>> I would suggest
>>           if (object instanceof String) {
>>               if (!((String) object).contains("<script language= \"JavaScript\">")) {
>>                   return new StringHtmlWrapperForFtl((String)  object, this);
>>               }
>>           }
>>
>>
>> but not sue it's the best way (it works of course)
>>
>> Jacques
>>
>> From: <jo...@apache.org>
>>> Author: jonesde
>>> Date: Sun Feb  8 07:40:40 2009
>>> New Revision: 742013
>>>
>>> URL: http://svn.apache.org/viewvc?rev=742013&view=rev
>>> Log:
>>> Implemented StringModel extension and BeansWrapper extension to  load it in order to encode strings for HTML use; this is only 
>>> done  throught the HtmlWidget class that is part of the screen widget, so  won't interfere with other FTL uses; note that there 
>>> is other  experimental code in here for wrapping the GenericValue object for  html encoding, but that option wasn't very 
>>> complete so went this  way instead; this option behaves better and is more transparent  than that escape x as x?html option for 
>>> FTL files; there are also a  few cleanups of typos and things in here; note that this means we  have a different Configuration 
>>> object and so a different template  cache, and so we have different cache settings and such; after  applying this I found a few 
>>> places that encoded things they  shouldn't but for the most part it is pretty good; will be  committing some changes in 
>>> applications in a bit to resolve a  couple of these issues in ecommerce; all should watch out for funny  things showing up as
>>> HTML text instead of being interpreted by the browser as HTML,  meaning it was encoded; in extreme cases just comment out lines 
>>> 71-73 of HtmlWidget.java to turn off this encoding
>>>
>>> Added:
>>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java   (with props)
>>> Modified:
>>>   ofbiz/trunk/framework/base/config/cache.properties
>>>   ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ FreeMarkerWorker.java
>>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericEntity.java
>>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
>>>   ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ RequestHandler.java
>>>   ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ HtmlWidget.java
>>>
>>> Modified: ofbiz/trunk/framework/base/config/cache.properties
>>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/cache.properties?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/base/config/cache.properties (original)
>>> +++ ofbiz/trunk/framework/base/config/cache.properties Sun Feb  8  07:40:40 2009
>>> @@ -91,8 +91,9 @@
>>> widget.tree.locationResource.expireTime=10000
>>> widget.tree.webappResource.expireTime=10000
>>>
>>> -template.ftl.general.expireTime=10000
>>> template.ftl.location.expireTime=10000
>>> +template.ftl.general.expireTime=10000
>>> +widget.screen.template.ftl.general.expireTime=10000
>>>
>>> ModelDataFile.expireTime=10000
>>>
>>>
>>> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ template/FreeMarkerWorker.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ FreeMarkerWorker.java (original)
>>> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ FreeMarkerWorker.java Sun Feb  8 07:40:40 2009
>>> @@ -62,7 +62,6 @@
>>> import freemarker.template.TemplateException;
>>> import freemarker.template.TemplateModel;
>>> import freemarker.template.TemplateModelException;
>>> -//import com.clarkware.profiler.Profiler;
>>>
>>> /** FreeMarkerWorker - Freemarker Template Engine Utilities.
>>> *
>>> @@ -73,17 +72,19 @@
>>>
>>>    // use soft references for this so that things from Content  records don't kill all of our memory, or maybe not for 
>>> performance  reasons... hmmm, leave to config file...
>>>    public static UtilCache<String, Template> cachedTemplates = new  UtilCache<String, Template>("template.ftl.general", 0, 0, 
>>> false);
>>> -    protected static Configuration defaultOfbizConfig = new  Configuration();
>>> +    protected static BeansWrapper defaultOfbizWrapper =  BeansWrapper.getDefaultInstance();
>>> +    protected static Configuration defaultOfbizConfig =  makeConfiguration(defaultOfbizWrapper);
>>>
>>> -    static {
>>> -        BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
>>> -        defaultOfbizConfig.setObjectWrapper(wrapper);
>>> -        defaultOfbizConfig.setSharedVariable("Static",  wrapper.getStaticModels());
>>> -        defaultOfbizConfig.setLocalizedLookup(false);
>>> -        defaultOfbizConfig.setTemplateLoader(new  FlexibleTemplateLoader());
>>> +    public static Configuration makeConfiguration(BeansWrapper  wrapper) {
>>> +        Configuration newConfig = new Configuration();
>>> +
>>> +        newConfig.setObjectWrapper(wrapper);
>>> +        newConfig.setSharedVariable("Static",  wrapper.getStaticModels());
>>> +        newConfig.setLocalizedLookup(false);
>>> +        newConfig.setTemplateLoader(new FlexibleTemplateLoader());
>>>        try {
>>> -            defaultOfbizConfig.setSetting("datetime_format", "yyyy- MM-dd HH:mm:ss.SSS");
>>> -            defaultOfbizConfig.setSetting("number_format",  "0.##########");
>>> +            newConfig.setSetting("datetime_format", "yyyy-MM-dd  HH:mm:ss.SSS");
>>> +            newConfig.setSetting("number_format", "0.##########");
>>>        } catch (TemplateException e) {
>>>            Debug.logError("Unable to set date/time and number  formats in FreeMarker: " + e, module);
>>>        }
>>> @@ -103,23 +104,25 @@
>>>            if (props == null || props.isEmpty()) {
>>>                Debug.logError("Unable to locate properties file " +  propertyURL, module);
>>>            } else {
>>> -                loadTransforms(loader, props);
>>> +                loadTransforms(loader, props, newConfig);
>>>            }
>>>        }
>>> +
>>> +        return newConfig;
>>>    }
>>>
>>>    /**
>>>     * Protected helper method.
>>>     */
>>> -    protected static void loadTransforms(ClassLoader loader,  Properties props) {
>>> +    protected static void loadTransforms(ClassLoader loader,  Properties props, Configuration config) {
>>>        for (Iterator<Object> i = props.keySet().iterator();  i.hasNext();) {
>>> -            String key = (String)i.next();
>>> +            String key = (String) i.next();
>>>            String className = props.getProperty(key);
>>>            if (Debug.verboseOn()) {
>>>                Debug.logVerbose("Adding FTL Transform " + key + "  with class " + className, module);
>>>            }
>>>            try {
>>> -                defaultOfbizConfig.setSharedVariable(key,  loader.loadClass(className).newInstance());
>>> +                config.setSharedVariable(key,  loader.loadClass(className).newInstance());
>>>            } catch (Exception e) {
>>>                Debug.logError(e, "Could not pre-initialize  dynamically loaded class: " + className + ": " + e, module);
>>>            }
>>> @@ -195,7 +198,7 @@
>>>        // FIXME: the casting from Appendable to Writer is a  temporary fix that could cause a
>>>        //        run time error if in the future we will pass a  different class to the method
>>>        //        (such as a StringBuffer).
>>> -        Environment env =  template.createProcessingEnvironment(context, (Writer)outWriter);
>>> +        Environment env =  template.createProcessingEnvironment(context, (Writer) outWriter);
>>>        applyUserSettings(env, context);
>>>        env.process();
>>>        return env;
>>> @@ -261,16 +264,20 @@
>>>     * @param templateLocation Location of the template - file path  or URL
>>>     */
>>>    public static Template getTemplate(String templateLocation)  throws TemplateException, IOException {
>>> -        Template template = (Template)  cachedTemplates.get(templateLocation);
>>> +        return getTemplate(templateLocation, cachedTemplates,  defaultOfbizConfig);
>>> +    }
>>> +
>>> +    public static Template getTemplate(String templateLocation,  UtilCache<String, Template> cache, Configuration config) 
>>> throws  TemplateException, IOException {
>>> +        Template template = (Template) cache.get(templateLocation);
>>>        if (template == null) {
>>> -            synchronized (cachedTemplates) {
>>> -                template = (Template)  cachedTemplates.get(templateLocation);
>>> +            synchronized (cache) {
>>> +                template = (Template) cache.get(templateLocation);
>>>                if (template == null) {
>>>                    // only make the reader if we need it, and then  close it right after!
>>>                    Reader templateReader =  makeReader(templateLocation);
>>> -                    template = new Template(templateLocation,  templateReader, defaultOfbizConfig);
>>> +                    template = new Template(templateLocation,  templateReader, config);
>>>                    templateReader.close();
>>> -                    cachedTemplates.put(templateLocation, template);
>>> +                    cache.put(templateLocation, template);
>>>                }
>>>            }
>>>        }
>>>
>>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericEntity.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericEntity.java (original)
>>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericEntity.java Sun Feb  8 07:40:40 2009
>>> @@ -142,21 +142,21 @@
>>>    /** Creates new GenericEntity */
>>>    protected void init(ModelEntity modelEntity) {
>>>        if (modelEntity == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null modelEntity parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null modelEntity parameter");
>>>        }
>>>        this.modelEntity = modelEntity;
>>>        this.entityName = modelEntity.getEntityName();
>>>
>>>        // check some things
>>>        if (this.entityName == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>>        }
>>>    }
>>>
>>>    /** Creates new GenericEntity from existing Map */
>>>    protected void init(ModelEntity modelEntity, Map<String, ?  extends Object> fields) {
>>>        if (modelEntity == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null modelEntity parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null modelEntity parameter");
>>>        }
>>>        this.modelEntity = modelEntity;
>>>        this.entityName = modelEntity.getEntityName();
>>> @@ -164,14 +164,14 @@
>>>
>>>        // check some things
>>>        if (this.entityName == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>>        }
>>>    }
>>>
>>>    /** Creates new GenericEntity from existing Map */
>>>    protected void init(ModelEntity modelEntity, Object  singlePkValue) {
>>>        if (modelEntity == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null modelEntity parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null modelEntity parameter");
>>>        }
>>>        if (modelEntity.getPksSize() != 1) {
>>>            throw new IllegalArgumentException("Cannot create a  GenericEntity with more than one primary key field");
>>> @@ -182,25 +182,22 @@
>>>
>>>        // check some things
>>>        if (this.entityName == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>>        }
>>>    }
>>>
>>>    /** Copy Constructor: Creates new GenericEntity from existing  GenericEntity */
>>>    protected void init(GenericEntity value) {
>>> -        if (value.modelEntity == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity from another GenericEntity with a null 
>>> modelEntity in  the value parameter");
>>> +        // check some things
>>> +        if (value.entityName == null) {
>>> +            throw new IllegalArgumentException("Cannot create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>>        }
>>> -        this.entityName = value.modelEntity.getEntityName();
>>> +        this.entityName = value.getEntityName();
>>> +        // NOTE: could call getModelEntity to insure we have a  value, just in case the value passed in has been serialized, 
>>> but  might as well leave it null to keep the object light if it isn't  there
>>>        this.modelEntity = value.modelEntity;
>>>        if (value.fields != null) this.fields.putAll(value.fields);
>>>        this.delegatorName = value.delegatorName;
>>>        this.internalDelegator = value.internalDelegator;
>>> -
>>> -        // check some things
>>> -        if (this.entityName == null) {
>>> -            throw new IllegalArgumentException("Cannont create a  GenericEntity with a null entityName in the modelEntity 
>>> parameter");
>>> -        }
>>>    }
>>>
>>>    public void reset() {
>>>
>>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValue.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValue.java (original)
>>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValue.java Sun Feb  8 07:40:40 2009
>>> @@ -24,8 +24,8 @@
>>> import java.util.List;
>>> import java.util.Map;
>>>
>>> -import javolution.lang.Reusable;
>>> import javolution.context.ObjectFactory;
>>> +import javolution.lang.Reusable;
>>> import javolution.util.FastMap;
>>>
>>> import org.ofbiz.base.util.Debug;
>>> @@ -33,7 +33,6 @@
>>> import org.ofbiz.base.util.UtilValidate;
>>> import org.ofbiz.entity.condition.EntityCondition;
>>> import org.ofbiz.entity.condition.EntityFieldMap;
>>> -import org.ofbiz.entity.condition.EntityOperator;
>>> import org.ofbiz.entity.model.ModelEntity;
>>> import org.ofbiz.entity.model.ModelKeyMap;
>>> import org.ofbiz.entity.model.ModelRelation;
>>> @@ -44,6 +43,7 @@
>>> * Generic Entity Value Object - Handles persistence for any defined  entity.
>>> *
>>> */
>>> +@SuppressWarnings("serial")
>>> public class GenericValue extends GenericEntity implements Reusable {
>>>
>>>    public static final GenericValue NULL_VALUE = new  NullGenericValue();
>>>
>>> Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java?rev=742013&view=auto
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java (added)
>>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java Sun Feb  8 07:40:40 2009
>>> @@ -0,0 +1,105 @@
>>> +/ *******************************************************************************
>>> + * Licensed to the Apache Software Foundation (ASF) under one
>>> + * or more contributor license agreements.  See the NOTICE file
>>> + * distributed with this work for additional information
>>> + * regarding copyright ownership.  The ASF licenses this file
>>> + * to you under the Apache License, Version 2.0 (the
>>> + * "License"); you may not use this file except in compliance
>>> + * with the License.  You may obtain a copy of the License at
>>> + *
>>> + * http://www.apache.org/licenses/LICENSE-2.0
>>> + *
>>> + * Unless required by applicable law or agreed to in writing,
>>> + * software distributed under the License is distributed on an
>>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>>> + * KIND, either express or implied.  See the License for the
>>> + * specific language governing permissions and limitations
>>> + * under the License.
>>> +  *******************************************************************************/
>>> +
>>> +package org.ofbiz.entity;
>>> +
>>> +
>>> +import javolution.context.ObjectFactory;
>>> +
>>> +import org.ofbiz.base.util.Debug;
>>> +import org.ofbiz.base.util.StringUtil;
>>> +
>>> +import freemarker.ext.beans.BeansWrapper;
>>> +import freemarker.ext.beans.MapModel;
>>> +import freemarker.ext.beans.StringModel;
>>> +import freemarker.template.TemplateModel;
>>> +import freemarker.template.TemplateModelException;
>>> +
>>> +
>>> +/**
>>> + * Generic Entity Value Object - Handles persistence for any  defined entity.
>>> + * WARNING: This object is experimental!
>>> + *
>>> + */
>>> +@SuppressWarnings("serial")
>>> +public class GenericValueHtmlWrapper extends GenericValue {
>>> +    protected static final ObjectFactory<GenericValueHtmlWrapper>  genericValueHtmlWrapperFactory = new 
>>> ObjectFactory<GenericValueHtmlWrapper>() {
>>> +        protected GenericValueHtmlWrapper create() {
>>> +            return new GenericValueHtmlWrapper();
>>> +        }
>>> +    };
>>> +
>>> +    /** Creates new GenericValueHtmlWrapper from existing  GenericValue */
>>> +    public static GenericValueHtmlWrapper create(GenericValue  value) {
>>> +        GenericValueHtmlWrapper newValue =  genericValueHtmlWrapperFactory.object();
>>> +        try {
>>> +            newValue.init(value);
>>> +        } catch (RuntimeException e) {
>>> +            Debug.logError(e, "Error in init for clone of value: "  + value, module);
>>> +            throw e;
>>> +        }
>>> +        return newValue;
>>> +    }
>>> +
>>> +    /* NOTE: this is NOT used because there are certain FTL files  that call services and things, and this messes those up, so 
>>> only  overriding the Map.get(Object) method to get use of this as a Map
>>> +     * Override the basic get method, which all other get methods  call so we only need to do this one (though most important 
>>> for the  Map.get(Object) and the getString() methods
>>> +    public Object get(String name) {
>>> +        Object value = super.get(name);
>>> +        if (value instanceof String) {
>>> +            return StringUtil.htmlEncoder.encode((String) value);
>>> +        } else {
>>> +            return value;
>>> +        }
>>> +    }*/
>>> +
>>> +    public Object get(Object name) {
>>> +        Object value = super.get(name);
>>> +        if (value instanceof String) {
>>> +            return StringUtil.htmlEncoder.encode((String) value);
>>> +        } else {
>>> +            return value;
>>> +        }
>>> +    }
>>> +
>>> +    // another experimental object, this one specifically for FTL
>>> +    public static class GenericValueHtmlWrapperForFtl extends  MapModel {
>>> +        public GenericValueHtmlWrapperForFtl(GenericValue gv,  BeansWrapper wrapper) {
>>> +            super(gv, wrapper);
>>> +        }
>>> +
>>> +        public TemplateModel get(String key) {
>>> +            TemplateModel tm = null;
>>> +            try {
>>> +                tm = super.get(key);
>>> +            } catch (TemplateModelException e) {
>>> +                Debug.logError(e, "Error getting Map with key [" +  key + "]: " + e.toString(), module);
>>> +            }
>>> +            if (tm instanceof StringModel) {
>>> +                String original = ((StringModel) tm).getAsString();
>>> +                if (original != null) {
>>> +                    String encoded =  StringUtil.htmlEncoder.encode(original);
>>> +                    if (!original.equals(encoded)) {
>>> +                        return new StringModel(encoded,  this.wrapper);
>>> +                    }
>>> +                }
>>> +            }
>>> +            return tm;
>>> +        }
>>> +    }
>>> +}
>>>
>>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java
>>> ------------------------------------------------------------------------------
>>>   svn:eol-style = native
>>>
>>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java
>>> ------------------------------------------------------------------------------
>>>   svn:keywords = "Date Rev Author URL Id"
>>>
>>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ GenericValueHtmlWrapper.java
>>> ------------------------------------------------------------------------------
>>>   svn:mime-type = text/plain
>>>
>>> Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ RequestHandler.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ RequestHandler.java (original)
>>> +++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ RequestHandler.java Sun Feb  8 07:40:40 2009
>>> @@ -950,7 +950,9 @@
>>>    public boolean trackStats(HttpServletRequest request) {
>>>        if  (!"false".equalsIgnoreCase(context.getInitParameter("track- serverhit"))) {
>>>            String uriString =  RequestHandler.getRequestUri(request.getPathInfo());
>>> -            return  controllerConfig.requestMapMap.get(uriString).trackServerHit;
>>> +            ConfigXMLReader.RequestMap requestMap =  controllerConfig.requestMapMap.get(uriString);
>>> +            if (requestMap == null) return false;
>>> +            return requestMap.trackServerHit;
>>>        } else {
>>>            return false;
>>>        }
>>> @@ -959,7 +961,9 @@
>>>    public boolean trackVisit(HttpServletRequest request) {
>>>        if  (!"false".equalsIgnoreCase(context.getInitParameter("track- visit"))) {
>>>            String uriString =  RequestHandler.getRequestUri(request.getPathInfo());
>>> -            return  controllerConfig.requestMapMap.get(uriString).trackVisit;
>>> +            ConfigXMLReader.RequestMap requestMap =  controllerConfig.requestMapMap.get(uriString);
>>> +            if (requestMap == null) return false;
>>> +            return requestMap.trackVisit;
>>>        } else {
>>>            return false;
>>>        }
>>>
>>> Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ HtmlWidget.java
>>> URL: 
>>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java?rev=742013&r1=742012&r2=742013&view=diff
>>> = = = = = = = = = =====================================================================
>>> --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ HtmlWidget.java (original)
>>> +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ HtmlWidget.java Sun Feb  8 07:40:40 2009
>>> @@ -21,7 +21,6 @@
>>> import java.io.IOException;
>>> import java.net.MalformedURLException;
>>> import java.util.ArrayList;
>>> -import java.util.Iterator;
>>> import java.util.List;
>>> import java.util.Map;
>>>
>>> @@ -29,9 +28,11 @@
>>>
>>> import org.ofbiz.base.util.Debug;
>>> import org.ofbiz.base.util.GeneralException;
>>> +import org.ofbiz.base.util.StringUtil;
>>> import org.ofbiz.base.util.UtilGenerics;
>>> import org.ofbiz.base.util.UtilValidate;
>>> import org.ofbiz.base.util.UtilXml;
>>> +import org.ofbiz.base.util.cache.UtilCache;
>>> import org.ofbiz.base.util.collections.MapStack;
>>> import org.ofbiz.base.util.string.FlexibleStringExpander;
>>> import org.ofbiz.base.util.template.FreeMarkerWorker;
>>> @@ -39,7 +40,13 @@
>>> import org.ofbiz.widget.html.HtmlWidgetRenderer;
>>> import org.w3c.dom.Element;
>>>
>>> +import freemarker.ext.beans.BeansWrapper;
>>> +import freemarker.ext.beans.StringModel;
>>> +import freemarker.template.Configuration;
>>> +import freemarker.template.Template;
>>> import freemarker.template.TemplateException;
>>> +import freemarker.template.TemplateModel;
>>> +import freemarker.template.TemplateModelException;
>>>
>>> /**
>>> * Widget Library - Screen model HTML class.
>>> @@ -47,6 +54,37 @@
>>> @SuppressWarnings("serial")
>>> public class HtmlWidget extends ModelScreenWidget {
>>>    public static final String module = HtmlWidget.class.getName();
>>> +
>>> +    public static UtilCache<String, Template> specialTemplateCache  = new UtilCache<String, 
>>> Template>("widget.screen.template.ftl.general", 0, 0, false);
>>> +    protected static BeansWrapper specialBeansWrapper = new  ExtendedWrapper();
>>> +    protected static Configuration specialConfig =  FreeMarkerWorker.makeConfiguration(specialBeansWrapper);
>>> +
>>> +    // not sure if this is the best way to get FTL to use my fancy  MapModel derivative, but should work at least...
>>> +    public static class ExtendedWrapper extends BeansWrapper {
>>> +        public TemplateModel wrap(Object object) throws  TemplateModelException {
>>> +            /* NOTE: don't use this and the  StringHtmlWrapperForFtl or things will be double-encoded
>>> +            if (object instanceof GenericValue) {
>>> +                return new  GenericValueHtmlWrapperForFtl((GenericValue) object, this);
>>> +            }*/
>>> +            // This StringHtmlWrapperForFtl option seems to be the  best option
>>> +            // and handles most things without causing too many  problems
>>> +            if (object instanceof String) {
>>> +                return new StringHtmlWrapperForFtl((String)  object, this);
>>> +            }
>>> +            return super.wrap(object);
>>> +        }
>>> +    }
>>> +
>>> +    public static class StringHtmlWrapperForFtl extends  StringModel {
>>> +        public StringHtmlWrapperForFtl(String str, BeansWrapper  wrapper) {
>>> +            super(str, wrapper);
>>> +        }
>>> +        public String getAsString() {
>>> +            return  StringUtil.htmlEncoder.encode(super.getAsString());
>>> +        }
>>> +    }
>>> +
>>> +    // End Static, begin class section
>>>
>>>    protected List<ModelScreenWidget> subWidgets = new  ArrayList<ModelScreenWidget>();
>>>
>>> @@ -87,6 +125,64 @@
>>>            throw new IllegalArgumentException("Template location is  empty");
>>>        }
>>>
>>> +
>>> +        /*
>>> +        //  = = =====================================================================
>>> +        // Go through the context and find GenericValue objects  and wrap them
>>> +
>>> +        // NOTE PROBLEM: there are still problems with this as it  gets some things
>>> +        // but does not get non-entity data including lots of  strings
>>> +        // directly in the context or things prepared or derived  right in
>>> +        // the FTL file, like the results of service calls, etc;  we could
>>> +        // do something more aggressive to encode and wrap  EVERYTHING in
>>> +        // the context, but I've been thinking that even this is  too much
>>> +        // overhead and that would be crazy
>>> +
>>> +        // NOTE ALTERNATIVE1: considering instead to use the FTL  features to wrap
>>> +        // everything in an <#escape x as x?html>...</#escape>,  but that could
>>> +        // cause problems with ${} expansions that have HTML in  them, including:
>>> +        // included screens (using ${screens.render(...)}),  content that should
>>> +        // have HTML in it (lots of general, product, category,  etc content), etc
>>> +
>>> +        // NOTE ALTERNATIVE2: kind of like the "#escape X as x? html" option,
>>> +        // implement an FTL *Model class and load it through a  ObjectWrapper
>>> +        // FINAL NOTE: after testing all of these alternatives,  this one seems
>>> +        // to behave the best, so going with that for now.
>>> +
>>> +        // isolate the scope so these wrapper objects go away  after rendering is done
>>> +        MapStack<String> contextMs;
>>> +        if (!(context instanceof MapStack)) {
>>> +            contextMs = MapStack.create(context);
>>> +            context = contextMs;
>>> +        } else {
>>> +            contextMs = UtilGenerics.cast(context);
>>> +        }
>>> +
>>> +        contextMs.push();
>>> +        for(Map.Entry<String, Object> mapEntry:  contextMs.entrySet()) {
>>> +            Object value = mapEntry.getValue();
>>> +            if (value instanceof GenericValue) {
>>> +                contextMs.put(mapEntry.getKey(),  GenericValueHtmlWrapper.create((GenericValue) value));
>>> +            } else if (value instanceof List) {
>>> +                if (((List) value).size() > 0 && ((List)  value).get(0) instanceof GenericValue) {
>>> +                    List<GenericValue> theList =  (List<GenericValue>) value;
>>> +                    List<GenericValueHtmlWrapper> newList =  FastList.newInstance();
>>> +                    for (GenericValue gv: theList) {
>>> +                         newList.add(GenericValueHtmlWrapper.create(gv));
>>> +                    }
>>> +                    contextMs.put(mapEntry.getKey(), newList);
>>> +                }
>>> +            }
>>> +            // TODO and NOTE: should get most stuff, but we could  support Maps
>>> +            // and Lists in Maps and such; that's tricky because  we have to go
>>> +            // through the entire Map and not just one entry, and  we would
>>> +            // have to shallow copy the whole Map too
>>> +
>>> +        }
>>> +        // this line goes at the end of the method, but moved up  here to be part of the big comment about this
>>> +        contextMs.pop();
>>> +         */
>>> +
>>>        if (location.endsWith(".ftl")) {
>>>            try {
>>>                Map<String, ? extends Object> parameters =  UtilGenerics.checkMap(context.get("parameters"));
>>> @@ -94,7 +190,11 @@
>>>                if (insertWidgetBoundaryComments) {
>>>                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("Begin",  "Template", location));
>>>                }
>>> -                 FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
>>> +
>>> +                // FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
>>> +                Template template =  FreeMarkerWorker.getTemplate(location, specialTemplateCache,  specialConfig);
>>> +                FreeMarkerWorker.renderTemplate(template, context,  writer);
>>> +
>>>                if (insertWidgetBoundaryComments) {
>>>                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("End",  "Template", location));
>>>                }
>>>
>>
> 


Re: svn commit: r742013 - in /ofbiz/trunk/framework: base/config/ base/src/org/ofbiz/base/util/template/ entity/src/org/ofbiz/entity/ webapp/src/org/ofbiz/webapp/control/ widget/src/org/ofbiz/widget/screen/

Posted by David E Jones <da...@hotwaxmedia.com>.
I'm looking into this now.

-David


On Feb 8, 2009, at 9:21 AM, Jacques Le Roux wrote:

> This causes an issue when rendering a javascript variable build in  
> groovy
> Commenting out lines 71-73 of HtmlWidget.java solves the problem.
> Please see Giant Widget with variant explosion in ecommerce when  
> viewing details for an example.
> I would suggest
>           if (object instanceof String) {
>               if (!((String) object).contains("<script language= 
> \"JavaScript\">")) {
>                   return new StringHtmlWrapperForFtl((String)  
> object, this);
>               }
>           }
>
>
> but not sue it's the best way (it works of course)
>
> Jacques
>
> From: <jo...@apache.org>
>> Author: jonesde
>> Date: Sun Feb  8 07:40:40 2009
>> New Revision: 742013
>>
>> URL: http://svn.apache.org/viewvc?rev=742013&view=rev
>> Log:
>> Implemented StringModel extension and BeansWrapper extension to  
>> load it in order to encode strings for HTML use; this is only done  
>> throught the HtmlWidget class that is part of the screen widget, so  
>> won't interfere with other FTL uses; note that there is other  
>> experimental code in here for wrapping the GenericValue object for  
>> html encoding, but that option wasn't very complete so went this  
>> way instead; this option behaves better and is more transparent  
>> than that escape x as x?html option for FTL files; there are also a  
>> few cleanups of typos and things in here; note that this means we  
>> have a different Configuration object and so a different template  
>> cache, and so we have different cache settings and such; after  
>> applying this I found a few places that encoded things they  
>> shouldn't but for the most part it is pretty good; will be  
>> committing some changes in applications in a bit to resolve a  
>> couple of these issues in ecommerce; all should watch out for funny  
>> things showing up as
>> HTML text instead of being interpreted by the browser as HTML,  
>> meaning it was encoded; in extreme cases just comment out lines  
>> 71-73 of HtmlWidget.java to turn off this encoding
>>
>> Added:
>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java   (with props)
>> Modified:
>>   ofbiz/trunk/framework/base/config/cache.properties
>>   ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ 
>> FreeMarkerWorker.java
>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericEntity.java
>>   ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
>>   ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ 
>> RequestHandler.java
>>   ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ 
>> HtmlWidget.java
>>
>> Modified: ofbiz/trunk/framework/base/config/cache.properties
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/cache.properties?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/base/config/cache.properties (original)
>> +++ ofbiz/trunk/framework/base/config/cache.properties Sun Feb  8  
>> 07:40:40 2009
>> @@ -91,8 +91,9 @@
>> widget.tree.locationResource.expireTime=10000
>> widget.tree.webappResource.expireTime=10000
>>
>> -template.ftl.general.expireTime=10000
>> template.ftl.location.expireTime=10000
>> +template.ftl.general.expireTime=10000
>> +widget.screen.template.ftl.general.expireTime=10000
>>
>> ModelDataFile.expireTime=10000
>>
>>
>> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ 
>> template/FreeMarkerWorker.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ 
>> FreeMarkerWorker.java (original)
>> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/ 
>> FreeMarkerWorker.java Sun Feb  8 07:40:40 2009
>> @@ -62,7 +62,6 @@
>> import freemarker.template.TemplateException;
>> import freemarker.template.TemplateModel;
>> import freemarker.template.TemplateModelException;
>> -//import com.clarkware.profiler.Profiler;
>>
>> /** FreeMarkerWorker - Freemarker Template Engine Utilities.
>> *
>> @@ -73,17 +72,19 @@
>>
>>    // use soft references for this so that things from Content  
>> records don't kill all of our memory, or maybe not for performance  
>> reasons... hmmm, leave to config file...
>>    public static UtilCache<String, Template> cachedTemplates = new  
>> UtilCache<String, Template>("template.ftl.general", 0, 0, false);
>> -    protected static Configuration defaultOfbizConfig = new  
>> Configuration();
>> +    protected static BeansWrapper defaultOfbizWrapper =  
>> BeansWrapper.getDefaultInstance();
>> +    protected static Configuration defaultOfbizConfig =  
>> makeConfiguration(defaultOfbizWrapper);
>>
>> -    static {
>> -        BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
>> -        defaultOfbizConfig.setObjectWrapper(wrapper);
>> -        defaultOfbizConfig.setSharedVariable("Static",  
>> wrapper.getStaticModels());
>> -        defaultOfbizConfig.setLocalizedLookup(false);
>> -        defaultOfbizConfig.setTemplateLoader(new  
>> FlexibleTemplateLoader());
>> +    public static Configuration makeConfiguration(BeansWrapper  
>> wrapper) {
>> +        Configuration newConfig = new Configuration();
>> +
>> +        newConfig.setObjectWrapper(wrapper);
>> +        newConfig.setSharedVariable("Static",  
>> wrapper.getStaticModels());
>> +        newConfig.setLocalizedLookup(false);
>> +        newConfig.setTemplateLoader(new FlexibleTemplateLoader());
>>        try {
>> -            defaultOfbizConfig.setSetting("datetime_format", "yyyy- 
>> MM-dd HH:mm:ss.SSS");
>> -            defaultOfbizConfig.setSetting("number_format",  
>> "0.##########");
>> +            newConfig.setSetting("datetime_format", "yyyy-MM-dd  
>> HH:mm:ss.SSS");
>> +            newConfig.setSetting("number_format", "0.##########");
>>        } catch (TemplateException e) {
>>            Debug.logError("Unable to set date/time and number  
>> formats in FreeMarker: " + e, module);
>>        }
>> @@ -103,23 +104,25 @@
>>            if (props == null || props.isEmpty()) {
>>                Debug.logError("Unable to locate properties file " +  
>> propertyURL, module);
>>            } else {
>> -                loadTransforms(loader, props);
>> +                loadTransforms(loader, props, newConfig);
>>            }
>>        }
>> +
>> +        return newConfig;
>>    }
>>
>>    /**
>>     * Protected helper method.
>>     */
>> -    protected static void loadTransforms(ClassLoader loader,  
>> Properties props) {
>> +    protected static void loadTransforms(ClassLoader loader,  
>> Properties props, Configuration config) {
>>        for (Iterator<Object> i = props.keySet().iterator();  
>> i.hasNext();) {
>> -            String key = (String)i.next();
>> +            String key = (String) i.next();
>>            String className = props.getProperty(key);
>>            if (Debug.verboseOn()) {
>>                Debug.logVerbose("Adding FTL Transform " + key + "  
>> with class " + className, module);
>>            }
>>            try {
>> -                defaultOfbizConfig.setSharedVariable(key,  
>> loader.loadClass(className).newInstance());
>> +                config.setSharedVariable(key,  
>> loader.loadClass(className).newInstance());
>>            } catch (Exception e) {
>>                Debug.logError(e, "Could not pre-initialize  
>> dynamically loaded class: " + className + ": " + e, module);
>>            }
>> @@ -195,7 +198,7 @@
>>        // FIXME: the casting from Appendable to Writer is a  
>> temporary fix that could cause a
>>        //        run time error if in the future we will pass a  
>> different class to the method
>>        //        (such as a StringBuffer).
>> -        Environment env =  
>> template.createProcessingEnvironment(context, (Writer)outWriter);
>> +        Environment env =  
>> template.createProcessingEnvironment(context, (Writer) outWriter);
>>        applyUserSettings(env, context);
>>        env.process();
>>        return env;
>> @@ -261,16 +264,20 @@
>>     * @param templateLocation Location of the template - file path  
>> or URL
>>     */
>>    public static Template getTemplate(String templateLocation)  
>> throws TemplateException, IOException {
>> -        Template template = (Template)  
>> cachedTemplates.get(templateLocation);
>> +        return getTemplate(templateLocation, cachedTemplates,  
>> defaultOfbizConfig);
>> +    }
>> +
>> +    public static Template getTemplate(String templateLocation,  
>> UtilCache<String, Template> cache, Configuration config) throws  
>> TemplateException, IOException {
>> +        Template template = (Template) cache.get(templateLocation);
>>        if (template == null) {
>> -            synchronized (cachedTemplates) {
>> -                template = (Template)  
>> cachedTemplates.get(templateLocation);
>> +            synchronized (cache) {
>> +                template = (Template) cache.get(templateLocation);
>>                if (template == null) {
>>                    // only make the reader if we need it, and then  
>> close it right after!
>>                    Reader templateReader =  
>> makeReader(templateLocation);
>> -                    template = new Template(templateLocation,  
>> templateReader, defaultOfbizConfig);
>> +                    template = new Template(templateLocation,  
>> templateReader, config);
>>                    templateReader.close();
>> -                    cachedTemplates.put(templateLocation, template);
>> +                    cache.put(templateLocation, template);
>>                }
>>            }
>>        }
>>
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericEntity.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericEntity.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericEntity.java Sun Feb  8 07:40:40 2009
>> @@ -142,21 +142,21 @@
>>    /** Creates new GenericEntity */
>>    protected void init(ModelEntity modelEntity) {
>>        if (modelEntity == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null modelEntity parameter");
>>        }
>>        this.modelEntity = modelEntity;
>>        this.entityName = modelEntity.getEntityName();
>>
>>        // check some things
>>        if (this.entityName == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>>        }
>>    }
>>
>>    /** Creates new GenericEntity from existing Map */
>>    protected void init(ModelEntity modelEntity, Map<String, ?  
>> extends Object> fields) {
>>        if (modelEntity == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null modelEntity parameter");
>>        }
>>        this.modelEntity = modelEntity;
>>        this.entityName = modelEntity.getEntityName();
>> @@ -164,14 +164,14 @@
>>
>>        // check some things
>>        if (this.entityName == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>>        }
>>    }
>>
>>    /** Creates new GenericEntity from existing Map */
>>    protected void init(ModelEntity modelEntity, Object  
>> singlePkValue) {
>>        if (modelEntity == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null modelEntity parameter");
>>        }
>>        if (modelEntity.getPksSize() != 1) {
>>            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with more than one primary key field");
>> @@ -182,25 +182,22 @@
>>
>>        // check some things
>>        if (this.entityName == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>>        }
>>    }
>>
>>    /** Copy Constructor: Creates new GenericEntity from existing  
>> GenericEntity */
>>    protected void init(GenericEntity value) {
>> -        if (value.modelEntity == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity from another GenericEntity with a null modelEntity in  
>> the value parameter");
>> +        // check some things
>> +        if (value.entityName == null) {
>> +            throw new IllegalArgumentException("Cannot create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>>        }
>> -        this.entityName = value.modelEntity.getEntityName();
>> +        this.entityName = value.getEntityName();
>> +        // NOTE: could call getModelEntity to insure we have a  
>> value, just in case the value passed in has been serialized, but  
>> might as well leave it null to keep the object light if it isn't  
>> there
>>        this.modelEntity = value.modelEntity;
>>        if (value.fields != null) this.fields.putAll(value.fields);
>>        this.delegatorName = value.delegatorName;
>>        this.internalDelegator = value.internalDelegator;
>> -
>> -        // check some things
>> -        if (this.entityName == null) {
>> -            throw new IllegalArgumentException("Cannont create a  
>> GenericEntity with a null entityName in the modelEntity parameter");
>> -        }
>>    }
>>
>>    public void reset() {
>>
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValue.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValue.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValue.java Sun Feb  8 07:40:40 2009
>> @@ -24,8 +24,8 @@
>> import java.util.List;
>> import java.util.Map;
>>
>> -import javolution.lang.Reusable;
>> import javolution.context.ObjectFactory;
>> +import javolution.lang.Reusable;
>> import javolution.util.FastMap;
>>
>> import org.ofbiz.base.util.Debug;
>> @@ -33,7 +33,6 @@
>> import org.ofbiz.base.util.UtilValidate;
>> import org.ofbiz.entity.condition.EntityCondition;
>> import org.ofbiz.entity.condition.EntityFieldMap;
>> -import org.ofbiz.entity.condition.EntityOperator;
>> import org.ofbiz.entity.model.ModelEntity;
>> import org.ofbiz.entity.model.ModelKeyMap;
>> import org.ofbiz.entity.model.ModelRelation;
>> @@ -44,6 +43,7 @@
>> * Generic Entity Value Object - Handles persistence for any defined  
>> entity.
>> *
>> */
>> +@SuppressWarnings("serial")
>> public class GenericValue extends GenericEntity implements Reusable {
>>
>>    public static final GenericValue NULL_VALUE = new  
>> NullGenericValue();
>>
>> Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java?rev=742013&view=auto
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java (added)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java Sun Feb  8 07:40:40 2009
>> @@ -0,0 +1,105 @@
>> +/ 
>> *******************************************************************************
>> + * Licensed to the Apache Software Foundation (ASF) under one
>> + * or more contributor license agreements.  See the NOTICE file
>> + * distributed with this work for additional information
>> + * regarding copyright ownership.  The ASF licenses this file
>> + * to you under the Apache License, Version 2.0 (the
>> + * "License"); you may not use this file except in compliance
>> + * with the License.  You may obtain a copy of the License at
>> + *
>> + * http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing,
>> + * software distributed under the License is distributed on an
>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> + * KIND, either express or implied.  See the License for the
>> + * specific language governing permissions and limitations
>> + * under the License.
>> +  
>> *******************************************************************************/
>> +
>> +package org.ofbiz.entity;
>> +
>> +
>> +import javolution.context.ObjectFactory;
>> +
>> +import org.ofbiz.base.util.Debug;
>> +import org.ofbiz.base.util.StringUtil;
>> +
>> +import freemarker.ext.beans.BeansWrapper;
>> +import freemarker.ext.beans.MapModel;
>> +import freemarker.ext.beans.StringModel;
>> +import freemarker.template.TemplateModel;
>> +import freemarker.template.TemplateModelException;
>> +
>> +
>> +/**
>> + * Generic Entity Value Object - Handles persistence for any  
>> defined entity.
>> + * WARNING: This object is experimental!
>> + *
>> + */
>> +@SuppressWarnings("serial")
>> +public class GenericValueHtmlWrapper extends GenericValue {
>> +    protected static final ObjectFactory<GenericValueHtmlWrapper>  
>> genericValueHtmlWrapperFactory = new  
>> ObjectFactory<GenericValueHtmlWrapper>() {
>> +        protected GenericValueHtmlWrapper create() {
>> +            return new GenericValueHtmlWrapper();
>> +        }
>> +    };
>> +
>> +    /** Creates new GenericValueHtmlWrapper from existing  
>> GenericValue */
>> +    public static GenericValueHtmlWrapper create(GenericValue  
>> value) {
>> +        GenericValueHtmlWrapper newValue =  
>> genericValueHtmlWrapperFactory.object();
>> +        try {
>> +            newValue.init(value);
>> +        } catch (RuntimeException e) {
>> +            Debug.logError(e, "Error in init for clone of value: "  
>> + value, module);
>> +            throw e;
>> +        }
>> +        return newValue;
>> +    }
>> +
>> +    /* NOTE: this is NOT used because there are certain FTL files  
>> that call services and things, and this messes those up, so only  
>> overriding the Map.get(Object) method to get use of this as a Map
>> +     * Override the basic get method, which all other get methods  
>> call so we only need to do this one (though most important for the  
>> Map.get(Object) and the getString() methods
>> +    public Object get(String name) {
>> +        Object value = super.get(name);
>> +        if (value instanceof String) {
>> +            return StringUtil.htmlEncoder.encode((String) value);
>> +        } else {
>> +            return value;
>> +        }
>> +    }*/
>> +
>> +    public Object get(Object name) {
>> +        Object value = super.get(name);
>> +        if (value instanceof String) {
>> +            return StringUtil.htmlEncoder.encode((String) value);
>> +        } else {
>> +            return value;
>> +        }
>> +    }
>> +
>> +    // another experimental object, this one specifically for FTL
>> +    public static class GenericValueHtmlWrapperForFtl extends  
>> MapModel {
>> +        public GenericValueHtmlWrapperForFtl(GenericValue gv,  
>> BeansWrapper wrapper) {
>> +            super(gv, wrapper);
>> +        }
>> +
>> +        public TemplateModel get(String key) {
>> +            TemplateModel tm = null;
>> +            try {
>> +                tm = super.get(key);
>> +            } catch (TemplateModelException e) {
>> +                Debug.logError(e, "Error getting Map with key [" +  
>> key + "]: " + e.toString(), module);
>> +            }
>> +            if (tm instanceof StringModel) {
>> +                String original = ((StringModel) tm).getAsString();
>> +                if (original != null) {
>> +                    String encoded =  
>> StringUtil.htmlEncoder.encode(original);
>> +                    if (!original.equals(encoded)) {
>> +                        return new StringModel(encoded,  
>> this.wrapper);
>> +                    }
>> +                }
>> +            }
>> +            return tm;
>> +        }
>> +    }
>> +}
>>
>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java
>> ------------------------------------------------------------------------------
>>   svn:eol-style = native
>>
>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java
>> ------------------------------------------------------------------------------
>>   svn:keywords = "Date Rev Author URL Id"
>>
>> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/ 
>> GenericValueHtmlWrapper.java
>> ------------------------------------------------------------------------------
>>   svn:mime-type = text/plain
>>
>> Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ 
>> RequestHandler.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ 
>> RequestHandler.java (original)
>> +++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ 
>> RequestHandler.java Sun Feb  8 07:40:40 2009
>> @@ -950,7 +950,9 @@
>>    public boolean trackStats(HttpServletRequest request) {
>>        if  
>> (!"false".equalsIgnoreCase(context.getInitParameter("track- 
>> serverhit"))) {
>>            String uriString =  
>> RequestHandler.getRequestUri(request.getPathInfo());
>> -            return  
>> controllerConfig.requestMapMap.get(uriString).trackServerHit;
>> +            ConfigXMLReader.RequestMap requestMap =  
>> controllerConfig.requestMapMap.get(uriString);
>> +            if (requestMap == null) return false;
>> +            return requestMap.trackServerHit;
>>        } else {
>>            return false;
>>        }
>> @@ -959,7 +961,9 @@
>>    public boolean trackVisit(HttpServletRequest request) {
>>        if  
>> (!"false".equalsIgnoreCase(context.getInitParameter("track- 
>> visit"))) {
>>            String uriString =  
>> RequestHandler.getRequestUri(request.getPathInfo());
>> -            return  
>> controllerConfig.requestMapMap.get(uriString).trackVisit;
>> +            ConfigXMLReader.RequestMap requestMap =  
>> controllerConfig.requestMapMap.get(uriString);
>> +            if (requestMap == null) return false;
>> +            return requestMap.trackVisit;
>>        } else {
>>            return false;
>>        }
>>
>> Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ 
>> HtmlWidget.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java?rev=742013&r1=742012&r2=742013&view=diff
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> = 
>> =====================================================================
>> --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ 
>> HtmlWidget.java (original)
>> +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ 
>> HtmlWidget.java Sun Feb  8 07:40:40 2009
>> @@ -21,7 +21,6 @@
>> import java.io.IOException;
>> import java.net.MalformedURLException;
>> import java.util.ArrayList;
>> -import java.util.Iterator;
>> import java.util.List;
>> import java.util.Map;
>>
>> @@ -29,9 +28,11 @@
>>
>> import org.ofbiz.base.util.Debug;
>> import org.ofbiz.base.util.GeneralException;
>> +import org.ofbiz.base.util.StringUtil;
>> import org.ofbiz.base.util.UtilGenerics;
>> import org.ofbiz.base.util.UtilValidate;
>> import org.ofbiz.base.util.UtilXml;
>> +import org.ofbiz.base.util.cache.UtilCache;
>> import org.ofbiz.base.util.collections.MapStack;
>> import org.ofbiz.base.util.string.FlexibleStringExpander;
>> import org.ofbiz.base.util.template.FreeMarkerWorker;
>> @@ -39,7 +40,13 @@
>> import org.ofbiz.widget.html.HtmlWidgetRenderer;
>> import org.w3c.dom.Element;
>>
>> +import freemarker.ext.beans.BeansWrapper;
>> +import freemarker.ext.beans.StringModel;
>> +import freemarker.template.Configuration;
>> +import freemarker.template.Template;
>> import freemarker.template.TemplateException;
>> +import freemarker.template.TemplateModel;
>> +import freemarker.template.TemplateModelException;
>>
>> /**
>> * Widget Library - Screen model HTML class.
>> @@ -47,6 +54,37 @@
>> @SuppressWarnings("serial")
>> public class HtmlWidget extends ModelScreenWidget {
>>    public static final String module = HtmlWidget.class.getName();
>> +
>> +    public static UtilCache<String, Template> specialTemplateCache  
>> = new UtilCache<String,  
>> Template>("widget.screen.template.ftl.general", 0, 0, false);
>> +    protected static BeansWrapper specialBeansWrapper = new  
>> ExtendedWrapper();
>> +    protected static Configuration specialConfig =  
>> FreeMarkerWorker.makeConfiguration(specialBeansWrapper);
>> +
>> +    // not sure if this is the best way to get FTL to use my fancy  
>> MapModel derivative, but should work at least...
>> +    public static class ExtendedWrapper extends BeansWrapper {
>> +        public TemplateModel wrap(Object object) throws  
>> TemplateModelException {
>> +            /* NOTE: don't use this and the  
>> StringHtmlWrapperForFtl or things will be double-encoded
>> +            if (object instanceof GenericValue) {
>> +                return new  
>> GenericValueHtmlWrapperForFtl((GenericValue) object, this);
>> +            }*/
>> +            // This StringHtmlWrapperForFtl option seems to be the  
>> best option
>> +            // and handles most things without causing too many  
>> problems
>> +            if (object instanceof String) {
>> +                return new StringHtmlWrapperForFtl((String)  
>> object, this);
>> +            }
>> +            return super.wrap(object);
>> +        }
>> +    }
>> +
>> +    public static class StringHtmlWrapperForFtl extends  
>> StringModel {
>> +        public StringHtmlWrapperForFtl(String str, BeansWrapper  
>> wrapper) {
>> +            super(str, wrapper);
>> +        }
>> +        public String getAsString() {
>> +            return  
>> StringUtil.htmlEncoder.encode(super.getAsString());
>> +        }
>> +    }
>> +
>> +    // End Static, begin class section
>>
>>    protected List<ModelScreenWidget> subWidgets = new  
>> ArrayList<ModelScreenWidget>();
>>
>> @@ -87,6 +125,64 @@
>>            throw new IllegalArgumentException("Template location is  
>> empty");
>>        }
>>
>> +
>> +        /*
>> +        //  
>> = 
>> = 
>> =====================================================================
>> +        // Go through the context and find GenericValue objects  
>> and wrap them
>> +
>> +        // NOTE PROBLEM: there are still problems with this as it  
>> gets some things
>> +        // but does not get non-entity data including lots of  
>> strings
>> +        // directly in the context or things prepared or derived  
>> right in
>> +        // the FTL file, like the results of service calls, etc;  
>> we could
>> +        // do something more aggressive to encode and wrap  
>> EVERYTHING in
>> +        // the context, but I've been thinking that even this is  
>> too much
>> +        // overhead and that would be crazy
>> +
>> +        // NOTE ALTERNATIVE1: considering instead to use the FTL  
>> features to wrap
>> +        // everything in an <#escape x as x?html>...</#escape>,  
>> but that could
>> +        // cause problems with ${} expansions that have HTML in  
>> them, including:
>> +        // included screens (using ${screens.render(...)}),  
>> content that should
>> +        // have HTML in it (lots of general, product, category,  
>> etc content), etc
>> +
>> +        // NOTE ALTERNATIVE2: kind of like the "#escape X as x? 
>> html" option,
>> +        // implement an FTL *Model class and load it through a  
>> ObjectWrapper
>> +        // FINAL NOTE: after testing all of these alternatives,  
>> this one seems
>> +        // to behave the best, so going with that for now.
>> +
>> +        // isolate the scope so these wrapper objects go away  
>> after rendering is done
>> +        MapStack<String> contextMs;
>> +        if (!(context instanceof MapStack)) {
>> +            contextMs = MapStack.create(context);
>> +            context = contextMs;
>> +        } else {
>> +            contextMs = UtilGenerics.cast(context);
>> +        }
>> +
>> +        contextMs.push();
>> +        for(Map.Entry<String, Object> mapEntry:  
>> contextMs.entrySet()) {
>> +            Object value = mapEntry.getValue();
>> +            if (value instanceof GenericValue) {
>> +                contextMs.put(mapEntry.getKey(),  
>> GenericValueHtmlWrapper.create((GenericValue) value));
>> +            } else if (value instanceof List) {
>> +                if (((List) value).size() > 0 && ((List)  
>> value).get(0) instanceof GenericValue) {
>> +                    List<GenericValue> theList =  
>> (List<GenericValue>) value;
>> +                    List<GenericValueHtmlWrapper> newList =  
>> FastList.newInstance();
>> +                    for (GenericValue gv: theList) {
>> +                         
>> newList.add(GenericValueHtmlWrapper.create(gv));
>> +                    }
>> +                    contextMs.put(mapEntry.getKey(), newList);
>> +                }
>> +            }
>> +            // TODO and NOTE: should get most stuff, but we could  
>> support Maps
>> +            // and Lists in Maps and such; that's tricky because  
>> we have to go
>> +            // through the entire Map and not just one entry, and  
>> we would
>> +            // have to shallow copy the whole Map too
>> +
>> +        }
>> +        // this line goes at the end of the method, but moved up  
>> here to be part of the big comment about this
>> +        contextMs.pop();
>> +         */
>> +
>>        if (location.endsWith(".ftl")) {
>>            try {
>>                Map<String, ? extends Object> parameters =  
>> UtilGenerics.checkMap(context.get("parameters"));
>> @@ -94,7 +190,11 @@
>>                if (insertWidgetBoundaryComments) {
>>                     
>> writer.append(HtmlWidgetRenderer.formatBoundaryComment("Begin",  
>> "Template", location));
>>                }
>> -                 
>> FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
>> +
>> +                // 
>> FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
>> +                Template template =  
>> FreeMarkerWorker.getTemplate(location, specialTemplateCache,  
>> specialConfig);
>> +                FreeMarkerWorker.renderTemplate(template, context,  
>> writer);
>> +
>>                if (insertWidgetBoundaryComments) {
>>                     
>> writer.append(HtmlWidgetRenderer.formatBoundaryComment("End",  
>> "Template", location));
>>                }
>>
>


Re: svn commit: r742013 - in /ofbiz/trunk/framework: base/config/ base/src/org/ofbiz/base/util/template/ entity/src/org/ofbiz/entity/ webapp/src/org/ofbiz/webapp/control/ widget/src/org/ofbiz/widget/screen/

Posted by Jacques Le Roux <ja...@les7arts.com>.
This causes an issue when rendering a javascript variable build in groovy
Commenting out lines 71-73 of HtmlWidget.java solves the problem.
Please see Giant Widget with variant explosion in ecommerce when viewing details for an example.
I would suggest
            if (object instanceof String) {
                if (!((String) object).contains("<script language=\"JavaScript\">")) {
                    return new StringHtmlWrapperForFtl((String) object, this);
                }
            }


but not sue it's the best way (it works of course)

Jacques

From: <jo...@apache.org>
> Author: jonesde
> Date: Sun Feb  8 07:40:40 2009
> New Revision: 742013
>
> URL: http://svn.apache.org/viewvc?rev=742013&view=rev
> Log:
> Implemented StringModel extension and BeansWrapper extension to load it in order to encode strings for HTML use; this is only done 
> throught the HtmlWidget class that is part of the screen widget, so won't interfere with other FTL uses; note that there is other 
> experimental code in here for wrapping the GenericValue object for html encoding, but that option wasn't very complete so went 
> this way instead; this option behaves better and is more transparent than that escape x as x?html option for FTL files; there are 
> also a few cleanups of typos and things in here; note that this means we have a different Configuration object and so a different 
> template cache, and so we have different cache settings and such; after applying this I found a few places that encoded things 
> they shouldn't but for the most part it is pretty good; will be committing some changes in applications in a bit to resolve a 
> couple of these issues in ecommerce; all should watch out for funny things showing up as
> HTML text instead of being interpreted by the browser as HTML, meaning it was encoded; in extreme cases just comment out lines 
> 71-73 of HtmlWidget.java to turn off this encoding
>
> Added:
>    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java   (with props)
> Modified:
>    ofbiz/trunk/framework/base/config/cache.properties
>    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java
>    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
>    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
>    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
>    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java
>
> Modified: ofbiz/trunk/framework/base/config/cache.properties
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/cache.properties?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/base/config/cache.properties (original)
> +++ ofbiz/trunk/framework/base/config/cache.properties Sun Feb  8 07:40:40 2009
> @@ -91,8 +91,9 @@
> widget.tree.locationResource.expireTime=10000
> widget.tree.webappResource.expireTime=10000
>
> -template.ftl.general.expireTime=10000
> template.ftl.location.expireTime=10000
> +template.ftl.general.expireTime=10000
> +widget.screen.template.ftl.general.expireTime=10000
>
> ModelDataFile.expireTime=10000
>
>
> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java (original)
> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/template/FreeMarkerWorker.java Sun Feb  8 07:40:40 2009
> @@ -62,7 +62,6 @@
> import freemarker.template.TemplateException;
> import freemarker.template.TemplateModel;
> import freemarker.template.TemplateModelException;
> -//import com.clarkware.profiler.Profiler;
>
> /** FreeMarkerWorker - Freemarker Template Engine Utilities.
>  *
> @@ -73,17 +72,19 @@
>
>     // use soft references for this so that things from Content records don't kill all of our memory, or maybe not for performance 
> reasons... hmmm, leave to config file...
>     public static UtilCache<String, Template> cachedTemplates = new UtilCache<String, Template>("template.ftl.general", 0, 0, 
> false);
> -    protected static Configuration defaultOfbizConfig = new Configuration();
> +    protected static BeansWrapper defaultOfbizWrapper = BeansWrapper.getDefaultInstance();
> +    protected static Configuration defaultOfbizConfig = makeConfiguration(defaultOfbizWrapper);
>
> -    static {
> -        BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
> -        defaultOfbizConfig.setObjectWrapper(wrapper);
> -        defaultOfbizConfig.setSharedVariable("Static", wrapper.getStaticModels());
> -        defaultOfbizConfig.setLocalizedLookup(false);
> -        defaultOfbizConfig.setTemplateLoader(new FlexibleTemplateLoader());
> +    public static Configuration makeConfiguration(BeansWrapper wrapper) {
> +        Configuration newConfig = new Configuration();
> +
> +        newConfig.setObjectWrapper(wrapper);
> +        newConfig.setSharedVariable("Static", wrapper.getStaticModels());
> +        newConfig.setLocalizedLookup(false);
> +        newConfig.setTemplateLoader(new FlexibleTemplateLoader());
>         try {
> -            defaultOfbizConfig.setSetting("datetime_format", "yyyy-MM-dd HH:mm:ss.SSS");
> -            defaultOfbizConfig.setSetting("number_format", "0.##########");
> +            newConfig.setSetting("datetime_format", "yyyy-MM-dd HH:mm:ss.SSS");
> +            newConfig.setSetting("number_format", "0.##########");
>         } catch (TemplateException e) {
>             Debug.logError("Unable to set date/time and number formats in FreeMarker: " + e, module);
>         }
> @@ -103,23 +104,25 @@
>             if (props == null || props.isEmpty()) {
>                 Debug.logError("Unable to locate properties file " + propertyURL, module);
>             } else {
> -                loadTransforms(loader, props);
> +                loadTransforms(loader, props, newConfig);
>             }
>         }
> +
> +        return newConfig;
>     }
>
>     /**
>      * Protected helper method.
>      */
> -    protected static void loadTransforms(ClassLoader loader, Properties props) {
> +    protected static void loadTransforms(ClassLoader loader, Properties props, Configuration config) {
>         for (Iterator<Object> i = props.keySet().iterator(); i.hasNext();) {
> -            String key = (String)i.next();
> +            String key = (String) i.next();
>             String className = props.getProperty(key);
>             if (Debug.verboseOn()) {
>                 Debug.logVerbose("Adding FTL Transform " + key + " with class " + className, module);
>             }
>             try {
> -                defaultOfbizConfig.setSharedVariable(key, loader.loadClass(className).newInstance());
> +                config.setSharedVariable(key, loader.loadClass(className).newInstance());
>             } catch (Exception e) {
>                 Debug.logError(e, "Could not pre-initialize dynamically loaded class: " + className + ": " + e, module);
>             }
> @@ -195,7 +198,7 @@
>         // FIXME: the casting from Appendable to Writer is a temporary fix that could cause a
>         //        run time error if in the future we will pass a different class to the method
>         //        (such as a StringBuffer).
> -        Environment env = template.createProcessingEnvironment(context, (Writer)outWriter);
> +        Environment env = template.createProcessingEnvironment(context, (Writer) outWriter);
>         applyUserSettings(env, context);
>         env.process();
>         return env;
> @@ -261,16 +264,20 @@
>      * @param templateLocation Location of the template - file path or URL
>      */
>     public static Template getTemplate(String templateLocation) throws TemplateException, IOException {
> -        Template template = (Template) cachedTemplates.get(templateLocation);
> +        return getTemplate(templateLocation, cachedTemplates, defaultOfbizConfig);
> +    }
> +
> +    public static Template getTemplate(String templateLocation, UtilCache<String, Template> cache, Configuration config) throws 
> TemplateException, IOException {
> +        Template template = (Template) cache.get(templateLocation);
>         if (template == null) {
> -            synchronized (cachedTemplates) {
> -                template = (Template) cachedTemplates.get(templateLocation);
> +            synchronized (cache) {
> +                template = (Template) cache.get(templateLocation);
>                 if (template == null) {
>                     // only make the reader if we need it, and then close it right after!
>                     Reader templateReader = makeReader(templateLocation);
> -                    template = new Template(templateLocation, templateReader, defaultOfbizConfig);
> +                    template = new Template(templateLocation, templateReader, config);
>                     templateReader.close();
> -                    cachedTemplates.put(templateLocation, template);
> +                    cache.put(templateLocation, template);
>                 }
>             }
>         }
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java Sun Feb  8 07:40:40 2009
> @@ -142,21 +142,21 @@
>     /** Creates new GenericEntity */
>     protected void init(ModelEntity modelEntity) {
>         if (modelEntity == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
>         }
>         this.modelEntity = modelEntity;
>         this.entityName = modelEntity.getEntityName();
>
>         // check some things
>         if (this.entityName == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity 
> parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity 
> parameter");
>         }
>     }
>
>     /** Creates new GenericEntity from existing Map */
>     protected void init(ModelEntity modelEntity, Map<String, ? extends Object> fields) {
>         if (modelEntity == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
>         }
>         this.modelEntity = modelEntity;
>         this.entityName = modelEntity.getEntityName();
> @@ -164,14 +164,14 @@
>
>         // check some things
>         if (this.entityName == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity 
> parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity 
> parameter");
>         }
>     }
>
>     /** Creates new GenericEntity from existing Map */
>     protected void init(ModelEntity modelEntity, Object singlePkValue) {
>         if (modelEntity == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null modelEntity parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null modelEntity parameter");
>         }
>         if (modelEntity.getPksSize() != 1) {
>             throw new IllegalArgumentException("Cannot create a GenericEntity with more than one primary key field");
> @@ -182,25 +182,22 @@
>
>         // check some things
>         if (this.entityName == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity 
> parameter");
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity 
> parameter");
>         }
>     }
>
>     /** Copy Constructor: Creates new GenericEntity from existing GenericEntity */
>     protected void init(GenericEntity value) {
> -        if (value.modelEntity == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity from another GenericEntity with a null modelEntity 
> in the value parameter");
> +        // check some things
> +        if (value.entityName == null) {
> +            throw new IllegalArgumentException("Cannot create a GenericEntity with a null entityName in the modelEntity 
> parameter");
>         }
> -        this.entityName = value.modelEntity.getEntityName();
> +        this.entityName = value.getEntityName();
> +        // NOTE: could call getModelEntity to insure we have a value, just in case the value passed in has been serialized, but 
> might as well leave it null to keep the object light if it isn't there
>         this.modelEntity = value.modelEntity;
>         if (value.fields != null) this.fields.putAll(value.fields);
>         this.delegatorName = value.delegatorName;
>         this.internalDelegator = value.internalDelegator;
> -
> -        // check some things
> -        if (this.entityName == null) {
> -            throw new IllegalArgumentException("Cannont create a GenericEntity with a null entityName in the modelEntity 
> parameter");
> -        }
>     }
>
>     public void reset() {
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValue.java Sun Feb  8 07:40:40 2009
> @@ -24,8 +24,8 @@
> import java.util.List;
> import java.util.Map;
>
> -import javolution.lang.Reusable;
> import javolution.context.ObjectFactory;
> +import javolution.lang.Reusable;
> import javolution.util.FastMap;
>
> import org.ofbiz.base.util.Debug;
> @@ -33,7 +33,6 @@
> import org.ofbiz.base.util.UtilValidate;
> import org.ofbiz.entity.condition.EntityCondition;
> import org.ofbiz.entity.condition.EntityFieldMap;
> -import org.ofbiz.entity.condition.EntityOperator;
> import org.ofbiz.entity.model.ModelEntity;
> import org.ofbiz.entity.model.ModelKeyMap;
> import org.ofbiz.entity.model.ModelRelation;
> @@ -44,6 +43,7 @@
>  * Generic Entity Value Object - Handles persistence for any defined entity.
>  *
>  */
> +@SuppressWarnings("serial")
> public class GenericValue extends GenericEntity implements Reusable {
>
>     public static final GenericValue NULL_VALUE = new NullGenericValue();
>
> Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java?rev=742013&view=auto
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java (added)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java Sun Feb  8 07:40:40 2009
> @@ -0,0 +1,105 @@
> +/*******************************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied.  See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + *******************************************************************************/
> +
> +package org.ofbiz.entity;
> +
> +
> +import javolution.context.ObjectFactory;
> +
> +import org.ofbiz.base.util.Debug;
> +import org.ofbiz.base.util.StringUtil;
> +
> +import freemarker.ext.beans.BeansWrapper;
> +import freemarker.ext.beans.MapModel;
> +import freemarker.ext.beans.StringModel;
> +import freemarker.template.TemplateModel;
> +import freemarker.template.TemplateModelException;
> +
> +
> +/**
> + * Generic Entity Value Object - Handles persistence for any defined entity.
> + * WARNING: This object is experimental!
> + *
> + */
> +@SuppressWarnings("serial")
> +public class GenericValueHtmlWrapper extends GenericValue {
> +    protected static final ObjectFactory<GenericValueHtmlWrapper> genericValueHtmlWrapperFactory = new 
> ObjectFactory<GenericValueHtmlWrapper>() {
> +        protected GenericValueHtmlWrapper create() {
> +            return new GenericValueHtmlWrapper();
> +        }
> +    };
> +
> +    /** Creates new GenericValueHtmlWrapper from existing GenericValue */
> +    public static GenericValueHtmlWrapper create(GenericValue value) {
> +        GenericValueHtmlWrapper newValue = genericValueHtmlWrapperFactory.object();
> +        try {
> +            newValue.init(value);
> +        } catch (RuntimeException e) {
> +            Debug.logError(e, "Error in init for clone of value: " + value, module);
> +            throw e;
> +        }
> +        return newValue;
> +    }
> +
> +    /* NOTE: this is NOT used because there are certain FTL files that call services and things, and this messes those up, so 
> only overriding the Map.get(Object) method to get use of this as a Map
> +     * Override the basic get method, which all other get methods call so we only need to do this one (though most important for 
> the Map.get(Object) and the getString() methods
> +    public Object get(String name) {
> +        Object value = super.get(name);
> +        if (value instanceof String) {
> +            return StringUtil.htmlEncoder.encode((String) value);
> +        } else {
> +            return value;
> +        }
> +    }*/
> +
> +    public Object get(Object name) {
> +        Object value = super.get(name);
> +        if (value instanceof String) {
> +            return StringUtil.htmlEncoder.encode((String) value);
> +        } else {
> +            return value;
> +        }
> +    }
> +
> +    // another experimental object, this one specifically for FTL
> +    public static class GenericValueHtmlWrapperForFtl extends MapModel {
> +        public GenericValueHtmlWrapperForFtl(GenericValue gv, BeansWrapper wrapper) {
> +            super(gv, wrapper);
> +        }
> +
> +        public TemplateModel get(String key) {
> +            TemplateModel tm = null;
> +            try {
> +                tm = super.get(key);
> +            } catch (TemplateModelException e) {
> +                Debug.logError(e, "Error getting Map with key [" + key + "]: " + e.toString(), module);
> +            }
> +            if (tm instanceof StringModel) {
> +                String original = ((StringModel) tm).getAsString();
> +                if (original != null) {
> +                    String encoded = StringUtil.htmlEncoder.encode(original);
> +                    if (!original.equals(encoded)) {
> +                        return new StringModel(encoded, this.wrapper);
> +                    }
> +                }
> +            }
> +            return tm;
> +        }
> +    }
> +}
>
> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
> ------------------------------------------------------------------------------
>    svn:keywords = "Date Rev Author URL Id"
>
> Propchange: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericValueHtmlWrapper.java
> ------------------------------------------------------------------------------
>    svn:mime-type = text/plain
>
> Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java (original)
> +++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java Sun Feb  8 07:40:40 2009
> @@ -950,7 +950,9 @@
>     public boolean trackStats(HttpServletRequest request) {
>         if (!"false".equalsIgnoreCase(context.getInitParameter("track-serverhit"))) {
>             String uriString = RequestHandler.getRequestUri(request.getPathInfo());
> -            return controllerConfig.requestMapMap.get(uriString).trackServerHit;
> +            ConfigXMLReader.RequestMap requestMap = controllerConfig.requestMapMap.get(uriString);
> +            if (requestMap == null) return false;
> +            return requestMap.trackServerHit;
>         } else {
>             return false;
>         }
> @@ -959,7 +961,9 @@
>     public boolean trackVisit(HttpServletRequest request) {
>         if (!"false".equalsIgnoreCase(context.getInitParameter("track-visit"))) {
>             String uriString = RequestHandler.getRequestUri(request.getPathInfo());
> -            return controllerConfig.requestMapMap.get(uriString).trackVisit;
> +            ConfigXMLReader.RequestMap requestMap = controllerConfig.requestMapMap.get(uriString);
> +            if (requestMap == null) return false;
> +            return requestMap.trackVisit;
>         } else {
>             return false;
>         }
>
> Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java?rev=742013&r1=742012&r2=742013&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java (original)
> +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/HtmlWidget.java Sun Feb  8 07:40:40 2009
> @@ -21,7 +21,6 @@
> import java.io.IOException;
> import java.net.MalformedURLException;
> import java.util.ArrayList;
> -import java.util.Iterator;
> import java.util.List;
> import java.util.Map;
>
> @@ -29,9 +28,11 @@
>
> import org.ofbiz.base.util.Debug;
> import org.ofbiz.base.util.GeneralException;
> +import org.ofbiz.base.util.StringUtil;
> import org.ofbiz.base.util.UtilGenerics;
> import org.ofbiz.base.util.UtilValidate;
> import org.ofbiz.base.util.UtilXml;
> +import org.ofbiz.base.util.cache.UtilCache;
> import org.ofbiz.base.util.collections.MapStack;
> import org.ofbiz.base.util.string.FlexibleStringExpander;
> import org.ofbiz.base.util.template.FreeMarkerWorker;
> @@ -39,7 +40,13 @@
> import org.ofbiz.widget.html.HtmlWidgetRenderer;
> import org.w3c.dom.Element;
>
> +import freemarker.ext.beans.BeansWrapper;
> +import freemarker.ext.beans.StringModel;
> +import freemarker.template.Configuration;
> +import freemarker.template.Template;
> import freemarker.template.TemplateException;
> +import freemarker.template.TemplateModel;
> +import freemarker.template.TemplateModelException;
>
> /**
>  * Widget Library - Screen model HTML class.
> @@ -47,6 +54,37 @@
> @SuppressWarnings("serial")
> public class HtmlWidget extends ModelScreenWidget {
>     public static final String module = HtmlWidget.class.getName();
> +
> +    public static UtilCache<String, Template> specialTemplateCache = new UtilCache<String, 
> Template>("widget.screen.template.ftl.general", 0, 0, false);
> +    protected static BeansWrapper specialBeansWrapper = new ExtendedWrapper();
> +    protected static Configuration specialConfig = FreeMarkerWorker.makeConfiguration(specialBeansWrapper);
> +
> +    // not sure if this is the best way to get FTL to use my fancy MapModel derivative, but should work at least...
> +    public static class ExtendedWrapper extends BeansWrapper {
> +        public TemplateModel wrap(Object object) throws TemplateModelException {
> +            /* NOTE: don't use this and the StringHtmlWrapperForFtl or things will be double-encoded
> +            if (object instanceof GenericValue) {
> +                return new GenericValueHtmlWrapperForFtl((GenericValue) object, this);
> +            }*/
> +            // This StringHtmlWrapperForFtl option seems to be the best option
> +            // and handles most things without causing too many problems
> +            if (object instanceof String) {
> +                return new StringHtmlWrapperForFtl((String) object, this);
> +            }
> +            return super.wrap(object);
> +        }
> +    }
> +
> +    public static class StringHtmlWrapperForFtl extends StringModel {
> +        public StringHtmlWrapperForFtl(String str, BeansWrapper wrapper) {
> +            super(str, wrapper);
> +        }
> +        public String getAsString() {
> +            return StringUtil.htmlEncoder.encode(super.getAsString());
> +        }
> +    }
> +
> +    // End Static, begin class section
>
>     protected List<ModelScreenWidget> subWidgets = new ArrayList<ModelScreenWidget>();
>
> @@ -87,6 +125,64 @@
>             throw new IllegalArgumentException("Template location is empty");
>         }
>
> +
> +        /*
> +        // =======================================================================
> +        // Go through the context and find GenericValue objects and wrap them
> +
> +        // NOTE PROBLEM: there are still problems with this as it gets some things
> +        // but does not get non-entity data including lots of strings
> +        // directly in the context or things prepared or derived right in
> +        // the FTL file, like the results of service calls, etc; we could
> +        // do something more aggressive to encode and wrap EVERYTHING in
> +        // the context, but I've been thinking that even this is too much
> +        // overhead and that would be crazy
> +
> +        // NOTE ALTERNATIVE1: considering instead to use the FTL features to wrap
> +        // everything in an <#escape x as x?html>...</#escape>, but that could
> +        // cause problems with ${} expansions that have HTML in them, including:
> +        // included screens (using ${screens.render(...)}), content that should
> +        // have HTML in it (lots of general, product, category, etc content), etc
> +
> +        // NOTE ALTERNATIVE2: kind of like the "#escape X as x?html" option,
> +        // implement an FTL *Model class and load it through a ObjectWrapper
> +        // FINAL NOTE: after testing all of these alternatives, this one seems
> +        // to behave the best, so going with that for now.
> +
> +        // isolate the scope so these wrapper objects go away after rendering is done
> +        MapStack<String> contextMs;
> +        if (!(context instanceof MapStack)) {
> +            contextMs = MapStack.create(context);
> +            context = contextMs;
> +        } else {
> +            contextMs = UtilGenerics.cast(context);
> +        }
> +
> +        contextMs.push();
> +        for(Map.Entry<String, Object> mapEntry: contextMs.entrySet()) {
> +            Object value = mapEntry.getValue();
> +            if (value instanceof GenericValue) {
> +                contextMs.put(mapEntry.getKey(), GenericValueHtmlWrapper.create((GenericValue) value));
> +            } else if (value instanceof List) {
> +                if (((List) value).size() > 0 && ((List) value).get(0) instanceof GenericValue) {
> +                    List<GenericValue> theList = (List<GenericValue>) value;
> +                    List<GenericValueHtmlWrapper> newList = FastList.newInstance();
> +                    for (GenericValue gv: theList) {
> +                        newList.add(GenericValueHtmlWrapper.create(gv));
> +                    }
> +                    contextMs.put(mapEntry.getKey(), newList);
> +                }
> +            }
> +            // TODO and NOTE: should get most stuff, but we could support Maps
> +            // and Lists in Maps and such; that's tricky because we have to go
> +            // through the entire Map and not just one entry, and we would
> +            // have to shallow copy the whole Map too
> +
> +        }
> +        // this line goes at the end of the method, but moved up here to be part of the big comment about this
> +        contextMs.pop();
> +         */
> +
>         if (location.endsWith(".ftl")) {
>             try {
>                 Map<String, ? extends Object> parameters = UtilGenerics.checkMap(context.get("parameters"));
> @@ -94,7 +190,11 @@
>                 if (insertWidgetBoundaryComments) {
>                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("Begin", "Template", location));
>                 }
> -                FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
> +
> +                //FreeMarkerWorker.renderTemplateAtLocation(location, context, writer);
> +                Template template = FreeMarkerWorker.getTemplate(location, specialTemplateCache, specialConfig);
> +                FreeMarkerWorker.renderTemplate(template, context, writer);
> +
>                 if (insertWidgetBoundaryComments) {
>                     writer.append(HtmlWidgetRenderer.formatBoundaryComment("End", "Template", location));
>                 }
>
>