I was trying to add AOP logger to the existing Spring(v3.1.3) application. Below is the code for the same.
Application launches successfully and am able to login. But, once the flow reaches the Controller that's specified in the ApplicationLogger.java, am getting 404 error in the screen and unfortunately aint getting any error trace in the console. Not getting any clue.
Kindly help me out to find where i have gone wrong.
TIA,
Arun
SERVLET.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd" >
<context:annotation-config />
<mvc:annotation-driven />
<!-- Enables the caching through annotations -->
<cache:annotation-driven />
<aop:aspectj-autoproxy />
<bean id="appLogger"
class="com.pmc.crm.risk.util.ApplicationLogger" />
.
.
.
ApplicationLogger.java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class ApplicationLogger
{
/**
* Log method entry.
*
* #param joinPoint
*/
#Before("execution(* com.pmc.crm.risk.mvc.controller.SearchController.loadParamSearch(..))")
public void logEntry(final JoinPoint joinPoint)
{
System.out.println("*--*-*-*-* LOG ENTRY -*-*-*");
log("Entering method " + joinPoint.getSignature().getName() + "...");
}
/**
* Log method exit.
*
* #param joinPoint
*/
#After("execution(* com.pmc.crm.risk.mvc.controller.SearchController.loadParamSearch(..))")
public void logExit(final JoinPoint joinPoint)
{
System.out.println("*--*-*-*-* LOG EXIT -*-*-*");
log("Exiting method " + joinPoint.getSignature().getName() + ".");
}
SEARCHCONTROLLER.java
package com.pmc.crm.risk.mvc.controller;
import ....
#Controller
public class SearchController extends AbstractPolicyController{
private static final Logger LOG = Logger.getLogger(SearchController.class);
#RequestMapping(value = "/loadParamSearch.htm", method = RequestMethod.GET)
public ModelAndView loadParamSearch(HttpServletRequest request, HttpServletResponse response,ModelMap model) throws Exception{
try
{
System.out.println("...");
}
.
.
AbstractPolicyController was actually implementing an interface and servlet couldnt inject a proxy for the same (Investigating on the reason.) On removing the 'implements interfaceName' it worked good. Anyone who know the reason may pls let me know.
Related
I am getting exception mentioned in subject line. Could you please explain what is wrong:
package mvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("/req")
public class Req {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String get(#RequestBody String body) {
return body;
}
}
SpringMVC-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!--It tells the Spring framework to look for annotations and then do appropriate dependency injections.-->
<context:annotation-config/>
<!--used to provide base package to scan components-->
<context:component-scan base-package="mvc"/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
When i tries to access http://localhost:8080/SpringMVC/req
HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect ().
Apache Tomcat/7.0.16
Kindly help me in figure out the cause of this issue.
Thanks,
Sandip
Change method to POST and send some data with HTTP POST so the (#RequestBody String body) binding works.
You could use SoapUi or HTTP Requester plugin for browsers to conveniently send HTTP POST.
Otherwise define method as:
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String get() {
return "Some string";
}
I'm developing a module on an OSGi application, using Spring MVC and Virgo Webserver.
On my module I have a Controller, that access a Manager, which has a list of handlers that are responsible for handling report generation.
Everything was doing fine until I had to call a transactional method from an external service. Since none of my classes were transactional I had to add the references to the transation manager and annotation-driven. Then, my Manager stopped being notified.
I understand that when using annotation-driven all my beans must implement a public interface in order for the proxying mechanism to work. And as far as I know, all the classes are (one of them wasn't, but then I changed it).
My configuration files are:
bundle-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="reportManager" class="reportmodule.manager.impl.ReportManagerImpl"/>
<bean id="mvpepReportHandler" class="reportmodule.manager.impl.MVPEPReportHandler"/>
<bean id="reportConfigDao" class="reportmodule.repository.impl.ReportConfigurationHibernateDAOImpl"/>
<bean id="oSGIChangeReportHandler" class="reportmodule.osgi.impl.OSGIChangeReportHandlerImpl"/>
<bean id="reportController"
class="reportmodule.controller.impl.ReportControllerImpl"/>
<bean id="reportControllerHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>/module/reportController/**=reportController</value>
</property>
<property name="alwaysUseFullPath" value="true"></property>
</bean>
</beans>
and my bundle-osgi.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/osgi-compendium
http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium-1.2.xsd">
<osgi:reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
<osgi:reference id="sessionFactory" interface="org.hibernate.SessionFactory" />
<osgi:reference id="smaCoreUtilService" interface="core.util.service.SmaCoreUtilService" />
<osgi:service ref="reportControllerHandlerMapping"
interface="org.springframework.web.servlet.HandlerMapping"
context-class-loader="service-provider"
auto-export="interfaces"/>
<osgi:service interface="reportmodule.api.manager.ReportManager" ref="reportManager" auto-export="interfaces"/>
<osgi:service interface="reportmodule.api.manager.ReportHandler" ref="mvpepReportHandler" auto-export="interfaces"/>
<osgi:service interface="reportmodule.repository.ReportConfigurationDAO" ref="reportConfigDao" auto-export="interfaces"/>
<osgi:service interface="reportmodule.osgi.OSGIChangeReportHandler" ref="oSGIChangeReportHandler" auto-export="interfaces"/>
<osgi:list cardinality="0..N" id="reportHandler" interface="reportmodule.api.manager.ReportHandler" greedy-proxying="true">
<osgi:listener ref="oSGIChangeReportHandler" bind-method="register" unbind-method="unregister"/>
</osgi:list>
</beans>
So, after all the services are being published the oSGIChangeReportHandler.register is called (I'm able to debbug it):
#Service(value="oSGIChangeReportHandler")
public class OSGIChangeReportHandlerImpl implements OSGIChangeReportHandler {
private ReportManager reportManager;
/**
* #param reportManager the reportManager to set
*/
#Autowired
public void setReportManager(ReportManager reportManager) {
this.reportManager = reportManager;
}
#SuppressWarnings("rawtypes")
public void register(ReportHandler reportHandler, Map properties) {
reportManager.addReportHandler(reportHandler);
}
#SuppressWarnings("rawtypes")
public void unregister(ReportHandler reportHandler, Map properties) {
reportManager.removeReportHandler(reportHandler);
}
}
And although the debugger shows Proxies for both the reportManager and reportHandler on the register method, the debugger does not halts on the ReportManagerImpl.addReportHandler method:
#Service(value="reportManager")
#Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
public class ReportManagerImpl implements ReportManager {
private ReportConfigurationDAO reportConfigurationDAO;
private ArrayList<ReportHandler> reportHandlers = new ArrayList<ReportHandler>();
/**
* #param reportConfigurationDAO the reportConfigurationDAO to set
*/
#Autowired
public void setReportConfigurationDAO(ReportConfigurationDAO reportConfigurationDAO) {
this.reportConfigurationDAO = reportConfigurationDAO;
}
#Override
#Transactional
public InputStream gerarRelatorio(ReportRequest repoReq) throws NegocioException {
// Generates the report...
}
/* (non-Javadoc)
* #see reportmodule.api.manager.ReportManager#addReportHandler(reportmodule.api.manager.ReportHandler)
*/
#Override
public void addReportHandler(ReportHandler handler) {
if (handler != null) {
this.reportHandlers.add(handler);
}
}
/* (non-Javadoc)
* #see reportmodule.api.manager.ReportManager#removeReportHandler(reportmodule.api.manager.ReportHandler)
*/
#Override
public void removeReportHandler(ReportHandler handler) {
if (handler != null) {
this.reportHandlers.remove(handler);
}
}
}
I must stress that when I remove the tx:annotation-driven tag from the bundle-context.xml file, everything works fine (the handler is properly added to the list during startup).
So, what am I missing here?
Problem solved!
As you can see on my code above, I was defining the beans both via XML and Annotation, thus every bean was duplicated in runtime. Then, when I added the tx:annotation-driven tag the application begun intercepting the wrong bean. It was indeed notifying a bean, but an orphan bean.
HereĀ“s an example working with tx. Look this line:
xmlns:tx="http://www.springframework.org/schema/tx"
and this on schemaLocation:
http://www.springframework.org/schema/tx/spring-tx.xsd
Source:
http://www.springbyexample.org/examples/hibernate-transaction-annotation-config.html
I am working on a Spring Project:Common that uses a combination of Annotaions and Spring IOC in XML.
I have a common.jar which contains Common classes used by various projects.
And I have another Spring Project:WebService that refers to the beans defined in common.jar.
For some reason beans marked with #Component Annotation in Common.jar are not being picked up by my WebService Project. But all beans defined using <bean id="" class="" /> in Common.jar were picked up.
Below are the code for all files that have necessary configuration. Would really appreciate your help. Thanks in advance.
In Common.jar, applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<import resource="springConfig/app/AppServices.xml"/> <!-- Beans in this file were loaded. -->
<context:annotation-config/>
<context:component-scan base-package="com.ipd.app1"/> <!-- Beans for all classes under app1 package were NOT loaded -->
</beans>
In Common.jar, AppServices.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="inquireOrderApp" class="com.ipd.app.inquireOrderDetail.InquireOrderDetailAppImpl"/>
</beans>
Common.jar, com.test.app.MyClass
package com.ipd.app1;
#Component("createOrderApp")
public class CreateOrderAppImpl implements CreateOrderApp {
#Override
public CreateOrderResponse processMSSOrder(TransactionContext tx,
CreateOrderRequest createOrderRequest)
throws ApplicationException, Exception {
System.out.println("In App Layer Class CreateOrderAppImpl to ProcessOrder.");
return response;
}
}
WebService Project, IpdService_IPDSoapHTTPPortImpl.java
#WebService(portName = "IpdSoapHTTPPort", serviceName = "IpdService", targetNamespace = "http://ipd.com/ipdIpdweb/", wsdlLocation = "/wsdls/Ipd.wsdl", endpointInterface = "com.ipd.ipdIpdweb.IpdPortType")
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
public class IpdService_IpdSoapHTTPPortImpl implements IpdPortType {
ApplicationContext ctx;
public IpdService_IpdSoapHTTPPortImpl() {
this.ctx = AppContext.getCtx();
}
#Override
public void createOrder(WSHeader wsHeader,
CreateOrderRequest createOrderRequest,
Holder<WSResponseHeader> wsResponseHeader,
Holder<CreateOrderResponse> createOrderResponse)
throws WSException {
CreateOrderApp createOrderApp = (CreateOrderApp) ctx.getBean("createOrderApp");
res = createOrderApp.processOrder(tx, createOrderRequest);
res.setResponseCode(BigInteger.valueOf(0));
res.setResponseMessage("Success");
.....
}
}
Please let me know if you need see the code for any other file.
Well add this to applicationContext.xml
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
As explained here and here it is quite clear how to do it but still can't seem to make it work.
I simply like to use the #Value annotation in order to inject a property to a spring bean. I created a basic spring MVC project with one controller and one bean.
Here is my application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="me.co.fatsecret" />
<!-- Properties -->
<bean id="props"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:fatProperties.properties" />
</bean>
</beans>
I have one bean called Configuration:
package me.co.fatsecret;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Configuration {
/*--- Members ---*/
#Value("${api_key}")
protected String API_KEY;
#Value("${api_secret}")
protected String API_SECRET;
#Value("${api_url}")
protected String API_URL;
/*--- Constructors ---*/
public Configuration() {
}
/*--- Getters & Setters ---*/
public String getAPI_KEY() {
return API_KEY;
}
public void setAPI_KEY(String aPI_KEY) {
API_KEY = aPI_KEY;
}
public String getAPI_SECRET() {
return API_SECRET;
}
public void setAPI_SECRET(String aPI_SECRET) {
API_SECRET = aPI_SECRET;
}
public String getAPI_URL() {
return API_URL;
}
public void setAPI_URL(String aPI_URL) {
API_URL = aPI_URL;
}
}
Now I have only one controller, injected with this Configuration class and as I call this controller I see that the values in the Configuration class are not populated right.
My properties file is located under the resources folder (src/main/resources) and is a part of my classpath (done by default since this is a maven project). Here it is:
api_url=http://platform.fatsecret.com/js?
api_key=SomeKey
api_secret=SomeSecret
The file name is fatProperties.properties.
As I debug my server when calling the controller I see that the content of the Configuration class is:
${api_key}
${api_secret}
${api_url}
This is the actual value of the Strings, wich means that the vales from the properties file are not getting injected for some reason.
Am I missing something here?
UPDATE1: I replaced the PropertyPlaceholderConfigurer bean with:
<context:property-placeholder location="classpath:fatProperties.properties"/>
Getting the same result
Ok, got it!
I'm using a spring MVC project, which means I have a separated context for my web layer (the controllers). The "Configuration" bean which hods the properties using the #Value annotation is injected to a controller. My property-placeholder is defined within my root-context hence it cannot be seen from my controller. To resolve the issue I simply added the property-placeholder definition to my DispatcherServlet context and it works like a charm :)
Add this to your application context file:
<context:property-placeholder location="classpath:fatProperties.properties" />
Try
#Value("#{props['api_key']}")
private String apiKey;
How do I implement AOP with an annotated Controller?
I've search and found two previous posts regarding the problem, but can't seem to get the solutions to work.
posted solution 1
posted solution 2
Here's what I have:
Dispatch Servlet:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.foo.controller"/>
<bean id="fooAspect" class="com.foo.aop.FooAspect" />
<aop:aspectj-autoproxy>
<aop:include name="fooAspect" />
</aop:aspectj-autoproxy>
</beans>
Controller:
#Controller
public class FooController {
#RequestMapping(value="/index.htm", method=RequestMethod.GET)
public String showIndex(Model model){
return "index";
}
}
Aspect:
#Aspect
public class FooAspect {
#Pointcut("#target(org.springframework.stereotype.Controller)")
public void controllerPointcutter() {}
#Pointcut("execution(* *(..))")
public void methodPointcutter() {}
#Before("controllerPointcutter()")
public void beforeMethodInController(JoinPoint jp){
System.out.println("### before controller call...");
}
#AfterReturning("controllerPointcutter() && methodPointcutter() ")
public void afterMethodInController(JoinPoin jp) {
System.out.println("### after returning...");
}
#Before("methodPointcutter()")
public void beforeAnyMethod(JoinPoint jp){
System.out.println("### before any call...");
}
}
The beforeAnyMethod() works for methods NOT in a controller; I cannot get anything to execute on calls to controllers. Am I missing something?
In order to put an aspect on a HandlerMethod in a class annotated with #Controller in Spring 3.1 you need to have the proxy-target-class="true" attribute on the aspectj-autoproxy element. You also need to have the CGLIB and the ASM libraries as a dependency in your WAR/EAR file. You can either specify your annotated aspect class as a bean and use the aop:include as stated above or you can leave the aop:include out and add a filter similar to this in your component scan element:
<context:component-scan>
<context:include-filter type="aspectj"
expression="com.your.aspect.class.Here"/>
</context:component-scan>
I do not know if this is a requirement as a result of Spring 3.1 only but I know that without this, you will not be able to put an aspect on your controller HandlerMethod. You would get an error similar to:
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
HandlerMethod details:
Controller [$Proxy82]
Method [public void com.test.TestController.testMethod(java.security.Principal,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException]
Resolved arguments:
[0] [null]
[1] [type=com.ibm.ws.webcontainer.srt.SRTServletResponse] [value=com.ibm.ws.webcontainer.srt.SRTServletResponse#dcd0dcd]
This is not required if your aspect is on a method in a class that is not a controller
I am going to state an alternative solution (sorry not a direct answer) but what you wanting to do is probably best done via interceptors and filters.