I have a Struts2 web application running on Tomcat 7.0.43 that uses Rest and Convention plugins to map all requests. Struts tries to map all requests by itself.
JSR 356 defines server end points using annotations like
#ServerEndpoint(value = "/websocket/chat")
Now when the broswer tries to connect to ws:/127.0.0.1:8080/websocket/chat, the request fails because the Struts mapper intercepts the request.
Is there anything I can specify in the XML files, such that the request reaches the right place?
EDIT:
As suggested, I added
<constant name="struts.action.excludePattern" value="/websocket.*?" />
to my Struts configuration, after which the URL /websocket/chat started reaching a 404 error.
Later I learnt that I need to configure a ServerApplicationConfig implementation. After doing that the websocket starts working fine but the rest of my application fails to load giving an error:
SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
Here is my class:
public class Socket implements ServerApplicationConfig {
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> scanned) {
Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
return result;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
Set<Class<?>> results = new HashSet<Class<?>>();
for (Class<?> clazz : scanned) {
results.add(clazz);
}
return results;
}
}
How can I get everything to work together in Harmony?
Note: I am using Struts Spring Plugin for Dependency Injection of Spring Security.
You can configure the Struts filter to exclude some URLs via regex pattern. You should add the constant in the struts.xml
<constant name="struts.action.excludePattern" value="^ws://.+$"/>
Use Websocket API for server endpoints.
Related
I'm trying to build a REST API using JAX-RS, specifically the Jersey implementation. I tried to implement Authentication like in this StackOverflow question.
Basically I'm using a ContainerRequestFilter to filter the HTTP Requests, based on the Authorization header. This class defines a property, annotated with the #Inject attribute (I'm using Kotlin, not Java):
#Inject
var authenticationService: IAuthenticationService? = null
I've registered this authentication service in my AbstractBinder:
class MyApplicationBinder : AbstractBinder() {
override fun configure() {
bind(AuthenticationService::class.java) to IAuthenticationService::class.java
}
}
and registering this application binder to my ResourceConfig:
class MyResourceConfig : ResourceConfig() {
init {
// ...
register(MyApplicationBinder())
}
}
However I'm getting the runtime exception on startup:
org.glassfish.hk2.api.UnsatisfiedDependencyException:
There was no object available for injection at SystemInjecteeImpl(
requiredType=IAuthenticationService,
parent=AuthenticationRequestFilter,
qualifiers={},
position=-1,
optional=false,
self=false,
unqualified=null,
452444366
)
I have no idea why the registration in my AbstractBinder is ignored by the HK2 Container! Can someone please help me out? Thanks!
I'm currently working on a Spring web application which makes use of both Spring MVC and Spring Websocket. The configuration is annotation based. I'm using the AbstractAnnotationConfigDispatcherServletInitializer class as initializer, and I am confused about the servlet mappings I should provide, and the way I should do so.
I'd like to have all my MVC controller mapped under "/webservices/" path, and my Websocket endpoint to be under "/websockets/".
Among my #Configuration classes, one is dedicated to configure Spring MVC (#EnableWebMVC) and another one is dedicated to Spring WebSocket (#EnableWebSocketMessageBroker).
I implemented my initializer as follows :
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebMVCConfiguration.class, WebSocketConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/webservices/*","/websockets/*"};
}
Also please note that I imported all of my configuration classes through the use of #Import on my Root Configuration class. I'm not sure if I should import the MVC and Websocket configuration though, as I already declared them in the getServletConfigClasses() method... But I did.
Anyway, It worked fine this way until now. But I recently added the use of #PropertySource annotation to my app (To inject my app properties through the use of #Value("${}") expressions), and thanks to that I noticed that at least the WebSocket Configuration class is ... scanned (?) twice : The first time with the #Value field value properly injected, but not the second time (Which caused an error).
While troubleshooting I noticed that I don't have this "double scanning" problem when I remove the WebSocketConfiguration class from the getServletConfigClasses() method : it is scanned only once, with the property valye properly injected. What surprised me is that even without declaring the WebSocketConfiguration in getServletConfigClasses(), the "/websockets" endpoints still works ! My guess is that it is scanned thanks to the #Import on my Root config class... but then how Spring knows it should bind the WebSocketConfiguration to the "/websockets" path ?
All of this made me wonder about my understanding of when / how I should import configurations classes. So here are my questions :
Do I really need to declare two servlet mappings to keep my services and websockets paths separated as they are ?
Is it necessary to declare as much Servlet Config classes as I have Servlet Mappings ? (Seeing how removing the WebSocketConfiguration class from getServletConfigClasses() didn't alter the WebSocket functionality... Or is it just a fluke ?)
Will Spring use the same DispatcherServlet for all the Servlet Config classes ? Or will it create one for each mapping I provide ?
From what I tried it looks like Spring cannot inject properties through the use of #Value in the configuration classes provided thanks to getServletConfigClasses()... It works only when it is imported via #Import, or a standard component scanning. Does it seems logical to you ?
Thanks for your help !
I noticed Spring Boot Actuator only works if your application uses Spring MVC (DispatcherServlet) to handle endpoints. By default, this servlet is included if you add the module spring-boot-starter-web into your project.
Once this servlet exists, the class EndpointWebMvcAutoConfiguration customize the Spring MVC to support endpoints and other management properties.
For record, my application implements a Vaadin Servlet to navigate on screens, so is there any way to enable Spring Boot Actuator in this case?
You won't be able to reuse the EndpointWebMVCAutoConfiguration class as it is explicitly conditionnal on DispatcherServlet.class. If you look at the implementation, you'll see that the Actuator has a lot of dependencies on Spring MVC.
It would be a little ballzy but you could consider implementing your own autoconfiguration class inspired by EndpointWebMVCAutoConfiguration.
I wish you good luck if you go down that path ;)
You can have both. If you have a VaadinServlet, you can try with something like:
#SpringBootApplication
public class AdminApplication {
#Bean
public ServletRegistrationBean<SpringVaadinServlet> springVaadinServlet() {
SpringVaadinServlet servlet = new SpringVaadinServlet();
ServletRegistrationBean<SpringVaadinServlet> registrationBean = new ServletRegistrationBean<>(servlet, "/your-web-app/*");
registrationBean.setLoadOnStartup(1);
registrationBean.setName("VaadinServlet");
return registrationBean;
}
}
#SpringUI(path = "/")
public class VaadinUI extends UI {
...
}
Notice the need for a registration name, a custom servlet mapping URL, and custom path in the #SpringUI annotation.
You can find a running demo here.
Servlet 3.0-enabled containers allows us to skip the web.xml servlet configuration and automatically scan your code for resources and providers once you extend javax.ws.rs.core.Application, annotate it with #ApplicationPath and do not override the getClasses() method. (hope I got all of that right :\)
At the moment I am using the Jersey implementation and securing resource methods using #RolesAllowed annotations. For this I need to register the org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature Provider class, however, the only ways I'm aware of to do this is either to:
Register the class in the getClasses() method of my Application class (which, I think, will cause the Servlet 3.0 container NOT to auto-scan)
Continue to use the web.xml Jersey servlet setup with
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature</param-value>
</init-param>
Now the context behind this question is that I might have to switch to using RESTeasy and if I use option 1 it adds a Jersey dependency in the code and the code is no longer generic.
How do I write my code to use security annotations while maintaining generic JAX-RS code that could be deployed to another Servlet 3.0 JAX-RS implementation?
One option is to use a javax.ws.rs.core.Feature (a JAX-RS standard class). You can register any components there, and then annotate the class with #Provider, and it will be picked up like any other #Provider or #Path annotated class
#Provider
public class MyFeature implements Feature {
#Overrride
public boolean configure(FeatureContext context) {
context.register(RolesAllowedDynamicFeature.class);
}
}
Do note that since you are using the Jersey feature, your app is no longer implementation independent, so you might as well use Jersey all the way. For one, Jersey does not recommend scanning the class-path, which is the affect of doing what you are doing. Instead Jersey has a mechanism that allows you to recursively scan a package (and its sub-packages). So you could instead do
#ApplicationPath("..")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("the.packages.to.scan");
register(RolesAllowedDynamicFeature.class);
}
}
Note that ResourceConfig is a sub-class of Application
See Also:
When to Use JAX-RS Class-path Scanning Mechanism
Sevlet Based Deployment - Servlet 3.x Container
Note:
If you wanted to stick to the classpath scanning mechanism, and wanted to keep the project independent of any Jersey dependencies, you could also override Map<String, Object> getProperties() in the Application class. In the returned Map, you could add the property that you would otherwis have added in the web.xml
#Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.provider.classnames",
"org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature");
return props;
}
But even though the source code is implementation independent, the application is still dependent on the Jersey roles feature. If you decided you wanted to port, you would still need a replacement for the feature.
If you wanted to stay completely independent, you could implement the feature yourself. It's not all that complicated. You can check out the source code for RolesAllowedDynamicFeature. If you decide to try and implement the same, just annotate your implementation class with #Provider, and it should get picked up.
I'm using CXF to generate a web service from wsdl.
The generated web service has the annotation #WebService
How do i get a reference to spring bean from the web service?
All my spring beans are annotated with #Service, and I can access them
in my web application. How do I access them also from my web service?
I've tried the following:
public class TestWSImpl implements TestWSSoap{
#Resource
public WebServiceContext wsContext;
#Override
public String getTest() {
ServletContext servletContext= (ServletContext) wsContext.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return "Test";
}
}
But the getWebApplicationContext method returns null
When I replace getWebApplicationContext with getRequiredWebApplicationContext
I get an error message: No WebApplicationContext found: no ContextLoaderListener registered?
Anyone has an idea?
Thanks
Alon
If you were using JUnit 4.4 or higher you could inject it using the Spring 2.5 JUnit annotations. Here's an example.
http://hamletdarcy.blogspot.com/2008/12/autowired-junit-tests-with-spring-25.html
Of course it goes without saying that this approach requires that the web service be running in a web context when the test is started. Have you done that?
You also might prefer testing WSDL based services using SOAP UI.
It was a long time ago.
I'm looking on my code and I see that I put the following method
that should init the spring:
#PostConstruct
public void init(){
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setServiceClass(MyWebService.class);
svrFactory.setAddress("http://address.com");
svrFactory.setServiceBean(wsHandler);
svrFactory.getInInterceptors().add(new LoggingInInterceptor());
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
svrFactory.create();
}
Please tell me if it solve you problem....