[ https://issues.apache.org/jira/browse/VELOCITY-817?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16016428#comment-16016428 ]
Mark S commented on VELOCITY-817: --------------------------------- To give you a couple of possible use case examples * A system user configures a custom email alert that will be sent to an email list. * A system user sends an email to to a customer list using 5 different email templates which are dynamically chosen depending on the customer profile. * A system user has an online store and configures a custom welcome message depending on a customer profile and context. Also, while it has been over 5 years since I contributed this code, I am pretty sure that the cache size is set with the following command. {code} p.setProperty( RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, "100" ); {code} > Dynamic Templates with Caching > ------------------------------ > > Key: VELOCITY-817 > URL: https://issues.apache.org/jira/browse/VELOCITY-817 > Project: Velocity > Issue Type: Improvement > Components: Engine > Affects Versions: 1.7 > Reporter: Mark S > Labels: performance > Original Estimate: 2h > Remaining Estimate: 2h > > 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. > {code:title=Velocity Call Snippet|borderStyle=solid} > String template = "message.to: $\{message.to} "; > StringWriter velocityWriter = new StringWriter(); > velocityEngine.evaluate( velocityContext, velocityWriter, "LOG", template ); > return velocityWriter.toString(); > {code} > 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. > +++++++++++++++++++++++++++++++++++++ > {code:title=Velocity Engine Setup Snippet|borderStyle=solid} > 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(); > {code} > {code:title=Velocity Call Snippet|borderStyle=solid} > String template = "message.to: ${message.to} "; > StringWriter velocityWriter = new StringWriter(); > Template veTemplate = velocityEngine.getTemplate( template ); > veTemplate.merge( velocityContext, velocityWriter ); > return velocityWriter.toString(); > {code} > {code:title=Velocity Supporting Class Snippet|borderStyle=solid} > 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 + "]"; > } > } > {code} -- This message was sent by Atlassian JIRA (v6.3.15#6346) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@velocity.apache.org For additional commands, e-mail: dev-h...@velocity.apache.org