Package org.olat.search.service.searcher

Source Code of org.olat.search.service.searcher.ClusteredSearchRequester

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.search.service.searcher;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.lucene.queryParser.ParseException;
import org.olat.core.commons.services.search.QueryException;
import org.olat.core.commons.services.search.SearchResults;
import org.olat.core.commons.services.search.ServiceNotAvailableException;
import org.olat.core.id.Identity;
import org.olat.core.id.Roles;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.Tracing;


/**
*
* Description:<br>
* This is a client side search proxy - delegates the search to the remote searcher.
*
* <P>
* Initial Date:  03.06.2008 <br>
* @author Lavinia Dumitrescu
*/
public class ClusteredSearchRequester implements OLATSearcherProxy {
 
  protected static final String JMS_RESPONSE_STATUS_PROPERTY_NAME = "response_status";
  protected static final String JMS_RESPONSE_STATUS_OK = "ok";
  protected static final String JMS_RESPONSE_STATUS_PARSE_EXCEPTION = "parse_exception";
  protected static final String JMS_RESPONSE_STATUS_QUERY_EXCEPTION = "query_exception";
  protected static final String JMS_RESPONSE_STATUS_SERVICE_NOT_AVAILABLE_EXCEPTION = "service_not_available";
 
  private long queryCount_ = 0; //counter for this cluster node
  private ConnectionFactory connectionFactory_;
  private Queue searchQueue_;
  private long receiveTimeout_ = 45000;
  private long timeToLive_ = 45000;
  private Connection connection_;
  private LinkedList<Destination> tempQueues_ = new LinkedList<Destination>();
  private LinkedList<Session> sessions_ = new LinkedList<Session>();
 
  /**
   * [used by spring]  
   */
  public ClusteredSearchRequester() {
    //default constructor   
  }
 
  public void setConnectionFactory(ConnectionFactory conFac) {
    connectionFactory_ = conFac;
  }
 
  public void setSearchQueue(Queue searchQueue) {
    this.searchQueue_ = searchQueue;
  }

  public void setReceiveTimeout(long receiveTimeout) {
    this.receiveTimeout_ = receiveTimeout;
  }

  public void setTimeToLive(long timeToLive) {
    this.timeToLive_ = timeToLive;
  }

  public void springInit() throws JMSException {
    connection_ = connectionFactory_.createConnection();
    connection_.start();
    Tracing.logInfo("springInit: JMS connectio started", ClusteredSearchRequester.class);
  }
 
  private synchronized Destination acquireTempQueue(Session session) throws JMSException {
    if (tempQueues_.size()==0) {
      if (session==null) {
        Session s = connection_.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination tempQ = s.createTemporaryQueue();
        s.close();
        return tempQ;
      }
      return session.createTemporaryQueue();
    } else {
      return tempQueues_.removeFirst();
    }
  }
 
  private synchronized Session acquireSession() throws JMSException {
    if (sessions_.size()==0) {
      return connection_.createSession(false, Session.AUTO_ACKNOWLEDGE);
    } else {
      return sessions_.removeFirst();
    }
  }
 
  private synchronized void releaseTempQueue(Destination tempQueue) {
    if (tempQueue==null) {
      return;
    }
    tempQueues_.addLast(tempQueue);
  }
 
  private synchronized void releaseSession(Session session) {
    if (session==null) {
      return;
    }
    sessions_.addLast(session);
  }

  /**
   * Uses Request/reply mechanism for synchronous operation.
   * @see org.olat.search.service.searcher.OLATSearcher#doSearch(java.lang.String, org.olat.core.id.Identity, org.olat.core.id.Roles, boolean)
   */
  public SearchResults doSearch(String queryString, Identity identity, Roles roles, boolean doHighlighting) throws ServiceNotAvailableException, ParseException, QueryException {
    boolean isDebug = Tracing.isDebugEnabled(ClusteredSearchRequester.class);
    if(isDebug){
      Tracing.logDebug("STARTqueryString=" + queryString,ClusteredSearchRequester.class);
    }
    SearchRequest searchRequest = new SearchRequest(queryString, identity.getKey(), roles, doHighlighting);
    Session session = null;
    try {
      session = acquireSession();
      if(isDebug){
        Tracing.logDebug("doSearch session=" + session,ClusteredSearchRequester.class);
      }
      Message requestMessage = session.createObjectMessage(searchRequest);
      Message returnedMessage = (Message) doSearchRequest(session, requestMessage);
      queryCount_++;
      if(returnedMessage!=null){
        String responseStatus = returnedMessage.getStringProperty(JMS_RESPONSE_STATUS_PROPERTY_NAME);
        if (responseStatus.equalsIgnoreCase(JMS_RESPONSE_STATUS_OK)) {
          SearchResults searchResult = (SearchResults)((ObjectMessage)returnedMessage).getObject();
          if(isDebug){
            Tracing.logDebug("ENDqueryString=" + queryString,ClusteredSearchRequester.class);
          }
          return searchResult;             
        } else if (responseStatus.equalsIgnoreCase(JMS_RESPONSE_STATUS_PARSE_EXCEPTION)) {
          throw new ParseException("can not parse query=" + queryString);
        } else if (responseStatus.equalsIgnoreCase(JMS_RESPONSE_STATUS_QUERY_EXCEPTION)) {
          throw new QueryException("invalid query=" + queryString);
        } else if (responseStatus.equalsIgnoreCase(JMS_RESPONSE_STATUS_SERVICE_NOT_AVAILABLE_EXCEPTION)) {
          throw new ServiceNotAvailableException("Remote search service not available" + queryString);
        } else {
          Tracing.logWarn("doSearch: receive unkown responseStatus=" + responseStatus, ClusteredSearchRequester.class);
          return null;
        }
      } else {
        //null returnedMessage
        throw new ServiceNotAvailableException("communication error with JMS - cannot receive messages!!!");
      }       
    } catch (JMSException e) {
      Tracing.logError("Search failure I",e,ClusteredSearchRequester.class);
      throw new ServiceNotAvailableException("communication error with JMS - cannot send messages!!!");
    } finally {
      releaseSession(session);
    }
  }
 
