You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by "Henning P . Schmiedehausen" <hp...@intermeta.de> on 2001/03/22 13:49:25 UTC

How to use velocity in a webapp?

Hi,

I'm currently building a webapp which should be deployed as a WAR
archive onto a variety of servlet containers. So I can not make any
assumptions about the pathes where this application will be installed
asides from pathes relative to the root of my app (I use Tomcat 3.2.1
for development).

I'm currently using the Velocity 1.0b1 template engine for my HTML
views.

So in the servlets, I do basically this:

public class TestServlet extends VelocityServlet
{
  public Template handleRequest(Context ctx)
  {
    Template templ = null;
    try {
      templ = getTemplate("test.vm");
    } catch(Exception e) {}

    return templ;
  }
}

and let velocity worry about the pathes where "test.vm" should be located.

So I set up a delopyment descriptor:

<servlet>
 <servlet-name>Test</servlet-name>
 <servlet-class>TestServlet</servlet-class>
 <init-param>
  <param-name>properties</param-name>
  <param-value>velocity.properties</param-value>
 </init-param>
</servlet>

and in velocity.properties (in the root of my app)

--- cut ---
runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem
runtime.log = velocity.log


resource.loader.public.name = File
resource.loader.description = Velocity File Resource Loader
resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
resource.loader.resource.path = templates
--- cut ---


and I ended up with these relative pathes referenced from the server
root (TOMCAT_HOME) and not from my web application root. The logfile
ends up in $TOMCAT_HOME and the templates are read from
$TOMCAT_HOME/templates and not from my webapp.

I am pretty sure that I am missing just a small piece of information
here. But I'm not able to figure it out on my own. :-(

Do I have to get the pathes on my own from the servlet runner and
override them before invoking velocity (just as turbine does and is
described in the org.apache.velocity.runtime.Runtime documentation?)

Or is there a simpler way to let velocity cooperate with the servlet
runner? It reads the properties file correctly from the webapp path.

Please answer directly as I am not (yet) am member of this mailing list.

	Thank you
		Henning


-- 
Dipl.-Inf. (Univ.) Henning P. Schmiedehausen       -- Geschaeftsfuehrer
INTERMETA - Gesellschaft fuer Mehrwertdienste mbH     hps@intermeta.de

Am Schwabachgrund 22  Fon.: 09131 / 50654-0   info@intermeta.de
D-91054 Buckenhof     Fax.: 09131 / 50654-20   

Re: How to use velocity in a webapp?

Posted by "Henning P . Schmiedehausen" <hp...@intermeta.de>.
Hi,

thanks for the info. After I wrote the mail, I basically came up with

protected Properties loadConfiguration(ServletConfig config) 
  throws IOException, FileNotFoundException
{
  Properties props = super.loadConfiguration(config);
  
  props.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH,
                    getServletContext().getRealPath(props.getProperty(Runtime.FILE_RESOURCE_LOADER_PATH)));
  
  props.setProperty(Runtime.RUNTIME_LOG,
                    getServletContext().getRealPath(props.getProperty(Runtime.RUNTIME_LOG)));
  
  return props;
}

and then simply stole the "load servlet on startup" idea from the
mailing list archive. =:-)

The "jar the templates" idea is cool and I will probably embrace it
for the deployment.

Thanks for your advice.

> Join the list!

Will do.

	Regards
		Henning


-- 
Dipl.-Inf. (Univ.) Henning P. Schmiedehausen       -- Geschaeftsfuehrer
INTERMETA - Gesellschaft fuer Mehrwertdienste mbH     hps@intermeta.de

Am Schwabachgrund 22  Fon.: 09131 / 50654-0   info@intermeta.de
D-91054 Buckenhof     Fax.: 09131 / 50654-20   

Re: VelociMacros and varargs

Posted by Jon Stevens <jo...@latchkey.com>.
on 3/27/01 9:06 AM, "Jon Stevens" <jo...@latchkey.com> wrote:

> You are doing things badly IMHO by not allowing people to compile the code
> that they are editing without having to first run it through a
> pre-processor. Another reason PP is bad is because it totally breaks the
> ability of javac to do conditional compilation. ALL your code will get
> re-compiled every time you run javac. That is bad.
> 
> -jon

I said this incorrectly:

What I meant to say is that in order to change the I18N or Logging stuff you
need to re-compile your code. That is bad IMHO.

-jon


Re: VelociMacros and varargs

Posted by Jon Stevens <jo...@latchkey.com>.
on 3/27/01 9:48 AM, "Kyle F. Downey" <kd...@amberarcher.com> wrote:

> Actually, Vpp subclasses Copy. It re-uses most of those facilities. I
> did consider using <replace>, as you said, but I needed something a little
> more robust in the parsing department to handle the logging and I18N
> macros. You're right it's sufficient for import changing, and a
> pre-processor would be dangerous and overkill in that case. Thanks.
> 
> --kd

Java Provides excellent facilities for I18N (ResourceBundles) and Logging
(including compiling out the logging statements with the use of a static
boolean) without having to use preprocessing.

You are doing things badly IMHO by not allowing people to compile the code
that they are editing without having to first run it through a
pre-processor. Another reason PP is bad is because it totally breaks the
ability of javac to do conditional compilation. ALL your code will get
re-compiled every time you run javac. That is bad.

-jon


