2010-12-09 3 views
1

나는 나를 위해 새로운 시나리오를 다루고있다. 나는 어떤 사람들에게는 공통적이라고 생각한다. ..요청 - 응답 패턴을 사용하여 동기 호출로 JMS를 WebSphere MQ 브릿지로 랩핑하는 방법은 무엇입니까?

요구 사항에 따라, 사용자 경험을 구축해야한다. 웹 서비스 호출은 실제로 비동기 JMS-MQ 브릿지를 사용하여 IBM MQ Series에 호출을 위임합니다.

클라이언트가 웹 서비스를 호출하고 그의 메시지가 WebSphere MQ로 전달 될 App 서버의 JMS 대기열에 게시되어야하고 처리 후 응답이 FIXED JMS 대기열 끝점의 App 서버로 다시 전달됩니다 .

WebSphere MQ가 클라이언트에게 시간 종료 신호를 보내고이 트랜잭션을 무시하는 것보다 WebSphere MQ가 정의 된 시간 내에 응답을 전달하지 않는 경우에 시간이 초과 될 필요가있는 요구 사항입니다.

문제의 스케치가 이어집니다.

응답이 도착하거나 시간이 초과 될 때까지 웹 서비스에 대한 요청을 차단해야합니다.

보다이 작업에 도움이되는 공개 라이브러리가 필요합니다. 아니면 유일한 해결책은 스레드를 차단하고 응답을 위해 풀링을 유지하는 것입니까? 응답이 도착하면 알림을받을 청취자가있는 블록을 구현할 수 있습니까?

토론의 비트가 내 아이디어를 정리하려고 지금 매우 도움이 될 것입니다. 제안 사항이 있으십니까? 나는 이것에 대한 해결책에 도착 코딩 며칠 후)

alt text

답변

1

을,

은 내가 사진을 삭제 도움이되기를 바랍니다 스케치를 가지고있다. JAX-WS 주석과 표준 JMS가있는 표준 EJB3을 사용하고 있습니다.

요구 사항을 충족시키기 위해 지금까지 작성한 코드가 다음과 같습니다. standart 컨테이너 관리 트랜잭션 (CMT)을 사용하여 bean 관리 트랜잭션 (BMT)이있는 Stateless Session Bean입니다. JMS 상호 작용을 두 트랜잭션 모두에 넣으려고했기 때문에 동일한 방법으로 JMS 대기열과의 각 상호 작용에 대한 트랜잭션을 시작하고 완료해야한다는 것을 알아 두십시오. 나는이 솔루션을 위해 weblogic을 사용하고있다. 또한 기본적으로 큐 엔드 포인트 jms/Pergunta에서 메시지를 소비하는 MDB를 코딩하고이 문제의 MQ 측에서 예상되는 동작을 조롱하기 위해 jms/Resposta 큐에 응답 메시지를 배치합니다. 실제로 실제 시나리오에서는 메인 프레임에 COBOL 응용 프로그램이 있거나 메시지를 처리하고 응답 큐에 응답을 배치하는 다른 Java 응용 프로그램이있을 것입니다.

누군가이 코드를 시도해야한다면 기본적으로 J2EE5 컨테이너가 있고 jndi 이름이있는 2 개의 대기열 (jms/Pergunta 및 jms/Resposta) 만 구성하면됩니다.

는 EJB/Webservice를 코드 :

@Stateless 
@TransactionManagement(TransactionManagementType.BEAN) 
@WebService(name="DJOWebService") 
public class DJOSessionBeanWS implements DJOSessionBeanWSLocal { 

    Logger log = Logger.getLogger(DJOSessionBeanWS.class.getName()); 

    @Resource 
    SessionContext ejbContext; 

    // Defines the JMS connection factory. 
    public final static String JMS_FACTORY = "weblogic.jms.ConnectionFactory"; 

    // Defines request queue 
    public final static String QUEUE_PERG = "jms/Pergunta"; 

    // Defines response queue 
    public final static String QUEUE_RESP = "jms/Resposta"; 


    Context ctx; 
    QueueConnectionFactory qconFactory; 

    /** 
    * Default constructor. 
    */ 
    public DJOSessionBeanWS() { 
     log.info("Construtor DJOSessionBeanWS"); 
    } 

