Java EE、JCA、およびjNode 2.Xが発衚



こんにちは、ナヌザヌ名。

すぐに蚀わなければならないのは、この投皿の99がJava EEコネクタアヌキテクチャに関するものであり、コヌド䟋があるずいうこずです。 Fidonetに぀いお1を獲埗したのは、最埌に理解できるでしょう。



怠け者のために再開
JMSおよびJCA-兄匟受信ボックスはMessageDrivenBeanを受け入れ、発信送信者はConnectionFactoryを介しお送信されたす。

むンバりンド接続の最小パッケヌゞは、アりトバりンド接続の堎合は4クラス-8クラスであり、アダプタヌはアプリケヌションサヌバヌ偎で構成されたす。

さらに-詳现ず痛みのみ





そもそも-問題の歎史ずビゞネス䞊の問題の解決策。



問題の声明



既存のビゞネスシステム「システムA」を、䜕幎も前に開発された独自のデヌタ転送プロトコル「システムB」のみを理解する別のシステムず統合するタスクを䞎えられたした。 他の人のシステムを倉曎するこずは䞍可胜です;したがっお、タスクは特定のバス/プロキシを曞くこずに芁玄されたす。 統合は、メッセヌゞをある圢匏から別の圢匏に倉換するプロセスでやり取りするこずにありたす。



システム「A」には倚くの最新の統合メカニズムがあり、最も䜿いやすいものはWebサヌビスずしお認識されおいたした。 JEEの暙準的な統合スケルトン-JAX-WS + EJB +保蚌されたメッセヌゞ配信のためのJMSが、この堎合に速やかに提出されたした。

しかし、システム「B」で動䜜する暙準ツヌルはありたせんでした。 EJBコンテキストからネットワヌクを操䜜しようずするTimidの詊みは倱敗に終わりたした。Googleはこの問題に察する2぀の解決策を提案したした。 2番目のパスが遞択されたこずは明らかです。以前はJCAで働いたこずはなかったので、䜕か新しいこずを孊ぶのは垞に面癜いです。



リサヌチ



Googleを掘り始めお、私はかなり䞭断したした。 圌らはWHATを曞いたすべおの堎所コネクタヌ、マネヌゞャヌ、アダプタヌなどを正確に行う必芁がありたすが、それを行う方法をほずんど曞きたせんでした。 「他の人のコヌドを芋おプロセスを理解する」暙準的な方法は倱敗したした-他の人のコヌドは非垞に貧匱であるため、䜕かを理解するこずができたせんでした。



JSR 322ずgoogle codeで唯䞀のgoogle adapterの2぀が助けになりたした。 実際、これが出発点でした。jca-socketsからサンプルを展開し、pdfを開くず、実際の動䜜を実際に理解しお理解し始めたした。



調査ず実隓に玄16時間を費やしお、次のこずがわかりたした。



JCAモゞュヌルには、内郚にInboxずOutboxの2぀の独立した郚分がありたす。 これらのパヌツは、䞀緒にするこずも別々にするこずもできたす。 さらに、いく぀かありたす。 モゞュヌル自䜓はjavax.resource.spi.ResourceAdapterを実装するクラスに登録され、 META-INF / ra.xmlで指定されたすが 、ResourceAdapterは䞻にInboxでの䜜業に必芁です。 Outboxの堎合、アダプタヌは䜕もせず、そのスケルトンを埋めるこずさえできたせん。



受信トレむ



着信チャネルはMessageEndpoint 'y通垞は@MessageDrivenBeanです。はい、JCAはJMSの根源ですにバむンドし 、 ActivationSpec ' ohmによっおアクティブ化されたす。

META-INF / ra.xml -ResourceAdapterおよびむンバりンドストリヌムの説明

ra.xml
<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" metadata-complete="true"> <vendor-name>xxx-services</vendor-name> <eis-type>FidoNet</eis-type> <resourceadapter-version>2.5</resourceadapter-version> <resourceadapter> <!-- ,   javax.resource.spi.ResourceAdapter; config-property - ,     / --> <resourceadapter-class>in.fidonode.binkp.ra.BinkpServerResourceAdapter</resourceadapter-class> <config-property> <config-property-name>version</config-property-name> <config-property-type>java.lang.String</config-property-type> <config-property-value>jnode-jee 2.5 binkp/1.1</config-property-value> </config-property> <!--    --> <inbound-resourceadapter> <messageadapter> <messagelistener> <!-- ,    @MessageDrivenBean  ,       --> <messagelistener-type>in.fidonode.binkp.ra.BinkpMessageListener</messagelistener-type> <activationspec> <!-- - ,    @ActivationConfigProperty,        --> <activationspec-class>in.fidonode.binkp.ra.BinkpActivationSpec</activationspec-class> <!--    --> <required-config-property> <config-property-name>listenPort</config-property-name> </required-config-property> <!--    --> <config-property> <config-property-name>listenPort</config-property-name> <config-property-type>java.lang.Integer</config-property-type> <config-property-value>24554</config-property-value> </config-property> </activationspec> </messagelistener> </messageadapter> </inbound-resourceadapter> </resourceadapter> </connector>
      
      









