You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Jacques Le Roux <ja...@les7arts.com> on 2009/02/08 17:21:10 UTC

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/

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>.
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));
>>                }
>>
>