REST на транспорте JMS вместо HTTP

Я пытаюсь создать несколько каналов для REST, чтобы мои конечные точки можно было вызывать из браузера с использованием протокола http, или другие приложения могли асинхронно вызываться, помещая сообщение в очередь. Хотя я могу настроить оба типа транспорта. Я могу получить доступ к службе REST, но не могу отправить сообщение JMS.

Вот полная настройка кода, которую я использую для воспроизведения проблемы.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.kp.swasthik</groupId>
    <artifactId>kp-rest-jms-artemis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>kp-rest-jms-artemis</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <cxf.version>3.1.10</cxf.version>
        <!-- <artemis.version>2.0.0</artemis.version> -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-jms</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-jms-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-artemis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Служба REST

@Service
@Path("/kp")
public class KPRest {

    @Autowired
    private JmsTemplate jmsTemplate;

    @POST
    @Path("/hello")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(String hello){
        System.out.println(hello);
        return "Hello from CXF";
    }

    @GET
    @Path("/send-message")
    public String sendMessage(){
        jmsTemplate.send("cxf_queue", (session)->{
            TextMessage msg = session.createTextMessage();
            msg.setBooleanProperty("OnewayMessage", true);
            msg.setStringProperty("org.apache.cxf.message.Message.REQUEST_URI", "/kp/hello");
            msg.setText("JMS message");
            return msg;
        });
        return "Sent message";
    }

}

Конфигурация Cxf

импортировать com.kp.swasthik.cxf.rest.KPRest;

@Configuration
public class CxfConfig {

    @Bean
    public Server jaxrsServerRest(Bus bus, KPRest rest){
        JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();
        server.setAddress("/kp");
        server.setBus(bus);
        server.setServiceBean(rest);
        server.setFeatures(Arrays.asList(new LoggingFeature()));
        return server.create();
    }

    @Bean
    public Server jaxrsServerJMS(Bus bus, KPRest rest, JMSConfigFeature feature){
        JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();
        server.setAddress("/");
        server.setTransportId("http://cxf.apache.org/transports/jms");
        server.setBus(bus);
        server.setServiceBean(rest);
        server.setFeatures(Arrays.asList(new LoggingFeature(), feature));
        return server.create();
    }

    @Bean
    public JMSConfigFeature getJMSFeature(JMSConfiguration jmsConfiguration) {
        JMSConfigFeature feature = new JMSConfigFeature();
        feature.setJmsConfig(jmsConfiguration);
        return feature;
    }

    @Bean
    public JMSConfiguration getjmsConfig(ConnectionFactory connectionFactory) {
        JMSConfiguration config = new JMSConfiguration();
        config.setConnectionFactory(connectionFactory);
        config.setTargetDestination("cxf_queue");
        return config;
    }
}

Стартовый курс Spring Boot

@SpringBootApplication
public class KpRestJmsArtimisApplication {

    public static void main(String[] args) {
        SpringApplication.run(KpRestJmsArtimisApplication.class, args);
    }
}

application.properties

spring.artemis.embedded.queues=cxf_queue
spring.artemis.embedded=true

Я вызываю API-интерфейс send-message rest, который помещает сообщение в cxf_queue, которое будет прочитано конечной точкой CXF. Однако я получаю сообщение об ошибке из-за наличия . в org.apache.cxf.message.Message.REQUEST_URI

Вот трассировка стека.

javax.jms.JMSRuntimeException: AMQ129012: The property name 'org.apache.cxf.message.Message.REQUEST_URI' is not a valid java identifier.
    at org.apache.activemq.artemis.jms.client.ActiveMQMessage.checkProperty(ActiveMQMessage.java:919) ~[artemis-jms-client-1.3.0.jar:1.3.0]
    at org.apache.activemq.artemis.jms.client.ActiveMQMessage.setStringProperty(ActiveMQMessage.java:657) ~[artemis-jms-client-1.3.0.jar:1.3.0]
    at com.kp.swasthik.cxf.rest.KPRest.lambda$0(KPRest.java:37) ~[classes/:na]
    at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate$4.doInJms(JmsTemplate.java:574) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:484) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:570) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at com.kp.swasthik.cxf.rest.KPRest.sendMessage(KPRest.java:34) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189) ~[cxf-rt-frontend-jaxrs-3.1.10.jar:3.1.10]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99) ~[cxf-rt-frontend-jaxrs-3.1.10.jar:3.1.10]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:262) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_102]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_102]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_102]

Не уверен, что Cxf Полностью поддерживает REST с транспортным типом JMS. хотя в документации говорится, что он поддерживает, но я не вижу в этом особых подробностей. А также не уверен, есть ли способ или свойство экранировать символ ..


person Karthik Prasad    schedule 05.04.2017    source источник


Ответы (2)


Реализация CXF в настоящее время не соответствует спецификации JMS. Я позабочусь, чтобы мы это исправили, сохраняя при этом совместимость со старыми клиентами CXF.

См. https://issues.apache.org/jira/browse/CXF-7344

person Christian Schneider    schedule 24.04.2017

Я не знаю всего контекста того, что вы пытаетесь сделать, но это...

'org.apache.cxf.message.Message.REQUEST_URI' is not a valid java identifier.

... довольно ясно. Вы не можете этого сделать...

msg.setStringProperty("org.apache.cxf.message.Message.REQUEST_URI", "/kp/hello");

... потому что в свойствах JMS не может быть . - они используют те же правила, что и идентификаторы Java (например, переменные).

Вы можете заменить . на _ на стороне отправки и поменять их местами на стороне получателя; если вам это нужно в этом формате.

person Gary Russell    schedule 05.04.2017
comment
Спасибо за ответ, искал в сети, как избежать ., но хотя я заменяю на _, существуют другие свойства, которые CXF устанавливает с помощью . в результате та же ошибка. Поэтому не уверен, что мне нужно включить что-то в CXF, чтобы экранировать символы. - person Karthik Prasad; 06.04.2017