OSGi Http Whiteboard pattern - java

Moving from web.xml to OSGi Http Whiteboard pattern created bundle-context.xml
how to pass below properties from web.xml in jspServletfilter's osgi:service-properties
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>
I tried below solution but it does not work.
<bean id="jspServlet" class="com.test.servlet.web.servlet.TestJSPServlet"/>
<osgi:service ref="jspServlet" interface="javax.servlet.Servlet" >
<osgi:service-properties>
<entry key="osgi.http.whiteboard.filter.name" value="JSPServlet" />
<entry key="osgi.http.whiteboard.servlet.pattern" value-ref="jspPatternsList"/>
<entry key="osgi.http.whiteboard.context.select" value="(osgi.http.whiteboard.context.name=cb)" />
<entry key="servlet.init.el-ignored" value="true" />
</osgi:service-properties>
</osgi:service>

I just checked one more time, but if I'm not completely wrong the OSGi spec doesn't handle JSPs in a certain way. So what you are trying to do there doesn't work with the Apache Felix implementation.
The only way to have JSPs working with the Http Whiteboard approach is to switch to the Pax - Web Project. As it not only supports the Whiteboard approach (spec compliance is still work in progress, 6.0.0-SNAPSHOT) but also more then there is in the spec right now.
To achieve what you want the following is needed with Pax-Web:
<!-- JSP handling -->
<service id="jspMapping" interface="org.ops4j.pax.web.extender.whiteboard.JspMapping">
<bean class="org.ops4j.pax.web.extender.whiteboard.runtime.DefaultJspMapping">
<property name="urlPatterns">
<array>
<value>/jsp</value>
</array>
</property>
</bean>
</service>
an example can also be found in the samples of the pax-web project.

Related

Conditionally including beans in XML ArrayList

I was wondering if it's possible to somehow conditionally include spring beans depending on some property.
In my applicationContext.xml I have a list of beans that I setup:
<bean id="server1Config" class="... />
<bean id="server2Config" class="... />
<bean id="server3Config" class="... />
...
Then I include them in a list:
<bean class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="server1Config"/>
<ref bean="server2Config"/>
<ref bean="server3Config"/>
...
</list>
</constructor-arg>
</bean>
I want to conditionally include server1Config, server2Config, server3Config, etc depending on whether ${includeServer1} == true, ${includeServer2} == true etc and if possible, only initialize those beans if they are marked for inclusion.
To clarify, it's a ping service checking if servers are online or not, each bean contains special urls. If I have 5 servers running, I'd like to set in my config includeServer1=true ... includeServer5=true ... includeServer6=false, if I shutdown server2, I'd like to change includeServer2=false before shutting down the server to not get bombarded with SMSe telling me server2 is offline.
As your names refer to different stages or enviroments, spring profiles might be helpful to use. You can define beans like this inside your context.xml
<beans profile="dev">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
In the example [1] you see the usage of two profiles called "dev" and "production".
Spring will always load every bean without a profile
Depending on the profiles (yes, you can load multiple profiles at once) all the related beans will be loaded
Loading a profile in Java:
ctx.getEnvironment().setActiveProfiles("dev");
Loading two profiles
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
Loading from CMD Line declaratively:
-Dspring.profiles.active="profile1,profile2"
Usage in web.xml (can be comma-separated)
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>
#Comment: If you want to do it using properties and you are able to use newer spring elements, annotations etc. please have a look at this tutorial [2] to make it work with properties file as you commented below.
[1] http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
[2] http://kielczewski.eu/2013/11/setting-active-profile-and-property-sources-in-spring-mvc/
This is almost an add-on to #swinkler's answer.
He gave the first part of the solution which is usage of Spring 3.1+ profiles.
The second part would be to use a kind of automatic registration :
<bean class="java.util.ArrayList" id="serverConfigList"/>
<beans profile="server1">
<bean id="server1Config" class="... />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="serverConfigList"/></property>
<property name="targetMethod"><value>add</value></property>
<property name="arguments"><ref local="server1Config/></property>
</bean>
</beans>
That way you create an empy list and only add relevant configs to it.
Your code shouldn't change based on environment. If your aim is to use different settings for each environment then load them as properties at start up.
Refer this for 'external configuration'
This can be done in Spring framework 3.1 onwards using a built in Spring environment profiles.
Here's a few resources:
http://java.dzone.com/articles/spring-31-environment-profiles
Hope this helps.

