SSE in Jersey: Could not find a suitable constructor in javax.ws.rs.sse.Sse class - jersey

I am implementing Server Sent Events with Jersey 2.28 and I can't get the basic examples to work.
Other answers mention a dependency problem, I've added all the necessary dependencies to no avail:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
</dependency>
</dependencies>
I basically copy-pasted the example and ran it, I've tried variations found in tutorials such as https://www.baeldung.com/java-ee-jax-rs-sse but it just won't work
#GET
#Path("/locations")
#Produces(MediaType.SERVER_SENT_EVENTS)
public void getServerSentEvents(#Context SseEventSink eventSink, #Context Sse sse) {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
final OutboundSseEvent event = sse.newEventBuilder().name("message-to-client")
.data(String.class, "Hello world " + i + "!").build();
eventSink.send(event);
}
}).start();
}
Can anyone provide me with the correct implementation for basic SSE using Jersey (I'm using the grizzly implementation)

Related

Spring Boot 3.0 - SAML Login redirect not working

I'm currently upgrading from Spring Boot 2.7.7 to Spring Boot 3.0.1.
Unfortunately the SAML-Redirect that works under Spring Boot 2.x does not work anymore.
I had to replace some deprecated code with what is recommended by Spring according to this commit:
https://github.com/spring-projects/spring-security/commit/953c9294d0912d65cd90c8e729a47a0d74697392
under Spring Boot 2.x
#Bean
public Saml2AuthenticationRequestContextResolver saml2AuthenticationRequestContextResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
return new DefaultSaml2AuthenticationRequestContextResolver(relyingPartyRegistrationResolver);
}
under Spring Boot 3.x
#Bean
public Saml2AuthenticationRequestResolver saml2AuthenticationRequestResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
return new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationResolver);
}
This was the only change I made in the class Saml2WebSecurityConfig, that is now as follows:
#EnableWebSecurity
#Configuration
public class Saml2WebSecurityConfig {
private final ConfigProperties configProperties;
public Saml2WebSecurityConfig(ConfigProperties configProperties) {
this.configProperties = configProperties;
}
#Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() throws Exception {
// Generate signing with private key and public key
Saml2X509Credential signingCredential = null; // not relevant for context
// Single verification certificate
Saml2X509Credential verificationCredential = null; // not relevant for context
RelyingPartyRegistration registration = RelyingPartyRegistration
.withRegistrationId(configProperties.getRegistrationId())
.entityId(configProperties.getEntity())
.signingX509Credentials(c -> c.add(signingCredential))
.singleLogoutServiceLocation(configProperties.getSingleLogoutServiceLocation())
.assertingPartyDetails(party -> party.entityId(configProperties.getAssertionId())
.singleSignOnServiceLocation(configProperties.getSingleSignOnServiceLocation())
.singleSignOnServiceBinding(Saml2MessageBinding.POST)
.wantAuthnRequestsSigned(true)
.signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256))
.verificationX509Credentials(c -> c.add(verificationCredential))
)
.build();
return new InMemoryRelyingPartyRegistrationRepository(registration);
}
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated())
.saml2Login(saml2 -> {
try {
saml2.relyingPartyRegistrationRepository(this.relyingPartyRegistrationRepository());
} catch (Exception e) {
throw new RuntimeException(e);
}
}).saml2Logout(withDefaults());
http.csrf().disable();
return http.build();
}
#Bean
public Saml2AuthenticationRequestResolver saml2AuthenticationRequestResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
return new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationResolver);
}
#Bean
public RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
return new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository);
}
}
This are the dependencies / repositories (effective-pom):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-saml2-service-provider</artifactId>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>6.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-xmlsec-api</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>10.1.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.14.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>2.2.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-api</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-core</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-impl</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth.utilities</groupId>
<artifactId>java-support</artifactId>
<version>8.4.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>Shibboleth</id>
<name>Shibboleth</name>
<url>https://build.shibboleth.net/nexus/content/repositories/releases/</url>
</repository>
</repositories>
Edit:
How the user is extracted:
#Profile("!local")
#RequestScope
#Component
public class SamlUserContext implements UserContext {
#Override
public LoggedInUser user() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof Saml2Authentication)) {
String message = String.format("The type %s is not the expected Saml2Authentication", authentication.getClass());
throw new IllegalStateException(message);
}
if (!(authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal saml2AuthenticatedPrincipal)) {
String message = String.format("The type %s is not the expected Saml2AuthenticatedPrincipal",
authentication.getPrincipal().getClass());
throw new IllegalStateException(message);
}
return new SamlUser(saml2AuthenticatedPrincipal);
}
}

