svn commit: r559384 - in /ofbiz/trunk/framework/widget: dtd/ src/org/ofbiz/widget/cache/ src/org/ofbiz/widget/screen/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r559384 - in /ofbiz/trunk/framework/widget: dtd/ src/org/ofbiz/widget/cache/ src/org/ofbiz/widget/screen/

jacopoc
Author: jacopoc
Date: Wed Jul 25 03:04:28 2007
New Revision: 559384

URL: http://svn.apache.org/viewvc?view=rev&rev=559384
Log:
This is the first version of the screen output cache mechanism.
It is still not ready for production because it needs much more tests, but I'm already committing it mainly for three reasons:
1) all the changes are well isolated
2) unless you explicitly set use-cache to true in a screen definition, everything will work as usual
3) I'd love to get some feedback from the community

To test it: just set the use-cache attribute to true in a screen definition (<screen name='someName' use-cache='true'>), then you'll find a new entry in the WebTools-->cache  screen.

Added:
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java   (with props)
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java   (with props)
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java   (with props)
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java   (with props)
Modified:
    ofbiz/trunk/framework/widget/dtd/widget-screen.xsd
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreen.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenRenderer.java

Modified: ofbiz/trunk/framework/widget/dtd/widget-screen.xsd
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/dtd/widget-screen.xsd?view=diff&rev=559384&r1=559383&r2=559384
==============================================================================
--- ofbiz/trunk/framework/widget/dtd/widget-screen.xsd (original)
+++ ofbiz/trunk/framework/widget/dtd/widget-screen.xsd Wed Jul 25 03:04:28 2007
@@ -36,6 +36,14 @@
     <xs:attributeGroup name="attlist.screen">
         <xs:attribute type="xs:string" name="name" use="required"/>
         <xs:attribute type="xs:string" name="transaction-timeout" use="optional"/>
