Package net.sf.regain.crawler.document

Source Code of net.sf.regain.crawler.document.RawDocument

/*
* regain - A file search engine providing plenty of formats
* Copyright (C) 2004  Til Schneider
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact: Til Schneider, info@murfman.de
*
* CVS information:
*  $RCSfile$
*   $Source$
*     $Date: 2009-05-17 21:20:00 +0200 (So, 17 Mai 2009) $
*   $Author: thtesche $
* $Revision: 391 $
*/
package net.sf.regain.crawler.document;

import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPSSLStore;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.zip.CRC32;

import java.util.HashMap;
import java.util.Properties;
import java.util.regex.Matcher;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.MimeMessage;
import jcifs.smb.SmbFile;
import net.sf.regain.ImapToolkit;
import net.sf.regain.RegainException;
import net.sf.regain.RegainToolkit;
import net.sf.regain.crawler.CrawlerToolkit;
import net.sf.regain.crawler.Profiler;
import net.sf.regain.crawler.RedirectException;

import net.sf.regain.crawler.access.AccountPasswordEntry;
import org.apache.log4j.Logger;


/**
* Enthält alle Rohdaten eines Dokuments.
* <p>
* Falls der Inhalt des Dokuments zur besseren Bearbeitung in Form eines Strings
* gebraucht wird, dann wird dieser zum spätest möglichen Zeitpunkt erstellt.
*
* @author Til Schneider, www.murfman.de
*/
public class RawDocument {

  /** The logger for this class */
  private static Logger mLog = Logger.getLogger(RawDocument.class);

  /** Der Profiler der das Laden via HTTP misst. */
  private static final Profiler HTTP_LOADING_PROFILER
    = new Profiler("Documents loaded with HTTP", "docs");

  /** Der Profiler der das Laden vom Dateisystem misst. */
  private static final Profiler FILE_LOADING_PROFILER
    = new Profiler("Documents loaded from the file system", "docs");
 
  /** The pattern which matches for imap-urls (folder, message and attachment) */
  //Pattern imapPattern = Pattern.compile(".*(message_([0-9]+))(_attachment_([0-9]+))$");

  /**
   * Der Timeout für HTTP-Downloads. Dieser Wert bestimmt die maximale Zeit
   * in Sekunden, die ein HTTP-Download insgesamt dauern darf.
   */
  private static int mHttpTimeoutSecs = 180;

  /** Die URL des Dokuments. */
  private String mUrl;

  /** Die URL jenen Dokuments, in dem die URL dieses Dokuments gefunden wurde. */
  private String mSourceUrl;

  /**
   * Der Text des Links in dem die URL gefunden wurde. Ist <code>null</code>,
   * falls die URL nicht in einem Link (also einem a-Tag) gefunden wurde oder
   * wenn aus sonstigen Gr�nden kein Link-Text vorhanden ist.
   */
  private String mSourceLinkText;

  /**
   * Der Inhalt des Dokuments.
   * Ist <CODE>null</CODE>, wenn sich das Dokument in einer Datei befindet und
   * noch nicht angefragt wurde.
   */
  private byte[] mContent;

  /**
   * Der Inhalt des Dokuments als String. Ist <CODE>null</CODE>, bis er zum
   * ersten mal angefragt wurde.
   */
  private String mContentAsString;

  /**
   * Die Datei, in der sich der Inhalt des Dokuments befindet.
   * Ist <CODE>null</CODE>, wenn das Dokument über HTTP bezogen wird und noch
   * nicht angefragt wurde.
   */
  private File mContentAsFile;

  /**
   * Ist die Datei {@link #mContentAsFile} tempor�r. Wenn <code>true</code>,
   * dann wird die Datei am Ende gel�scht.
   *
   * @see #dispose()
   */
  private boolean mContentAsFileIsTemporary;

  /**
   * The mimetype of the document. This value will be set through file extension
   * mapping or by using the *nix-file command (java version)
   */
  private String mMimeType;

  /** HashMap links containing the URL as key and the linktext as value. */
  private HashMap <String,String>mLinks;
 
  /** account-password entry for the url in processing. */
  AccountPasswordEntry mAccountPasswordEntry;
 
  /** Last modified date. Will be changed by protocolls which can determine this date correctly. */
  Date mLastModifiedDate = new Date();
 
