2017-02-27 6 views
0

Ich versuche CDI und die beste Methode zu finden, die meinen Bedürfnissen entspricht. Ich habe einen Dienst (TcpServiceImpl), der mit einfacher TCP-Kommunikation interagiert. Jetzt hat dieser Dienst einige Punkte, an denen er jemanden darüber informieren muss, dass etwas passiert ist. Für diese Informationen habe ich die Schnittstelle TcpConnection, die CDI in die richtige Implementierung injiziert werden muss. Ein anderes Problem ist, dass der Dienst TcpServiceImpl selbst in einen Job (TcpConnectionJob) eingefügt wird, der periodisch ausgeführt wird und den Dienst anruft, um Dinge zu tun. Das bedeutet, dass der Service TcpServiceImpl mehrfach vorhanden ist. Jeder hat eine andere tcp-Verbindung, die er behandelt und ein anderes Gerät hat, das einen anderen Treiber/Protokoll benötigt, um in die Schnittstelle TcpConnection injiziert zu werden.Injectind Implementierung automatisch zur Laufzeit über CDI

Lassen Sie zeigen mir die drei Elemente Teil in diesem Szenario unter:

Hier ist die Schnittstelle, die mehrere Implementierungen erhalten wird:

public interface TcpConnection 
{ 

    /** 
    * Connected. 
    * 
    * @throws NGException the NG exception 
    */ 
    public void connected() throws NGException; 

    /** 
    * This method will send the received data from the InputStream of the connection. 
    * 
    * @param data the received data 
    * @throws NGException the NG exception 
    */ 
    public void received(byte[] data) throws NGException; 

    /** 
    * Usable for the protocol to send data to the device. 
    * 
    * @param data the data to send to the device (Will be converted to byte[] with getBytes()) 
    * @throws NGException the NG exception 
    */ 
    public void send(String data) throws NGException; 

    /** 
    * Usable for the protocol to send data to the device. 
    * 
    * @param data the data to send to the device (Will be send as is) 
    * @throws NGException the NG exception 
    */ 
    public void send(byte[] data) throws NGException; 

    /** 
    * This method will inform the protocol that the connection got closed. 
    * 
    * @throws NGException the NG exception 
    */ 
    public void closed() throws NGException; 
} 

Auch hier ist ein Beispiel-Snippet, wenn dies in heißen mein bestehender Service:

public class TCPServiceImpl implements TCPService, Runnable 
{ 
/** The callback. */ 
private TcpConnection callback; 
private void disconnect() 
{ 
    connection.disconnect(); 
    if (!getStatus(jndiName).equals(ConnectionStatus.FAILURE)) 
    { 
    setStatus(ConnectionStatus.CLOSED); 
    } 
    /* TODO: Tell driver connection is closed! */ 
    callback.closed(); 
} 
} 

Unten ist die Klasse, die den Dienst aufruft, die dann die korrekte Umsetzung dynamisch injizieren muss für die Schnittstelle.

public class TcpConnectionJob implements JobRunnable 
{ 
    /** The service. */ 
    private TCPService service; 

    public void execute() 
    { 
    service.checkConnection(connection); 
    } 
} 

Der Service Injektion callback muss die Umsetzung des richtigen „Protokoll“ oder „Treiber“ verknüpft werden, die die Daten verarbeiten oder die Logik für das Gerät übersetzen. Es wird mehrere Treiber-Implementierungen der Schnittstelle geben, die anders funktionieren und ich muss die richtige injizieren. Ein Qualifier für diese Entscheidung könnte der Name des Geräts sein. Nun schaute ich auf die folgenden Links:

Understanding the necessity of type Safety in CDI

How to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class

How to use CDI qualifiers with multiple class implementations?

Frage:

Aber ich bin immer noch unsicher, welchen Weg/Methode zu verwenden, und was ist das richtiger Weg. Jede Hilfe wäre willkommen.

Mein erster Gedanke war, meine Schnittstelle zu einer Qualifier-Schnittstelle zu kopieren und diese mit der Möglichkeit anzufügen, den Qualifier einzugeben. Ist das eine gute Idee?

Antwort

0

Das ist also meine Lösung kam ich mit. Das einzige Problem ist jetzt, einen Callback zur Arbeit zu bekommen, aber das ist etwas anderes.Heres die Lösung, die für mich gearbeitet:

/** 
* The Qualifier interface TcpDriver. The value of this annotation is the name the implementation 
* is found under. Please only enter values that are configured in the wildfly config as the name of 
* the device. 
*/ 
@Documented 
@Qualifier 
@Retention(RUNTIME) 
@Target({ TYPE, FIELD, METHOD, PARAMETER }) 
public @interface TcpDriver 
{ 

