Re: Deadlock issue

Daniel Dekany <[email protected]>
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Thursday, April 19, 2012, 9:33:14 PM, Jacopo Cappellato wrote:

[snip]
>> I'm also surprised on the kind of wrapper used here. Most frameworks
>> should just use `new DefaultObjectWrapper()`, or `bw = new
>> BeansWrapper(); bw.setSimpleMapWrapper(true);`. However, to be honest,
>> this is messy part of FreeMarker (which wrapper to use and why), so
>> I'm not blaming the OFBiz developers. Do you access map items as
>> `someMap.get(theKey)` in templates under OFBiz?
>
> We do something like this:
>
> ${someMap.theKey}

> Do you think we should use a different object wrapper?

I'm not sure. There are two problems with the current one:

- If you look at what map keys FreeMarker sees (`<#list k as
  someMap?keys>${k} </#list>`), it mixes the actual Map keys with the
  methods of the Map class. This I already find annoying enough to
  stay away. But it's also dangerous, because if you are unlucky and
  have key like "get", then someMap.get and someMap[myDynamicKey]
  where myDynamicKey happens to be "get" will return the get method
  instead of the map item. You can think further what if you have
  a custom Map class and you add methods to it. Using
  someMap.get("theKey") is robust however, but too verbose.

- It doesn't wrap W3C DOM nodes automatically in a way so that the
  user can use FreeMarker's XML processing facility. It also doesn't
  wrap Jython or Rhino JavaScript objects nicely.

What I like to use is:

   BeansWrapper wrapper = new BeansWrapper();
   wrapper.setSimpleMapWrapper(true);

This will not expose the methods of Map-s, only the keys of it. If you
want to get a map item that has a non-string key, you don't have
someMap.get(key) anymore, but you can use someMap(key) instead. If
it's a custom Map class with custom methods that you want to call from
the template, then you are out of luck, however. And in your case
these changes wouldn't be backward-compatible.

As of supporting W3C DOM nodes, Jython and such, it's very easy to
create a custom ObjectWrapper that does that. Just look at
DefaultObjectWrapper.

As of DefaultObjectWrapper, it's burdened with backward-compatibly,
and so wraps collections on an technically awkward way, plus it
doesn't provide any hacks for the non-String key problem. I don't see
a point of using that.

Anyway, the situation with Map-s and the "advertised" object wrappers
is something that had to be hammered out for ages. Sadly nobody has
found the time/incentive for it so far...

> Thanks,
>
> Jacopo
>
>> 
>>>    protected static Configuration defaultOfbizConfig =
>>> makeConfiguration(defaultOfbizWrapper);
>>> 
>>>    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());
>>> 
>>> newConfig.setAutoImports(UtilProperties.getProperties("freemarkerImports"));
>>>        newConfig.setTemplateExceptionHandler(new
>>> FreeMarkerWorker.OFBizTemplateExceptionHandler());
>>>        // Transforms properties file set up as key=transform name, property=transform class name
>>>        ClassLoader loader =
>>> Thread.currentThread().getContextClassLoader();
>>>        Enumeration<URL> resources;
>>>        try {
>>>            resources =
>>> loader.getResources("freemarkerTransforms.properties");
>>>        } catch (IOException e) {
>>>            Debug.logError(e, "Could not load list of
>>> freemarkerTransforms.properties", module);
>>>            throw UtilMisc.initCause(new
>>> InternalError(e.getMessage()), e);
>>>        }
>>>        while (resources.hasMoreElements()) {
>>>            URL propertyURL = resources.nextElement();
>>>            Debug.logInfo("loading properties: " + propertyURL, module);
>>>            Properties props =
>>> UtilProperties.getProperties(propertyURL);
>>>            if (props == null || props.isEmpty()) {
>>>                Debug.logError("Unable to locate properties file " + propertyURL, module);
>>>            } else {
>>>                loadTransforms(loader, props, newConfig);
>>>            }
>>>        }
>>> 
>>>        return newConfig;
>>>    }
>>> 
>>> 
>>> and in the same class we use this static method to render the template:
>>> 
>>>    public static Environment renderTemplate(Template template,
>>> Map<String, Object> context, Appendable outWriter) throws TemplateException, IOException {
>>>        // make sure there is no "null" string in there as FreeMarker will try to use it
>>>        context.remove("null");
>>>        // Since the template cache keeps a single instance of a
>>> Template that is shared among users,
>>>        // and since that Template instance is immutable, we need
>>> to create an Environment instance and
>>>        // use it to process the template with the user's settings.
>>>        Environment env =
>>> template.createProcessingEnvironment(context, (Writer) outWriter); 
>>> // NOTE: this is where the process blocks in a deadlock
>>>        applyUserSettings(env, context);
>>>        env.process();   // NOTE: this is where the process blocks in a deadlock
>>>        return env;
>>>    }
>>> 
>>> Jacopo
>> 
>> -- 
>> Best regards,
>> Daniel Dekany

-- 
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.