spring httpinvoker client can not find the service url - spring

I have following configuration for the web application.
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:mail-application-context.xml
....
</context-param>
....
<servlet>
<servlet-name>mailbox</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mailbox</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
mailbox-servlet.xml
<bean name="remoteProvisioningServiceImpl" class="pw.domain.service.RemoteProvisioningServiceImpl"/>
<bean name="/remote/domain/provision.htm" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="remoteProvisioningServiceImpl" />
<property name="serviceInterface" value="pw.domain.service.RemoteProvisioningService" />
</bean>
I have the clients configured properly, like following, in mail-application-context.xml
<bean id="remoteProvisioningService1" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://${mailapp.dc.host.1.url}/remote/domain/provision.htm" />
<property name="serviceInterface" value="pw.domain.service.RemoteProvisioningService" />
</bean>
<bean id="remoteProvisioningService2" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://${mailapp.dc.host.2.url}/remote/domain/provision.htm" />
<property name="serviceInterface" value="pw.domain.service.RemoteProvisioningService" />
</bean>
And now... the problem.
On an appropriate event, the clients rightly call service through httpinvoker facility but the response is http-404. In nginx logs, i trace that spring makes a POST call to http://{host}/remote/domain/provision.htm.
Questions :
Do i need to create a separate app-context for httpInvoker bit? i mean, i already have one web context to deal with normal web operations. Do i need to declare {another-context} in web.xml for httpInvoker facility and having the service config. defined in {another-context}-servlet.xml?
If not 1, what is wrong in my configuration?

Got it.. Question 1 above has the answer attached to it. I need to create a separate web context for http-invoking facility to work.
This is because, in my normal webapp context (mailbox), i already have defined SimpleUrlHandlerMapping which maps appropriate urls to controllers. There it doesnt find place for http-invoker-serivce i want to define. When i separated web contexts, it worked like a charm! :D
Happy coding! :)

Related

Spring Interceptors are called twice in mixed configuration (annotation-based and SimpleUrlHandlerMapping)