BinkpMessageListenerむンタヌフェむスはクラむアント甚であり、クラスパスにある必芁がありたす。



ここに持っおきたす

 public interface BinkpMessageListener { public void onMessage(FidoMessage message); }
      
      







次に、 ResourceAdapterの最も単玔な実装を怜蚎したす。

BinkpServerResourceAdapter.java
 public class BinkpServerResourceAdapter implements ResourceAdapter, Serializable { private static final long serialVersionUID = 1L; private static Logger log = Logger.getLogger(BinkpServerResourceAdapter.class .getName()); private ConcurrentHashMap<BinkpActivationSpec, BinkpEndpoint> activationMap = new ConcurrentHashMap<BinkpActivationSpec, BinkpEndpoint>(); private BootstrapContext ctx; private String version; @Override public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) throws ResourceException { BinkpEndpoint activation = new BinkpEndpoint(ctx.getWorkManager(), (BinkpActivationSpec) spec, endpointFactory); activationMap.put((BinkpActivationSpec) spec, activation); activation.start(); log.info("endpointActivation(" + activation + ")"); } @Override public void endpointDeactivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) { BinkpEndpoint activation = activationMap.remove(spec); if (activation != null) activation.stop(); log.info("endpointDeactivation(" + activation + ")"); } @Override public void start(BootstrapContext ctx) throws ResourceAdapterInternalException { this.ctx = ctx; log.info("start()"); } @Override public void stop() { for (BinkpEndpoint act : activationMap.values()) { act.stop(); } activationMap.clear(); log.info("stop()"); } @Override public XAResource[] getXAResources(ActivationSpec[] arg0) throws ResourceException { return null; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } }
      
      









ここで䜕が起こっおいたすか JCAモゞュヌルがロヌドされるず、BinkpServerResourceAdapterクラスのむンスタンスが䜜成され、そのパラメヌタヌこの堎合はバヌゞョンフィヌルドが入力され、startメ゜ッドが呌び出されたす。

実際、startメ゜ッド内で倚くのこずができたすが、この䟋では、埌でWorkManagerを取埗するためにコンテキストを保存するだけです。



アプリケヌションサヌバヌが@MessageDrivenBeanを芋぀けるず、Beanが実装するむンタヌフェヌスにメッセヌゞを送信するアダプタヌを芋぀けようずしたす。 JMSの堎合、これはMessageListenerであり、 BinkpMessageListenerがありたす。 ActivationSpecが䜜成され javax.resource.spi.ActivationSpecを実装するBinkpActivationSpecがありたす、activationConfigのデヌタに埓っお入力されるフィヌルド、MessageEndpointFactoryが䜜成され、ResourceAdapter.endpointActivationが呌び出されたす。 この機胜では、MDBにあった構成に基づいお䜜成するために、tcp / ipサヌバヌたたはunix-socketで動䜜するストリヌムのいずれであっおも、着信接続を受け入れる「サヌバヌ」を䜜成する必芁がありたす。 BinkpEndpointクラスは、たさにこの「サヌバヌ」です。

Binkpendnd.java
 public class BinkpEndpoint implements Work, FidoMessageListener { private static final Logger logger = Logger.getLogger(BinkpEndpoint.class .getName()); private BinkpServer server; private final WorkManager workManager; private final MessageEndpointFactory messageEndpointFactory; public BinkpEndpoint(WorkManager workManager, BinkpActivationSpec activationSpec, MessageEndpointFactory messageEndpointFactory) { this.workManager = workManager; this.messageEndpointFactory = messageEndpointFactory; server = new BinkpServer(activationSpec.getListenPort(), this); } public void start() throws ResourceException { workManager.scheduleWork(this); } public void stop() { if (server != null) { server.stop(); } } /**  FidoMessageListener **/ @Override public Message incomingMessage(FidoMessage message) { String message = msg.encode(); BinkpMessageListener listener = (BinkpMessageListener) messageEndpointFactory .createEndpoint(null); listener.onMessage(message); } /**  Work **/ @Override public void run() { server.start(); } /**  Work **/ @Override public void release() { stop(); } }
      
      









䞀郚の゚ンドポむントがどこにでも衚瀺されるこずに気付くかもしれたせん。 私はこれにいく぀かのギャグがあったので、解読したす

゚ンドポむントは、着信ストリヌムがリッスンしおいるものです。 これは、endpointActication関数が適甚される堎所です。

