SNMPエージェントをリッスンし、受信したSNMPメッセージをJFrameウィンドウのJTextAreaに出力することを目的としたJavaのSNMPトラップアプリケーションがあります。
以下のパート I は、クラス TrapReceiver の内容を示すソース コードです。このクラスでは、リッスン メソッドが仕事を最大限に活用する場所です。このクラスは、前述の JTeaxtArea にメッセージを表示する予定の JFrame クラス内でインスタンス化されます。JTextArea オブジェクトの参照、SNMP エージェントの URL、およびポートを TrapReceiver クラスのコンストラクターに送信し、TrapReceiver オブジェクトの run メソッドを呼び出して、JFrame インスタンス以外の別のスレッドで実行を開始します。以下のパート II では、JFrame インスタンス内でクラス TrapReeceiver をインスタンス化する方法を示します。
アプリケーションを実行すると、JFrame インスタンス (つまり、GUI) がフリーズし、以下のパート I に示すクラス TrapReeceiver をインスタンス化する JFrame インスタンス内の JTeaxtArea にメッセージが出力されていないことに気付きました。
私の質問は、TRapReceiver 自体が別のスレッドとして実行されているのに、なぜ JFrame インスタンス (すなわち GUI) がフリーズしているのかということです。また、このフリーズの問題を解決するにはどうすればよいのでしょうか。前もって感謝します。
PS: TrapReceiver が正常に動作し、GUI なしでスタンドアロン アプリケーションとして実行している場合にメッセージを標準出力に出力できることを確認しましたが、スレッド同期の問題が原因で何らかの形でフリーズしているのはこの GUI です。スレッドに入れずに TrapReceiver を実行しようとしましたが、この場合でも GUI はまだフリーズしていました。
パート I
package com.[Intenionally removed].snmp;
import java.io.IOException;
import javax.swing.JTextArea;
import org.snmp4j.*;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.security.Priv3DES;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.TransportIpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.transport.AbstractTransportMapping;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
public class TrapReceiver implements CommandResponder, Runnable {
private String targetSnmpAgentURL;
private int targetSnmpAgentPort;
private JTextArea outConsole;
public TrapReceiver() {
}
public TrapReceiver(JTextArea outConsole) {
this.outConsole = outConsole;
}
public TrapReceiver(JTextArea outConsole, String targetSnmpAgentURL, int targetSnmpAgentPort) {
this.targetSnmpAgentURL = targetSnmpAgentURL;
this.targetSnmpAgentPort = targetSnmpAgentPort;
this.outConsole = outConsole;
try {
listen(new UdpAddress(targetSnmpAgentURL + "/" + targetSnmpAgentPort));
} catch (IOException e) {
e.printStackTrace();
}
}
public final synchronized void listen(TransportIpAddress address) throws IOException {
AbstractTransportMapping transport;
if (address instanceof TcpAddress) {
transport = new DefaultTcpTransportMapping((TcpAddress) address);
} else {
transport = new DefaultUdpTransportMapping((UdpAddress) address);
}
ThreadPool threadPool = ThreadPool.create("DispatcherPool", 10);
MessageDispatcher mDispathcher = new MultiThreadedMessageDispatcher(
threadPool, new MessageDispatcherImpl());
// add message processing models
mDispathcher.addMessageProcessingModel(new MPv1());
mDispathcher.addMessageProcessingModel(new MPv2c());
// add all security protocols
SecurityProtocols.getInstance().addDefaultProtocols();
SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES());
// Create Target
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
Snmp snmp = new Snmp(mDispathcher, transport);
snmp.addCommandResponder(this);
transport.listen();
System.out.println("Listening on " + address);
try {
this.wait();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* This method will be called whenever a pdu is received on the given port
* specified in the listen() method
*/
@Override
public synchronized void processPdu(CommandResponderEvent cmdRespEvent) {
//System.out.println("Received PDU...");
outConsole.append("Received PDU...\n");
PDU pdu = cmdRespEvent.getPDU();
if (pdu != null) {
outConsole.append("Trap Type = " + pdu.getType() + "\n");
outConsole.append("Alarm Type: " + pdu.getVariableBindings().get(4) + "\n");
outConsole.append("Alarm Message: " + pdu.getVariableBindings().get(9) + "\n\n");
}
}
@Override
public void run() {
try {
listen(new UdpAddress(targetSnmpAgentURL + "/" + targetSnmpAgentPort));
} catch (IOException e) {
outConsole.append("\nError occured while listening to SNMP messages: \n" + e.getMessage() + "\n\n");
}
}
} //end of class TrapReceiver
パートⅡ
以下では、スレッド内でクラス TrapReceiver のインスタンスを実行します。
private void jButtonStartListeningSNMPActionPerformed(java.awt.event.ActionEvent evt) {
Thread snmpThread =
new Thread(new TrapReceiver(jTextAreaSNMPAlarmOutput, jTextFieldSnmpAgentUrl.getText().trim(), Integer.parseInt(jTextFieldSnmpAgentPort.getText().trim())));
snmpThread.start()
}