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>
Related
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.
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.
I have a requirement to log business activities that can also map to the audit trail data generated. I use Hibernate envers as the audit trail mechanism.
The way I have implemented the activities log is
I have service classes that are proxied using concrete classes
(using CGLIB) and extend TransactionProxyFactoryBean . This is what
provides the transaction aspect.
My method either has the base object carrying the activity data as
a return type or argument of the service.
The assumption is that when I apply a pre-interceptor on the
TransactionProxyFactoryBean ; its AfterReturningAdvice method
should be called after the transaction is completed.
As per my understanding the pre and post interceptors for the TransactionProxyFactoryBean should behave as follows based on the assumptions that the interceptors are added on the stack.
The pre-interceptors before advice method run
Spring starts the transaction
The post-interceptors before advice method runs
The main service method runs
The post-interceptors after returning advice method runs
Spring commits the transaction
The pre-interceptors after returning advice method runs
However when I de-bugged the application I found that the pre-interceptor's after returning advice method runs before the transaction is commited.
Can anyone please guide me as to what am I doing wrong?
TransactionProxyFactoryBean configuration
<bean id="fqngTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<bean id="fqngTxProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="fqngTransactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="process*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="activityLogInterceptor"
class="com.fuelquest.mothra.activitylogs.interceptors.ActivityLogInterceptor">
<property name="activityLogPostingService">
<ref bean="activityLogPostingService" />
</property>
<property name="methodList">
<list>
<value>save*</value>
<value>execute*</value>
<value>calculate*</value>
</list>
</property>
</bean>
Activity Interceptor Java file Definition
public class ActivityLogInterceptor implements AfterReturningAdvice {
private static final Logger logger = Logger
.getLogger(ActivityLogInterceptor.class);
private ActivityLogPostingService activityLogPostingService;
private List<String> methodList;
#SuppressWarnings("rawtypes")
#Override
public void afterReturning(Object returnValue, Method method,
Object[] methodParams, Object target) throws Throwable {
// If return type is ActivityLoggingBaseVO
if (isLoggedMethod(method.getName())) {
.......................
Service Configuration
<bean id="inventoryControlRuleService" parent="fqngTxProxyTemplate">
<property name="target">
<bean
class="com.fuelquest.mothra.inventorycontrol.service.impl.InventoryControlRuleServiceImpl">
<property name="assetService">
<ref bean="assetService" />
</property>
<property name="pointOfSaleService">
<ref bean="pointOfSaleService" />
</property>
<property name="inventoryService">
<ref bean="inventoryService" />
</property>
<property name="deliveryService">
<ref bean="deliveryService" />
</property>
<property name="languageCdDao">
<ref bean="languageCdDao" />
</property>
<property name="inventoryBizRulesDao">
<ref bean="inventoryBizRulesDao" />
</property>
<property name="bizRulesResultsDao">
<ref bean="bizRulesResultsDao" />
</property>
<property name="ruleEngineService">
<ref bean="ruleEngineService" />
</property>
<property name="icRuleCalculationDataDao">
<ref bean="icRuleCalculationDataDao" />
</property>
<property name="inventoryControlService">
<ref bean="inventoryControlService" />
</property>
<property name="fqngESBMessagePoster">
<ref bean="fqngESBMessagePoster" />
</property>
<property name="droolsRuleTemplateService">
<ref bean="droolsRuleTemplateService" />
</property>
<property name="uomsDao">
<ref bean="uomDao" />
</property>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="calculate*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="execute*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="f*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS</prop>
</props>
</property>
<property name="preInterceptors">
<list>
<ref bean="activityLogInterceptor"/>
</list>
</property>
</bean>
We use the Spring OpenSessionInViewFilter to share the same Hibernate session across the HTTP thread request that comes to the application/web server from GWT.
We also require to have Hibernate sessions available for the cron jobs that are launched using Quartz scheduler. These threads can't use the Hibernate session made available through the OpenSessionInViewFilter and the TransactionProxyFactoryBean proxy that we use to proxy the transactions fails. Hence we needed to use an additional org.springframework.aop.framework.autoproxy.BeanNa meAutoProxyCreator to proxy the polling and SV rule service so that they can be called from the Quartz scheduler.
Because we now had 2 transactional proxies for the same bean; Spring functionality like having pre-interceptor etc was not working as expected because the interceptor was applied on the proxy created with BeanNameAutoProxyCreator and NOT TransactionProxyFactoryBean.
The solution was to move to Spring 2.x transactions using AOP and TX namespace that resulted in creating a single proxy that was utilized by both the OpenSessionInViewFilter and the Quartz scheduler.
Your understanding matches mine.
Would switching to an Around advice (MethodInterceptor) for ActivityLogInterceptor help? If that resolves the issue you may have a bug to report.
We are migrating our web application from Spring 2.5 to Spring 3.0.5. Looks like all the Controller classes (the classes in org.springframework.web.servlet.mvc package: BaseCommandController, AbstractCommandController, SimpleFormController, etc) have been deprecated. We used those classes heavily in our application. These classes have been replaced by #Controller annotation instead.
I have a few questions regarding Spring 3.0.x Controller configuration...
We used the following XML to create a Controller bean in Spring 2.5. If <context:component-scan> is used instead to create the Controller beans, then how do I wire-in the dependencies? If possible I would like to avoid Auto-Wiring.
<bean id="photosetViewController" class="com.xyz.web.PhotosetViewController"
p:photosetManager-ref="photosetManager"
p:photoManager-ref="photoManager" />
We have created 3 Interceptors. We use SimpleUrlHandlerMapping to map these Interceptors to different request URLs and also to map URLs to Controllers. How do we achieve the same in Spring 3.0.x?
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="interceptors">
<list>
<ref bean="httpRedirectInterceptor"/>
<ref bean="loginInterceptor"/>
</list>
</property>
<property name="mappings">
<value>
/abc.html=abcLookupController
/photoupload.html=photoUploadController
</value>
</property>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="interceptors">
<list>
<ref bean="httpRedirectInterceptor"/>
<ref bean="loginInterceptor"/>
<ref bean="userMenuInterceptor" />
</list>
</property>
<property name="mappings">
<value>
/index.html=homepageController
/success.html=simpleController
</value>
</property>
</bean>
In case of SimpleFormControllers we used different methods like initBinder, referenceData, formBackingObject. We also used command objects and validation classes. How do we achieve the same in Spring 3.0.x?
<bean id="photosetAddController" class="com.xyz.web.PhotosetAddController"
p:photosetManager-ref="photosetManager"
p:photosetTypeManager-ref="photosetTypeManager"
p:stateManager-ref="stateManager" >
<property name="validator">
<bean class="com.xyz.form.PhotosetAddValidator" />
</property>
<property name="formView" value="photosetadd" />
<property name="successView" value="redirect:/photoset" />
</bean>
Any pointers are greatly appreciated.
As skaffman noted - your code will work fine without any modifications. I'll answer your questions in short:
You can use #Resource(name="beanName") for name-based injection. But autowiring is also a good option. Either #Autowired, or #javax.inject.Inject. Note that you can use #Qualifier("name") to differentiate between beans with the same interface/base class. You can even use the javax.inject qualifiers (read about all these in the docs)
interceptor mappings can stay the same
There is #InitBinder, which denotes the initBinder method. I can't tell about the other.
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?