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