Re: VelociMacros and varargs

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
> on 3/27/01 8:18 AM, "Kyle F. Downey" <kd...@amberarcher.com> wrote:
>
> > There's no way to change an import package with any fancy
> > Java tricks short of pre-processing, just as there's also no way to do
> > things that require knowing the calling source file name and line (short
> > of a hack I wrote that parses a StackTrace!).
>
> BTW, I just use Ant for this...when you do the compile, first <copy> the
> source code into a different directory...then use the <replace> tag to
> search/replace for specific import strings depending on what JDK version you
> are using or target version.

Actually, Vpp subclasses Copy. It re-uses most of those facilities. I
did consider using <replace>, as you said, but I needed something a little
more robust in the parsing department to handle the logging and I18N
macros. You're right it's sufficient for import changing, and a
pre-processor would be dangerous and overkill in that case. Thanks.

--kd


Re: VelociMacros and varargs

Posted by Jon Stevens <jo...@latchkey.com>.
on 3/27/01 8:18 AM, "Kyle F. Downey" <kd...@amberarcher.com> wrote:

> There's no way to change an import package with any fancy
> Java tricks short of pre-processing, just as there's also no way to do
> things that require knowing the calling source file name and line (short
> of a hack I wrote that parses a StackTrace!).

BTW, I just use Ant for this...when you do the compile, first <copy> the
source code into a different directory...then use the <replace> tag to
search/replace for specific import strings depending on what JDK version you
are using or target version.

This way, your code still compiles on the JDK version of your choosing
without having to run it through a pre-processor first.

pre-processing code is still bad IMHO. especially since your only real
complaint has been about the issue that I just solved for you. :-)

p.s. I did that above compatibility system for WebMacro, but Justin decided
to throw all of my work into the trash because he couldn't get it to work on
his particular buggy Linux JVM at the time (yet it worked on every other
JVM). Totally pissed me off and of course the rest of the WM community
suffered as a result...absolutely stupid.

-jon


Re: VelociMacros and varargs

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
>
> Well, remember, it's not supposed to be a function or method :)
> 'Subroutine' is a verboten word. (We had some interesting and 'lively'
> debates when VMs were first proposed... )
>

Burn him! Burn him! He's a witch! ;-) I know what you mean about the
pre-processor heresy. It's kept me from pursuing this for a long time;
practically every book on intro Java sings the praises of the lack of a
pre-processor for the language, and it's become received wisdom in the
Java developer community.

However, the thing #ifdef and friends are so useful for (accounting for
platform differences) IS becoming an issue for Java because of Sun's
tendency to add cool new API classes to the java.* space rather than
javax.*, even when they can still work under Java 1.1 (I'll never
understand why they didn't do the same thing with Collections that they
did with Swing). There's no way to change an import package with any fancy
Java tricks short of pre-processing, just as there's also no way to do
things that require knowing the calling source file name and line (short
of a hack I wrote that parses a StackTrace!).

Since IBM's Java port of cpp isn't free or supported, jpp and others are
outdated and it's silly to write YAML (yet another macro language),
Velocity seems like a good choice for this.

> Seriously - I understand your need.  It's just that I'm wired right now
> for conservative VTL designed for  the designer, but I'm sure others
> will have different opinions.   I'll certainly think about this...
>

Totally understood. BTW, I figured out how to get what I want with the
existing VM set-up. It's still pretty clean on the client side at the
expense of the macro definition being ugly. As you suggested, just pass a
list. It works.

--kd



Re: VelociMacros and varargs

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
"Kyle F. Downey" wrote:
> 
> > > #macro (I18N $msgid)
> > >    // some Java code for getting int'lized text that uses $msgid to look
> > >    // up a string resource in a Properties file
> > > #end
> > >
> > > #macro (I18N_VA $msgid $argList)
> > >   // some code that merges the list argument into an
> > >   // Object[] array to use the java.text tools to
> > >   // replace parameters in the strings from the
> > >   // properties code
> > > #end
> >
> > Why not just declare one and check for nulls?
> >
> 
> Because I'd like to keep the macro call as simple as possible. If it's
> not going to happen, then that is an option, though.

Right. ok.

> 
> > Or how about a hash of name value pairs?
> >
> 
> Even worse.

True.  That also makes it not much better than the old #parse() 'hail
mary'....
 
> > > behaving like other scripting languages; disadvantage of likely being
> > > the most complex to implement, cutting across large parts of code)
> >
> > Yuk.  We are starting to move quickly away from VTL as simple and small.
> >
> 
> Agreed.
> 
> > > * have #macro ALWAYS take a list type rather than having it declare
> > > named parameters (don't like this option at all because it breaks
> > > code and makes macros less self-documenting, but it has performance and
> > > simplicity benefits over the first verison)
> >
> > -1
> >
> 
> Agreed.
> 
> > > # create a #va_macro primitive that has the above properties instead
> > > (advantage of not breaking existing code and isolating the special
> > > case; disadvantage of probably creating duplicate code inside the
> > > interpreter and bloating the language)
> >
> > It's not an interpreter issue.  This might be straightforward, but you
> > still have the problem of accessing the args in the VM body.
> >
> 
> That's fine. With 70,000 lines of Java code and 50 lines of macros, I'd
> much rather jump through a hoop or two in a macro than make calling the
> macro call any more verbose than necessary.
> 
> > > * have the interpreter pass a null value for any "missing" trailing
> > > arguments so the macro can figure out its own defaults
> >
> > This sounds like it could cause chaos for normal designer users.
> >
> 
> Not sure I understand this objection. Are you saying it's confusion to
> have the option of both
> 
> #LOG("foo")
> 
> and
> 
> #LOG("foo", "bar")
> 
> I agree that's more familiar to programmers, but it has the advantage of
> being there only if you need it. If you are writing macros for designers,
> they probably wouldn't need to know about this facility or use it.

