Administrator
|
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: <[hidden email]> > 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)); > } > > |
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: <[hidden email]> >> 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)); >> } >> > |
Administrator
|
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" <[hidden email]> > > 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: <[hidden email]> >>> 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)); >>> } >>> >> > |
Free forum by Nabble | Edit this page |