  /**
   * Erzeugt eine neue RawDocument-Instanz.
   *
   * @param url Die URL des Dokuments.
   * @param sourceUrl Die URL jenen Dokuments, in dem die URL dieses Dokuments
   *        gefunden wurde.
   * @param sourceLinkText Der Text des Links in dem die URL gefunden wurde. Ist
   *        <code>null</code>, falls die URL nicht in einem Link (also einem
   *        a-Tag) gefunden wurde oder wenn aus sonstigen Gründen kein Link-Text
   *        vorhanden ist.
   * @throws RegainException Wenn das Dokument nicht geladen werden konnte.
   */
  public RawDocument(String url, String sourceUrl, String sourceLinkText,
    AccountPasswordEntry accountPasswordEntry )
    throws RegainException
  {
    this.mLinks = new HashMap<String,String>();
    this.mUrl = url;
    this.mSourceUrl = sourceUrl;
    this.mSourceLinkText = sourceLinkText;
    this.mAccountPasswordEntry = accountPasswordEntry;

    if (url.startsWith("file://")) {
      mContentAsFile = RegainToolkit.urlToFile(url);
      mLastModifiedDate = new Date(mContentAsFile.lastModified());
    } else if( url.startsWith("smb://" )) {
      mContent = null;
      mContentAsFile = null;
   } else if( url.startsWith("imap://") || url.startsWith("imaps://")) {
      mContent = null;
      mContentAsFile = null;
    } else {
      mContent = loadContent(url);
      mContentAsFile = null;
    }
  }

  /**
   * Setzt den Timeout für HTTP-Downloads.
   * <p>
   * Dieser Wert bestimmt die maximale Zeit, die ein HTTP-Download insgesamt
   * dauern darf.
   *
   * @param httpTimeoutSecs Der neue Timeout.
   */
  public static void setHttpTimeoutSecs(int httpTimeoutSecs) {
    mHttpTimeoutSecs = httpTimeoutSecs;
  }

  /**
   * Loads a mime message from an IMAP server.
   *
   * @param url the URL of the mime message
   * @return content of the message
   * @throws RegainException if loading fails
   */
 
  private byte[] loadIMAPMessage(String url) throws RegainException {
   
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] bytearrayMessage = null;

    try {
      Matcher matcher = ImapToolkit.getMessagePattern().matcher(url);
      matcher.find();
      if( matcher.groupCount()>0 ) {
        // We found a message url. Determine the message UID from the url.
        int messageUID = Integer.parseInt(matcher.group(3));
        mLog.debug("Read mime message uid: " + messageUID + " for IMAP url: " + url);
        Session session = Session.getInstance(new Properties());
   
        URLName originURLName = new URLName(ImapToolkit.cutMessageIdentifier(
          CrawlerToolkit.replaceAuthenticationValuesInURL(url, mAccountPasswordEntry)));
        // Replace all %20 with whitespace in folder pathes
        String folder = "";
        if(originURLName.getFile()!=null){
          folder = originURLName.getFile().replaceAll("%20", " ");
        }
        URLName urlName = new URLName(originURLName.getProtocol(), originURLName.getHost(),
          originURLName.getPort(), folder, originURLName.getUsername(), originURLName.getPassword());
   
        IMAPSSLStore imapStore = new IMAPSSLStore(session, urlName);
        imapStore.connect();
        IMAPFolder currentFolder;

        if (urlName.getFile() == null) {
          // There is no folder given
          currentFolder = (IMAPFolder) imapStore.getDefaultFolder();
        } else {
          currentFolder = (IMAPFolder) imapStore.getFolder(urlName.getFile());
        }

        currentFolder.open(Folder.READ_WRITE);
        MimeMessage cplMessage = (MimeMessage) currentFolder.getMessageByUID(messageUID);
   
        if (cplMessage != null) {
          cplMessage.setFlag(Flags.Flag.SEEN, true);
          cplMessage.writeTo(baos);
          baos.flush();
          bytearrayMessage = baos.toByteArray();
          baos.close();
          mLastModifiedDate = cplMessage.getSentDate();

        }

        currentFolder.close(false);
        imapStore.close();      
       
      }

    } catch (Throwable thr) {
      throw new RegainException( thr.getMessage(), thr );
   
    CRC32 crc = new CRC32();
    crc.update(bytearrayMessage);
   
    mLog.debug("loadIMAPMessage crc: " + crc.getValue() + " for IMAP url: " + url);
    return bytearrayMessage;
  }
 