Agreed - I recognize what you are saying.  I do feel very 'yecchy' about
this idea, though.  It's one of those deals where we would be pushing
Velocity pretty far out of original intent.  That doesn't mean it can't
and shouldn't change as a rule, but as one of the tenets is to keep
things simple, especially on the designer side, I am very conservative
and cautious about something like this.

> > > * tell Kyle to go hang himself ;-)
> >
> > Starting to think seriously about the last bit :)
> >
> 
> ...huntin' fer a sufficient length 'a rope...

I was just kidding, of course :) 

> > > I prefer the penultimate option myself, and am willing to give it a shot.
> > > What do you folks think?
> >
> > There is another option - what about just redefining the VMs as you need
> > to?  I.e. since this is a standalone program, why not establish the VMs
> > at runtime?
> >
> 
> It's not a standalone program. It's an ant task, as I said in the original
> message.

Right - sorry.  I guess I was thinking 'servlet based' versus
'otherwise', but that isn't clean when you consider that ant could be
running other velocity-using tasks in the same VM.

>  Also, I'm not sure I understand what you mean about redefining as
> needed. They're all loaded up at start-up, and I don't want the Java code
> to include any #macro definitions. Trying to minimize the horror that is
> a code pre-processor. :-)

I will note that I am very used to having a pre-processor as well,
coming from a C/C++ background, but isn't the notion of a pre-processor
sort of the "Burn the witch!" kind of heresy? :)

What I meant is that you have great flexibility in adding macros at
runtime.  You can use the Velocity class to evaluate strings and
streams, and those strings and streams can be nothing more than macro
definitions. 

Now, of course I don't know if possible, but if you could know which VMs
you would need, you could simply 'register' them just before
pre-processing your code by using the Velocity class's evaluate method. 
You could even contruct the macro sets dynamically.

But I have no clue if that's even possible for your app.

> 
> Even in a single source unit a program might have a mix of different
> argument sets for calling a particular macro, so if I understand what you
> mean about redefining, it's not a solution.

Ok.
 
> > Do you know while processing which set of VMs you would need?
> >
> 
> Yes. It's just the set that are in the "profile" VM file that defines
> available macros for the pre-processing run.

So it's an 'all' not 'this set'... ?

> > > --kd
> > >
> > > p.s. I can donate Vpp to the project as well if you don't feel it overlaps
> > > too much with Texen. It's very simple thanks to Ant and Velocity. The only
> > > problem with using it on Java code is that you hve to escape out the #
> > > signs from Javadoc cross-references and any dollar-sign references that
> > > break the parser.
> >
> > Doesn't this seem  more like an Ant task?
> >
> 
> Like I said, it is an ant task. That's why I said I was able to use the
> facilities of Ant from within it. I just put this before my <javac>:
> 
>     <vpp todir="${build.gensrc}" profileDir="${profile.dir}"
>          profile="debug.vm">
>       <fileset dir="${src.dir}">
>         <include name="**/*.java"/>
>       </fileset>
>     </vpp>
> 
> and I'm able to use the FileSet scanner to find all the changed Java files
> and then pass them to be pre-processed by Velocity. By changing from
> debug.vm -> production.vm (which could be an Ant property set on the
> command line too) all the #DEBUG and #TRACE macros get commented out.
> Very convenient.

This is cool.  
 
> Thanks. I guess I'll have it pass null from the Java code for
> "missing" args, or maybe use a list/hash. That's not very clean, IMHO,
> because it doesn't look like a function/method call, but I can
> certainly see your objections to introducing this facility.

Well, remember, it's not supposed to be a function or method :) 
'Subroutine' is a verboten word. (We had some interesting and 'lively'
debates when VMs were first proposed... )

Seriously - I understand your need.  It's just that I'm wired right now
for conservative VTL designed for  the designer, but I'm sure others
will have different opinions.   I'll certainly think about this...

geir

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: VelociMacros and varargs

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
> > #macro (I18N $msgid)
> >    // some Java code for getting int'lized text that uses $msgid to look
> >    // up a string resource in a Properties file
> > #end
> >
> > #macro (I18N_VA $msgid $argList)
> >   // some code that merges the list argument into an
> >   // Object[] array to use the java.text tools to
> >   // replace parameters in the strings from the
> >   // properties code
> > #end
>
> Why not just declare one and check for nulls?
>

Because I'd like to keep the macro call as simple as possible. If it's
not going to happen, then that is an option, though.

> Or how about a hash of name value pairs?
>

Even worse.

> > behaving like other scripting languages; disadvantage of likely being
> > the most complex to implement, cutting across large parts of code)
>
> Yuk.  We are starting to move quickly away from VTL as simple and small.
>

Agreed.

> > * have #macro ALWAYS take a list type rather than having it declare
> > named parameters (don't like this option at all because it breaks
> > code and makes macros less self-documenting, but it has performance and
> > simplicity benefits over the first verison)
>
> -1
>

Agreed.

