Unable to use macros with velocity in email templates? - spring

greetings all
i am using velocity templates when sending emails
and i want to read texts dynamically from property files depending on user locale
the xml config:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages</value>
<value>classpath:messages_ar</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
<prop key="velocimacro.library">org/springframework/web/servlet/view/velocity/spring.vm</prop>
</props>
</property>
</bean>
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/classes/com/spacerdv/mailTemplates"/>
</bean>
<!--
View resolvers can also be configured with ResourceBundles or XML files. If you need
different view resolving based on Locale, you have to use the resource bundle resolver.
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<!-- if you want to use the Spring Velocity macros, set this property to true -->
<property name="exposeSpringMacroHelpers" value="true"/>
</bean>
and when trying to read the text from property file like :
<span>#springMessage("hi.message")</span>
it doesn't read any thing, or prints the default value, just prints:
$springMacroRequestContext.getMessage($code)
i don't know why? , am i missing something ?, any help ?

When using the velocity engine for sending emails, you may have to configure your engine tu use the velocimacro librabry shipped within spring.
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
<prop key="velocimacro.library">org/springframework/web/servlet/view/velocity/spring.vm</prop>
</props>
</property>
</bean>
You can check the example in spring documentation.
If Spring doesn't inject automatically the $springMacroRequestContext variable into your model, you should put it yourself:
model.put("springMacroRequestContext", new RequestContext(request, response, getServletContext(), model));
That's basically what they do in the AbstractTemplateView class. I guess you won't be able to do it, since you're handling emails here, and not web requests. But that's definitely a hint on what you can do to get it working.

macros can't be used outside web app like in email templates, so a solution would be to pass messageSource to the vm file and read from the property file by it like the answer in here:
Is it possible to read static text dynamically from property files in velocity template?

Related

Hibernate Envers not Finding JPA Transaction:

I've been trying to wrap my head around this issue all day.
Currently our project has setup JPATransactionManager through a Spring Application Context to take care of our various session transactions with the use of #Transactional on all services that take care of persistence and deletions (DAO usage).
Changing over from Hibernate 3 to 5, we wanted to remove our use of a custom audit interceptor and move onto using Hibernate Envers. I have annotated all my classes properly and have the tables being created, but once it actually gets to a point of insertion, the listener throws an error in which it can't find the current transaction given by JPA:
org.hibernate.envers.exception.AuditException: Unable to create revision because of non-active transaction
at org.hibernate.envers.event.spi.BaseEnversEventListener.checkIfTransactionInProgress(BaseEnversEventListener.java:132)
at org.hibernate.envers.event.spi.EnversPostInsertEventListenerImpl.onPostInsert(EnversPostInsertEventListenerImpl.java:34)
at org.hibernate.action.internal.EntityIdentityInsertAction.postInsert(EntityIdentityInsertAction.java:156)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:102)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:597)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:232)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:213)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:256)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:638)
Looking inside the code, it seems that it's basing the transaction status off it's default value of INACTIVE meaning that it's not hooking into the transaction properly. I know that Hibernate Envers also automatically pushes the listeners into hibernate with recent versions so I don't know if this may also be a source of the issue.
I know that its been documented to work with HibernateTransactionManager but we wish to step away from using that in favor of hooking up our transactions and sessions solely via Spring making things easier so it may also be the need of finding an alternative to envers. Does anyone have any advice or solutions to this problem? Or also hit this issue?
ApplicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref=“dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sourceforge.jtds.jdbcx.JtdsDataSource" />
<property name="url" value="jdbc:jtds:sqlserver://.." />
<property name="username" value=“..." />
<property name="password" value=“..." />
</bean>
<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>classpath:hibernate.properties</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<ref bean="hibernateProperties" />
</property>
</bean>
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="load*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="make*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="refresh">PROPAGATION_SUPPORTS</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly
</prop>
</props>
</property>
</bean>
<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="transactionManager" />
</bean>
hibernate.properties
#hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.connection.datasource=java\:comp/env/datasource
#hibernate.connection.provider_class=org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl
hibernate.connection.provider_class=org.hibernate.connection.DatasourceConnectionProvider
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
#hibernate.generate_statistics=true
hibernate.cache.use_structured_entries=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
hibernate.id.new_generator_mappings=false
hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
hibernate.listeners.envers.autoRegister=false
org.hibernate.envers.track_entities_changed_in_revision=false
org.hibernate.envers.audit_table_prefix=AUD_
org.hibernate.envers.audit_table_suffix=
My DAOs are hooked up using the txProxyTemplate like so
<bean id="objectDAO" parent="txProxyTemplate">
<property name="target">
<bean
class="path.to.objectDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
</property>
</bean>
All my services that use the various DAOs are simply hooked up using the #Transactional annotation where we want to have transactions. I've been able to see through trace that my transactions are succeeding in completing and rolling back as well when there are errors. Once I added envers into the mix, the auditing can't find the transaction to join. There must be something I'm missing but I'm not sure what it is.
I don't believe you need to define a txProxyTemplate bean nor a SpringTransactionPolicy from my experience. This functionality has since been superseded with the <tx:/> tags and the use of the #Transactional annotation.
You just need to make sure a JpaTransactionManager has been created and associated as the transactionManager associated with the <tx:annotation-driven/> tag.