  /**
   * Uses Request/reply mechanism for synchronous operation.
   * @see org.olat.search.service.searcher.OLATSearcher#spellCheck(java.lang.String)
   */
  public Set<String> spellCheck(String query) throws ServiceNotAvailableException  {
    Session session = null;
    try {
      session = acquireSession();
      TextMessage requestMessage = session.createTextMessage(query);
      Message returnedMessage = (Message) doSearchRequest(session, requestMessage);     
      if(returnedMessage!=null){
        List<String> spellStringList = (List<String>)((ObjectMessage)returnedMessage).getObject()
        return new HashSet<String>(spellStringList);   
      } else {
        //null returnedMessage
        throw new ServiceNotAvailableException("spellCheck, communication error with JMS - cannot receive messages!!!");
      }       
    } catch (JMSException e) {
      throw new ServiceNotAvailableException("spellCheck, communication error with JMS - cannot send messages!!!");
    } catch (ServiceNotAvailableException e) {     
      throw e;
    } catch (Throwable th) {     
      throw new OLATRuntimeException("ClusteredSearchRequester.spellCheck() error!!!", th);
    } finally{
      releaseSession(session);
    }
  }
 
  private String createRandomString() {
    Random random = new Random(System.currentTimeMillis());
    long randomLong = random.nextLong();
    return Long.toHexString(randomLong);
  }

  /**
   * Returns the queryCount number for this cluster node.
   * @see org.olat.search.service.searcher.OLATSearcher#getQueryCount()
   */
  public long getQueryCount() {   
    return queryCount_;
  }

  public void stop() {
    try {
      for (Iterator iterator = sessions_.iterator(); iterator.hasNext();) {
        Session session = (Session) iterator.next();
        session.close();
      }
      connection_.close();
      Tracing.logInfo("ClusteredSearchRequester stopped",ClusteredSearchRequester.class);
    } catch (JMSException e) {
      Tracing.logError("Exception in stop ClusteredSearchRequester, ",e,ClusteredSearchRequester.class);
    }
  }
 
  public void setSearchWorker(OLATSearcher searchWorker) {
    //not used: here the searcherWorker is the remote search service   
  }

  private Message doSearchRequest(Session session, Message message) throws JMSException {
    Destination replyQueue = acquireTempQueue(session);
    if(Tracing.isDebugEnabled(ClusteredSearchRequester.class)){
      Tracing.logDebug("doSearchRequest replyQueue=" + replyQueue,ClusteredSearchRequester.class);
    }
    try{
      MessageConsumer responseConsumer = session.createConsumer(replyQueue);
     
      message.setJMSReplyTo(replyQueue);
      String correlationId = createRandomString();
      message.setJMSCorrelationID(correlationId);
   
      MessageProducer producer = session.createProducer(searchQueue_);
      producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
      producer.setTimeToLive(timeToLive_);
      if (Tracing.isDebugEnabled(ClusteredSearchRequester.class)) {
        Tracing.logDebug("Sending search request message with correlationId="+correlationId,ClusteredSearchRequester.class);
      }
      producer.send(message);
      producer.close();
 
      Message returnedMessage = null;
      final long start = System.currentTimeMillis();
      while(true) {
        final long diff = (start + receiveTimeout_) - System.currentTimeMillis();
        if (diff<=0) {
          // timeout
          Tracing.logInfo("Timeout in search. Remaining time zero or negative.", ClusteredSearchRequester.class);
          break;
        }
        if (Tracing.isDebugEnabled(ClusteredSearchRequester.class)) {
          Tracing.logDebug("doSearchRequest: call receive with timeout=" + diff,ClusteredSearchRequester.class);
        }
        returnedMessage = responseConsumer.receive(diff);
        if (returnedMessage==null) {
          // timeout case, we're stopping now with a reply...
          Tracing.logInfo("Timeout in search. Repy was null.", ClusteredSearchRequester.class);
          break;
        } else if (!correlationId.equals(returnedMessage.getJMSCorrelationID())) {
          // we got an old reply from a previous search request
          Tracing.logInfo("Got a response with a wrong correlationId. Ignoring and waiting for the next", ClusteredSearchRequester.class);
          continue;
        } else {
          // we got a valid reply
          break;
        }
      }
      responseConsumer.close();
      if (Tracing.isDebugEnabled(ClusteredSearchRequester.class)) {
        Tracing.logDebug("doSearchRequest: returnedMessage=" + returnedMessage,ClusteredSearchRequester.class);
      }
      return returnedMessage;
    } finally {
      releaseTempQueue(replyQueue);
    }
  }
 
}
TOP

Related Classes of org.olat.search.service.searcher.ClusteredSearchRequester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.