> > # create a #va_macro primitive that has the above properties instead
> > (advantage of not breaking existing code and isolating the special
> > case; disadvantage of probably creating duplicate code inside the
> > interpreter and bloating the language)
>
> It's not an interpreter issue.  This might be straightforward, but you
> still have the problem of accessing the args in the VM body.
>

That's fine. With 70,000 lines of Java code and 50 lines of macros, I'd
much rather jump through a hoop or two in a macro than make calling the
macro call any more verbose than necessary.

> > * have the interpreter pass a null value for any "missing" trailing
> > arguments so the macro can figure out its own defaults
>
> This sounds like it could cause chaos for normal designer users.
>

Not sure I understand this objection. Are you saying it's confusion to
have the option of both

#LOG("foo")

and

#LOG("foo", "bar")

I agree that's more familiar to programmers, but it has the advantage of
being there only if you need it. If you are writing macros for designers,
they probably wouldn't need to know about this facility or use it.

> > * tell Kyle to go hang himself ;-)
>
> Starting to think seriously about the last bit :)
>

...huntin' fer a sufficient length 'a rope...

> > I prefer the penultimate option myself, and am willing to give it a shot.
> > What do you folks think?
>
> There is another option - what about just redefining the VMs as you need
> to?  I.e. since this is a standalone program, why not establish the VMs
> at runtime?
>

It's not a standalone program. It's an ant task, as I said in the original
message. Also, I'm not sure I understand what you mean about redefining as
needed. They're all loaded up at start-up, and I don't want the Java code
to include any #macro definitions. Trying to minimize the horror that is
a code pre-processor. :-)

Even in a single source unit a program might have a mix of different
argument sets for calling a particular macro, so if I understand what you
mean about redefining, it's not a solution.

> Do you know while processing which set of VMs you would need?
>

Yes. It's just the set that are in the "profile" VM file that defines
available macros for the pre-processing run.

> > --kd
> >
> > p.s. I can donate Vpp to the project as well if you don't feel it overlaps
> > too much with Texen. It's very simple thanks to Ant and Velocity. The only
> > problem with using it on Java code is that you hve to escape out the #
> > signs from Javadoc cross-references and any dollar-sign references that
> > break the parser.
>
> Doesn't this seem  more like an Ant task?
>

Like I said, it is an ant task. That's why I said I was able to use the
facilities of Ant from within it. I just put this before my <javac>:

    <vpp todir="${build.gensrc}" profileDir="${profile.dir}"
         profile="debug.vm">
      <fileset dir="${src.dir}">
        <include name="**/*.java"/>
      </fileset>
    </vpp>

and I'm able to use the FileSet scanner to find all the changed Java files
and then pass them to be pre-processed by Velocity. By changing from
debug.vm -> production.vm (which could be an Ant property set on the
command line too) all the #DEBUG and #TRACE macros get commented out.
Very convenient.

Thanks. I guess I'll have it pass null from the Java code for
"missing" args, or maybe use a list/hash. That's not very clean, IMHO,
because it doesn't look like a function/method call, but I can
certainly see your objections to introducing this facility.

--kd


Re: VelociMacros and varargs

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
"Kyle F. Downey" wrote:
> 
> The manual says that you must call a macro with the declared set of
> args. How solid is this limit? At the parser level? At the interpreter
> level? At a higher level? Any pointers to the corresponding place in the
> code where this limit manifests? Also, how important is this limit to the
> design of the language and software--i.e., if I were to write a patch that
> removed it, would it be accepted (assuming it's decent code, works, etc.)?

It's a code-level limit, and would't be that hard to work around,  I
think it would take me about 10 minutes...

but this seems like trouble in a simple template language.  I am not
sure we'd really want to go there.

> I've written a tool (Vpp) that integrates with Ant to provide a
> pre-processor for Java. Like Texen, it loads an additional template
> that contains #set's and #macro definitions. Unlike Texen, it doesn't
> have that template control the code generation process (so Ant can
> do things like use its internal facilities to determine which source
> files need (re)pre-processing).
> 
> Velocity is ideal for things like
> 
> #if $java2
>   import java.util.Map;
> #else
>   import com.sun.java.util.collections.Map;
> 
> and cross-cutting code like logging and internationalization that
> often require the name of the source class. (Vpp passes in
> $callerClassName--any way to pass in line number too?)
> 
> It's working to our needs for now, but I've had to do the following:
> 
> #macro (I18N $msgid)
>    // some Java code for getting int'lized text that uses $msgid to look
>    // up a string resource in a Properties file
> #end
> 
> #macro (I18N_VA $msgid $argList)
>   // some code that merges the list argument into an
>   // Object[] array to use the java.text tools to
>   // replace parameters in the strings from the
>   // properties code
> #end

Why not just declare one and check for nulls?

Or how about a hash of name value pairs?

> Essentially, I'm simulating varargs using the Velocity list primitive.
> Ugly, but not too bad. But now I want to be able to pass an additional,
> optional argument (the Locale). Using my current method, that means two
> more versions of the I18N macro. That's starting to get ugly. Worse, I
> have eight other macros that delegate to these macros, so their arg lists
> must be replicated as well--yielding three cut-and-paste variants apiece
> on nine different base macros! One begins to understand how OO started...
> 
> There seem to be several ways to approach this:
> 
> * have a smarter interpreter that matches # of arguments passed
> to the macro with one of several macros with the same name (advantage of
> behaving like other scripting languages; disadvantage of likely being
> the most complex to implement, cutting across large parts of code)

Yuk.  We are starting to move quickly away from VTL as simple and small.

> * have #macro ALWAYS take a list type rather than having it declare
> named parameters (don't like this option at all because it breaks
> code and makes macros less self-documenting, but it has performance and
> simplicity benefits over the first verison)

-1

> # create a #va_macro primitive that has the above properties instead
> (advantage of not breaking existing code and isolating the special
> case; disadvantage of probably creating duplicate code inside the
> interpreter and bloating the language)

It's not an interpreter issue.  This might be straightforward, but you
still have the problem of accessing the args in the VM body.

Any reason a hash won't work?

> * have the interpreter pass a null value for any "missing" trailing
> arguments so the macro can figure out its own defaults

This sounds like it could cause chaos for normal designer users.

> * tell Kyle to go hang himself ;-)