  /**
   * Loads the content from a smb file
   *
   * @param url The URL
   * @return content of the document
   * @throws net.sf.regain.RegainException if loading fails
   */
  private byte[] loadSmbFile(String url) throws RegainException {
       
    InputStream in = null;
    try {
      SmbFile smbFile = RegainToolkit.urlToSmbFile(
        CrawlerToolkit.replaceAuthenticationValuesInURL(url, mAccountPasswordEntry));
   
      if( smbFile.canRead() && !smbFile.isDirectory() ) {
        in = smbFile.getInputStream();
        mLastModifiedDate = new Date(smbFile.lastModified());
       
        return CrawlerToolkit.loadFileFromStream(in,smbFile.getContentLength());
       
      } else {
        throw new RegainException("Can't load content from: "
        + smbFile.getCanonicalPath());
      }
     
    } catch (Throwable thr) {
      throw new RegainException( thr.getMessage(), thr );
     
    } finally {
       if (in != null) {
        try { in.close(); } catch (IOException exc) {}
      }
    }
   
  }

  /**
   * Load content from URL for http/https documents.
   *
   * @param url The URL.
   * @return content of document.
   * @throws RegainException if loading was erroneous
   */
  private byte[] loadContent(String url) throws RegainException {
    HTTP_LOADING_PROFILER.startMeasuring();
    HttpDownloadThread loaderThread = new HttpDownloadThread(
      CrawlerToolkit.replaceAuthenticationValuesInURL(url, mAccountPasswordEntry),
      Thread.currentThread());
    loaderThread.start();

    // Warten bis entweder der Timeout abläuft, oder bis dieser Thread vom
    // HttpContentLoaderThread unterbrochen wird.
    try {
      Thread.sleep(mHttpTimeoutSecs * 1000);
    } catch (InterruptedException exc) {
    }

    // Prüfen, ob wir mittlerweile den Inhalt haben
    byte[] content = loaderThread.getContent();
    if (content != null) {
      HTTP_LOADING_PROFILER.stopMeasuring(content.length);
      return content;
    } else {
      // Wir haben keinen Inhalt
      HTTP_LOADING_PROFILER.abortMeasuring();

      // Check whether download failed
      if (loaderThread.getError() != null) {
        if (loaderThread.getError() instanceof RedirectException) {
          throw (RedirectException) loaderThread.getError();
        } else {
          throw new RegainException("Loading Document by HTTP failed: " + url,
                                    loaderThread.getError());
        }
      }

      // Wir haben weder einen Inhalt noch einen Fehler
      // -> Der Download läuft noch
      // -> Da jedoch mittlerweile der Timeout abgelaufen ist -> Exception werfen
      throw new RegainException("Loading Document by HTTP timed out after " +
          mHttpTimeoutSecs + " seconds: " + url);
    }
  }


  /**
   * Return the lentgth of the document (in bytes).
   *
   * @return int length of document.
   */
  public int getLength() /*throws RegainException*/ {
    int length = 0;
   
    if (mContent != null) {
      length = mContent.length;
   
    } else {
      // document still not loaded because it's a file
      if( mContentAsFile != null ) {
        length = (int) mContentAsFile.length();
     
      } else if( mUrl.startsWith("smb://")) {
        // @todo : define a suitable way to hold different kinds of files (local fs, windows share, other share types)
        try{
          length = (int) RegainToolkit.urlToSmbFile(
            CrawlerToolkit.replaceAuthenticationValuesInURL(mUrl, mAccountPasswordEntry)).length();
        } catch( Exception ex ){
          //throw new RegainException("Detection of file length failed: ", ex);
        }
      }
    }
    return length;
  }


  /**
   * Gibt zurück, wann das Dokument zuletzt geändert wurde.
   * <p>
   * Wenn die letzte Änderung nicht ermittelt werden kann (z.B. bei
   * HTTP-Dokumenten), dann wird <code>null</code> zurückgegeben.
   *
   * @return Wann das Dokument zuletzt geändert wurde.
   */
  public Date getLastModified() {
    return mLastModifiedDate;
  }


  /**
   * Gibt die URL des Dokuments zurück.
   *
   * @return Die URL des Dokuments.
   */
  public String getUrl() {
    return mUrl;
  }



  /**
   * Gibt die URL jenen Dokuments zurück, in dem die URL dieses Dokuments
   * gefunden wurde.
   *
   * @return Die URL jenen Dokuments, in dem die URL dieses Dokuments gefunden
   *         wurde.
   */
  public String getSourceUrl() {
    return mSourceUrl;
  }