How return MTOM in Spring BOOT WS

I have a problem with my Spring Boot Soap Server, im using Spring WS, i have to return my files in attachments, i return a Datahandler to the listtype created by Jaxb, but i see in the response in soap ui, attachments 0, and return me the files in base64.
I dont know how to do this.
Can you help me.
Thanks so much.
My Configuration Bean is:
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/services/*");
}
#Bean(name = "students")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("StudentPort");
wsdl11Definition.setLocationUri("/ws/services/test");
wsdl11Definition.setTargetNamespace("http://www.example.org/demo/");
wsdl11Definition.setSchema(countriesSchema);
Properties props = new Properties();
props.put("getDemo", "http://www.example.org/demo/getDemoRequest");
wsdl11Definition.setSoapActions(props);
return wsdl11Definition;
}
#Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("/it/xsd/demo.xsd"));
}
My endpoint have only these annotations:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getDemoRequest")
#ResponsePayload
In my demo.xsd, i setted the fileType in
<element name="fileType" type="base64Binary" maxOccurs="unbounded" xmime:expectedContentTypes="application/octet-stream">
I havent xml configuration for now, i would like dont use any xml if it is not necessary in perfect style of Spring Boot.
Thanks so much.
UP:
My code to try enable MTOM.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import java.util.List;
#Configuration
public class MTOMEnable extends WsConfigurerAdapter {
#Override
public void addArgumentResolvers(List<MethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(methodProcessor());
}
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(GetStudentsResponse.class);
marshaller.setMtomEnabled(true);
return marshaller;
}
#Bean
public MarshallingPayloadMethodProcessor methodProcessor() {
return new MarshallingPayloadMethodProcessor(marshaller());
}
}
POM
<dependencies>
<!-- SOAP DEPENDENCIES-->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.2</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-ri</artifactId>
<version>2.3.2</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.sun.org.apache.xml.internal</groupId>
<artifactId>resolver</artifactId>
<version>20050927</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
<!--<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.2.0.jre8</version>
<scope>runtime</scope>
</dependency>-->
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180830.0359</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.4.0-b180830.0438</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version> <!-- makesure you put a correct version here -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
The problem is that the DefaultMethodEndpointAdapter bean adds our MTOM-enabled JAXB marshaller/unmarshaller to the END of the handlers' list. The trick is to override the DefaultMethodEndpointAdapter bean and put them FIRST. This way you don't even need to override the addArgumentResolvers().
The following is Kotlin but should be easy enough to convert to plain Java.
#Bean
override fun defaultMethodEndpointAdapter() = object: DefaultMethodEndpointAdapter() {
override fun initDefaultStrategies() {
super.initDefaultStrategies()
methodArgumentResolvers.add(0, methodProcessor()) // needs to be FIRST in list
methodReturnValueHandlers.add(0, methodProcessor()) // needs to be FIRST in list
}
}
You also need to make sure the relevant #RequestPayload and return params are JAXBELement<...>

SAAJ0537: Invalid Content-Type. Could be an error message instead of a SOAP message

Currently i'm implementing a usecase where i'm supposed to create a soap client which writes over HTTP protocol.
To test the same usecase i have a mock service up and running. Now when i execute the SAAJ implementation of mine as a standalone jar my application works just well and doesn't have any issue.
My problem currently is that when i merge that code in an spring 4 based application and deploy it on Jboss AS 7.1.1, it gives me an error as below :
12:40:33,992 ERROR [stderr] (ActiveMQ Session Task-1) com.sun.xml.messaging.saaj.SOAPExceptionImpl: Invalid Content-Type:text/html. Is this an error message instead of a SOAP response?
12:40:33,994 ERROR [stderr] (ActiveMQ Session Task-1) at com.sun.xml.messaging.saaj.soap.MessageImpl.identifyContentType(MessageImpl.java:670)
12:40:33,996 ERROR [stderr] (ActiveMQ Session Task-1) at com.sun.xml.messaging.saaj.soap.MessageFactoryImpl.createMessage(MessageFactoryImpl.java:100)
12:40:33,997 ERROR [stderr] (ActiveMQ Session Task-1) at com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:342)
12:40:33,999 ERROR [stderr] (ActiveMQ Session Task-1) at com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:159)
Initially i assumed it to be an issue due to other spring dependencies because previously i have struggled with same issues however that isn't the case here, as u can see in pom entries below i removed the conflicting spring -boot-autoconfigure APIS from my war build by making them optional.
my maven dependencies are as below :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.saaj.client</groupId>
<artifactId>notification</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>notification</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.1.6.RELEASE</spring.version><!-- 3.0.5.RELEASE 4.1.6.RELEASE -->
<activemq.version>5.14.3</activemq.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.4.3.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
<version>1.4.3.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
<version>${activemq.version}</version>
</dependency>
<!--
<dependency>
<groupId>com.sun.xml.messaging.saaj</groupId>
<artifactId>saaj-impl</artifactId>
<version>1.3</version>
</dependency>
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<optional>false</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2.1</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-702.jdbc4</version>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.6</version>
</dependency>
</dependencies>
</project>
And my SAAJ implementation is as below :
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.xml.sax.InputSource;
import com.saaj.client.constants.NotificationConstants;
import com.saaj.client.exception.CustomException;
import com.saaj.client.logger.LoggerManager;
#Component("adapterServiceHelper")
public class AdapterServiceHelper {
private static Logger logger = LoggerManager.getInstance().getNotificationProcessingLogger();
public AdapterServiceHelper(){
}
public URL getEndpointConnection(String url) throws MalformedURLException, CustomException{
URL endpoint = null;
try{
endpoint = new URL (null, url, new URLStreamHandler () {
protected URLConnection openConnection (URL url) throws IOException {
// The url is the parent of this stream handler, so must create clone
URL clone = new URL (url.toString ());
URLConnection connection = clone.openConnection ();
connection.setRequestProperty("Content-Type",
"text/xml");
connection.setRequestProperty("Accept",
"application/soap+xml, text/*");
// If we cast to HttpURLConnection, we can set redirects
// connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (5 * 1000); // 15 sec
connection.setReadTimeout (5 * 1000); // 15 sec
// Custom header
return connection;
}});
}catch(MalformedURLException e){
throw e;
}catch(Exception exp){
exp.printStackTrace();
throw new CustomException(exp.getMessage(),"Error occured while getting endpoint connection to IP");
}
return endpoint;
}
//main SAAJ implementation
public SOAPMessage writeCommand(URL endpoint, String command) throws Exception{
SOAPMessage soapResponse = null;
SOAPConnection soapConnection = null;
InputStream is = null;
System.out.println("command written is "+command);
try{
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory
.newInstance();
soapConnection = soapConnectionFactory
.createConnection();
//write to PG over soapConnection can be made generic
is = new ByteArrayInputStream(command.getBytes());
SOAPMessage request = MessageFactory.newInstance(
SOAPConstants.SOAP_1_1_PROTOCOL).createMessage(
new MimeHeaders(), is);
MimeHeaders headers = request.getMimeHeaders();
headers.addHeader("Content-Type", "text/xml");
request.saveChanges();
soapResponse = soapConnection.call(request, endpoint);
//soapConnection.close();
//is.close();
//process soap response
printSOAPResponse(soapResponse);
}
catch(SOAPException exp)
{
exp.printStackTrace();
logger.error("ERROR while connecting SOAP service" + exp.getMessage());
throw new Exception("ERROR : SOAPException encountered while writing ");
} catch (IOException e) {
e.printStackTrace();
throw new Exception("ERROR : SOAPException encountered while writing ");
} catch (TransformerException e) {
e.printStackTrace();
throw new Exception("ERROR : SOAPException encountered while writing ");
}
finally{
soapConnection.close();
is.close();
}
return soapResponse;
}
public static void printSOAPResponse(SOAPMessage soapResponse) throws TransformerException, SOAPException {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
Source sourceContent = soapResponse.getSOAPPart().getContent();
StreamResult result = new StreamResult(System.out);
transformer.transform(sourceContent, result);
}
}
Please do let me know if there is any suggestion for this problem.
I tried using the basic java.net HTTP connection to check what data i'm getting and found that i was really getting the html page for the mock service's port.(localhost:9997)
Say my service is up on the URL : "http://localhost:9997/mockSoapBinding"
So i was getting data for the URL : "http://localhost:9997" instead of the web service exposed.
To check same i used the code below :
public String handleRequest(String method, String url, String xmlPayload,String readTimeout,String connectTimeout,String soapAction) throws IOException {
HttpURLConnection connection = null;
OutputStreamWriter wr = null;
BufferedReader in = null;
String result = "";
try {
URL connectionUrl = new URL(url);
connection = (HttpURLConnection) connectionUrl.openConnection();
connection.setRequestMethod(method);
if ( xmlPayload != null && ! xmlPayload.equals("")) {
connection.setReadTimeout(Integer.parseInt(readTimeout));
connection.setConnectTimeout(Integer.parseInt(connectTimeout));
connection.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
/*connection.setRequestProperty("SOAPAction", soapAction);*/
connection.setDoOutput(true);
wr = new OutputStreamWriter(connection.getOutputStream());
wr.write(xmlPayload);
wr.flush();
}
try {
// getInputStream will throw exception when response code is
// greater than 400, so we need to getErrorStream
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} catch (Exception e) {
in = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}
StringBuilder bodyBuilder = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null) {
bodyBuilder.append(inputLine);
}
in.close();
result = String.valueOf( bodyBuilder.toString());
System.out.println(result);
} catch(Exception e){
logger.error("Error occured while send message for : " , e);
}finally {
if (wr != null) {
wr.close();
}
if (in != null) {
in.close();
}
if ( connection != null ) {
connection.disconnect();
}
}
return result;
}
Do note this is also an alternative to SAAJ implementation.
I got this error message when I provided the wrong namespace in the soap enveloppe. This likely has the same effect as what the accepted answer describes, i.e. the request arrives at the wrong URL.
I have found a dependency issue.
Ok with POI 4.0.1, and fails with 5.0.0, using this pom.xml :
</dependencies>
<!-- #see https://stackoverflow.com/questions/43574426/how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception -->
<!-- API, java.xml.bind module -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Runtime, com.sun.xml.bind module -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
<!-- <version>5.0.0</version> -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
<!-- <version>5.0.0</version> -->
</dependency>
</dependencies>