Why is MultiActionController deprecated in Spring 4.3?

In most cases, I'm able to replace MultiActionController with an annotated controller just fine. But I have a use-case where I need to map different URLs to DIFFERENT instances of the same controller class, each wired with a different implementation of the same interface. (It's for various find-as-you-type APIs.) I've been using SimpleUrlHandlerMapping for this. Is there any way to do this with an annotated controller? Or do I now have to make separate controller classes for each API? Here's my config with only two MultiActionControllers shown, although I have more:
<bean name="regionAutocompleteController" class="...ajax.autocomplete.AutocompleteController" autowire="byName">
<property name="finder" ref="regionFinder"/>
</bean>
<bean name="blockAutocompleteController" class="...ajax.autocomplete.AutocompleteController" autowire="byName">
<property name="finder" ref="blockFinder"/>
</bean>
<bean id="atlasAjaxControllerMappings"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="4" />
<property name="mappings">
<props>
<prop key="/findBlock/*">blockAutocompleteController</prop>
<prop key="/findRegion/*">regionAutocompleteController</prop>
</props>
</property>
</bean>

Spring webservice: validate that a timestamp is signed

In my SOAP webservice, we agreed that the body is signed. For that, I use Spring, configured like this:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor" id="wsSecurityInterceptor">
<property name="validationActions" value="Timestamp Signature"/>
<property name="timestampStrict" value="true"/>
<property name="validationSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="configuration">
<props>
<prop key="org.apache.ws.security.crypto.merlin.keystore.type">JKS</prop>
<prop key="org.apache.ws.security.crypto.merlin.file">${ws.security.truststore.location}</prop>
<prop key="org.apache.ws.security.crypto.merlin.keystore.password">${ws.security.truststore.password}</prop>
</props>
</property>
</bean>
</property>
</bean>
But now, I'm asked to also check that the timestamp is correctly signed.
When I read Spring's documentation on the matter, I can see how to sign a timestamp, but nowhere is it mentioned how to validate a timestamp signature.
So anyone knows how I can do that?
If that's any indication, I use org.springframework.ws:spring-ws-core:2.1.2.RELEASE.

Mapping a url to one servlet

I am using the class org.springframework.web.servlet.mvc.ServletWrappingController to wrap a servlet, that we need to process one http request in Spring MVC, but reference spring mvc version 3.2 guide says:
There are also several things no longer possible:
Select a controller first with a SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping
So then this is not possible any longer, as the api says:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="*.do">strutsWrappingController</prop>
</props>
</property>
</bean>
<bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController">
<property name="servletClass">
<value>org.apache.struts.action.ActionServlet</value>
</property>
<property name="servletName">
<value>action</value>
</property>
<property name="initParameters">
<props>
<prop key="config">/WEB-INF/struts-config.xml</prop>
</props>
</property>
</bean>
how can i map a url to a ServletWrappingController bean?
Thanks in advance.

org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter generateDdl Not Working

I'm using Spring 3.* using JPA hibernate impl and I've set the Spring org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter generateDdl to true, but I don't see it actually doing anything. I swap it to false and I get the same output in my log. Anyone know what this setting is supposed to do? Its not generating the ddl.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="api" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.use_sql_comments">${jpa.vendor.showsql}</prop>
<prop key="hibernate.generate_statistics">${jpa.vendor.generate.statistics}</prop>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.cache.use_second_level_cache">${cache.use.secondLevel}</prop>
<prop key="hibernate.cache.use_query_cache">${cache.use.query}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${console.show.sql}" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
If you use an IDE that has good Spring/XML support (notably IntelliJ IDEA), you can view what each property should do (in IDEA put the cursor on it and press CTRL+Q). The specc says:
Set whether to generate DDL after the EntityManagerFactory has been
initialized, creating/updating all relevant tables. Note that the
exact semantics of this flag depend on the underlying persistence
provider. For any more advanced needs, specify the appropriate
vendor-specific settings as "jpaProperties".
Having the value true means that if the database tables don't exist or need to be updated, it will be done automatically. If the value is false, you will have to do it manually.

Resources