  /**
   * Gibt den Text des Links zurück in dem die URL gefunden wurde.
   * <p>
   * Ist <code>null</code>, falls die URL nicht in einem Link (also einem a-Tag)
   * gefunden wurde oder wenn aus sonstigen Gr�nden kein Link-Text vorhanden ist.
   *
   * @return Der Text des Links zurück in dem die URL gefunden wurde.
   */
  public String getSourceLinkText() {
    return mSourceLinkText;
  }



  /**
   * Gibt den Inhalt des Dokuments zurück.
   *
   * @return Der Inhalt des Dokuments.
   * @throws RegainException Wenn das Dokument nicht geladen werden konnte.
   */
  public byte[] getContent() throws RegainException {
    if (mContent == null) {
      // Das Dokument befindet sich in einer Datei -> Diese laden
      FILE_LOADING_PROFILER.startMeasuring();
      try {
        byte[] content = null;
        if( mUrl.startsWith("file://")) {
          content = CrawlerToolkit.loadFile(mContentAsFile);
        } else if( mUrl.startsWith("smb://")) {
          content =  loadSmbFile(mUrl);
          mContent = content;
        } else if( mUrl.startsWith("imap://") || mUrl.startsWith("imaps://")) {
          content =  loadIMAPMessage(mUrl);
          mContent = content;
        }
        FILE_LOADING_PROFILER.stopMeasuring(content.length);
        return content;
      }
      catch (RegainException exc) {
        FILE_LOADING_PROFILER.abortMeasuring();
        throw new RegainException("Loading Document for url: " + mUrl + " failed: "
          + mContentAsFile, exc);
      }
    }

    return mContent;
  }



  /**
   * Gibt den Inhalt des Dokuments als String zurück.
   * <p>
   * Dieser String wird erst bei der ersten Abfrage erzeugt und dann gecached.
   *
   * @return Der Inhalt des Dokuments als String.
   * @throws RegainException Wenn das Dokument nicht geladen werden konnte.
   */
  public String getContentAsString() throws RegainException {
    if (mContentAsString == null) {
      mContentAsString = new String(getContent());
    }

    return mContentAsString;
  }


  /**
   * Gets the content of the document as stream. The stream must be closed by
   * the caller.
   *
   * @return The content of the document as stream.
   * @throws RegainException If creating the stream failed.
   */
  public InputStream getContentAsStream()
    throws RegainException
  {
    if (mContent != null) {
      return new ByteArrayInputStream(mContent);
    } else {
      // This document must be a file
      if(mUrl.startsWith("file://")){
        try {
          return new FileInputStream(mContentAsFile);
       
        } catch (Throwable thr) {
          throw new RegainException("Creating stream for file failed: " +
              mContentAsFile, thr);
        }
      } else if(mUrl.startsWith("smb://")) {
        try {
           SmbFile smbFile = RegainToolkit.urlToSmbFile(
             CrawlerToolkit.replaceAuthenticationValuesInURL(mUrl, mAccountPasswordEntry));
           return smbFile.getInputStream();
          
        } catch (Throwable thr) {
          throw new RegainException("Creating stream for file failed: " +
              mContentAsFile, thr);
        }
      } else {
        throw new RegainException("Creating stream for unknown file protocoll failed.");
       
      }
    }
  }


  /**
   * Schreibt den Inhalt des Dokuments in eine Datei.
   *
   * @param file Die Datei in die geschrieben werden soll.
   * @throws RegainException Wenn das Schreiben fehl schlug.
   */
  public void writeToFile(File file) throws RegainException {
    try {
      RegainToolkit.writeToFile(getContent(), file);

      if (mContentAsFile == null) {
        // Falls das Dokument in Dateiform benötigt wird, dann diese Datei
        // nutzen.
        mContentAsFile = file;
      }
    }
    catch (RegainException exc) {
      throw new RegainException("Creating file that contains the "
        + "document from '" + mUrl + "' failed", exc);
    }
  }


  /**
   * Gibt den Datei des Dokuments zurück. Falls das Dokument nicht als Datei
   * existiert, wird eine tempor�re Datei erzeugt.
   *
   * @return Die Datei des Dokuments.
   * @throws RegainException Wenn entweder keine tempor�re Datei erstellt werden
   *         konnte oder wenn nicht in die tempor�re Datei geschrieben werden
   *         konnte.
   */
  public File getContentAsFile() throws RegainException {
    return getContentAsFile(false);
  }