MessageEndpoint-特定のメッセヌゞを凊理するMDBむンスタンス。 MessageEndpointFactory.createEndpointを呌び出しお取埗したすこの関数はメむンスレッドから呌び出すこずはできたせん。 MDBむンタヌフェヌスに簡単にキャストできたす。



実際には、それだけです。 䞍芁なBinkpServerの実装は省略したすが、原則は明確である必芁がありたす。最小の「むンバりンド」JCAは4぀のクラスResourceAdapter、MessageListener、ActivationSpec、Endpointで構成されたす。



゚ンドポむントの䜜成ず着信の凊理

 @MessageDriven(messageListenerInterface = BinkpMessageListener.class, activationConfig = { @ActivationConfigProperty(propertyName = "listenPort", propertyValue = "24554") }) public class ReceiveMessageBean implements BinkpMessageListener { @Override public void onMessage(FidoMessage msg) { // do smth with mesaage } }
      
      







発信





そしおここでは、すべおがもっず楜しく、最小の「発信」JCAは最倧8クラスで構成されおおり、これは「着信」の2倍です。 しかし、順番に芋おみたしょう。



META-INF / ra.xml -ResourceAdapterおよびアりトバりンドストリヌムの説明



ra.xml
 <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" metadata-complete="true"> <vendor-name>xxx-services</vendor-name> <eis-type>FidoNet</eis-type> <resourceadapter-version>2.5</resourceadapter-version> <resourceadapter> <!-- ,   javax.resource.spi.ResourceAdapter; config-property - ,     / --> <resourceadapter-class>in.fidonode.binkp.ra.BinkpServerResourceAdapter</resourceadapter-class> <config-property> <config-property-name>version</config-property-name> <config-property-type>java.lang.String</config-property-type> <config-property-value>jnode-jee 2.5 binkp/1.1</config-property-value> </config-property> <!--   .    --> <outbound-resourceadapter> <connection-definition> <!--      JEE-,       --> <managedconnectionfactory-class>in.fidonode.binkp.ra.ManagedConnectionFactory</managedconnectionfactory-class> <!--  ,     .       classpath --> <connectionfactory-interface>in.fidonode.binkp.ra.ConnectionFactory</connectionfactory-interface> <connectionfactory-impl-class>in.fidonode.binkp.ra.ConnectionFactoryImpl</connectionfactory-impl-class> <!-- ,     .       classpath --> <connection-interface>in.fidonode.binkp.ra.Connection</connection-interface> <connection-impl-class>in.fidonode.binkp.ra.ConnectionImpl</connection-impl-class> </connection-definition> <!--       ,     --> <transaction-support>NoTransaction</transaction-support> <reauthentication-support>false</reauthentication-support> </outbound-resourceadapter> <!--    --> <inbound-resourceadapter> <!-- ... --> </inbound-resourceadapter> </resourceadapter> </connector>
      
      









ConnectionおよびConnectionFactoryむンタヌフェヌスはクラむアント甚であり、クラスパスにある必芁がありたす。 すぐにそれらをここに持っおきおください、面癜いものは䜕もありたせん。



BinkpClientは提䟛したせん:-)

 public interface Connection { public BinkpClient connect(String hostname, int port); } public interface ConnectionFactory { public Connection createConnection(); }
      
      







接続は管理察象および管理察象倖です。 1぀目-ホむッスル、リスナヌ、その他、2぀目-なし。

ManagedConnectionFactoryを実装するクラスは、䞡方のタむプの接続を䜜成できる必芁がありたす。

ManagedConnectionFactory.java
 public class ManagedConnectionFactory implements javax.resource.spi.ManagedConnectionFactory { private PrintWriter logwriter; private static final long serialVersionUID = 1L; /** *    unmanaged- */ @Override public Object createConnectionFactory() throws ResourceException { return new ConnectionFactoryImpl(); } /** *  managed-  managed-connection */ @Override public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException { return new ManagedConnectionFactoryImpl(this, cxManager); } /** *  managed- */ @Override public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { return new in.fidonode.binkp.ra.ManagedConnection(); } @Override public PrintWriter getLogWriter() throws ResourceException { return logwriter; } @SuppressWarnings("rawtypes") @Override public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { ManagedConnection result = null; Iterator it = connectionSet.iterator(); while (result == null && it.hasNext()) { ManagedConnection mc = (ManagedConnection) it.next(); if (mc instanceof in.fidonode.binkp.ra.ManagedConnection) { result = mc; } } return result; } @Override public void setLogWriter(PrintWriter out) throws ResourceException { logwriter = out; } }
      
      









アプリケヌションがJEEサヌバヌからコネクタを芁求するず、アプリケヌションサヌバヌはManagedConnectionFactoryにConnectionFactoryを䜜成するよう芁求し、それをアプリケヌションに枡したす。



ご芧のずおり、 ConnectionFactoryも管理および非管理です。 原則ずしお、これはすべお1぀のクラスに枛らすこずができたすが、䜕をどのように転送するか、トランザクションがあるかどうかなどに倧きく䟝存したす。

ConnectionFactoryImlは新しいConnectionImplを䜜成するだけですが、 ManagedConnectionFactoryImplはもう少し耇雑です。



ManagedConnectionFactoryImpl.java
 public class ManagedConnectionFactoryImpl implements ConnectionFactory { private ManagedConnectionFactory factory; private ConnectionManager manager; public ManagedConnectionFactoryImpl(ManagedConnectionFactory factory, ConnectionManager manager) { super(); this.factory = factory; this.manager = manager; } /**  managed-  -ManagedConnectionFactory **/ @Override public Connection createConnection() { try { return (Connection) manager.allocateConnection(factory, null); } catch (ResourceException e) { return null; } } }
      
      









javax.resource.spi.ManagedConnectionを実装するManagedConnectionは、ホむッスルずリスナヌを远加するだけのConnectionむンタヌフェむスのラッパヌです。 ManagedConnectionFactoryImpl.createConnectionからConnectionManager.allocateConnection経由で接続を䜜成するずきに呌び出すManagedConnectionFactory.createManagedConnectionを返すのはこのクラスです。



ManagedConnection.java
 public class ManagedConnection implements javax.resource.spi.ManagedConnection { private PrintWriter logWriter; private Connection connection; private List<ConnectionEventListener> listeners; public ManagedConnection() { listeners = Collections .synchronizedList(new ArrayList<ConnectionEventListener>()); } @Override public void associateConnection(Object connection) throws ResourceException { if (connection != null && connection instanceof Connection) { this.connection = (Connection) connection; } } @Override public Object getConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { if (connection == null) { connection = new ManagedConnectionImpl(); } return connection; } @Override public void cleanup() throws ResourceException { } @Override public void destroy() throws ResourceException { } @Override public PrintWriter getLogWriter() throws ResourceException { return logWriter; } @Override public ManagedConnectionMetaData getMetaData() throws ResourceException { throw new NotSupportedException(); } @Override public XAResource getXAResource() throws ResourceException { throw new NotSupportedException(); } @Override public LocalTransaction getLocalTransaction() throws ResourceException { return null; } @Override public void setLogWriter(PrintWriter out) throws ResourceException { logWriter = out; } @Override public void addConnectionEventListener(ConnectionEventListener listener) { if (listener != null) { listeners.add(listener); } } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { if (listener != null) { listeners.remove(listener); } } }
      
      









さお、今、私たちは最も簡単なこずになりたす-接続を実装する:-)

 public class ConnectionImpl implements Connection { @Override public BinkpClient connect(String hostname, int port) { return new BinkpClient(hostname, port); } }
      
      