jersey skip filtering on specific resource

I have REST API application running in Jetty + Jersey, all the requests will be filtered by some security filter,which is provided some excluded paths defined in config file. With old version Jersey 2.5 the API works fine, now i upgraded Jersey to 2.22.1, the excluded paths are subjected to filtering too and failed because no authentication token were provided.
here is my filter:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter extends AbstractAuthenticationFilter implements ContainerRequestFilter, DynamicFeature {
...
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (getExcludeUrlPatterns() != null) {
for (String urlPattern : getExcludeUrlPatterns()) {
Pattern p = Pattern.compile(urlPattern);
Matcher m = p.matcher(requestContext.getUriInfo().getPath()); <-- here went wrong
if (m.matches()) {
// skip filtering
}
}
}
// continue filtering.
}
}
here is my resource:
#Path("/version")
public class VersionResource {
...
#GET
#ResponseClass(AppVersion.class)
public Response getVersion() {
AppVersion version =
new AppVersion()
.withBuildPlan(BUILD_PLAN_SETTING)
.withBuildNumber(BUILD_NUMBER_SETTING)
.withBuildTimestamp(BUILD_TIMESTAMP_SETTING)
return Response.ok(version).build();
}
}
Excluded url paths:
/status,/status/?.*,/version,..
as I debugged the code, i noticed for an excluded request context "/myresources/version", requestContext.getUriInfo().getPath() return 'version', however the Pattern is like '/version', thus it doesn't match the pattern and continue the authentication process, and further failed. anyone understand why it works like this?
I use Jersey 2.22.1 and jetty-maven-plugin 9.2.1.v20140609, here is my pom.xml
<jersey.version>2.22.1</jersey.version>
<jetty.version>9.2.1.v20140609</jetty.version>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-jetty-connector</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>

