Свобода активирует @MessageDriven

Я хочу активировать пользовательский прослушиватель сообщений на сервере приложений Liberty.

это мой код:

@MessageDriven(name = "Receiver")
public class Receiver implements InboundListener {

    @Override
    public void receiveMessage(String message) {
        System.out.println("Message Received : " + message);
    }
}      

и это server.xml:

<?xml version="1.0" encoding="UTF-8"?>
<server description="Dandelion IOT server">
    <featureManager>
        <feature>cdi-2.0</feature>
        <feature>beanValidation-2.0</feature>
        <feature>appSecurity-3.0</feature>
        <feature>jpa-2.2</feature>
        <feature>jaxrs-2.1</feature>
        <feature>jsonb-1.0</feature>
        <feature>jsonp-1.1</feature>
        <feature>managedBeans-1.0</feature>
        <feature>websocket-1.1</feature>
        <feature>ejbLite-3.2</feature>
        <feature>jca-1.7</feature>
        <feature>jndi-1.0</feature>
        <feature>mdb-3.2</feature>
        <feature>localConnector-1.0</feature>
    </featureManager>
    <library id="DandelionLibs">
        <fileset dir="/etc/dandelion/lib" includes="*.jar"/>
    </library>
    <jdbcDriver id="database-driver" libraryRef="DandelionLibs"/>
    <dataSource jndiName="JTA-DataSource" transactional="true" jdbcDriverRef="database-driver">
        <properties databaseName="${database.name}" serverName="${database.hostname}" portNumber="${database.port}"
                    user="${database.username}" password="${database.password}"/>
    </dataSource>

    <resourceAdapter id="dra" autoStart="true" location="/etc/dandelion/lib/RA.rar"/>

    <connectionFactory jndiName="h5/sampleConnection">
        <properties.dra/>
    </connectionFactory>

    <activationSpec id="h5/inboundListener">
        <properties.dra.DandelionActivationSpec/>
    </activationSpec>

    <webApplication id="dandelion-web"
                    location="dandelion-war-0.1-SNAPSHOT.war"
                    name="dandelion-web">
        <classloader classProviderRef="dra"/>
    </webApplication>

    <basicRegistry id="basic" realm="BasicRealm"/>
    <httpSession securityIntegrationEnabled="false"/>
    <httpEndpoint id="defaultHttpEndpoint" httpPort="8080" httpsPort="9443">
        <httpOptions http2="enabled"/>
    </httpEndpoint>
    <webContainer disableXPoweredBy="true"/>
    <applicationManager autoExpand="true"/>
    <applicationMonitor updateTrigger="mbean"/>
</server>    

и моя спецификация активации:

@Activation(messageListeners = InboundListener.class)
public class DandelionActivationSpec implements ActivationSpec {

    private ResourceAdapter resourceAdapter;

    @Override
    public void validate() throws InvalidPropertyException {
    }

    @Override
    public ResourceAdapter getResourceAdapter() {
        return resourceAdapter;
    }

    @Override
    public void setResourceAdapter(ResourceAdapter ra) throws ResourceException {
        this.resourceAdapter = ra;
    }
}       

и ra.xml:

<?xml version="1.0" encoding="UTF-8"?>
<connector xmlns="http://xmlns.jcp.org/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
           http://xmlns.jcp.org/xml/ns/javaee/connector_1_7.xsd"
           version="1.7">
    <description>Sample Resource Adapter</description>
    <display-name>Sample Resource Adapter</display-name>
    <eis-type>Sample Resource Adapter</eis-type>
    <resourceadapter-version>1.0</resourceadapter-version>
    <license>
        <license-required>false</license-required>
    </license>
    <resourceadapter>
        <resourceadapter-class>org.company.dandelion.adapter.DandelionResourceAdapter</resourceadapter-class>
        <outbound-resourceadapter>
            <connection-definition>
                <managedconnectionfactory-class>org.company.dandelion.adapter.DandelionManagedConnectionFactory</managedconnectionfactory-class>
                <connectionfactory-interface>org.company.dandelion.api.DandelionConnectionFactory</connectionfactory-interface>
                <connectionfactory-impl-class>org.company.dandelion.adapter.DandelionConnectionFactoryImpl</connectionfactory-impl-class>
                <connection-interface>org.company.dandelion.api.DandelionConnection</connection-interface>
                <connection-impl-class>org.company.dandelion.adapter.DandelionConnectionImpl</connection-impl-class>
            </connection-definition>
            <transaction-support>NoTransaction</transaction-support>
            <reauthentication-support>false</reauthentication-support>
        </outbound-resourceadapter>
        <inbound-resourceadapter>
            <messageadapter>
                <messagelistener>
                    <messagelistener-type>org.company.dandelion.api.InboundListener</messagelistener-type>
                    <activationspec>
                        <activationspec-class>org.company.dandelion.adapter.DandelionActivationSpec</activationspec-class>
                    </activationspec>
                </messagelistener>
            </messageadapter>
        </inbound-resourceadapter>
    </resourceadapter>
</connector>

Сервер приложений Liberty приводит к этому журналу на консоли:

[WARNING ] CNTR4015W: The message endpoint for the Receiver message-driven bean cannot be activated because the dandelion-war-0.1-SNAPSHOT/Receiver activation specification is not available. The message endpoint will not receive messages until the activation specification becomes available.        

Адаптер исходящих ресурсов работает без проблем, но входящие не получают никаких сообщений!
Я прочитал эти ссылки, прежде чем задавать этот вопрос, но не могу понять, как можно решить эту проблему:
Ссылка 1
Ссылка 2
Ссылка 3
В какой части конфигурации/кода возникла проблема?