We have a Spring web application with mixed configuration for Spring 2.x and Spring 3.1 mvc objects. There are same set of interceptors defined by mvc:interceptors tag and SimpleUrlHandlerMapping interceptor property. Our thought was that each handler mapping applies its own interceptors only, but we notice that on Spring 2 urls the interceptors are called twice. When we remove the interceptors from the SimpleUrlHandlerMapping the interceptors are still applied which means mvc:interceptors are effective anyway. Below please see the snippet of configuration:
mvc-config.xml
<mvc:annotation-driven />
<mvc:interceptors>
<ref bean="clientDataInterceptor" />
<ref bean="securityInterceptor" />
<ref bean="resourceCleanupInterceptor" />
</mvc:interceptors>
springdispatcher.xml
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<property name="mappings">
<props>
<prop key="/path/**">myController</prop>
...
</props>
</property>
<property name="interceptors">
<list>
<ref bean="clientDataInterceptor" />
<ref bean="securityInterceptor" />
<ref bean="resourceCleanupInterceptor" />
</list>
</property>
</bean>
web.xml
<servlet>
<servlet-name>springdispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springdispatcher.xml, /WEB-INF/mvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Appreciate any insight why this is happening and if it is safe to simply remove Spring 2.x interceptor list.
You have a handler mapping that matches some URLs (like /path/** in your case). Also, you can have another handler mapping that matches some other URLs (like BeanNameUrlHandlerMapping mapping to bean names or SimpleUrlHandlerMapping). The point is that with your mappings you define associations between URLs and handlers. <mvc:interceptors/> apply to all URLs if no include or exclude patterns are defined.
I looked in the source code here and especially here and if there are no excludePatterns defined then code goes on and checks for includePatterns. If these are null, as well, then the interceptor matches. So, I'm reading this that if I define an interceptor using <mvc:interceptors/> and I'm not giving it any patterns to include or exclude then that interceptor applies to all URLs.

Can't map dispatcherServlet to context root

this is the current configuration i am using for spring mvc:
1- web.xml:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/config/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2- dispatcherServlet.xml:
<context:component-scan base-package="com.app" />
<context:annotation-config />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
3- Controller: my web pages are under webapp folder directly
#Controller
public class SearchController {
private Log log = LogFactory.getLog(getClass());
#RequestMapping("/search.jsp")
public String search(Model model, HttpServletRequest request,
HttpSession session) {
log.debug("Search Controller");
return "search";
}
ISSUE: when trying to access the search page as follows:
http://localhost:8080/MyAPP/search.jsp
the controller is not invoked, but when i was mapping the dispatcher servlet to /mapping/* and accessing the search page as follows:
http://localhost:8080/MyAPP/mapping/search.jsp
the controller was invoked correctly, i am using spring 3.0.5.RELEASE.
please advise, thanks.
I think you are forgetting about the built in default servlet configured in your web server/servlet container. For example in Tomcat7/conf/web.xml there exists:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
which is catching the *.jsp before it ever gets to Spring. I tested this locally by removing all of the Spring configuration and could still get the search.jsp.
How DefaultAnnotationHandlerMapping works should be useful in explaining why this works they way it does.
When you had <url-pattern>/mapping/*</url-pattern> you created a more specific match than the simple / so requests were ignored by the default (i.e. Tomcat) servlet and routed to your correctly configured controller.
One way to fix this is to force everything through your servlet by using <url-pattern>/*</url-pattern> but you will also need to make a few other changes to avoid mapping resolution problems.
I moved the *.jsp files into the (standard?) subdirectory /WEB-INF and added
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/*</url-pattern>
</servlet-mapping>
to web.xml and changed dispatcherServlet.xml to match like so:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
If you do not make these changes, a request to /search.jsp would be resolved by the InternalResourceViewResolver you configured to /search.jsp sending Tomcat into an infinite forwarding loop!
No mapping found for HTTP request with URI [/WEB-INF/pages/apiForm.jsp] may be useful here.
Aside: For most of my Spring XML configured projects I use /WEB-INF/views to keep the view layer separate from any configuration in the /WEB-INF root.
The following mapping will cause the dispatcher servlet to handle urls that were not explicitly mapped by other url mappings within web.xml. Think of this as almost a catch all mapping, as long as the url was not handled by some other mapping.
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
When you configure the ViewResolver as follows:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
The ViewMapping must point to a JSP within your project or else the catch all mapping provided for the dispatcher is going to attempt to handle the forward/redirect to the appropriate view. You must make sure that a view exists within your project for the result of the viewresolver, which is /search.jsp. This means there must be a search.jsp within the root of your projects web content folder. It is much more common to see these views placed within the WEB-INF folder and a mapping of:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>

How do I catch Spring errors when starting up a Tomcat webapp?

I have a webapp running in Tomcat which uses Spring for dependency injection. (It's a GWT application, but I don't think that makes much of a difference to the solution I'm looking for.)
My web.xml file is of the following format:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>dispatch</servlet-name>
<servlet-class>com.example.my.gwt.dispatch.DispatchServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatch</servlet-name>
<url-pattern>/my_gwt/dispatch</url-pattern>
</servlet-mapping>
... more servlets ...
</web-app>
One of the things my Spring configuration does is to connect to a databse via Hibernate:
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url"
value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="databaseSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="packagesToScan">
<array>
<value>com.example.my.gwt.model</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
If the database is unavailable, this causes an org.h2.jdbc.JdbcSQLException to be thrown, so the Spring initialisation does not continue, so the rest of the webapp cannot be used. Navigating to the webapp's URL gives an HTTP 503 'Service Unavailable' error.
What I want to do is to catch that error and display a page to the user (when they first navigate to the app) explaining what the problem is likely to be and suggested fixes. How can I do this?
I have tried using a custom ContextLoaderListener class that delegates to the one in the XML above, but catches any exceptions. This allows me to catch the exception, but there is not much I can do - the web.xml is still pointing the user's request to a servlet that is not running after the Spring initialisation has failed. Is there any way that I can change the webapp config when I catch that exception, so that it doesn't try to load the servlets from the web.xml and perhaps changes the welcome file to point to a page about the error? Or is there any other way that I can make the webapp gracefully handle this exception?
Thanks
Basically you're asking if you can have a functioning web application after the web application fails to start up.
You could try configuring a 503 handler page and/or have a welcome page, not dependent on Spring, that checks for something in the application context that's set only on a good spin up. If it didn't spin up, the exception you've already captured could be placed into the app context.
Not sure if anything in the app, even web.xml-only resources, if Spring doesn't spin up, though.
You could add a Servlet Filter to your web app that would intercept all the requests to the Spring servlet and forward to your custom error page if the Spring initialization has failed.

Spring MVC Tiles - Not picking up resource folder

I need to change mapping for my spring servlet to point to /sample vs. /sample.html.
I made a change in the url pattern to the following. The urlPattern is
<url-pattern>*.html</url-pattern>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Once this change is made, none of the style sheets reference in a folder are picking up. I thought this was because DispatcherServlet was trying to read this. When I try the following to my servlet-context.xml file, NOTHING works.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
p:basename="views" />
<context:component-scan base-package="*****" />
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
p:definitions="/WEB-INF/tiles-defs.xml" />
<mvc:resources mapping="/_res/**" location="/_res/"/>
I thought maybe I needed to add another view resolver, but that doesn't make any difference.
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
Any help would be greatly appreciated. It seems no matter what I do I get a 404 Error.
The resourses are accessed througt the spring dispatcher. So you need to make sure that the requests are delegated to the spring dispatcher sevlet in the web.xml.
You must delegate all requests to the dispatcher, not only html, but also css, images,...

Faces conversion service is not found for converting 'dataModel'

While creating my first swf application with JSF integration, I get the following error : Unable to load class 'dataModel' when parsing my flow definition on the first request.
It appears that the FacesConversionService (the class that understands the 'dataModel' alias) is not invoked while trying to find a class for that alias, although my webflow application context contains the <faces:flow-builder-services/> tag in it.
Doing some debug while trying to find out the cause, I noticed the following:
the xml file containing <faces:flow-builder-services/> is loaded by the context loader listener, and the facesConversionService bean is registered
the flow handler mapping and adapter are correctly invoked and the request is forwarded to the expected flow, which definition is created on the fly.
while creating internal infrastructure objects for the flow, swf creates a web application context on top of the app context loaded by the listener. This new wac contains the definitions for the swf scopes, etc, and has the listener's application context from above as parent.
the flow definition file for my flow is found and parsed, and when it tries to find the class for the result type of an evaluate element, the conversion service does not know about the 'dataModel' alias.
Actually, the funny thing on the last point is that the conversion service is either looked up as a local bean in the application context created on point 3. above, or -if not found- looked up in the parent flow builder context.
The faces conversion service is neither a local bean of the context (it is registered in the parent context of the flow context), nor is it registered as the conversion service of the flow builder context (at least the FlowBuilderContextImpl that is created by the <flow:flow-registry/> element).
Does anybody know what went wrong ?
I don't think it's related to the application server, but just in case, I'm running on websphere 6.1.0.23, with spring 2.5.6 and webflow 2.0.8.RELEASE.
Here are my configuration files:
web.xml:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-*.xml</param-value>
</context-param>
...
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/swf/*</url-pattern>
</servlet-mapping>
Beans definitions for the MVC part (/WEB-INF/applicationContext-webmvc.xml):
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
<bean id="faceletsViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jspx" />
</bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
Beans definitions for the swf part (/WEB-INF/applicationContext-webflow.xml):
<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows">
<flow:flow-location path="/navigation/navigation.xml"/>
<flow:flow-location path="/edition/edition.xml"/>
</flow:flow-registry>
<flow:flow-executor id="flowExecutor">
<flow:flow-execution-listeners>
<flow:listener ref="jpaFlowExecutionListener" criteria="edition"/>
</flow:flow-execution-listeners>
</flow:flow-executor>
<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>
<bean id="jpaFlowExecutionListener"
class="org.springframework...JpaFlowExecutionListener">
<constructor-arg ref="entityManagerFactory" />
<constructor-arg ref="transactionManager" />
</bean>
The stack trace for the exception:
[Servlet Error]-[Spring MVC Dispatcher Servlet]: java.lang.IllegalArgumentException: Unable to load class 'dataModel'
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.toClass(FlowModelFlowBuilder.java:965)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseEvaluationActionResultExposer(FlowModelFlowBuilder.java:867)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseEvaluateAction(FlowModelFlowBuilder.java:858)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseActions(FlowModelFlowBuilder.java:834)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseAndAddViewState(FlowModelFlowBuilder.java:547)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.buildStates(FlowModelFlowBuilder.java:207)
at org.springframework.webflow.engine.builder.FlowAssembler.directAssembly(FlowAssembler.java:106)
at org.springframework.webflow.engine.builder.FlowAssembler.assembleFlow(FlowAssembler.java:91)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.assembleFlow(DefaultFlowHolder.java:109)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.getFlowDefinition(DefaultFlowHolder.java:84)
at org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl.getFlowDefinition(FlowDefinitionRegistryImpl.java:61)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:138)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:193)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:743)
I forgot to specify the flow-builder-services attribute on flow:flow-registry element !!! Works perfectly now.
<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows" flow-builder-services="facesFlowBuilderServices">
<flow:flow-location path="/navigation/navigation.xml"/>
<flow:flow-location path="/edition/edition.xml"/>
</flow:flow-registry>
<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>
I had the same problem but it was because I was specifying my own conversion service which extended DefaultConversionService rather than FacesConversionService.

Resources