Starting to think seriously about the last bit :)
 
> I prefer the penultimate option myself, and am willing to give it a shot.
> What do you folks think?

There is another option - what about just redefining the VMs as you need
to?  I.e. since this is a standalone program, why not establish the VMs
at runtime? 

Do you know while processing which set of VMs you would need?  I

> --kd
> 
> p.s. I can donate Vpp to the project as well if you don't feel it overlaps
> too much with Texen. It's very simple thanks to Ant and Velocity. The only
> problem with using it on Java code is that you hve to escape out the #
> signs from Javadoc cross-references and any dollar-sign references that
> break the parser.

Doesn't this seem  more like an Ant task?

geir

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: VelociMacros and varargs

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
>
> Velocity is ideal for things like
>
> #if $java2
>   import java.util.Map;
> #else
>   import com.sun.java.util.collections.Map;
>

*sheepish*

Whoops! That wouldn't be ideal because it would break the parser. ;-)
What I thought, not what I typed:

#if ($java2)
  import java.util.Map;
#else
  import com.sun.java.util.collections.Map
#end

--kd



VelociMacros and varargs

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
The manual says that you must call a macro with the declared set of
args. How solid is this limit? At the parser level? At the interpreter
level? At a higher level? Any pointers to the corresponding place in the
code where this limit manifests? Also, how important is this limit to the
design of the language and software--i.e., if I were to write a patch that
removed it, would it be accepted (assuming it's decent code, works, etc.)?

I've written a tool (Vpp) that integrates with Ant to provide a
pre-processor for Java. Like Texen, it loads an additional template
that contains #set's and #macro definitions. Unlike Texen, it doesn't
have that template control the code generation process (so Ant can
do things like use its internal facilities to determine which source
files need (re)pre-processing).

Velocity is ideal for things like

#if $java2
  import java.util.Map;
#else
  import com.sun.java.util.collections.Map;

and cross-cutting code like logging and internationalization that
often require the name of the source class. (Vpp passes in
$callerClassName--any way to pass in line number too?)

It's working to our needs for now, but I've had to do the following:

#macro (I18N $msgid)
   // some Java code for getting int'lized text that uses $msgid to look
   // up a string resource in a Properties file
#end

#macro (I18N_VA $msgid $argList)
  // some code that merges the list argument into an
  // Object[] array to use the java.text tools to
  // replace parameters in the strings from the
  // properties code
#end

Essentially, I'm simulating varargs using the Velocity list primitive.
Ugly, but not too bad. But now I want to be able to pass an additional,
optional argument (the Locale). Using my current method, that means two
more versions of the I18N macro. That's starting to get ugly. Worse, I
have eight other macros that delegate to these macros, so their arg lists
must be replicated as well--yielding three cut-and-paste variants apiece
on nine different base macros! One begins to understand how OO started...

There seem to be several ways to approach this:

* have a smarter interpreter that matches # of arguments passed
to the macro with one of several macros with the same name (advantage of
behaving like other scripting languages; disadvantage of likely being
the most complex to implement, cutting across large parts of code)
* have #macro ALWAYS take a list type rather than having it declare
named parameters (don't like this option at all because it breaks
code and makes macros less self-documenting, but it has performance and
simplicity benefits over the first verison)
# create a #va_macro primitive that has the above properties instead
(advantage of not breaking existing code and isolating the special
case; disadvantage of probably creating duplicate code inside the
interpreter and bloating the language)
* have the interpreter pass a null value for any "missing" trailing
arguments so the macro can figure out its own defaults
* tell Kyle to go hang himself ;-)

I prefer the penultimate option myself, and am willing to give it a shot.
What do you folks think?

--kd

p.s. I can donate Vpp to the project as well if you don't feel it overlaps
too much with Texen. It's very simple thanks to Ant and Velocity. The only
problem with using it on Java code is that you hve to escape out the #
signs from Javadoc cross-references and any dollar-sign references that
break the parser.



Re: API nitpick - no VelocityException

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Davide Mora wrote:
> 
> About exceptions, is possible add also the name of the
> template file when an exception is thrown?
> If the template is complex, with nested #parse() can
> be difficult find the "line:xx".

Ja.  It will be in the log though.