  /**
   * Gibt den Datei des Dokuments zurück. Falls das Dokument nicht als Datei
   * existiert, wird eine tempor�re Datei erzeugt.
   *
   * @param forceTempFile Bigt an, ob erzwungen werden soll, dass eine
   *        tempor�re Datei erzeugt wird. Auf diese Weise kann man sicher sein,
   *        dass die Datei von niemandem ge�ffnet ist.
   * @return Die Datei des Dokuments.
   * @throws RegainException Wenn entweder keine tempor�re Datei erstellt werden
   *         konnte oder wenn nicht in die tempor�re Datei geschrieben werden
   *         konnte.
   */
  public File getContentAsFile(boolean forceTempFile) throws RegainException {
    if ((mContentAsFile == null) || (forceTempFile && ! mContentAsFileIsTemporary)) {
      // Das Dokument wurde via HTTP geladen
      // -> Inhalt in eine Datei schreiben

      // Determine the file extension
      String extension = "";
      URL url;
      String path;
      if( mUrl.toLowerCase().startsWith("http") | mUrl.toLowerCase().startsWith("https") ) {
        try {
          url = new URL(mUrl);
          path = url.getPath();
          // Handles urls like http://www.thtesche.com/ an http://www.thtesche.com/blog/
          if( (path.length()==0
                  && (url.getProtocol().equalsIgnoreCase("http") || url.getProtocol().equalsIgnoreCase("https") ))
                  || path.endsWith("/")) {
            path = "index.html";
          }
        } catch (MalformedURLException ex) {
           mLog.debug("Couldn't create URL", ex);
           path = mUrl;
        }

        int lastDot = path.lastIndexOf('.');
        if (lastDot == -1 || path.length()-lastDot>=6 ) {
          extension = "";
        } else {
          extension = path.substring(lastDot);
        }
      } else if( mUrl.toLowerCase().startsWith("imap") | mUrl.toLowerCase().startsWith("imaps") ) {
        // @todo: consider extensions for attachments too
        extension = ".mht";
       
      }
     
      // Get an unused file
      File tmpFile;
      try {
        tmpFile = File.createTempFile("lucenesearch_", extension);
      }
      catch (IOException exc) {
        throw new RegainException("Getting temporary File failed", exc);
      }

      // write content in temporary file
      writeToFile(tmpFile);

      mContentAsFile = tmpFile;
      mContentAsFileIsTemporary = true;
    }

    return mContentAsFile;
  }


  /**
   * Gibt alle genutzten System-Ressourcen, wie temporäre Dateien, wieder frei.
   * <p>
   * Ressourcen der VM, wie z.B. Arrays, werden nicht freigegeben. Das soll der
   * GarbageCollector erledigen.
   */
  public void dispose() {
    if ((mContentAsFile != null) && mContentAsFileIsTemporary) {
      if (mLog.isDebugEnabled()) {
        mLog.debug("Deleting temporary file: " + mContentAsFile.getAbsolutePath());
      }
      if (! mContentAsFile.delete()) {
        mContentAsFile.deleteOnExit();
        mLog.debug("Deleting temporary file failed: " + mContentAsFile.getAbsolutePath() +
                "File will be deleted on program exit.");
      }
    }
  }


  /**
   * Gets the String representation of this class.
   *
   * @return The String representation of this class.
   */
  @Override
  public String toString() {
    return getUrl();
  }

  /**
   * Gets the mimetype of this document.
   *
   * @return The mimetype
   */
  public String getMimeType() {
    return mMimeType;
  }

  /**
   * Sets the mimetype of this document.
   */
  public void setMimeType(String mMimeType) {
    this.mMimeType = mMimeType;
  }

  /**
   * Gets the information wether the document contains links
   * @return true if the document contains at least one link
   */
  public boolean hasLinks() {
    if( this.mLinks.isEmpty() )
      return false;
    else
      return true;
  }
 
  /**
   * Adds a single link to the Hashmap of links
   */
  public void addLink( String url, String linkText ) {
    this.mLinks.put(url,linkText);
  }
  /**
   * Gets the links
   * @return Hashmap of links. key is the URL, value the link text
   */
  public HashMap getLinks(){
    return mLinks;
  }
}
TOP

Related Classes of net.sf.regain.crawler.document.RawDocument

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.