+        <xs:attribute name="use-cache" default="false">
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value="true"/>
+                    <xs:enumeration value="false"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
     </xs:attributeGroup>
     <xs:element name="section" substitutionGroup="AllWidgets">
         <xs:complexType>

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java?view=auto&rev=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java Wed Jul 25 03:04:28 2007
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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.widget.cache;
+
+import org.ofbiz.base.util.cache.UtilCache;
+
+public abstract class AbstractCache {
+
+    protected String id;
+
+    protected AbstractCache(String id) {
+        this.id = id;
+    }
+
+    public void remove(String widgetName) {
+        UtilCache.clearCache(getCacheName(widgetName));
+    }
+
+    public void clear() {
+        UtilCache.clearCachesThatStartWith(getCacheNamePrefix());
+    }
+
+    public String getCacheNamePrefix() {
+        return "widgetcache." + id + ".";
+    }
+
+    public String getCacheName(String widgetName) {
+        return getCacheNamePrefix() + widgetName;
+    }
+
+    protected UtilCache getCache(String widgetName) {
+        synchronized (UtilCache.utilCacheTable) {
+            return (UtilCache) UtilCache.utilCacheTable.get(getCacheName(widgetName));
+        }
+    }
+
+    protected UtilCache getOrCreateCache(String widgetName) {
+        synchronized (UtilCache.utilCacheTable) {
+            String name = getCacheName(widgetName);
+            UtilCache cache = (UtilCache) UtilCache.utilCacheTable.get(name);
+            if (cache == null) {
+                cache = new UtilCache(name, 0, 0, true);
+                cache.setPropertiesParams(new String[] {name});
+            }
+            return cache;
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/AbstractCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java?view=auto&rev=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java Wed Jul 25 03:04:28 2007
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.widget.cache;
+
+public class GenericWidgetOutput {
+
+    public static final String module = GenericWidgetOutput.class.getName();
+
+    protected String output;
+
+    public GenericWidgetOutput(String output) {
+        this.output = new String(output);
+    }
+    
+    public String toString() {
+        return this.output;
+    }
+}

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/GenericWidgetOutput.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java?view=auto&rev=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java Wed Jul 25 03:04:28 2007
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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.widget.cache;
+
+import java.util.Iterator;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.cache.UtilCache;
+
+public class ScreenCache extends AbstractCache {
+    public static final String module = ScreenCache.class.getName();
+
+    public ScreenCache() {
+        super("screen");
+    }
+
+    public GenericWidgetOutput get(String screenName, WidgetContextCacheKey wcck) {
+        UtilCache screenCache = getCache(screenName);
+        if (screenCache == null) return null;
+        return (GenericWidgetOutput) screenCache.get(wcck);
+    }
+
+    public GenericWidgetOutput put(String screenName, WidgetContextCacheKey wcck, GenericWidgetOutput output) {
+        UtilCache screenCache = getOrCreateCache(screenName);
+        return (GenericWidgetOutput)screenCache.put(wcck, output);
+    }
+
+    public GenericWidgetOutput remove(String screenName, WidgetContextCacheKey wcck) {
+        UtilCache screenCache = getCache(screenName);
+        if (Debug.verboseOn()) Debug.logVerbose("Removing from ScreenCache with key [" + wcck + "], will remove from this cache: " + (screenCache == null ? "[No cache found to remove from]" : screenCache.getName()), module);
+        if (screenCache == null) return null;
+        GenericWidgetOutput retVal = (GenericWidgetOutput) screenCache.remove(wcck);
+        if (Debug.verboseOn()) Debug.logVerbose("Removing from ScreenCache with key [" + wcck + "], found this in the cache: " + retVal, module);
+        return retVal;
+    }
+}

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/ScreenCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java?view=auto&rev=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java Wed Jul 25 03:04:28 2007
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * 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.widget.cache;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilMisc;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javolution.util.FastMap;
+import javolution.util.FastSet;
+
+public class WidgetContextCacheKey {
+
+    public static final String module = WidgetContextCacheKey.class.getName();
+    
+    private static Set fieldNamesToSkip;
+    
+    static {
+        fieldNamesToSkip = FastSet.newInstance();
+        fieldNamesToSkip.add("globalContext");
+        fieldNamesToSkip.add("delegator");
+        fieldNamesToSkip.add("dispatcher");
+        fieldNamesToSkip.add("security");
+        fieldNamesToSkip.add("webSiteId");
+        fieldNamesToSkip.add("userLogin");
+        fieldNamesToSkip.add("screens");
+        fieldNamesToSkip.add("nullField");
+        fieldNamesToSkip.add("availableLocales");
+        fieldNamesToSkip.add("availableTimeZones");
+        fieldNamesToSkip.add("autoUserLogin");
+        fieldNamesToSkip.add("person");
+        fieldNamesToSkip.add("partyGroup");
+        fieldNamesToSkip.add("timeZone");
+        fieldNamesToSkip.add("sessionAttributes");
+        fieldNamesToSkip.add("requestAttributes");
+        fieldNamesToSkip.add("JspTaglibs");
+        fieldNamesToSkip.add("requestParameters");
+        fieldNamesToSkip.add("page");
+        fieldNamesToSkip.add("controlPath");
+        fieldNamesToSkip.add("contextRoot");
+        fieldNamesToSkip.add("serverRoot");
+        fieldNamesToSkip.add("checkLoginUrl");
+        fieldNamesToSkip.add("externalLoginKey");
+        fieldNamesToSkip.add("externalKeyParam");
+        fieldNamesToSkip.add("nowTimestamp");
+        fieldNamesToSkip.add("session");
+        fieldNamesToSkip.add("request");
+        fieldNamesToSkip.add("response");
+        fieldNamesToSkip.add("application");
+        fieldNamesToSkip.add("formStringRenderer");
+        fieldNamesToSkip.add("null");
+        fieldNamesToSkip.add("sections");
+        fieldNamesToSkip.add("uiLabelMap");
+        // remove
+        fieldNamesToSkip.add("layoutSettings");
+        fieldNamesToSkip.add("activeApp");
+        fieldNamesToSkip.add("appheaderTemplate");
+        fieldNamesToSkip.add("servletContext");
+        // parameters
+        fieldNamesToSkip.add("visit");
+        fieldNamesToSkip.add("visitor");
+    }
+            
+    protected Map context;
+
+    public WidgetContextCacheKey(Map context) {
+        this.context = FastMap.newInstance();
+        this.context.putAll(context);
+    }
+
+    public int hashCode() {
+        return 0;
+    }
+    public boolean equals(Object obj) {
+        WidgetContextCacheKey key = null;
+        if (obj instanceof WidgetContextCacheKey) {
+            key = (WidgetContextCacheKey)obj;
+        }
+        if (key == null || key.context == null) {
+            return this.context == null;
+        }
+        if (this.context == null) {
+            return false;
+        }
+
+        Set unifiedContext = FastSet.newInstance();
+        unifiedContext.addAll(this.context.keySet());
+        unifiedContext.addAll(key.context.keySet());
+        Iterator fieldNameIt = unifiedContext.iterator();
+        while (fieldNameIt.hasNext()) {
+            String fieldName = (String)fieldNameIt.next();
+            if (fieldNamesToSkip.contains(fieldName)) {
+                continue;
+            }
+            Object field1 = this.context.get(fieldName);
+            Object field2 = key.context.get(fieldName);
+            if (field1 == null && field2 == null) {
+                continue;
+            }
+            if ((field1 == null || field2 == null) && field1 != field2) {
+                Debug.logWarning("Screen Key doesn't match for :" + fieldName + "; value1 = " + field1 + "; value2 = " + field2, module);
+                return false;
+            }
+            if ("parameters".equals(fieldName)) {
+                if (!parametersAreEqual((Map)field1, (Map)field2)) {
+                    return false;
+                }
+                continue;
+            }
+            if (!field1.equals(field2)) {
+                Debug.logWarning("Screen Key doesn't match for :" + fieldName + "; value1 = " + field1 + "; value2 = " + field2, module);
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    public String toString() {
+        Map printableMap = FastMap.newInstance();
+        Iterator fieldNameIt = this.context.keySet().iterator();
+        while (fieldNameIt.hasNext()) {
+            String fieldName = (String)fieldNameIt.next();
+            if (!fieldNamesToSkip.contains(fieldName) && !"parameters".equals(fieldName)) {
+                printableMap.put(fieldName, this.context.get(fieldName));
+            }
+        }
+        return printMap(printableMap) + "\n" + printMap((Map)this.context.get("parameters"));
+    }
+
+    public static String printMap(Map map) {
+        Map printableMap = FastMap.newInstance();
+        Iterator fieldNameIt = map.keySet().iterator();
+        while (fieldNameIt.hasNext()) {
+            String fieldName = (String)fieldNameIt.next();
+            if (!fieldNamesToSkip.contains(fieldName) &&
+                    !fieldName.startsWith("javax.servlet") &&
+                    !fieldName.startsWith("org.apache") &&
+                    !fieldName.startsWith("_CLIENT_")) {
+                printableMap.put(fieldName, map.get(fieldName));
+            }
+        }
+        return UtilMisc.printMap(printableMap);
+    }
+
+    public static boolean parametersAreEqual(Map map1, Map map2) {
+        Set unifiedContext = FastSet.newInstance();
+        unifiedContext.addAll(map1.keySet());
+        unifiedContext.addAll(map2.keySet());
+        Iterator fieldNameIt = unifiedContext.iterator();
+        while (fieldNameIt.hasNext()) {
+            String fieldName = (String)fieldNameIt.next();
+            if (fieldNamesToSkip.contains(fieldName)) {
+                continue;
+            }
+            if (fieldName.startsWith("javax.servlet") ||
+                    fieldName.startsWith("org.apache") ||
+                    fieldName.startsWith("_CLIENT_")) {
+                continue;
+            }
+            Object field1 = map1.get(fieldName);
+            Object field2 = map2.get(fieldName);
+            if (field1 == null && field2 == null) {
+                continue;
+            }
+            if ((field1 == null || field2 == null) && field1 != field2) {
+                Debug.logWarning("Screen Key doesn't match for :" + fieldName + "; value1 = " + field1 + "; value2 = " + field2, module);
+                return false;
+            }
+            if (!field1.equals(field2)) {
+                Debug.logWarning("Screen Key doesn't match for :" + fieldName + "; value1 = " + field1 + "; value2 = " + field2, module);
+                return false;
+            }
+        }
+        return true;
+    }
+}

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Propchange: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/cache/WidgetContextCacheKey.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreen.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreen.java?view=diff&rev=559384&r1=559383&r2=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreen.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreen.java Wed Jul 25 03:04:28 2007
@@ -45,6 +45,7 @@
     protected String sourceLocation;
     protected FlexibleStringExpander transactionTimeoutExdr;
     protected Map modelScreenMap;
+    protected boolean useCache;
     
     protected ModelScreenWidget.Section section;
 
@@ -58,6 +59,7 @@
         this.name = screenElement.getAttribute("name");
         this.transactionTimeoutExdr = new FlexibleStringExpander(screenElement.getAttribute("transaction-timeout"));
         this.modelScreenMap = modelScreenMap;
+        this.useCache = "true".equals(screenElement.getAttribute("use-cache"));
 
         // read in the section, which will read all sub-widgets too
         Element sectionElement = UtilXml.firstChildElement(screenElement, "section");

Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenRenderer.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenRenderer.java?view=diff&rev=559384&r1=559383&r2=559384
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenRenderer.java (original)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ScreenRenderer.java Wed Jul 25 03:04:28 2007
@@ -19,6 +19,7 @@
 package org.ofbiz.widget.screen;
 
 import java.io.IOException;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.util.LinkedList;
 import java.util.List;
@@ -36,6 +37,7 @@
 import javolution.util.FastMap;
 import javolution.util.FastSet;
 
+import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.base.util.UtilDateTime;
 import org.ofbiz.base.util.UtilFormatOut;
@@ -50,6 +52,9 @@
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.webapp.control.LoginWorker;
+import org.ofbiz.widget.cache.GenericWidgetOutput;
+import org.ofbiz.widget.cache.ScreenCache;
+import org.ofbiz.widget.cache.WidgetContextCacheKey;
 import org.xml.sax.SAXException;
 
 import freemarker.ext.beans.BeansWrapper;
@@ -101,7 +106,30 @@
      */
     public String render(String resourceName, String screenName) throws GeneralException, IOException, SAXException, ParserConfigurationException {
         ModelScreen modelScreen = ScreenFactory.getScreenFromLocation(resourceName, screenName);
-        modelScreen.renderScreenString(writer, context, screenStringRenderer);
+        if (modelScreen.useCache) {
+            // if in the screen definition use-cache is set to true
+            // then try to get an already built screen output from the cache:
+            // 1) if we find it then we get it and attach it to the passed in writer
+            // 2) if we can't find one, we create a new StringWriter,
+            //    and pass it to the renderScreenString;
+            //    then we wrap its content and put it in the cache;
+            //    and we attach it to the passed in writer
+            WidgetContextCacheKey wcck = new WidgetContextCacheKey(context);
+            String screenCombinedName = resourceName + ":" + screenName;
+            ScreenCache screenCache = new ScreenCache();
+            GenericWidgetOutput gwo = screenCache.get(screenCombinedName, wcck);
+            if (gwo == null) {
+                Writer sw = new StringWriter();
+                modelScreen.renderScreenString(sw, context, screenStringRenderer);
+                gwo = new GenericWidgetOutput(sw.toString());
+                screenCache.put(screenCombinedName, wcck, gwo);
+                writer.write(gwo.toString());
+            } else {
+                writer.write(gwo.toString());
+            }
+        } else {
+            modelScreen.renderScreenString(writer, context, screenStringRenderer);
+        }
         return "";
     }