> Davide
> 
> --- "Geir Magnusson Jr." <ge...@optonline.net> wrote:
> > Magnus ?or Torfason wrote:
> > >
> > > >
> > > > "Kyle F. Downey" wrote:
> > > > >
> > > > > Is there a reason none of the
> > org.apache.velocity.exception classes
> > > > > inherit from a common base class? Most systems
> > I work with do this so
> > > > > you can catch any error related to that
> > subsystem with one block
> > > > > without resorting to catching all Exceptions.
> > > >
> > > > Cuz I didn't think of it :)
> > > >
> > > > Good idea.  Will put in there tomorrow post
> > release of release candidate
> > > > 2 / beta 2.
> > >
> > > OK, Geir, now I understand your concerns about
> > velocity just throwing
> > > Exceptions of the correct type, some time ago.  I
> > thought there was a
> > > VelocityException that everything inherited from.
> >
> > Now there is :)  I put in Kyle's suggestion last
> > night.  There is a
> > VelocityException that the other three inherit from,
> > so you can just
> > catch( VelocityException )
> >
> > >
> > > You might want to consider copying Rafal's
> > TurbineException.  It allows
> > > you to encapsulate other exceptions inside the new
> > one.  You get the
> > > full stack trace for all the exceptions, neatly
> > concatenated, and
> > > no duplicate text. It is totally awesome.
> >
> > Will look.  The only place where we currently wrap
> > other exceptions is
> > the MethodInvocationException, which is thrown by
> > Velocity when a method
> > invoked by a reference in a template throws an
> > exception.  It does wrap
> > the thrown exception so you can dig it out at app
> > level, and contains
> > the method and reference which 'caused' the problem.
> >  I will look at
> > TurbineException to see if there is anything else to
> > steal.
> >
> > thx
> >
> > geir
> >
> > --
> > Geir Magnusson Jr.
> > geirm@optonline.net
> > Developing for the web?  See
> http://jakarta.apache.org/velocity/
> 
> __________________________________________________
> Do You Yahoo!?
> Get email at your own domain with Yahoo! Mail.
> http://personal.mail.yahoo.com/?.refer=text

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: API nitpick - no VelocityException

Posted by Davide Mora <d_...@yahoo.com>.
About exceptions, is possible add also the name of the
template file when an exception is thrown?
If the template is complex, with nested #parse() can
be difficult find the "line:xx".
Davide

--- "Geir Magnusson Jr." <ge...@optonline.net> wrote:
> Magnus ?or Torfason wrote:
> > 
> > >
> > > "Kyle F. Downey" wrote:
> > > >
> > > > Is there a reason none of the
> org.apache.velocity.exception classes
> > > > inherit from a common base class? Most systems
> I work with do this so
> > > > you can catch any error related to that
> subsystem with one block
> > > > without resorting to catching all Exceptions.
> > >
> > > Cuz I didn't think of it :)
> > >
> > > Good idea.  Will put in there tomorrow post
> release of release candidate
> > > 2 / beta 2.
> > 
> > OK, Geir, now I understand your concerns about
> velocity just throwing
> > Exceptions of the correct type, some time ago.  I
> thought there was a
> > VelocityException that everything inherited from.
> 
> Now there is :)  I put in Kyle's suggestion last
> night.  There is a
> VelocityException that the other three inherit from,
> so you can just
> catch( VelocityException )
> 
> > 
> > You might want to consider copying Rafal's
> TurbineException.  It allows
> > you to encapsulate other exceptions inside the new
> one.  You get the
> > full stack trace for all the exceptions, neatly
> concatenated, and
> > no duplicate text. It is totally awesome.
> 
> Will look.  The only place where we currently wrap
> other exceptions is
> the MethodInvocationException, which is thrown by
> Velocity when a method
> invoked by a reference in a template throws an
> exception.  It does wrap
> the thrown exception so you can dig it out at app
> level, and contains
> the method and reference which 'caused' the problem.
>  I will look at
> TurbineException to see if there is anything else to
> steal.
> 
> thx
> 
> geir
> 
> -- 
> Geir Magnusson Jr.                              
> geirm@optonline.net
> Developing for the web?  See
http://jakarta.apache.org/velocity/


__________________________________________________
Do You Yahoo!?
Get email at your own domain with Yahoo! Mail. 
http://personal.mail.yahoo.com/?.refer=text

Re: API nitpick - no VelocityException

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Magnus ?or Torfason wrote:
> 
> >
> > "Kyle F. Downey" wrote:
> > >
> > > Is there a reason none of the org.apache.velocity.exception classes
> > > inherit from a common base class? Most systems I work with do this so
> > > you can catch any error related to that subsystem with one block
> > > without resorting to catching all Exceptions.
> >
> > Cuz I didn't think of it :)
> >
> > Good idea.  Will put in there tomorrow post release of release candidate
> > 2 / beta 2.
> 
> OK, Geir, now I understand your concerns about velocity just throwing
> Exceptions of the correct type, some time ago.  I thought there was a
> VelocityException that everything inherited from.

Now there is :)  I put in Kyle's suggestion last night.  There is a
VelocityException that the other three inherit from, so you can just
catch( VelocityException )

> 
> You might want to consider copying Rafal's TurbineException.  It allows
> you to encapsulate other exceptions inside the new one.  You get the
> full stack trace for all the exceptions, neatly concatenated, and
> no duplicate text. It is totally awesome.

Will look.  The only place where we currently wrap other exceptions is
the MethodInvocationException, which is thrown by Velocity when a method
invoked by a reference in a template throws an exception.  It does wrap
the thrown exception so you can dig it out at app level, and contains
the method and reference which 'caused' the problem.  I will look at
TurbineException to see if there is anything else to steal.

thx

geir

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: API nitpick - no VelocityException

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Commons! :)


