I am trying to load spring dm in my OSGi bundle. I have followed a tutorial. My aim is, for a particular URL, the URL should be processed by spring instead of default sling servlet. I am partly successful in achieving the same.
Sometimes, It doesn't work. My globaldispatcher servlet is not being initialized. The issue is intermittent. Some times my spring servlet gets initialized just fine. But some times I get this error :
[SpringOsgiExtenderThread-2] net.jasonday.examples.sling.spring.mvc.sling.SlingDispatcherServlet FrameworkServlet 'globaldispatcher': initialization started
[SpringOsgiExtenderThread-2] net.jasonday.examples.sling.spring.mvc.sling.SlingDispatcherServlet Context initialization failed
java.lang.IllegalArgumentException: bundle context should be set before refreshing the application context
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.normalRefresh(AbstractDelegatedExecutionApplicationContext.java:179)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext$NoDependenciesWaitRefreshExecutor.refresh(AbstractDelegatedExecutionApplicationContext.java:89)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:175)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:467)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:483)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:358)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:325)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.sling.servlets.resolver.internal.SlingServletResolver.createServlet(SlingServletResolver.java:988)
at org.apache.sling.servlets.resolver.internal.SlingServletResolver.bindServlet(SlingServletResolver.java:936)
at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
Java version : 1.7.0_45
I am using following dependencies as mentioned in tutorial: (All are OSGi bundles)
Spring AOP v3.0.6.RELEASE
Spring ASM v3.0.6.RELEASE
Spring Aspects v3.0.6.RELEASE
Spring Beans v3.0.6.RELEASE
Spring Context v3.0.6.RELEASE
Spring Context Support v3.0.6.RELEASE
Spring Core v3.0.6.RELEASE
Spring Expression v3.0.6.RELEASE
Spring Web v3.0.6.RELEASE
Spring Web Servlet v3.0.6.RELEASE
Spring OSGi IO v1.2.1
Spring OSGi Core v1.2.1
Spring OSGi Extender v1.2.1
Spring OSGi Annotation v1.2.1
Spring OSGi Web v1.2.1
AOP Alliance v1.0.0
CGLib 2.2.0
Commons Lang v2.6
Commons Codec v1.5
Commons Logging v1.1.1
ASM v3.2.0
JSR 330 (javax.inject) v1.0.0
JSR 250 (javax.annotation) v1.0.0
Following is the code from my spring-osgi.xml which is present in META-INF/spring/ folder
<osgi:service ref="globalSlingDispatcherServlet">
<osgi:interfaces>
<value>javax.servlet.Servlet</value>
</osgi:interfaces>
<osgi:service-properties>
<entry key="sling.servlet.resourceTypes" value="examples/sling/spring/mvc/dispatcher/global" />
<entry key="sling.servlet.extensions">
<array>
<value>json</value>
<value>html</value>
</array>
</entry>
<entry key="sling.servlet.methods">
<array>
<value>GET</value>
<value>POST</value>
</array>
</entry>
<entry key="contextClass" value="org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext"/>
<entry key="sling.core.servletName" value="globaldispatcher" />
</osgi:service-properties>
Below is the code from META-INF\spring\spring.xml
<context:annotation-config />
<context:component-scan base-package="net.jasonday.examples.sling.spring.mvc.sling" />
<aop:aspectj-autoproxy />
<bean class="org.springframework.osgi.extensions.annotation.ServiceReferenceInjectionBeanPostProcessor" />
Following is the code from WEB-INF/globaldispatcher
<context:annotation-config />
<context:component-scan base-package="net.jasonday.examples.sling.spring.mvc">
<context:exclude-filter type="regex"
expression="net\.jasonday\.examples\.sling\.spring\.mvc\.sling\..*" />
</context:component-scan>
<aop:aspectj-autoproxy />
<bean class="org.springframework.osgi.extensions.annotation.ServiceReferenceInjectionBeanPostProcessor" />
SlingConfiguration.java :
#Configuration
public class SlingConfiguration {
#Bean
#DependsOn("slingContextLoader")
public SlingDispatcherServlet globalSlingDispatcherServlet() {
return new SlingDispatcherServlet();
}
}
SlingContextLoader.java :
#Component
public class SlingContextLoader extends ContextLoader {
private ServletContext servletContext;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
#Inject
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public ServletContext getServletContext() {
return servletContext;
}
#ServiceReference
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
#Override
protected Class<?> determineContextClass(
ServletContext currentServletContext) {
return OsgiBundleXmlWebApplicationContext.class;
}
#Override
protected ApplicationContext loadParentContext(
ServletContext currentServletContext) {
return applicationContext;
}
#PostConstruct
public void init() {
initWebApplicationContext(servletContext);
}
#PreDestroy
public void destroy() {
closeWebApplicationContext(servletContext);
}
}
My SlingDispatcherServlet.java
public class SlingDispatcherServlet extends DispatcherServlet implements Servlet {
#PreDestroy
#Override
public void destroy() {
super.destroy();
String attrName = getServletContextAttributeName();
getServletContext().removeAttribute(attrName);
}
}
This issue is being caused because the Spring annotations like #PostConstruct are not working as expected some times because of OSGi class loading issues.
Hence a workaround would be to not to rely on annotations. The below code solved the issue for me.
I am calling init() method manually in setServletContext() in SlingContextLoader
#ServiceReference
public void setServletContext(ServletContext servletContext) {
log.info("in setServletContext");
this.servletContext = servletContext;
init();
}
in init() method I am adding following code :
//#PostConstruct
public void init() {
log.info("in init");
//Remove existing application context if any
if (servletContext
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
log.info("removing existing application context to create new one");
closeWebApplicationContext(servletContext);
}
initWebApplicationContext(servletContext);
}
I am trying to integrate test a Spring Controller method that uses a spring session scoped bean which is injected into the controller. In order for my test to pass I must be able to access my session bean to set some values on it before I make my mock call to this controller method. Issue is a new session bean is created when I make the call instead of using the one I pulled of the mock application context. How can I make my controller use the same UserSession bean?
Here is my test case
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("src/main/webapp")
#ContextConfiguration({"file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml"})
public class RoleControllerIntegrationTest {
#Autowired
private WebApplicationContext wac;
protected MockMvc mockMvc;
protected MockHttpSession mockSession;
#BeforeClass
public static void setupClass(){
System.setProperty("runtime.environment","TEST");
System.setProperty("com.example.UseSharedLocal","true");
System.setProperty("com.example.OverridePath","src\\test\\resources\\properties");
System.setProperty("JBHSECUREDIR","C:\\ProgramData\\JBHSecure");
}
#Before
public void setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
mockSession = new MockHttpSession(wac.getServletContext(), UUID.randomUUID().toString());
mockSession.setAttribute("jbhSecurityUserId", "TESTUSER");
}
#Test
public void testSaveUserRole() throws Exception {
UserSession userSession = wac.getBean(UserSession.class);
userSession.setUserType(UserType.EMPLOYEE);
userSession.setAuthorizationLevel(3);
Role saveRole = RoleBuilder.buildDefaultRole();
Gson gson = new Gson();
String json = gson.toJson(saveRole);
MvcResult result = this.mockMvc.perform(
post("/role/save")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.session(mockSession))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = result.getResponse();
}
Here is my controller method I am needing tested
#Resource(name="userSession")
private UserSession userSession;
#RequestMapping(method = RequestMethod.POST, value = "/save")
public #ResponseBody ServiceResponse<Role> saveRole(#RequestBody Role role,HttpSession session){
if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3){
try {
RoleDTO savedRole = roleService.saveRole(role,ComFunc.getUserId(session));
CompanyDTO company = userSession.getCurrentCompany();
It is not passing this line because the UserSession Object is not the same
if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3){
This is the declaration of my user session bean.
#Component("userSession")
#Scope(value="session",proxyMode= ScopedProxyMode.INTERFACES)
public class UserSessionImpl implements UserSession, Serializable {
private static final long serialVersionUID = 1L;
Both controlle and bean are created using component scan in my applicationContext.xml
<context:annotation-config />
<!-- Activates various annotations to be detected in bean classes -->
<context:component-scan
base-package="
com.example.app.externalusersecurity.bean,
com.example.app.externalusersecurity.service,
com.example.app.externalusersecurity.wsc"/>
<mvc:annotation-driven />
Add the following bean configuration, which adds a session context for each thread
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="session">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
An equivalent in Java's configuration class would the following bean declaration
#Bean
public CustomScopeConfigurer scopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
Map<String, Object> workflowScope = new HashMap<String, Object>();
workflowScope.put("session", new SimpleThreadScope());
configurer.setScopes(workflowScope);
return configurer;
}
For more details, see
http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-custom-using
Using different Bean definition profiles for test and production worked for me - here's how a XML based setup could look like:
<beans profile="production">
<bean id="userSession" class="UserSessionImpl" scope="session" >
<aop:scoped-proxy/>
</bean>
</beans>
<beans profile="test">
<bean id="userSession" class="UserSessionImpl" >
</bean>
</beans>
To use the test profile for your test, add #ActiveProfiles to your test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("src/main/webapp")
#ContextConfiguration({"file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml"})
#ActiveProfiles(profiles = {"test"})
public class RoleControllerIntegrationTest {
[...]
Trying to figure out what the equivalent #Bean configuration would be for the XML element
<mvc:view-controller path="..." />
Thanks!
An example of forwarding a request for "/" to a view called "home" in Java:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
And the same in XML use the element:
<mvc:view-controller path="/" view-name="home"/>
The above example was copied from the Spring reference docs
What is the recommended way to add Spring Security to a web application that is using Spring's new WebApplicationInitializer interface instead of the web.xml file? I'm looking for the equivalent of:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
UPDATE
The provided answers are reasonable but they both assume that I've got a servletContext instance. I've looked through the hierarchy of WebApplicationInitializers and I don't see any access to the servlet context unless I choose to override one of Spring's initializer methods. AbstractDispatcherServletInitializer.registerServletFilter seems like the sensible choice but it doesn't default to URL pattern mapping and I'd hate to change filter registration for everything if there is a better way.
This is the way that I have done it:
container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
container is an instance of ServletContext
The Spring Security Reference answers this question and the solution depends on whether or not you are using Spring Security in conjunction with Spring or Spring MVC.
Using Spring Security without Spring or Spring MVC
If you are not using Spring Security with Spring or Spring MVC (i.e. you do not have an existing WebApplicationInitializer) then you need to provide the following additional class:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
Where SecurityConfig is your Spring Security Java configuration class.
Using Spring Security with Spring or Spring MVC
If you are using Spring Security with Spring or Spring MVC (i.e. you have an existing WebApplicationInitializer) then firstly you need to provide the following additional class:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Then you need to ensure that your Spring Security Java configuration class, SecurityConfig in this example, is declared in your existing Spring or Spring MVC WebApplicationInitializer. For example:
import org.springframework.web.servlet.support.*;
public class MvcWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SecurityConfig.class};
}
// ... other overrides ...
}
Dynamic securityFilter = servletContext.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
EnumSet.allOf(DispatcherType.class) to be sure that you add a mapping not only for default DispatcherType.REQUEST, but for DispatcherType.FORWARD, etc...
After a bit of work, I've discovered that it's actually quite simple:
public class Initialiser extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
#Override
protected Class< ? >[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
#Override
protected Class< ? >[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
return new Filter[] { new DelegatingFilterProxy("springSecurityFilterChain") };
}
}
The most important thing, though, is that you must have a root context (e.g. RootConfig in this case), and that must contain a reference to all the spring security information.
Thus, my RootConfig class:
#ImportResource("classpath:spring/securityContext.xml")
#ComponentScan({ "com.example.authentication", "com.example.config" })
#Configuration
public class RootConfig {
#Bean
public DatabaseService databaseService() {
return new DefaultDatabaseService();
}
#Bean
public ExceptionMappingAuthenticationFailureHandler authExceptionMapping() {
final ExceptionMappingAuthenticationFailureHandler emafh = new ExceptionMappingAuthenticationFailureHandler();
emafh.setDefaultFailureUrl("/loginFailed");
final Map<String, String> mappings = new HashMap<>();
mappings.put(CredentialsExpiredException.class.getCanonicalName(), "/change_password");
emafh.setExceptionMappings(mappings);
return emafh;
}
}
And spring/securityContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:noNamespaceSchemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<security:http security="none" pattern="/favicon.ico"/>
<!-- Secured pages -->
<security:http use-expressions="true">
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login default-target-url="/index" login-processing-url="/login_form" login-page="/login" authentication-failure-handler-ref="authExceptionMapping" />
</security:http>
<security:authentication-manager>
<security:authentication-provider ref="customAuthProvider" />
</security:authentication-manager>
</beans>
I could not get it to work if I merged the RootConfig and WebAppConfig classes into just WebAppConfig and had the following:
#Override
protected Class< ? >[] getRootConfigClasses() {
return null;
}
#Override
protected Class< ? >[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
public class SIServerSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
Dynamic registration = servletContext.addFilter("TenantServletFilter", TenantServletFilter.class);
EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
}
}
This scenario is for executing a filter before executing other filters.
If you want to execute a filter after other filers pass true in registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");. Also check the DispatcherType ASYNC, FORWARD etc.
Faced with the same problem. Merge RootConfig and WebAppConfig - not best way - because this i did not try this solution. Tried all other solutions - everty time got "org.apache.catalina.core.StandardContext.startInternal Error filterStart". After some work, got something like this:
FilterRegistration.Dynamic enc= servletContext.addFilter("encodingFilter",
new CharacterEncodingFilter());
encodingFilter .setInitParameter("encoding", "UTF-8");
encodingFilter .setInitParameter("forceEncoding", "true");
encodingFilter .addMappingForUrlPatterns(null, true, "/*");
But is not working with DelegatingFilterProxy(). Continue finding for best common solution for all filters.
UPDATE:
I did it.
So, the main issue is: if you want add filters using java config, especially if you want to add security filter, such as DelegatingFilterProxy, then you have to create WebAppSecurityConfig:
#Configuration
#EnableWebSecurity
#ImportResource("classpath:security.xml")
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
}
In this case i create WebAppSecurityConfig and make import resource ("security.xml").
This let me to do that in Initializer class:
servletContext.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
This is related to those interested in Spring Boot with security: You don't need anything, Spring Boot picks up the #components and solves the other issues
I am using seam with tomcate and icefaces the problem is when I inject entity manager in component bean it works well but if put it in generic DAO it returns null my code is like that:
this the bean
#Scope(ScopeType.PAGE)
#Name("TestBean")
public class TestBean {
public void test(ActionEvent actionEvent) {
Roles entity = new Roles();
entity.setName("cons");
RolesDao dao = new RolesDao();
dao.emPrisit(entity);
}
}
DAO
public class RolesDao {
#In
EntityManager em;
public void emPrisit(Roles entity) {
em.persist(entity);
}
}
Component.xml
<persistence:entity-manager-factory name="bookingDatabase"/>
<persistence:managed-persistence-context name="em"
auto-create="true"
entity-manager-factory="#{bookingDatabase}"/>
persistence.xml
<persistence-unit name="bookingDatabase"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence </provider>
<jta-data-source>java:comp/env/AP</jta-data-source>
<properties>
<property name="transaction.flush_before_completion" value="true" />
<property name="transaction.factory_class"
value="org.hibernate.transaction.JDBCTransactionFactory" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<!--
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
-->
</properties>
</persistence-unit>
if I inject entitymanger in bean not dao it runs well the second problem when I add this annotation before entitymanger
#In
#PersistenceContext(type = PersistenceContextType.EXTENDED)
EntityManager em;
it give this exception
caused by: java.lang.IllegalArgumentException: #PersistenceContext may only be used on session bean or message driven bean components: TestBean
at org.jboss.seam.Component.checkPersistenceContextForComponentType(Component.java:901)
at org.jboss.seam.Component.scanField(Component.java:877)
at org.jboss.seam.Component.initMembers(Component.java:557)
at org.jboss.seam.Component.<init>(Component.java:244)
at org.jboss.seam.Component.<init>(Component.java:205)
at org.jboss.seam.init.Initialization.addComponent(Initialization.java:1186)
... 13 more
You don't need both #In and #PersistenceContext on your EntityManager. It is enough with one of them.
Injection only occurs in Beans, so your DAO should have a #Name("something"), otherwise Seam doesn't knows what to do with your class.
#Name("RolesDao")
public class RolesDao {
#In
EntityManager em;
public void emPrisit(Roles entity) {
em.persist(entity);
}
}
Then to use this class you should either do:
#In(value="RolesDao") // value="..." is optional
private RolesDao rolesDao;
or
org.jboss.seam.Component.getInstance(RolesDao.class)
Sorry if the sample code has some errors, didn't had eclipse to try it.
Hope this helps