    @WebMethod(operationName = "processaMensagem") 
    public String processaMensagem(String mensagemEntrada, String idUnica) 
    { 
     //gets UserTransaction reference as this is a BMT EJB. 
     UserTransaction ut = ejbContext.getUserTransaction(); 
     try { 

      ctx = new InitialContext(); 
      //get the factory before any transaction it is a weblogic resource. 
      qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY); 
      log.info("Got QueueConnectionFactory"); 
      ut.begin(); 
      QueueConnection qcon = qconFactory.createQueueConnection(); 
      QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 
      Queue qs = (Queue) (new InitialContext().lookup("jms/Pergunta")); 
      TextMessage message = qsession.createTextMessage("this is a request message"); 
      message.setJMSCorrelationID(idUnica); 
      qsession.createSender(qs).send(message); 
      ut.commit(); 
      qcon.close(); 
      //had to finish and start a new transaction, I decided also get new references for all JMS related objects, not sure if this is REALLY required 
      ut.begin(); 
      QueueConnection queuecon = qconFactory.createQueueConnection(); 
      Queue qreceive = (Queue) (new InitialContext().lookup("jms/Resposta")); 
      QueueSession queuesession = queuecon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 
      String messageSelector = "JMSCorrelationID = '" + idUnica + "'"; 
      //creates que receiver and sets a message selector to get only related message from the response queue. 
        QueueReceiver qr = queuesession.createReceiver(qreceive, messageSelector); 
      queuecon.start(); 
      //sets the timeout to keep waiting for the response... 
      TextMessage tresposta = (TextMessage) qr.receive(10000); 
      if(tresposta != null) 
      { 
       ut.commit(); 
       queuecon.close(); 
       return(tresposta.toString()); 
      } 
      else{ 
       //commints anyway.. does not have a response though 
       ut.commit(); 
       queuecon.close(); 
       log.info("null reply, returned by timeout.."); 
       return "Got no reponse message."; 
      } 



     } catch (Exception e) { 
      log.severe("Unexpected error occurred ==>> " + e.getMessage()); 
      e.printStackTrace(); 
      try { 
       ut.commit(); 
      } catch (Exception ex) { 
       ex.printStackTrace(); 
      } 
      return "Error committing transaction after some other error executing ==> " + e.getMessage(); 
     } 

    } 
} 

그리고이 문제의 MQ 측 조롱 MDB에 대한 코드이다. 내 테스트 중에 Thread.sleep 조각을 사용하여 솔루션의 유효성을 검사하기 위해 클라이언트 측에서 시간 초과를 시뮬레이트하고 테스트했지만이 버전에서는 존재하지 않습니다.

/** 
* Mock to get message from request queue and publish a new one on the response queue. 
*/ 
@MessageDriven(
     activationConfig = { @ActivationConfigProperty(
       propertyName = "destinationType", propertyValue = "javax.jms.Queue" 
     ) }, 
     mappedName = "jms/Pergunta") 
public class ConsomePerguntaPublicaRespostaMDB implements MessageListener { 

    Logger log = Logger.getLogger(ConsomePerguntaPublicaRespostaMDB.class.getName()); 

    // Defines the JMS connection factory. 
    public final static String JMS_FACTORY = "weblogic.jms.ConnectionFactory"; 

    // Define Queue de resposta 
    public final static String QUEUE_RESP = "jms/Resposta"; 


    Context ctx; 
    QueueConnectionFactory qconFactory; 



    /** 
    * Default constructor. 
    */ 
    public ConsomePerguntaPublicaRespostaMDB() { 
     log.info("Executou construtor ConsomePerguntaPublicaRespostaMDB"); 
     try { 
      ctx = new InitialContext(); 
     } catch (NamingException e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * @see MessageListener#onMessage(Message) 
    */ 
    public void onMessage(Message message) { 
     log.info("Recuperou mensagem da fila jms/FilaPergunta, executando ConsomePerguntaPublicaRespostaMDB.onMessage"); 
     TextMessage tm = (TextMessage) message; 

     try { 
      log.info("Mensagem recebida no onMessage ==>> " + tm.getText()); 

      //pega id da mensagem na fila de pergunta para setar corretamente na fila de resposta. 
      String idMensagem = tm.getJMSCorrelationID(); 
      log.info("Id de mensagem que sera usada na resposta ==>> " + idMensagem); 

      qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY); 
      log.info("Inicializou contexto jndi e deu lookup na QueueConnectionFactory do weblogic com sucesso. Enviando mensagem"); 
      QueueConnection qcon = qconFactory.createQueueConnection(); 
      QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 
      Queue queue = (Queue) (ctx.lookup("jms/Resposta")); 
      TextMessage tmessage = qsession.createTextMessage("Mensagem jms para postar na fila de resposta..."); 
      tmessage.setJMSCorrelationID(idMensagem); 
      qsession.createSender(queue).send(tmessage); 
     } catch (JMSException e) { 
      log.severe("Erro no onMessage ==>> " + e.getMessage()); 
      e.printStackTrace(); 
     } catch (NamingException e) { 
      log.severe("Erro no lookup ==>> " + e.getMessage()); 
      e.printStackTrace(); 
     } 

    } 

} 

[]의

2

이봐, 당신의 자신의 솔루션을 게시 주셔서 감사합니다!

그래,이 경우 가장 좋은 방법은 timeout을 사용하는 receive()입니다.

시간 초과로 인해 읽지 않은 메시지에 어떤 일이 발생하는지주의하십시오. 클라이언트가 동일한 대기열에 다시 액세스하면 부실 메시지를받을 수 있습니다.

타임 아웃 된 메시지가시기 적절하게 삭제되었는지 확인하십시오 (다른 이유로 인해 처리되지 않은 메시지가있는 큐를 채우지 않는 경우).

코드 (메시지 생성자의 유효 기간 설정) 또는 Websphere MQ 서버 (메시지를 자동으로 만료시키는 대기열 사용)를 통해 쉽게 수행 할 수 있습니다.

코드의 MQ 측을 수정할 수 없거나 수정하지 않으려면 후자가 더 쉽습니다. 그것은 내가 뭘 할거야 :

+0

예, 우리는 시간이 초과 된 메시지가 앞으로 전달되며 다른 코드가 그들과 거래하는 오류 대기열이 있습니다. –

관련 문제