Rafal Krzewski wrote:
> 
> Magnus ?or Torfason wrote:
> 
> > You might want to consider copying Rafal's TurbineException.  It allows
> > you to encapsulate other exceptions inside the new one.  You get the
> > full stack trace for all the exceptions, neatly concatenated, and
> > no duplicate text. It is totally awesome.
> 
> Thanks :-). Actually I came up with another solution after diging
> through
> Catalina code. Is uses reflection to look up the root cause exceptions.
> The methods that are checked are getRootCause, getException and
> getNextException.
> The Stacktrace class is able to render a stack trace of a sequence of
> arbitrary Throwables, provided that each of them has one of the methods
> mentioned above available for determining the underlying Throwable.
> 
> You can find the class source attached to this message. Feel free to
> use it in Velocity if you like it. It would be cool to have it in some
> common package, along with Configuration class that both Turbine and
> Velocity could use.
> 
> Rafal
> 
> --
> Rafal Krzewski
> Senior Internet Developer
> mailto:Rafal.Krzewski@e-point.pl
> +48 22 8534830 http://e-point.pl
> 
>   ------------------------------------------------------------------------
> import java.io.*;
> import java.util.*;
> import java.lang.reflect.*;
> 
> /**
>  * A stack trace, including 'root cause' <code>Throwables</code> if known.
>  *
>  * You can wrap <code>Throwables</code> into instances of this class, or use
>  * {@link #capture(Throwable)} class method to acquire the stack traces
>  * as strings.
>  *
>  * @author <a href="mailto:rafal@apache.org">Rafal Krzewski</a>
>  */
> public class Stacktrace
>     implements Serializable
> {
>     String value;
> 
>     /**
>      * Constructs a stack trace of the specified <code>Throwable</code>.
>      *
>      * If the 'root cause' <code>Throwable</code> can be determined,
>      * it will be included in the stacktrace as well.
>      *
>      * @param t a <code>Throwable</code>.
>      */
>     public Stacktrace(Throwable t)
>     {
>         value = capture(t);
>     }
> 
>     /**
>      * Returns the contents of the stack trace as a <code>String</code>.
>      *
>      * @returns the contents of the stack trace as a <code>String</code>.
>      */
>     public String toString()
>     {
>         return value;
>     }
> 
>     /**
>      * Captures all stack traces in a multi level <code>Throwable</code> sequence.
>      *
>      * @param t a <code>Throwable</code>.
>      * @return a <code>String</code> containing a formated stack trace.
>      */
>     public static String capture(Throwable t)
>     {
>         LinkedList traces = captureTraces(t);
>         StringWriter out = new StringWriter();
>         print(traces, new PrintWriter(out), 0);
>         return out.getBuffer().toString();
>     }
> 
>     // ------------------------------------------------------------------------
> 
>     /**
>      * Prints a single level of a stack trace into the specified <code>
>      * PrintWriter</code>.
>      *
>      * This method prints out the least nested stack trace in the sequence
>      * after calling itself recursively to print out the more nested stactraces.
>      *
>      * @param traces a <code>LinkedList</code> of stack traces
>      * @param writer a <code>PrintWriter</code>
>      * @param skip the number of stack frames to skip in this level.
>      */
>     private final static void print(LinkedList traces, PrintWriter out, int skip)
>     {
>         List frames = (List)traces.removeFirst();
>         if(traces.size() > 0) {
>             print(traces, out, frames.size() - 2);
>             out.print("rethrown as ");
>         }
>         for(int i=0; i<frames.size() - skip; i++) {
>             out.println((String)frames.get(i));
>         }
>     }
> 
>     /**
>      * Captures all stack traces in a multi level <code>Throwable</code>
>      * sequence.
>      *
>      * All <code>Throwables</code> in the sequence are probed for the presence
>      * of a 'root cause' <code>Throwable</code> by reflecting them and searching
>      * for <code>getRootCause</code>, <code>getException</code> and <code>
>      * getNextException</code> methods.
>      *
>      * The returned <code>LinkedList</code> contains lists of stack frame
>      * <code>Strings</code>, as returned by the {@link #captureFrames(Throwable)}
>      * method. The most nested exception is returned as the first element of the
>      * list.
>      *
>      * @param t The <code>Throwable</code>.
>      * @return a list of lists of Strings.
>      */
>     private final static LinkedList captureTraces(Throwable t)
>     {
>         LinkedList traces = new LinkedList();
>         Throwable prev;
>         Method method;
>         Class[] noarg = new Class[0];
>         Object[] noobj = new Object[0];
>         do {
>             traces.addLast(captureFrames(t));
> 
>             method = null;
>             prev = t;
>             try {
>                 method = t.getClass().getDeclaredMethod("getRootCause", noarg);
>             } catch(NoSuchMethodException e) {
>                 try {
>                     method = t.getClass().getDeclaredMethod("getException", noarg);
>                 } catch(NoSuchMethodException ee) {
>                     try {
>                         method = t.getClass().getDeclaredMethod("getNextException", noarg);
>                     } catch(NoSuchMethodException eee) {
>                     }
>                 }
>             }
>             if(method != null) {
>                 try {
>                     t = (Throwable)method.invoke(t, noobj);
>                 } catch(Exception e) {
>                 }
>             }
>         } while(prev != t);
> 
>         return traces;
>     }
> 
>     /**
>      * Captures the stack trace associated with a <code>Throwable</code>
>      * object and splits it into a list of stack frames.
>      *
>      * @param t The <code>Throwable</code>.
>      * @return a list of <code>Strings</code> describing each stack frame.
>      */
>     private final static LinkedList captureFrames(Throwable t)
>     {
>         StringWriter sw = new StringWriter();
>         t.printStackTrace(new PrintWriter(sw, true));
> 
>         String linebreak = System.getProperty("line.separator");
>         StringTokenizer st = new StringTokenizer(sw.getBuffer().toString(), linebreak);
>         LinkedList frames = new LinkedList();
>         while(st.hasMoreTokens())
>         {
>             frames.add(st.nextToken());
>         }
>         return frames;
>     }
> }

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: API nitpick - no VelocityException