ConnectionLostException using Spring Boot with Tomcat Websocket

I have a Java Stomp Websocket Client application using Spring Boot 1.3.0-BUILD-SNAPSHOT. Here is my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
My StompSessionHandlerAdapter subscribes to a timer topic which receives a message every second which works fine. On another topic, I receive messages every few minutes. When a message arrives on that topic I receive the following exception in the StompSessionHandlerAdapter handleTransportError method
org.springframework.messaging.simp.stomp.ConnectionLostException: Connection closed
at org.springframework.messaging.simp.stomp.DefaultStompSession.afterConnectionClosed(DefaultStompSession.java:458)
at org.springframework.web.socket.messaging.WebSocketStompClient$WebSocketTcpConnectionHandlerAdapter.afterConnectionClosed(WebSocketStompClient.java:356)
at org.springframework.web.socket.sockjs.client.AbstractClientSockJsSession.afterTransportClosed(AbstractClientSockJsSession.java:321)
at org.springframework.web.socket.sockjs.client.WebSocketTransport$ClientSockJsWebSocketHandler.afterConnectionClosed(WebSocketTransport.java:172)
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.onClose(StandardWebSocketHandlerAdapter.java:143)
at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:527)
at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:479)
at org.apache.tomcat.websocket.WsSession.close(WsSession.java:445)
at org.apache.tomcat.websocket.WsFrameClient.close(WsFrameClient.java:94)
at org.apache.tomcat.websocket.WsFrameClient.access$100(WsFrameClient.java:31)
at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:134)
at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:108)
at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
at sun.nio.ch.Invoker$2.run(Invoker.java:218)
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Here is the code
public class SocketSessionHandler extends StompSessionHandlerAdapter {
private StompSession stompSession;
#Override
public void afterConnected(StompSession stompSession, StompHeaders connectedHeaders) {
this.stompSession = stompSession;
stompSession.setAutoReceipt(true);
stompSession.subscribe("/topic/timer", new StompFrameHandler() {
#Override
public Type getPayloadType(StompHeaders headers) {
return String.class;
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
System.out.println((payload.toString());
}
});
stompSession.subscribe("/topic/scores", new StompFrameHandler() {
#Override
public Type getPayloadType(StompHeaders headers) {
return ScoresPublish.class;
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
ScoresPublish pub = (ScoresPublish)payload;
System.out.println(pub.getScore());
}
});
}
#Override
public void handleException(StompSession session, StompCommand command, StompHeaders headers,
byte[] payload, Throwable exception) {
exception.printStackTrace();
}
#Override
public void handleTransportError(StompSession session, Throwable exception) {
exception.printStackTrace();
}
}
If I define my own Websocket dependencies in the pom.xml I don't have the problem. By doing this I also don't get embedded Tomcat started
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-client-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus.bundles</groupId>
<artifactId>tyrus-standalone-client</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
I think my issue may have been due to my pom.xml missing the spring-messaging dependency. The following dependencies allow my websocket application to work in Spring Boot Release 1.3.1
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>

Resources