Dynamic Templates
I thought I would share the following code with the Apache Velocity community. Problem Description: I wanted to use Dynamic Templates though I found the following had massive performance implications. -- Velocity Call Snippet -- String template = "message.to: ${message.to} "; StringWriter velocityWriter = new StringWriter(); velocityEngine.evaluate( velocityContext, velocityWriter, "LOG", template ); return velocityWriter.toString(); -- Velocity Call Snippet -- As such, I needed an alternate solution and guessed that if I could cache the Velocity templates used I could see big performance gains. I initially looked to the org.apache.velocity.runtime.resource.loader.StringResourceLoader class to solve my problems. The StringResourceLoader class requires an instance of the StringResourceRepository class, and the only implementation of StringResourceRepository is StringResourceRepositoryImpl. Unfortunately, since the number of unique templates will grow over time, in time the StringResourceRepositoryImpl.resources Map will cause an out of memory error. Why doesn't StringResourceRepositoryImpl use a cache with a maximum size? Is a cache even needed as the Velocity ResourceCacheImpl will cache Templates? + In the end I settled on the following solution. From my tests using YourKit Java Profiler I invoked the static Velocity wrapping method 100,000 times, and discovered a performance difference of around 75 fold (146,937ms vs 1,981ms). Below is my solution. Feedback appreciated. + Regards, Mark -- Velocity Engine Setup Snippet -- Properties p = new Properties(); p.setProperty( RuntimeConstants.INPUT_ENCODING, DEFAULT_ENCODING ); p.setProperty( RuntimeConstants.OUTPUT_ENCODING, DEFAULT_ENCODING ); p.setProperty( RuntimeConstants.RESOURCE_MANAGER_CLASS, "org.apache.velocity.runtime.resource.ResourceManagerImpl" ); p.setProperty( RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS, "org.apache.velocity.runtime.resource.ResourceCacheImpl" ); p.setProperty( RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, "100" ); p.setProperty( RuntimeConstants.RESOURCE_LOADER, "string" ); p.setProperty( "string.resource.loader.class", "custom.SimpleStringResourceLoader" ); p.setProperty( "string.resource.loader.encoding", DEFAULT_ENCODING ); p.setProperty( "string.resource.loader.cache", Boolean.TRUE.toString() ); p.setProperty( "string.resource.loader.modificationCheckInterval", "-1" ); VelocityEngine engine = new VelocityEngine( p ); engine.init(); -- Velocity Engine Setup Snippet -- -- Velocity Call Snippet -- String template = "message.to: ${message.to} "; StringWriter velocityWriter = new StringWriter(); Template veTemplate = velocityEngine.getTemplate( template ); veTemplate.merge( velocityContext, velocityWriter ); return velocityWriter.toString(); -- Velocity Call Snippet -- -- Velocity Supporting Class Snippet -- package custom; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.collections.ExtendedProperties; import org.apache.velocity.exception.VelocityException; import org.apache.velocity.runtime.resource.Resource; import org.apache.velocity.runtime.resource.loader.ResourceLoader; import org.apache.velocity.runtime.resource.util.StringResource; public class SimpleStringResourceLoader extends ResourceLoader { protected static int classMetricsLevel; protected static AtomicLong totalClassInstancesCreatedCount; protected static AtomicLong totalStringsGeneratedCount; static { classMetricsLevel = 1; totalClassInstancesCreatedCount = new AtomicLong(); totalStringsGeneratedCount = new AtomicLong(); } protected String encoding; public SimpleStringResourceLoader() { if ( classMetricsLevel > 0 ) { totalClassInstancesCreatedCount.incrementAndGet(); } this.encoding = "UTF-8"; } @Override public void init( ExtendedProperties paramExtendedProperties ) { String paramEncoding = paramExtendedProperties.getString( "encoding" ); if ( null != encoding && encoding.trim().length() > 0 ) { this.encoding = paramEncoding; } } @Override public InputStream getResourceStream( String contents ) { if ( classMetricsLevel > 1 ) { totalStringsGeneratedCount.incrementAndGet(); } StringResource resource = new StringResource( contents, encoding ); byte[] byteArray = null; try { byteArray = resource.getBody().getBytes( resource.getEncoding() ); return new B
Re: Dynamic Templates
Would you consider submitting this via https://issues.apache.org/jira/browse/VELOCITY? That would allow us to possibly incorporate improvements from your code into future versions. On Thu, Feb 9, 2012 at 2:47 PM, Mark-12345 wrote: > > I thought I would share the following code with the Apache Velocity > community. > > > Problem Description: I wanted to use Dynamic Templates though I found the > following had massive performance implications. > > -- Velocity Call Snippet -- > String template = "message.to: ${message.to} "; > StringWriter velocityWriter = new StringWriter(); > velocityEngine.evaluate( velocityContext, velocityWriter, "LOG", template ); > return velocityWriter.toString(); > -- Velocity Call Snippet -- > > > As such, I needed an alternate solution and guessed that if I could cache > the Velocity templates used I could see big performance gains. > > I initially looked to the > org.apache.velocity.runtime.resource.loader.StringResourceLoader class to > solve my problems. The StringResourceLoader class requires an instance of > the StringResourceRepository class, and the only implementation of > StringResourceRepository is StringResourceRepositoryImpl. Unfortunately, > since the number of unique templates will grow over time, in time the > StringResourceRepositoryImpl.resources Map will cause an out of memory > error. > > Why doesn't StringResourceRepositoryImpl use a cache with a maximum size? > Is a cache even needed as the Velocity ResourceCacheImpl will cache > Templates? > > + > In the end I settled on the following solution. From my tests using YourKit > Java Profiler I invoked the static Velocity wrapping method 100,000 times, > and discovered a performance difference of around 75 fold (146,937ms vs > 1,981ms). > > Below is my solution. Feedback appreciated. > > + > > > Regards, > Mark > > -- Velocity Engine Setup Snippet -- > Properties p = new Properties(); > > p.setProperty( RuntimeConstants.INPUT_ENCODING, DEFAULT_ENCODING ); > p.setProperty( RuntimeConstants.OUTPUT_ENCODING, DEFAULT_ENCODING ); > > p.setProperty( RuntimeConstants.RESOURCE_MANAGER_CLASS, > "org.apache.velocity.runtime.resource.ResourceManagerImpl" ); > p.setProperty( RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS, > "org.apache.velocity.runtime.resource.ResourceCacheImpl" ); > p.setProperty( RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, "100" ); > > p.setProperty( RuntimeConstants.RESOURCE_LOADER, "string" ); > p.setProperty( "string.resource.loader.class", > "custom.SimpleStringResourceLoader" ); > p.setProperty( "string.resource.loader.encoding", DEFAULT_ENCODING ); > p.setProperty( "string.resource.loader.cache", Boolean.TRUE.toString() ); > p.setProperty( "string.resource.loader.modificationCheckInterval", "-1" ); > > VelocityEngine engine = new VelocityEngine( p ); > engine.init(); > -- Velocity Engine Setup Snippet -- > > -- Velocity Call Snippet -- > String template = "message.to: ${message.to} "; > StringWriter velocityWriter = new StringWriter(); > Template veTemplate = velocityEngine.getTemplate( template ); > veTemplate.merge( velocityContext, velocityWriter ); > return velocityWriter.toString(); > -- Velocity Call Snippet -- > > > > > -- Velocity Supporting Class Snippet -- > > package custom; > > import java.io.ByteArrayInputStream; > import java.io.InputStream; > import java.io.UnsupportedEncodingException; > import java.util.concurrent.atomic.AtomicLong; > > import org.apache.commons.collections.ExtendedProperties; > import org.apache.velocity.exception.VelocityException; > import org.apache.velocity.runtime.resource.Resource; > import org.apache.velocity.runtime.resource.loader.ResourceLoader; > import org.apache.velocity.runtime.resource.util.StringResource; > > public class SimpleStringResourceLoader extends ResourceLoader > { > > protected static int classMetricsLevel; > protected static AtomicLong totalClassInstancesCreatedCount; > protected static AtomicLong totalStringsGeneratedCount; > > static { > classMetricsLevel = 1; > totalClassInstancesCreatedCount = new AtomicLong(); > totalStringsGeneratedCount = new AtomicLong(); > } > > > protected String encoding; > > > public SimpleStringResourceLoader() > { > > if ( classMetricsLevel > 0 ) > { > totalClassInstancesCreatedCount.incrementAndGet(
Re: Dynamic Templates
More than happy to create an improvement request. See below: https://issues.apache.org/jira/browse/VELOCITY-817 Would you consider submitting this via https://issues.apache.org/jira/browse/VELOCITY? That would allow us to possibly incorporate improvements from your code into future versions. On Thu, Feb 9, 2012 at 2:47 PM, Mark-12345 wrote: > > I thought I would share the following code with the Apache Velocity > community. > > > Problem Description: I wanted to use Dynamic Templates though I found the > following had massive performance implications. -- View this message in context: http://old.nabble.com/Dynamic-Templates-tp33297076p33298309.html Sent from the Velocity - User mailing list archive at Nabble.com. - To unsubscribe, e-mail: user-unsubscr...@velocity.apache.org For additional commands, e-mail: user-h...@velocity.apache.org