With the environment:
Karaf 3.0.1
Spring 3.2.4
Hessian 4.0.33
I have already exposed a service via CXF and now I'm trying to expose the same service as a Hessian Service.
There is no war or web.xml, just plain beans + pax-http and I have tried the following:
<bean name="/hessian" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="promocionalOnLineWebServiceBean"/>
<property name="serviceInterface" value="org.fideliapos.promos.webservice.PromocionalOnLineFacade"/>
</bean>
...
<bean id="hessianServlet" class="org.springframework.web.context.support.HttpRequestHandlerServlet"/>
...
<osgi:service ref="hessianServlet" interface="javax.servlet.http.HttpServlet">
<service-properties>
<entry key="alias" value="/hessian"/>
</service-properties>
</osgi:service>
The idea is to register a servlet (a HttpRequestHandlerServlet) whose target is a HessianServiceExporter but I'm getting a No WebApplicationContext found: no ContextLoaderListener registered?.
I have traced the spring code and the internal jetty is recognizing the servlet and calling its init method:
#Override
public void init() throws ServletException {
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
this.target = wac.getBean(getServletName(), HttpRequestHandler.class);
}
and here lies the problem, since there is no spring WebApplicationContext and the target property cannot be inyected.
Am I missing something? or it is not possible to make it work like this.
As a workaround I'm considering extending the Servlet with my own implementation (setTarget and so) but I'd rather not to do it.
UPDATE
After trying to create and add my own HttpContext there is still something missing:
I implemented my own HttpContext:
public class HessianContext implements HttpContext{
...
}
added the bean
<bean id="hessianContext" class="org.fideliapos.promos.hessian.HessianContext"/>
the service:
<osgi:service id="hessianContextService" ref="hessianContext" interface="org.osgi.service.http.HttpContext">
<service-properties>
<entry key="httpContext.id" value="hessian"/> <!-- also tried with contextId-->
</service-properties>
</osgi:service>
and finally the servlet as a service:
<osgi:service ref="hessianServlet" interface="javax.servlet.http.HttpServlet">
<service-properties>
<entry key="alias" value="/hessian"/>
<entry key="httpContext.id" value="hessian"/> <!-- also tried with contextId-->
</service-properties>
</osgi:service>
Since the init method is looking for a WebApplicationContext it looks like I should declare and explicit GenericWebApplicationContext bean but I dont know how to 'join' this bean with the required HttpContext for OSGi.
Looks like you need to add the Spring WebApplicationContext to the HttpContext used for your servlet. Right now you use the DefaultHttpContext of Pax Web. In your case you'll need to register a custom HttpContext that is aware of the Spring stuff so the WebApplicationContextUtils.getRequireWebApplicationContext is capable of extracting this information.
For this you'll need to register your custom HttpContext as Service and reference it in your Servlet, a complete Example of this using Blueprint (similar to spring) can be found here
Following is an excerpt of it:
<service id="forbiddenCtxtService" ref="forbiddenContext" interface="org.osgi.service.http.HttpContext">
<service-properties>
<entry key="httpContext.id" value="forbidden"/>
</service-properties>
</service>
The Important part is the httpContext.id
<bean id="forbiddenServlet" class="org.ops4j.pax.web.extender.samples.whiteboard.internal.WhiteboardServlet">
<argument type="java.lang.String" value="/forbidden"/>
</bean>
<service id="forbiddenServletService" ref="forbiddenServlet" interface="javax.servlet.Servlet">
<service-properties>
<entry key="alias" value="/forbidden"/>
<entry key="httpContext.id" value="forbidden"/>
</service-properties>
</service>
Again here the registered Servlet does have a configuration for the corresponding httpContext.id, this binds this Servlet to the previously registered HttpContext.
Related
I have a legacy product's JAR that contain Spring (4.3.8) managed classes. I need to integrate it with CDI (JavaEE 7).
I have an interface from the legacy JAR, that is implemented by a CDI bean. The CDI bean is requested from the CDI BeanManager and returned from a factory method. The factory method is registered inside Spring XML and works as expected.
The problem occurs, when a Spring bean of the legacy JAR depends on the implemented interface. Spring than injects the CDI implementation instance and scans the class it for known annotations, namingly #Inject. It then tries to resolve the dependency, which doesn't work since the dependency is not available to Spring.
I already tweaked context:property-placeholder excludes, but that changes nothing.
So how can I tell Spring to stop trying to inject something in my factory produced bean instance?
I finally was able to solve (work around) the problem. I had to remove all CDI-Annotations in the legacy JAR (by replacining them with their Spring counterparts), so spring would any longer work.
Then I added the following XML block to the applicationContext.xml of my CDI WAR:
<context:component-scan annotation-config="false" base-package="com.example">
</context:component-scan>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationTypes">
<set>
<value>org.springframework.beans.factory.annotation.Autowired</value>
<value>org.springframework.beans.factory.annotation.Value</value>
</set>
</property>
</bean>
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>org.springframework.beans.factory.annotation.Qualifier</value>
</set>
</property>
</bean>
Basically that drops the support for #Inject, etc. from Spring and leaves it where it belongs: CDI.
It's a bit easier.
AutowiredAnnotationBeanPostProcessor is already a bean, so you can configure it before Spring starts to scan with a ServletContextListener to exclude #Inject annotations. At least from Spring 4.1+, AutowiredAnnotationBeanPostProcessor has a method setAutowiredAnnotationTypes, e.g.:
#WebListener
public class ApplicationConfigListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ApplicationContext appCtx = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>();
AutowiredAnnotationBeanPostProcessor bean = appCtx.getBean(AutowiredAnnotationBeanPostProcessor.class);
autowiredAnnotationTypes.add(Autowired.class);
autowiredAnnotationTypes.add(Value.class);
bean.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
}
}
You could use a SpringBeanAutowiringInterceptor too.
This is explained here.
I created a JSF Application and I'm not sure what I should put into the faces-config?
One of my ManagedBeans looks like the following:
#ManagedBean(name = "ProfileBean")
#ViewScoped
public class ProfileBean implements Serializable
my applicationcontext
<context:annotation-config />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean id="QuestionDao" class="code.elephant.dao.QuestionDao"></bean>
<bean id="QuestionService" class="code.elephant.service.QuestionService">
<constructor-arg ref="QuestionDao"/>
</bean>
<bean id="QuestionBean" class="controller.QuestionBean">
<constructor-arg ref="QuestionService"/>
</bean>
<bean id="UserDao" class="code.elephant.dao.UserDao"></bean>
<bean id="UserService" class="code.elephant.service.UserService">
<constructor-arg ref="UserDao"/>
</bean>
<bean id="LoginBean" class="controller.LoginBean">
<constructor-arg ref="UserService"/>
</bean>
<bean id="ProfileBean" class="controller.ProfileBean">
<constructor-arg ref="UserService" />
<property name="_LoginBean" ref="LoginBean"></property>
</bean>
my faces-config
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
I saw some examples which defines <managed-beans> in the java-faces.config but I already used the #ManagedBean annotation in the java class. Is this rly necessary? Is my setup up with jsf spring correct? Should I also define the managed beans in the faces-config?
The purpose of the SpringBeanFacesELResolver that you have configured in faces-config is to make it so that you can use Spring beans instead of the old-style JSF managed beans or CDI dependency injection.
Remove the #ManagedBean annotation from your ProfileBean class. You don't need it since you are using Spring instead of JSF's old managed beans mechanism.
The #ManagedBean annotation is a remnant from old versions of JSF; don't use it if you are using a newer version of JSF. Current versions of JSF use CDI (the standard Java EE API for dependency injection), but you are using Spring instead, so you should configure your beans the Spring way (which you are already doing since you've defined ProfileBean in your Spring XML config).
I am using Apache Karaf, CXF, and Aries Blueprint.
I have a bundle which defines a number of JAX-RS services. By default, CXF will make these services singletons, but this will not work for me. I need a new instance to handle each request.
Referencing the CXF documentation, I tried to create JAX-RS ServiceFactories which return new instances of the services. The documentation had examples for Spring and I tried to Blueprint equivalent.
<reference id="groupService" interface="org.ozoneplatform.owf.server.service.api.GroupService"/>
<bean id="groups" class="org.ozoneplatform.owf.server.rest.GroupController" scope="prototype">
<property name="service" ref="groupService"/>
</bean>
<bean id="groupFactory" class="org.apache.cxf.blueprint.jaxrs.BlueprintResourceFactory">
<property name="beanId" value="groups" />
</bean>
<jaxrs:server id="ozoneplatform_cxf_endpoint" address="/owf">
<jaxrs:serviceFactories>
<ref bean="groupFactory" />
</jaxrs:serviceFactories>
Blueprint fails to start giving the error
org.osgi.service.blueprint.container.ComponentDefinitionException:
Error setting property: PropertyDescriptor <name: resourceProviders, getter: null, setter: [class org.apache.cxf.jaxrs.JAXRSServerFactoryBean.setResourceProviders(interface java.util.List)]
You must define "blueprintContainer" property for BlueprintResourceFactory instance as:
<bean id="groupFactory" class="org.apache.cxf.blueprint.jaxrs.BlueprintResourceFactory">
<property name="beanId" value="groups" />
<property name="blueprintContainer" ref="blueprintContainer"/>
</bean>
Where ref="blueprintContainer" is a reference to top-level manager (see 121.11 Blueprint Container)
I have one Annotation bean with some methods. It works fine.
public #Controller("adminController") class AdminController {
...
private #Autowired AdminDAO adminDAO;
public void resetTemporalList() {
System.out.println("HE SIDO EJECUTADO.");
this.adminDAO.resetTemporalRegisters();
}
...
}
Now, I am integrating one quartz task. But I am load it with XML definition beans that call previus annotation bean.
<bean id="resetTemporalRegisters" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="adminController" />
<property name="targetMethod" value="resetTemporalList" />
<property name="concurrent" value="false" />
</bean>
Whan I start my app appear next error.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'adminController' is defined
I believe the problem is that Spring load XML beans first, after Annotation beans, then in this moment "adminController" bean not exits...
How Can I fix it?
SOLVED IT!!
Problem was in I put xml bean definitions in applicationContext.xml.
No, XML and annotations integrate fine, but do you actually have the component scanning code in your XML?
<context:component-scan base-package="com.yourcompany.yourapp"/>
See: 4.10 Classpath scanning and managed components
A little bit of guessing: your controller is defined in child application context created by Spring MVC while you resetTemporalRegisters job in main application context (parent). Child context can access beans from parent context but not the other way around.
This raises important question: why is your business logic trying to call a method of a controller? These methods should be called only be the MVC framework. Can't you just call
this.adminDAO.resetTemporalRegisters();
directly from your job?
<bean id="resetTemporalRegisters" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="adminDAO" />
<property name="targetMethod" value="resetTemporalRegisters" />
<property name="concurrent" value="false" />
</bean>
adminDAO is probably defined in parent context, so you can access it easily.
I have a working web service client based on Spring, defined as:
<bean id="myService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="wsdlDocumentUrl" value="classpath:/ex/MyService.wsdl" />
<property name="namespaceUri" value="http://ex.tld/namespace" />
<property name="serviceName" value="MyService" />
<property name="portName" value="MyServicePort01" />
<property name="serviceInterface" value="ex.MyService" />
</bean>
I need to access the same service on a list of different endpoints. Since the list is dynamic I cannot simply configure several Spring JaxWsPortProxy beans for this.
Can I change the binding dynamically? How can I solve this while still leveraging Spring facilities for WS clients?
I simply changed the endpoint address of the proxy:
((BindingProvider)myService).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpoint/address");
As seen above, the proxy that Spring returns can be casted to a BindingProvider (like a normal JaxWs proxy).
If someone adopts this, beware of synchronization issues.
I configured in xml, as you.
After, in postConsruct set endpoint, and call afterPropertiesSet:
#Autowired
private JaxWsPortProxyFactoryBean myService;
#PostConstruct
public void init() {
myService.setEndpointAddress("http://new/endpoint/address");
myService.afterPropertiesSet();
}