アりトバりンド接続を確立する発信コヌルチェヌン

ManagedConnectionFactory.createConnectionFactory

-> ManagedConnectionFactoryImpl.createConnection

-> onnectionManager.allocateConnection

---> ManagedConnectionFactory.createManagedConnection

----> ManagedConnection.getConnection

-----> ManagedConnectionImpl.connect



さお、このアダプタで動䜜するようにアプリケヌションサヌバヌを構成するこずを忘れないでください。たあ、jndiを指定しおください。



呌び出すコヌド

  private BinkpClient createBinkpClient(String host, int port) { ConnectionFactory cf = ((ConnectionFactory) new InitialContext().lookup("java:eis/BinkpConnectionFactory")); Connection conn = cf.getConnection(); return conn.connect(host, port); }
      
      





そしお、フィドはどこにいたすか





そしお、ほずんど理由はありたせん。 実際のずころ、元のタスクはbinkpに関するものではなく、機胜しおいたため、NDAの察象ずなりたした。 したがっお、JCAを理解し、Habréに関する蚘事を曞くために必芁なものを決定した埌振り返っおみるず、誰もそのような蚘事を曞いおいない理由を理解し始めたす。これはトランザクションなしですノヌドを単䞀の耳ずしお実行したす。 か぀お、私がプロゞェクトを開始するにはJCAの知識では䞍十分でした:-)



このために、私は䞊蚘の䟋を曞きたした、そしお、圌らは働きさえしたした。 したがっお、䞀般的にJava eeを緎習し、特にJava seからリファクタリングする堎合は、文字を曞いおコヌドをコミットしおください。 はい、私はただポむントを取りたす。



ご静聎ありがずうございたした。 タむプミスはコメントに曞くこずができたす、私はそれらがたくさんあるこずは間違いありたせん。



All Articles