    /** 
    * Value. 
    * 
    * @return the string 
    */ 
    String value(); 
} 

Die Standardimplementierung nur für die Qualifier-Schnittstelle:

/** 
* The Class TcpDriverImpl. 
*/ 
public class TcpDriverImpl extends AnnotationLiteral<TcpDriver> implements TcpDriver 
{ 

    /** The Constant serialVersionUID. */ 
    private static final long serialVersionUID = 1L; 

    /** The name. */ 
    private final String name; 

    /** 
    * Instantiates a new tcp driver impl. 
    * 
    * @param name the name 
    */ 
    public TcpDriverImpl(final String name) 
    { 
    this.name = name; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public String value() 
    { 
    return name; 
    } 

} 

nun eine Testimplementierung zu testen:

@TcpDriver("terminal1") 
@Dependent 
public class TestDriverImpl implements TcpConnection 
{ 

    /** The log. */ 
    private Log log; 

    @Inject 
    public void init(Log log) 
    { 
    this.log = log; 
    } 

    @Override 
    public void connected() throws NGException 
    { 
    // TODO Auto-generated method stub 
    log.info("IT WORKS!!"); 
    } 

    @Override 
    public void received(byte[] data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void send(String data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void send(byte[] data) throws NGException 
    { 
    // TODO Auto-generated method stub 

    } 

    @Override 
    public void closed() throws NGException 
    { 
    // TODO Auto-generated method stub 
    log.info("BYE BYE"); 
    } 

}

Last but not least, die Art, wie ich all das in meinen Service injiziert habe:

/** The callback Instance for the driver to find. */ 
    @Inject 
    @Any 
    private Instance<TcpConnection> callback; 

    private TcpConnection driver; 
    /** 
    * Inject driver. 
    */ 
    private void injectDriver() 
    { 
    final TcpDriver driver = new TcpDriverImpl(name); 
    this.driver = callback.select(driver).get(); 
    } 

Ich hoffe, das hilft jemand mit den gleichen Anforderungen, die ich hatte.

PS: Ein kleines Protokoll zu zeigen, es funktioniert, wenn Sie die Log-Ausgaben in der Testimplementierung überprüfen und dann auf dem Protokoll sehen :)

2017-02-28 08:37:00,011 INFO starting TCPConnection: TcpDevice1 with status: NOT_CONNECTED 
2017-02-28 08:37:00,018 INFO initializing terminal1 
2017-02-28 08:37:00,019 INFO Creating socket for: terminal1 with port: XXXXX 
2017-02-28 08:37:00,023 INFO Updated Status to CONNECTED for connection TcpDevice1 
2017-02-28 08:37:00,024 INFO opened connection to terminal1 
2017-02-28 08:37:00,026 INFO (terminal1) IT WORKS!! 
2017-02-28 08:37:00,038 INFO (terminal1) terminal1: In threaded method run 
2017-02-28 08:37:00,039 INFO (terminal1) waiting for data... 
2017-02-28 08:39:00,045 INFO (terminal1) Socket closed! 
2017-02-28 08:39:00,045 INFO (terminal1) BYE BYE 
1
+0

Leider kann ich nicht CDI Events verwenden. Ich wollte es ursprünglich so machen, aber da von der Anwendung eine große Menge an Datenverkehr und Daten erwartet wird, wurde meine Empfehlung abgelehnt. Soweit ich weiß, sind Ereignisse synchron, so dass das Auslösen eines Ereignisses dazu führt, dass das Programm darauf wartet, dass alle Beobachter beendet sind, bis weiterer Code ausgeführt wird. Was aber, wenn ich während der Benachrichtigung anderer über eingehende Daten aufpassen muss, dass Daten eintreffen? – Nico

+0

@Nico: Werfen Sie einen Blick auf diesen interessanten Artikel, der erklärt, wie Sie CDI Event Asynchronous machen können. Es kann eine Lösung für Sie sein: http://piotrowicki.com/2013/05/asynchronous-cdi-events/ – Rouliboy

+0

Vielen Dank für Ihren Artikel. Wirklich gut zu wissen und ich werde es speichern, aber ich würde gerne über eine Lösung nachdenken, ohne CDI-Ereignisse zu verwenden. Sagen wir es ist nicht möglich wegen der Ablehnung von jemandem. Meine Gedanken waren, irgendwie einen Produzenten in Kombination mit einem Qualifier zu erschaffen. Ist das eine gültige Strategie? – Nico

Verwandte Themen