On Sat, Jan 16, 2016 at 8:09 PM, vinc...@massol.net <vinc...@massol.net> wrote:
> Hi Thomas and all,
>
> On 15 Jan 2016 at 17:53:04, Thomas Mortagne 
> (thomas.morta...@xwiki.com(mailto:thomas.morta...@xwiki.com)) wrote:
>
>> What about making possible to enable/disable as a {{velocity}} macro
>> parameter (disabled by default) ?
>
> It’s a very good idea but it raises questions for migrating existing code to 
> this strategy.

Not sure why you want to migrate existing code. Modifying existing
methods to make them throw exceptions would be an API breakage.

> I think we could do better with the proposal below.
>
> Wanted behavior:
>
> Mandatory:
> * Throw Exceptions from script APIs.
> * Easily handle raised exceptions from Velocity.
> * Early exception-raising if exception is not handled, i.e. if we have 2 
> statements in Velocity and the first one raises an exception we don’t want 
> the second one to execute, unless the velocity code tests for it.
>
> Nice to have:
> * Ability to modify existing script APIs so that they all throw exceptions 
> without having to touch client scripts using those script APIs
>
> Let’s see some examples.
>
> * UC1: Server code is currently catching exception and calling code is in a 
> velocity macro (or in a template)
>
> ** Example of what we have now:
>
> Server:
> public Object something()
> {
>     try {
>         …
>     } catch (…) {
>         return null;
>     }
> }
>
> Calling code:
> {{velocity}}
>   #set ($result = $var.something())
>   #if ($result)
>      ...
> {{/velocity}}
>
> ** Example of what we want to move to:
>
> Server:
> public Object something() throws Exception
> {
>    …
> }
>
> Calling code:
> The same code as now
>
> ** How it could work:
>
> The Exception Catching uberspector catches the exception raised by 
> something(), stores it into a velocity binding and returns null. Thus the 
> calling code doesn’t need to be modified, we’re good.
>
> * UC2: Server code is currently throwing exception and calling code is in a 
> velocity macro (or in a template)
>
> ** Example of what we have now:
>
> Server:
> public Object something() throws Exception
> {
>    ...
> }
>
> Calling code:
> {{velocity}}
>   #set ($result = $var.something())
>   ...
> {{/velocity}}
>
> ** Example of what we want to move to:
>
> Server:
> The same code as now
>
> Calling code:
> The same code as now
>
> ** How it could work:
>
> Currently if the calling code is in a velocity macro then the velocity macro 
> will throw the Exception and the MacroTransformation will catch it and 
> display an error box. If the calling code is in a template then it’s captured 
> with the #try directive and displayed. With the Exception Catching 
> uberspector, it’s caught and doesn’t bubble up.
>
> One solution for this use case is to wrap the captured Exception into an 
> ExceptionResult object such as:
>
> ExceptionResult
> {
>     Exception getException();
>     boolean hasException();
>     boolean isHandled();
> }
>
> And when getException() is called then isHandled() returns true.
>
> Then modify:
> * VelocityMacro so that if an ExceptionResult object exists in the Velocity 
> Context and isHandled() is false then raise the exception. And thus 
> MacroTransformation will also get it and will display an error box as before.
> * Similarly, modify the Template Manager code to also throw an exception if 
> an unhandled exception is found
>
> This let the script writer to decide if he wants to handle the exception or 
> let it bubble up.
>
> * UC3: Several consecutive lines with an exception in calling code
>
> ** Example of what we have now:
>
> Server code:
> Any code
>
> Calling code:
> {{velocity}}
>   #set ($result = $var.something1()) <— throws an Exception
>   #set ($result = $var.something2())
>   ...
> {{/velocity}}
>
> ** Example of what we want to move to:
>
> Server:
> The same code as now
>
> Calling code:
> The same code as now
>
> ** How it could work:
>
> Right now the velocity macro or template will display the first Exception 
> that happens in an error box and the second line (something2()) will not get 
> called. We need to do the same.
>
> The idea is simply to check in the Exception-catching uberspector is an 
> unhandled exception exists and if so, then raise it.
>
> * Conclusion:
>
> I think this strategy would not require to configuration at the level of the 
> velocity macro and that it could work for all cases.
>
> Do you see a case where it would not work?
>
> WDYT of it?
>
> Thanks
> -Vincent
>
> FTR (and as a backup for me ;)) before I start modifying the code here are 
> what I had so far for TryCatchDirective and ExceptionCatchingUberspector:
> * https://gist.github.com/vmassol/ec3c407f264091eeb4b3 and 
> https://gist.github.com/vmassol/83db5df84a4041ec018f
> * https://gist.github.com/vmassol/c887cb92f76afa5fba4d
>
>> On Fri, Jan 15, 2016 at 5:41 PM, vinc...@massol.net wrote:
>> > I need to think more about this because it means velocity macros won’t 
>> > show an error box anymore in case of error….
>> >
>> > Thanks
>> > -Vincent
>> >
>> >
>> > On 15 Jan 2016 at 17:20:21, vinc...@massol.net 
>> > (vinc...@massol.net(mailto:vinc...@massol.net)) wrote:
>> >
>> >> Ok I’ve finished the implementation and will be committing soon.
>> >>
>> >>
>> >> Note that this could change slightly what the user sees.
>> >>
>> >> For example in the past if you had this velocity script:
>> >>
>> >> {{velocity}}
>> >> $someclass.someMethodThrowingException()
>> >> … rest of the script here...
>> >> {{/velocity}}
>> >>
>> >>
>> >> The user would see a stack trace on his screen before upgrading to 8.0 
>> >> and after upgrading to 8.0 he’ll see something different which depends on 
>> >> what the “… rest of the script here…” does.
>> >>
>> >> What I don’t like too much is that this could lead to unwanted side 
>> >> effects. For example, imagine that we have the following:
>> >>
>> >>
>> >> {{velocity}}
>> >> #set ($docReference = 
>> >> $someclass.someMethodComputingTheReferenceButThrowingException())
>> >> …
>> >> $xwiki.getDocument($docReference).save()
>> >> ...
>> >> {{/velocity}}
>> >>
>> >> Then if an exception is raised in 
>> >> someMethodComputingTheReferenceButThrowingException() it used to display 
>> >> an exception but will now do something else. It happens that in this case 
>> >> it’ll report a NPE (AFAICS in the code) but we could imagine it would 
>> >> create a wrong document in the wiki, etc.
>> >>
>> >> Any thoughts about this? Should I still go ahead (I think so).
>> >>
>> >> Thanks
>> >> -Vincent
>> >>
>> >>
>> >> On 15 Jan 2016 at 13:37:39, vinc...@massol.net 
>> >> (vinc...@massol.net(mailto:vinc...@massol.net)) wrote:
>> >>
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> > On 15 Jan 2016 at 13:26:08, vinc...@massol.net 
>> >> > (vinc...@massol.net(mailto:vinc...@massol.net)) wrote:
>> >> >
>> >> > >
>> >> > > On 15 Jan 2016 at 13:23:07, vinc...@massol.net 
>> >> > > (vinc...@massol.net(mailto:vinc...@massol.net)) wrote:
>> >> > >
>> >> > > > Forget what I’ve said regarding the #try directive.
>> >> > > >
>> >> > > > Actually the way to use it is:
>> >> > > >
>> >> > > > #try()
>> >> > > > … wrap some script snipper, one or several calls…
>> >> > > > #end
>> >> > > > .. here only you can access the $exception binding.
>> >> > > >
>> >> > > > Thus:
>> >> > > >
>> >> > > > * Wrapping the whole content to evaluate won’t work
>> >> > > > * The Exception Catching Uberspector is really what we need. It’s 
>> >> > > > more fine-grained than the #try directive (or it’s equivalent if 
>> >> > > > you use #try() for each line of script calling methods).
>> >> > > >
>> >> > > > In addition:
>> >> > > >
>> >> > > > * We provide script APIs in xwiki-commons too so if we want this 
>> >> > > > best practice of throwing exceptions in script APIs, we also need 
>> >> > > > to make this work in xwiki-commons when used outside of XWiki. Thus 
>> >> > > > we need a solution there too.
>> >> > > > ** A) One solution would be to use XWiki’s Context and make the 
>> >> > > > last exception available with $xcontext.lastVelocityException but 
>> >> > > > it’s not very natural, I hope we can find a better solution
>> >> > > > ** B) Another solution is to move VelocityManager to commons in 
>> >> > > > xwiki-commons-velocity, offer a basic impl without skin support and 
>> >> > > > override it in xwiki-platform to add the platform-specific stuff.
>> >> > > >
>> >> > > > I’ll start exploring B). Let me know if you don’t agree or if you 
>> >> > > > have a better idea.
>> >> > >
>> >> > > Actually VelocityManager is already in commons, it’s the impl that is 
>> >> > > in platform. So right now it will work for us; it just won’t work for 
>> >> > > users who use just commons. Like if you use the Rendering in 
>> >> > > standalone mode.
>> >> >
>> >> > Actually forget that, I don’t need to use VelocityManager in practice 
>> >> > (and it would be costly to do so). I just need to use the Execution 
>> >> > component:
>> >> >
>> >> > VelocityContext vcontext =
>> >> > (VelocityContext) this.execution.getContext().getProperty(
>> >> > VelocityExecutionContextInitializer.VELOCITY_CONTEXT_ID);
>> >> >
>> >> >
>> >> > Thanks
>> >> > -Vincent
>> >> >
>> >> > Ps: Sorry for the live design noise...
>> >> >
>> >> > >
>> >> > > Thanks
>> >> > > -Vincent
>> >> > >
>> >> > > > Thanks
>> >> > > > -Vincent
>> >> > > >
>> >> > > >
>> >> > > > On 15 Jan 2016 at 12:15:41, vinc...@massol.net 
>> >> > > > (vinc...@massol.net(mailto:vinc...@massol.net)) wrote:
>> >> > > >
>> >> > > > >
>> >> > > > > [snip]
>> >> > > > >
>> >> > > > > > > > > > >> > Hi devs,
>> >> > > > > > > > > > >> >
>> >> > > > > > > > > > >> > Right now our strategy is for script services and 
>> >> > > > > > > > > > >> > script APIs in general
>> >> > > > > > > > > > >> > to catch exceptions, store them and offer a 
>> >> > > > > > > > > > >> > getLastError() method to get
>> >> > > > > > > > > > >> > them (see
>> >> > > > > > > > > > >> > http://extensions.xwiki.org/xwiki/bin/view/Extension/Script+Module#HBestPractices
>> >> > > > > > > > > > >> > )
>> >> > > > > > > > > > >> >
>> >> > > > > > > > > > >> > However it would be much nicer to:
>> >> > > > > > > > > > >> > * Let our script services generate exceptions
>> >> > > > > > > > > > >> > * Offer a velocity script service to get the last 
>> >> > > > > > > > > > >> > exception raised by a
>> >> > > > > > > > > > >> > java call from velocity
>> >> > > > > > > > > > >> > * Implement this uberspector to catch the 
>> >> > > > > > > > > > >> > exceptions and to set them in
>> >> > > > > > > > > > >> > the execution context
>> >> > > > > > > > > > >> >
>> >> > > > > > > > > > >> > That should be quite easy to implement IMO.
>> >> > > > > > > > > > >> >
>> >> > > > > > > > > > >> > WDYT?
>> >> > > > > > > > > > >> >
>> >> > > > > > > > > > >>
>> >> > > > > > > > > > >> +1, it's a pain to call setLastError() everywhere 
>> >> > > > > > > > > > >> there can be an exception
>> >> > > > > > > > > > >> thrown, and we almost always forget to do it (for 
>> >> > > > > > > > > > >> this reason).
>> >> > > > > > > > > > >>
>> >> > > > > > > > > > >> Note that we also have the #try() directive now.
>> >> > > > > > > > > > >
>> >> > > > > > > > > > > Yes, I should have mentioned that there’s indeed also 
>> >> > > > > > > > > > > this possibility:
>> >> > > > > > > > > > > * Have script API throw Exceptions
>> >> > > > > > > > > > > * Force velocity script users to wrap their code with 
>> >> > > > > > > > > > > the try directive when they need to catch exceptions
>> >> > > > > > > > > > >
>> >> > > > > > > > > > > I still believe that the use of the 
>> >> > > > > > > > > > > Exception-catching uberspector is better.
>> >> > > > > > > > > > >
>> >> > > > > > > > > > > WDYT?
>> >> > > > > > > > > >
>> >> > > > > > > > > > Does it mean you plan to get rid of new #try directive 
>> >> > > > > > > > > > ? Because it
>> >> > > > > > > > > > will be broken with this new uberspector.
>> >> > > > > > > > >
>> >> > > > > > > > > That’s a good point, I had not thought about the 
>> >> > > > > > > > > implementation at this stage.
>> >> > > > > > > > >
>> >> > > > > > > > > I think this could still work. When the #try directive is 
>> >> > > > > > > > > used I’d just have to setup some flag somewhere in 
>> >> > > > > > > > > Velocity and in the uberspector I could check if this 
>> >> > > > > > > > > flag is set and if so then don’t catch the exception.
>> >> > > > > > > >
>> >> > > > > > > >
>> >> > > > > > > > Actually, thinking more, I think you’re right and that the 
>> >> > > > > > > > #try directive plays exactly the same role as an 
>> >> > > > > > > > Exception-catching uberspector and I don’t see the need for 
>> >> > > > > > > > the #try directive if we provide an uberspector.
>> >> > > > > > > >
>> >> > > > > > > > So I’m proposing to deprecate it but still keep it for 
>> >> > > > > > > > backward compatibility for now (probably a full cycle).
>> >> > > > > > > >
>> >> > > > > > > > WDYT?
>> >> > > > > > >
>> >> > > > > > > Note that I’d like to change a bit the proposal and instead 
>> >> > > > > > > of making the exception available from a script service, I’d 
>> >> > > > > > > prefer to make it available as a known velocity binding such 
>> >> > > > > > > as $lastException. There’s no reason to use a script service 
>> >> > > > > > > since that would mean it would work for all scripts and in 
>> >> > > > > > > this case we only want it to work for Velocity.
>> >> > > > > > >
>> >> > > > > > > Since there’s no way to get the Velocity Context from within 
>> >> > > > > > > an uberspector, I’ll get it by using our Component Manager 
>> >> > > > > > > and get the VelocityManager component and call 
>> >> > > > > > > getVelocityContext()… If you know a better way, let me know.
>> >> > > > > >
>> >> > > > > > hmm… this would mean that I’d need to put this new uberspector 
>> >> > > > > > in xwiki-platform since VelocityManager is in platform ATM… 
>> >> > > > > > (@Thomas: our discussion of yesterday ;)).
>> >> > > > >
>> >> > > > >
>> >> > > > > There’s an alternative, which is to modify our implementation of 
>> >> > > > > VelocityEngine.evaluate() and decorate the source with a #try() 
>> >> > > > > directive so that it’s always called (and make sure that calling 
>> >> > > > > it nested won’t affect it for backward compat).
>> >> > > > >
>> >> > > > > This could be simpler to implement and doesn’t force us to move 
>> >> > > > > some velocity code to platform.
>> >> > > > >
>> >> > > > > WDYT?
>> >> > > > >
>> >> > > > > Thanks
>> >> > > > > -Vincent
>> >> > > > >
>> >> > > > > [snip]
> _______________________________________________
> devs mailing list
> devs@xwiki.org
> http://lists.xwiki.org/mailman/listinfo/devs



-- 
Thomas Mortagne
_______________________________________________
devs mailing list
devs@xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs

Reply via email to