ОБНОВЛЕНИЕ:
я меняю конфигурацию на это:

<activationSpec id="dandelion-web/Receiver">
    <properties.dra/>
</activationSpec>
<webApplication id="dandelion-web"
                location="dandelion-web.war"
                name="dandelion-web">
    <classloader classProviderRef="dra"/>
</webApplication>     

теперь получите эту ошибку на консоли:

[AUDIT   ] J2CA7001I: Resource adapter dra installed in 1.911 seconds.
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:8080/
[AUDIT   ] CWWKZ0001I: Application dandelion started in 8.064 seconds.
[err] javax.resource.spi.UnavailableException: activating thread not allowed to create endpoint during activation.
[err]   at com.ibm.ws.ejbcontainer.mdb.BaseMessageEndpointFactory.createEndpoint(BaseMessageEndpointFactory.java:406)
[err]   at [internal classes]
[err]   at com.company.dandelion.adapter.DandelionResourceAdapter.endpointActivation(DandelionResourceAdapter.java:56)
[err]   at com.ibm.ws.jca.service.EndpointActivationService.activateEndpoint(EndpointActivationService.java:585)
[err]   at [internal classes]
[err]   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[err]   at org.apache.felix.scr.impl.inject.methods.BaseMethod.invokeMethod(BaseMethod.java:242)
[err]   at org.apache.felix.scr.impl.inject.methods.BaseMethod.access$500(BaseMethod.java:41)
[err]   at org.apache.felix.scr.impl.inject.methods.BaseMethod$Resolved.invoke(BaseMethod.java:678)
[err]   at [internal classes]
[err]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[err]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[err]   at java.base/java.lang.Thread.run(Thread.java:834)
[AUDIT   ] CWWKF0012I: The server installed the following features: [appSecurity-3.0, beanValidation-2.0, cdi-2.0, distributedMap-1.0, ejbLite-3.2, el-3.0, jaxrs-2.1, jaxrsClient-2.1, jca-1.7, jdbc-4.2, jndi-1.0, jpa-2.2, jpaContainer-2.2, jsonb-1.0, jsonp-1.1, localConnector-1.0, managedBeans-1.0, mdb-3.2, servlet-4.0, ssl-1.0, websocket-1.1].
[AUDIT   ] CWWKF0011I: The dandelion server is ready to run a smarter planet. The dandelion server started in 12.919 seconds.     

это мой DandelionResourceAdapter:

@Connector(
        description = "Sample Resource Adapter",
        displayName = "Sample Resource Adapter",
        eisType = "Sample Resource Adapter",
        version = "1.0"
)
public class DandelionResourceAdapter implements ResourceAdapter {

    final Map<DandelionActivationSpec, EndpointTarget> targets = new ConcurrentHashMap<>();

    public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException {
    }

    public void stop() {
    }

    public void endpointActivation(final MessageEndpointFactory messageEndpointFactory,
                                   final ActivationSpec activationSpec) {
        final DandelionActivationSpec sampleActivationSpec = (DandelionActivationSpec) activationSpec;

        // ->>>>>>>>> EXCEPTION FOR THIS LINES : 
        try {
            final MessageEndpoint messageEndpoint = messageEndpointFactory.createEndpoint(null);
            final EndpointTarget target = new EndpointTarget(messageEndpoint);
            targets.put(sampleActivationSpec, target);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void endpointDeactivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) {
        final DandelionActivationSpec sampleActivationSpec = (DandelionActivationSpec) activationSpec;

        final EndpointTarget endpointTarget = targets.get(sampleActivationSpec);
        if (endpointTarget == null) {
            throw new IllegalStateException("No EndpointTarget to undeploy for ActivationSpec " + activationSpec);
        }

        endpointTarget.messageEndpoint.release();
    }

    public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException {
        return new XAResource[0];
    }

    public void sendMessage(final String message) {
        final Collection<EndpointTarget> endpoints = this.targets.values();
        for (final EndpointTarget endpoint : endpoints) {
            endpoint.invoke(message);
        }
    }

    public static class EndpointTarget {
        private final MessageEndpoint messageEndpoint;

        public EndpointTarget(final MessageEndpoint messageEndpoint) {
            this.messageEndpoint = messageEndpoint;
        }

        public void invoke(final String message) {
            ((InboundListener) this.messageEndpoint).receiveMessage(message);
        }
    }
}

person mah454    schedule 03.07.2020    source источник
comment
Кто-нибудь когда-либо работал с входящим JCA на сервере приложений Liberty?   -  person mah454    schedule 06.07.2020


Ответы (2)


У иранцев есть пословица: кто ищет, тот ищет
Наконец, после 10 дней поиска в интернете и написания простых кодов. Я нашел, как решить эту проблему.
Зависит от сервера приложений, конечная точка сообщения не должна создаваться методом endpointActivation.
на самом деле сервер приложений TomEE не приводит к каким-либо исключениям для этого кода, но сервер приложений Liberty приводит к этим исключениям.
Я написал несколько простых приложений и опубликовал их на github.
вы можете скомпилировать и запустить это приложение как на TomEE, так и на Liberty.
В будущем я опубликую больше примеров, чтобы вы тоже могли его использовать .

Мой репозиторий GitHub

person mah454    schedule 24.07.2020

Я также получил CNTR4015W: Конечная точка сообщения для .. bean не может быть активирована, поскольку спецификация активации .. недоступна.

Проблема заключалась в том, что я использовал .ear-name/.mdb-name/ejb-name, но также установил другой <module-name> в ejb-jar.xml (который имеет приоритет)

Это описано в примечании по адресу https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_dep_msg_mdbjca.html

person weberjn    schedule 28.08.2020