Spring 4.1 MVC + Hibernate 4.3 + Webflow 2.4 + OpenSessionInViewFilter = java.lang.IllegalStateException, Already value for key bound to thread

I am upgrading an application from these component versions to their latest counterparts:
Spring 3.0.4 -> Spring 4.1.6
Hibernate 3.3.0 -> Hibernate 4.3.8
Spring Webflow 2.0.7 -> Spring Webflow 2.4.1
Spring Security 2.0.4 -> Spring Security 3.2.6
I am currently very stuck on a problem related the OpenSessionInViewFilter and Spring Webflows. None of the code pertaining to my webflow is even executed, the problem occurs upon initialization of the webflow and Hibernate SessionHolder. I have not changed the webflow configuration during this Spring/Hibernate upgrade and everything has been working fine in production for almost 6 years. I am getting the following exception for which there is little help available on the web. The stack trace is a mile long, so I am including what I think are the important parts.
2015/04/06 18:39:31 ERROR exception_jsp Stack Trace -
org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'null' of flow 'process/order'
at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:573)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:227)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:238)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
...
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at
...
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at
...
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Already value [org.springframework.orm.hibernate4.SessionHolder#30b921ac] for key [org.hibernate.internal.SessionFactoryImpl#486fe7cb] bound to thread [http-nio-8080-exec-8]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:190)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.bind(HibernateFlowExecutionListener.java:250)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.sessionStarting(HibernateFlowExecutionListener.java:137)
at org.springframework.webflow.engine.impl.FlowExecutionListeners.fireSessionStarting(FlowExecutionListeners.java:117)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:367)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:223)
... 76 more
Pertinent parts of web.xml:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
Pertinent parts of Application Context configuration:
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0"/>
<property name="flowRegistry" ref="flowRegistry"/>
</bean>
<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
...
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>
...
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="flowExecutionListener" />
<webflow:listener ref="securityFlowExecutionListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
...
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
Webflow configuration file:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.4.xsd">
<persistence-context/>
<on-start>
<evaluate expression="orderFormFactory.createOrderForm(externalContext.sessionMap.inboxCriteria)" result="flowScope.orderForm"/>
</on-start>
...
It seems that the OpenSessionInViewFilter is creating the Hibernate Session first, then the HibernateFlowExecutionListener is attempting to create one rather than using the one created by the OpenSessionInViewFilter thus causing the "Already value [org.springframework.orm.hibernate4.SessionHolder#xxxxxxxx] for key [org.hibernate.internal.SessionFactoryImpl#xxxxxxxx] bound to thread [xxxxxxxxxxxxxxx]" error.
Any ideas on what I can tweak or further delve into for troubleshooting? Any solutions or workarounds? Anyone else seen this? Thank you for the help!
My solution to this was to split out my Web Flows from being handled by the OpenSessionInViewFilter. Before I made the change, all URLs in the app that ended in *.htm were routed through the OpenSessionInViewFilter. This was my web.xml before the changes:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
Now my web.xml has this configuration:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.somepackage.MyCustomOpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
<url-pattern>*.flow</url-pattern>
</filter-mapping>
Notice that I added a new *.flow url-pattern to my filter-mapping for the openSessionInViewFilter and I now have a custom class that overrides the Spring OpenSessionInViewFilter (more on that below). I then had to change the URL suffix of the places in my views (and controllers in a few cases) where I invoked webflows from using '.htm' to using '.flow'.
So, for example, if I had previously used webflow url of '/customer/customer-add.htm', I changed it to '/customer/customer-add.flow'.
The next piece is that I added a class derived from Spring's OpenSessionInViewFilter whose purpose was to pass all *.htm URLs to the OpenSessionInViewFilter while simply forwarding all *.flow URLs to the next filter in the chain (thereby allowing the HibernateFlowExecutionListener to eventually handle the URL and manage the session properly):
package org.somepackage;
import javax.servlet.http.HttpServletRequest;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
public class MyCustomOpenSessionInViewFilter extends OpenSessionInViewFilter {
#Override
public boolean shouldNotFilter( HttpServletRequest request ) {
return request.getRequestURI().contains( ".flow" );
}
}
Finally, please note that you should leave the Spring configuration you already have for the HibernateFlowExecutionListener alone -- no changes required there:
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>

