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 <marks1900-pos...@yahoo.com.au> 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(); > } > > 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 ByteArrayInputStream( byteArray ); > } > catch ( UnsupportedEncodingException ue ) > { > throw new VelocityException( "Failed to convert contents to > String " > + resource.getEncoding(), ue ); > } > > } > > @SuppressWarnings( "unused" ) > @Override > public boolean isSourceModified( Resource paramResource ) > { > return false; > } > > @SuppressWarnings( "unused" ) > @Override > public long getLastModified( Resource paramResource ) > { > return 0; > } > > > public String getEncoding() > { > return encoding; > } > > public void setEncoding( String encoding ) > { > this.encoding = encoding; > } > > > public static int getClassMetricsLevel() > { > return classMetricsLevel; > } > > public static void setClassMetricsLevel( int classMetricsLevel ) > { > SimpleStringResourceLoader.classMetricsLevel = classMetricsLevel; > } > > public static void setTotalClassInstancesCreatedCount( long counterValue > ) > { > > SimpleStringResourceLoader.totalClassInstancesCreatedCount.getAndSet( > counterValue ); > } > > public static long getTotalClassInstancesCreatedCount() > { > return > SimpleStringResourceLoader.totalClassInstancesCreatedCount.get(); > } > > > public static void setTotalStringsGeneratedCount( long counterValue ) > { > SimpleStringResourceLoader.totalStringsGeneratedCount.getAndSet( > counterValue ); > } > > public static long getTotalStringsGeneratedCount() > { > return SimpleStringResourceLoader.totalStringsGeneratedCount.get(); > } > > @Override > public String toString() > { > return "SimpleStringResourceLoader [encoding=" + encoding + "]"; > } > > } > > -- Velocity Supporting Class Snippet -- > > -- > View this message in context: > http://old.nabble.com/Dynamic-Templates-tp33297076p33297076.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 > --------------------------------------------------------------------- To unsubscribe, e-mail: user-unsubscr...@velocity.apache.org For additional commands, e-mail: user-h...@velocity.apache.org