view src/de/mpiwg/dwinter/fulltextSearchServer/SearchTicket.java @ 0:db87c1b7eb6d

initial
author dwinter
date Wed, 03 Nov 2010 12:18:46 +0100
parents
children 83e9a828e794
line wrap: on
line source

package de.mpiwg.dwinter.fulltextSearchServer;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.store.LockObtainFailedException;
import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Options;
import org.restlet.resource.Post;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

import sun.misc.UUEncoder;
import sun.security.provider.MD5;

import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility;


import de.mpiwg.dwinter.fulltext.search.FulltextSearchDocsLines;
import de.mpiwg.dwinter.fulltext.ticket.TicketWriter;
import de.mpiwg.dwinter.fulltextSearchServer.Utils.ConfigurationManager;
import de.mpiwg.dwinter.fulltextSearchServer.searchThreads.SearchInlinesThread;


/**
 * REST-Klasse, die die eigentliche Suche startet. 
 * @author dwinter
 *
 */
public class SearchTicket extends ServerResource {

	
	private File lineDir;
	private File docIndex; 
	private Logger logger = Logger.getRootLogger();
	private String ticketIdentifier;
	
	
	/**
	 * Initialisiert die Methode, die Indixes fŸr die Dokumente und Zeilen werden aus dem Konfigurationsfile gelesen.
	 * @throws IOException
	 */
	public SearchTicket() throws IOException{
		Properties defaultProperties = ConfigurationManager.getConfig();
		lineDir = new File(defaultProperties.getProperty("lineIndex"));
		docIndex = new File(defaultProperties.getProperty("docIndex"));
		ticketIdentifier = defaultProperties.getProperty("ticketIdentifier");
;	}
	//need options for crossdomain scripting
	/**
	 * Erlaubt Cross-Domain Scripting
	 * @param entity
	 */
	@Options
	public void doOptions(Representation entity) {
	    Form responseHeaders = (Form) getResponse().getAttributes().get("org.restlet.http.headers");
	    if (responseHeaders == null) {
	        responseHeaders = new Form();
	        getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
	    }
	    responseHeaders.add("Access-Control-Allow-Origin", "*");
	    responseHeaders.add("Access-Control-Allow-Methods", "POST,OPTIONS,GET");
	    responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
	    responseHeaders.add("Access-Control-Allow-Credentials", "false");
	    responseHeaders.add("Access-Control-Max-Age", "60");
	}
	
	/**
	 * Methode wird aufgerufen, wenn Ÿber REST mit POST auf diese zurueckgegriffen wird. search muss eine FORM mit Wert 
	 * fuer "searchString" enthalten, sonst wird null zurueckgegeben. Weitere Felder in sind "languages" welches einen String
	 * mit den Sprachen, in denen gesucht werden soll, enthaelt. Dieser hat die Form "lang1_lang2_...". Ausserdem kann ein
	 * Feld "searchMetaData" uebergeben werden, dann wird die Suche auf Texte eingeschraenkt, die die ensprechenden Metadaten enthalten.
	 * 
	 * Zurueck gegeben wird <html><body><a href=\"tickets/"+ticket+"\">"+ticket+"</a></html>. Wobeit ticket die entsprechende ticketnummer der Suche ist.
	 * Auf dem Server wird ein entsprechendes Ticket angelegt und kann dann mit REST abgefragt werden.
	 * @param search
	 * @return
	 */
	@Post
	public Representation getTicketHTML(Representation search){
			
		// response header fuer cross-site.scripting
		Form responseHeaders = (Form) getResponse().getAttributes().get("org.restlet.http.headers");
		    if (responseHeaders == null) {
		        responseHeaders = new Form();
		        getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
		    }
		responseHeaders.add("Access-Control-Allow-Origin", "*");
		
		
		//now do the search
		Form searchForm = new Form(search);
		
		//String ticket = generateTicket();
		String searchString=searchForm.getValues("searchString");
		String languages=searchForm.getValues("languages"); // language der form la1_la2_la3___
		String searchMetaData=searchForm.getValues("searchMetaData");
		//no Searchstring
		if (searchString==null || languages==null )
			return null;
		
		logger.debug("SearchTicket:"+searchString);
		logger.debug("Languages:"+languages);
		logger.debug("SearchMetaData:"+searchMetaData);
		
		String ticket = generateTicket(searchString,languages,searchMetaData);
		
		
		// ticket alreaday exist, then no new search is needed
		if (TicketWriter.exists(ticket)){
			String htmlTicket = wrapHTML(ticket);
			Representation representation = new StringRepresentation(htmlTicket,MediaType.TEXT_HTML);
			return representation;
		}
			
		
		//add the searcher to the context, if there is none
		Context context = Context.getCurrent();
		ConcurrentMap<String, Object> attrs = context.getAttributes();
		FulltextSearchDocsLines fulltextSearcher = null;
		if (!attrs.containsKey("searcher")){
			try {
				fulltextSearcher = new FulltextSearchDocsLines(docIndex,lineDir);
			} catch (CorruptIndexException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (LockObtainFailedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
		} else {
			fulltextSearcher = (FulltextSearchDocsLines) attrs.get("searcher");
		}
		
	
		
		String[] langs = languages.split("_");
		
		for (String lang: langs){
		SearchInlinesThread st = new SearchInlinesThread(fulltextSearcher, searchString, searchMetaData,lang,ticket);
		st.start();
		}
		
		String htmlTicket = wrapHTML(ticket);
		Representation representation = new StringRepresentation(htmlTicket,MediaType.TEXT_HTML);
		return representation;
	}

//	@Post("xml")
//	public Representation getTicketXML(Representation search){
//			
//		Form searchForm = new Form(search);
//		
//		String ticket = generateTicket();
//		String searchString=searchForm.getValues("searchString");
//		
//		SearchInlinesThread st = new SearchInlinesThread(docIndex, lineDir, searchString, "de",ticket);	
//		st.start();
//		String xmlTicket = wrapXML(ticket);
//		Representation representation = new StringRepresentation(xmlTicket,MediaType.TEXT_XML);
//		return representation;
//	}
//	


	private String wrapHTML(String ticket) {
		String ret ="<html><body><a href=\"tickets/"+ticket+"\">"+ticket+"</a></html>";// TODO Auto-generated method stub
		return ret;
	}

	private String wrapXML(String ticket) {
		String ret ="<xml><ticketnr xlink=\"tickets/"+ticket+"\">"+ticket+"</ticketnr></xml>";
		return ret;
	}

	private String generateTicket() {
		return TicketWriter.getNewTicket();
		
	}
	
	/**
	 * Erzeugt ein Ticket aus den Strings (aus den Strings wird ein MD5 hash erzeugt, 
	 * so dass fŸr jede Suche mit den gleichen Perametern das Ticket, gleich ist.
	 * @param searchString
	 * @param languages
	 * @param searchMetaData
	 * @return
	 */
	private String generateTicket(String searchString, String languages,
			String searchMetaData) {
		
		//return generateTicket();
		
		String tmpString= ticketIdentifier+"|"+searchMetaData+"|"+searchString+"|"+languages;
	
			
		return String.valueOf(tmpString.hashCode());
			
	
	}
	
	/**
	 * Methode wird aufgerufen bei GET auf diese Klasse und gibt alle gespeicherten Tickets zurueck. 
	 * @return
	 */
	@Get("XML")
	public Representation getAllTickets(){
		return new StringRepresentation(TicketWriter.getAllTickets(),MediaType.TEXT_XML);
	}
}