Spring web flow: the flow XMLs are not being registered

I am using spring webflow and I have registered all the flow xmls in the webflow.xml like this
<!-- The Flow handler adapter, to handle flows request recieved by the dispatcher servlet -->
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
<flow:flow-registry id="myflowRegistry" flow-builder-services="flowBuilderServices" >
<!-- all xml files in base path and subfolders -->
<flow:flow-location path="/WEB-INF/flows/payslips.xml" />
<flow:flow-location path="/WEB-INF/flows/admissions.xml" />
<flow:flow-location id="cash-advance" path="/WEB-INF/flows/cashadvance.xml"/>
<flow:flow-location path="/WEB-INF/flows/services.xml" />
<flow:flow-location path="/WEB-INF/flows/undergradadm.xml" />
</flow:flow-registry>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0" />
<property name="flowRegistry" ref="myflowRegistry" />
</bean>
Now when I tr to access any of these pages with payslips.go or cash-advance.go they dont work and give me :
Error 500: Request processing failed; nested exception is java.lang.StringIndexOutOfBoundsException: String index out of range: 1
I am very new to webflow and It seems logical that it should work. The views in the spring MVC that are not part of the webflow or dont have any xmls defined under flow work perfectly fine because it has nothing to do with webflow. but these pages which have a flow defined. I dont think mozilla has anything to do with it.
On some other machine, these are working fine. there must be something with my own setup that its not letting it work.
May be this will help as well
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.String.substring(String.java:1060)
at org.springframework.webflow.context.servlet.DefaultFlowUrlHandler.getFlowId(DefaultFlowUrlHandler.java:83)
at org.springframework.webflow.mvc.servlet.FlowHandlerMapping.getHandlerInternal(FlowHandlerMapping.java:92)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:184)
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1057)
Thanks
This is how I am configuring SWF:
<!--
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SPRING WEB FLOW'S CONFIGURATION
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
<!-- Creates a flow executor in Spring, responsible for creating and executing flows -->
<flow:flow-executor id="flowExecutor" flow-registry="flowRegistry" />
<!-- Load flow definitions and make them available to the flow executor -->
<flow:flow-registry id="flowRegistry">
<flow:flow-location id="process-flow" path="/process/flows/process-flow.xml" />
</flow:flow-registry>
<!-- The FlowHandlerMapping helps DispatcherServlet to knowing that it should send flow requests to Spring Web Flow -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
</bean>
<!-- The FlowHandlerAdapter is equivalent to a Spring MVC controller in that it handles requests coming in for a flow and processes those requests -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
My flow is in the root of my web folder, but you can also use the WEB-INF dir; this way, the path should be "/WEB-INF/foo/bar.xml/".
I hope it helps, regards.

Is there a built-in Spring environment variable for the web context root?