Posted by Rafal Krzewski <Ra...@e-point.pl>.
Magnus ?or Torfason wrote:

> You might want to consider copying Rafal's TurbineException.  It allows
> you to encapsulate other exceptions inside the new one.  You get the
> full stack trace for all the exceptions, neatly concatenated, and
> no duplicate text. It is totally awesome.

Thanks :-). Actually I came up with another solution after diging
through
Catalina code. Is uses reflection to look up the root cause exceptions.
The methods that are checked are getRootCause, getException and
getNextException. 
The Stacktrace class is able to render a stack trace of a sequence of
arbitrary Throwables, provided that each of them has one of the methods
mentioned above available for determining the underlying Throwable.

You can find the class source attached to this message. Feel free to
use it in Velocity if you like it. It would be cool to have it in some
common package, along with Configuration class that both Turbine and
Velocity could use.

Rafal

--
Rafal Krzewski
Senior Internet Developer
mailto:Rafal.Krzewski@e-point.pl
+48 22 8534830 http://e-point.pl

RE: API nitpick - no VelocityException

Posted by Magnus ?or Torfason <ma...@handtolvur.is>.
> 
> "Kyle F. Downey" wrote:
> > 
> > Is there a reason none of the org.apache.velocity.exception classes
> > inherit from a common base class? Most systems I work with do this so
> > you can catch any error related to that subsystem with one block
> > without resorting to catching all Exceptions.
> 
> Cuz I didn't think of it :)
> 
> Good idea.  Will put in there tomorrow post release of release candidate
> 2 / beta 2.

OK, Geir, now I understand your concerns about velocity just throwing
Exceptions of the correct type, some time ago.  I thought there was a
VelocityException that everything inherited from.

You might want to consider copying Rafal's TurbineException.  It allows
you to encapsulate other exceptions inside the new one.  You get the
full stack trace for all the exceptions, neatly concatenated, and 
no duplicate text. It is totally awesome.

Magnus

Re: API nitpick - no VelocityException

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
"Kyle F. Downey" wrote:
> 
> Is there a reason none of the org.apache.velocity.exception classes
> inherit from a common base class? Most systems I work with do this so
> you can catch any error related to that subsystem with one block
> without resorting to catching all Exceptions.

Cuz I didn't think of it :)

Good idea.  Will put in there tomorrow post release of release candidate
2 / beta 2.

geir

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/

Re: API nitpick - no VelocityException

Posted by Jon Stevens <jo...@latchkey.com>.
on 3/26/01 2:02 PM, "Kyle F. Downey" <kd...@amberarcher.com> wrote:

> Is there a reason none of the org.apache.velocity.exception classes
> inherit from a common base class? Most systems I work with do this so
> you can catch any error related to that subsystem with one block
> without resorting to catching all Exceptions.
> 
> --kd

Thank you for the suggestion and volunteering to make the changes. :-)

-jon


API nitpick - no VelocityException

Posted by "Kyle F. Downey" <kd...@amberarcher.com>.
Is there a reason none of the org.apache.velocity.exception classes
inherit from a common base class? Most systems I work with do this so
you can catch any error related to that subsystem with one block
without resorting to catching all Exceptions.

--kd


Re: How to use velocity in a webapp?

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
"Henning P . Schmiedehausen" wrote:

> [SNIP]
> I am pretty sure that I am missing just a small piece of information
> here. But I'm not able to figure it out on my own. :-(

You are doing nothing wrong - I do the same thing, but take care of the
'relative' path problem in one of two ways :

1) jar the template directory and put that jar into WEB-INF/lib, and
then use the classpath loader.  That should solve it right off.

2) You can convert the relative path to an absolute one by overriding
the VelocityServlet method 

   protected Properties loadConfiguration(ServletConfig config )

and either do something like

  Properties p = super.loadConfiguration( config );

   // and now use  config.getServletContext().getRealPath()
   // to convert the relative path in the properties to the realpath

or load the properties yourself from the file and do the same thing with
getRealPath()

You should do the same thing with your logfile as well.  Any relative
path :)
I 
> 
> Do I have to get the pathes on my own from the servlet runner and
> override them before invoking velocity (just as turbine does and is
> described in the org.apache.velocity.runtime.Runtime documentation?)

I think that is just what I described...
 
> Or is there a simpler way to let velocity cooperate with the servlet
> runner? It reads the properties file correctly from the webapp path.

The easiest way is with the Classpath loader, but you still have the
problem of the logfile...

> Please answer directly as I am not (yet) am member of this mailing list.

Join the list!

geir

-- 
Geir Magnusson Jr.                               geirm@optonline.net
Developing for the web?  See http://jakarta.apache.org/velocity/