I'm using Spring Web Services to expose a service as a web service. In my spring configuration xml file, I have a bean which is an instance of DefaultWsdl11Definition. One of the properties that needs to be set is the locationUri. This needs to be a fully qualified Uri, but I don't want to have to change this value when the application gets promoted from dev to uat and to production. Spring knows what the web application context root is, so is there a variable that I can specify in my configuration file to access it?
Something like:
<bean id="myWebServices"
class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schemaCollection">
<bean
class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="xsds" ref="xsdList"/>
<property name="inline" value="true" />
</bean>
</property>
<property name="portTypeName" value="myWebServices" />
<property name="locationUri" value="${webContextRoot}/webServices" />
</bean>
With Spring 3.0, you should be able to access the servlet context through the servletContext bean in the web application context:
<property name="locationUri" value="#{servletContext.contextPath}/webServices" />
If you're using pre-Spring-EL (before 3.0), you should be able to do
<bean name="servletContextBean" class="org.springframework.web.context.support.ServletContextFactoryBean" />
<bean name="contextPath" factory-bean="servletContextBean" factory-method="getContextPath" />
<bean name="locationUri" factory-bean="contextPath" factory-method="concat">
<constructor-arg value="/webServices" />
</bean>
and inside your myWebservices bean
<property name="locationUri" ref="locationUri" />
EDIT:
I don't think getting the server name and port from the ServletContext, as depending on the setup the web container may not know the hostname (i.e. a HTTP server may be in front of the web container, e.g. tomcat may be behind an Apache web server or depending on the Websphere configuration).
However, the following may be part of a solution to get the hostname. With Spring 3.0, you could do the following:
<property name="host"
class="java.net.InetAddress"
factory-method="getLocalHost"/>
<property name="locationUri"
value="http://#{host.canonicalHostName}:8080/#{servletContext.contextPath}/webServices" />
I had a similar problem that you described, I use property files to do this
ws_dev.properties
ws_prod.properties
I configured my property file like this, The deployment property is java vm argument like
-Ddeployment=dev
<context:property-placeholder location="ws_${deployment}.properties"/>
May be late, but may some other need a solution too:
set property in servlet:
web.xml
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring-ws-context.xml</param-value>
</init-param>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
The bean declaration in spring-ws-context.xml:
<bean id="WebService"
class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"
p:portTypeName="App" p:locationUri="/WebServices" p:requestSuffix="Request"
p:responseSuffix="Response">
<property name="schema">
<bean class="org.springframework.xml.xsd.SimpleXsdSchema" p:xsd="classpath:/requestTypes.xsd" />
</property>
</bean>
You can add ApplicationContextAware interface to your bean, cast it to WebApplicationContext and then get ServletContext. Also see class org.springframework.web.context.ContextLoader

Spring - Rewrite one URL to another

I have a Spring 2.5 application that contains a Flash banner. I don't have the source for the Flash component but it has links hardcoded to certain pages that end in .html I want to be able to redirect those .html pages to existing jsp pages. How can I have Spring resolve a few .html pages to .jsp pages?
My project looks like:
WebContent
|
-sample.jsp
-another.jsp
WEB-INF
|
-myapp-servlet.xml
-web.xml
I want localhost:8080/offers.html to redirect to localhost:8080/sample.jsp
Can I do this with Spring? I already have a SimpleUrlHandlerMapping and UrlFilenameViewController defined in the myapp-servlet.xml that has to continue serving the pages it already is.
In my web.xml, I have
<servlet-mapping>
<servlet-name>myapp</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Update
Here is the URL mapper. If I add a controller, how do I return the jsp view that is in the WebContent directory as the view resolver includes the /WEB-INF/jsp directory.
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/page1.htm">page1Controller</prop>
<prop key="/page2.htm">page2Controller</prop>
</props>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
I think you could benefit from the open source URL Rewriting library made by tuckey.org. The guys at SpringSource endorse this library, since it is set up for you automatically if you use Spring Roo to create a project, so it is of good quality. I have used it successfully in a number of projects.
See here for its homepage. And Skaffman is right, you want it to 'forward' instead of redirect, which is the default behaviour.
Configure it in web.xml like this:
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
Then, in WEB-INF/urlrewrite.xml have an element like this:
<rule>
<from>offers.html</from>
<to>offers.jsp</to>
</rule>
I would use OCPsoft PrettyFaces or OCPsoft Rewrite for this:
With PrettyFaces:
create WEB-INF/pretty-config.xml
<url-mapping>
<pattern value="/offers.html" />
<view-id value="/offers.jsp" />
</url-mapping>
With Rewrite:
ConfigurationBuilder.begin()
.addRule(Join.path("/offers.html").to("/offers.jsp"));
I hope this helps.
~Lincoln
Firstly, I'm assuming that when you say "redirect", you really mean "forward". HTTP Redirects would not be appropriate here.
SO given that, here are some things to try:
Can't you just move the JSP files from WebContent into /WEB-INF/jsp/? You wouldn't have to change the ViewResolver definition, then.
You could try to have the controllers return a view name of something like ../../another.jsp, and hope that the servlet container resolves to /WEB-INF/jsp/../../another.jsp to /another.jsp.
The ViewResolver is only consulted if the controllers return the name of a view. Your controllers don't have to return the name of a view, they can return a View object directly, in this case a JstlView. This can point to whichever JSP you like. You can some controllers returning view names, and some returning View objects.
Remove the prefix property from your view resolver. This means you'd also have to change every existing controller, to prefix every view name they return with /WEB-INF/jsp/. Then you could refer to the JSPs under WebContent by name.

Categories

Resources