view software/eXist/mpdl-modules/src/de/mpg/mpiwg/berlin/mpdl/externalObjects/app/ExternalObjectsHandler.java @ 12:fba5577e49d9

diverse Fehlerbehebungen
author Josef Willenborg <jwillenborg@mpiwg-berlin.mpg.de>
date Tue, 19 Apr 2011 16:51:26 +0200
parents 59ff47d1e237
children 5df60f24e997
line wrap: on
line source

package de.mpg.mpiwg.berlin.mpdl.externalObjects.app;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;

import de.mpg.mpiwg.berlin.mpdl.schedule.MpdlDocOperation;
import de.mpg.mpiwg.berlin.mpdl.util.StringUtilEscapeChars;
import de.mpg.mpiwg.berlin.mpdl.util.Util;
import de.mpg.mpiwg.berlin.mpdl.xml.SchemaHandler;
import de.mpg.mpiwg.berlin.mpdl.exception.ApplicationException;
import de.mpg.mpiwg.berlin.mpdl.externalObjects.db.DbEnvExternalObjects;
import de.mpg.mpiwg.berlin.mpdl.general.MpdlConstants;

public class ExternalObjectsHandler {
  private static ExternalObjectsHandler instance;
  private static String MPDL_DATA_DIR = MpdlConstants.MPDL_EXIST_DATA_DIR;
  private static String DB_DIR_EXTERNAL_OBJECTS = MPDL_DATA_DIR + "/dataBerkeleyDB/externalObjects";
  private DbEnvExternalObjects dbEnvExternalObjects;
  private Date beginOfOperation;
  private Date endOfOperation;
  
  public static ExternalObjectsHandler getInstance() throws ApplicationException {
    if (instance == null) {
      instance = new ExternalObjectsHandler();
      instance.init();
    }
    return instance;
  }

  public void createExternalElement(ExtElement element) throws ApplicationException {
    createDBExternalElement(element);
  }
  
  public void updateExternalElement(ExtElement element) throws ApplicationException {
    updateDBExternalElement(element);
  }
  
  public void deleteExternalElement(ExtElement element) throws ApplicationException {
    deleteDBExternalElement(element);
  }

  public ArrayList<ExtElement> readExternalElements(ExtElement element) throws ApplicationException {
    return readDBExternalElements(element);
  }
  
  public void createExternalObject(ExtObject object) throws ApplicationException {
    createDBExternalObject(object);
  }
  
  public void updateExternalObject(ExtObject object) throws ApplicationException {
    updateDBExternalObject(object);
  }
  
  public void deleteExternalObject(ExtObject object) throws ApplicationException {
    deleteDBExternalObject(object);
  }

  public ArrayList<ExtObject> readExternalObjects(ExtObject object) throws ApplicationException {
    return readDBExternalObjects(object);
  }

  private void createDBExternalElement(ExtElement element) throws ApplicationException {
    try {
      test(element);
      String content = element.getContent();
      String valueStr = element.getXmlString();
      if (content == null)
        throw new ApplicationException("External object: no content element specified in: " + valueStr);
      Date now = new Date();
      element.setModificationDate(now);
      String docId = element.getDocumentId();
      String pageNumber = element.getPageNumber();
      String keyStr = docId + "###" + pageNumber;
      DatabaseEntry dbEntryKey = new DatabaseEntry(keyStr.getBytes("utf-8"));
      DatabaseEntry dbEntryValue = new DatabaseEntry(valueStr.getBytes("utf-8"));
      Database elementDB = dbEnvExternalObjects.getElementDB();
      elementDB.put(null, dbEntryKey, dbEntryValue);
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private void updateDBExternalElement(ExtElement element) throws ApplicationException {
    test(element);
    String content = element.getContent();
    String elementXmlStr = element.getXmlString();
    if (content == null)
      throw new ApplicationException("External object: no content element specified in: " + elementXmlStr);
    Date now = new Date();
    element.setModificationDate(now);
    String docId = element.getDocumentId();
    String pageNumber = element.getPageNumber();
    String uid = element.getUid();
    String xpath = element.getXpath();
    String hashKey = docId + "###" + pageNumber;
    boolean updated = false;
    try {
      Database elementDB = dbEnvExternalObjects.getElementDB();
      Transaction t = dbEnvExternalObjects.getEnv().beginTransaction(null, null);
      Cursor cursor = elementDB.openCursor(t, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS && ! updated) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtElement elem = ExtElement.parseXmlStr(foundValueStr);
        String elemUid = elem.getUid();
        String elemXPath = elem.getXpath();
        if (uid.equals(elemUid) && xpath.equals(elemXPath)) {
          cursor.delete();
          byte[] elementXmlStrBytes = elementXmlStr.getBytes("utf-8");
          DatabaseEntry dbEntryValue = new DatabaseEntry(elementXmlStrBytes);
          cursor.put(dbEntryKey, dbEntryValue);
          updated = true;
          break;
        }
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
      t.commit();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private void deleteDBExternalElement(ExtElement element) throws ApplicationException {
    test(element);
    String docId = element.getDocumentId();
    String pageNumber = element.getPageNumber();
    String uid = element.getUid();
    String xpath = element.getXpath();
    String hashKey = docId + "###" + pageNumber;
    try {
      Database elementDB = dbEnvExternalObjects.getElementDB();
      Transaction t = dbEnvExternalObjects.getEnv().beginTransaction(null, null);
      Cursor cursor = elementDB.openCursor(t, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtElement elem = ExtElement.parseXmlStr(foundValueStr);
        String elemUid = elem.getUid();
        String elemXPath = elem.getXpath();
        if (uid.equals(elemUid) && xpath.equals(elemXPath)) {
          cursor.delete();
        }
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
      t.commit();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private ArrayList<ExtElement> readDBExternalElements(ExtElement element) throws ApplicationException {
    ArrayList<ExtElement> retElements = new ArrayList<ExtElement>();
    String documentId = element.getDocumentId();
    String pageNumber = element.getPageNumber();
    String hashKey = documentId + "###" + pageNumber;
    try {
      Database elementDB = dbEnvExternalObjects.getElementDB();
      Cursor cursor = elementDB.openCursor(null, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtElement e = ExtElement.parseXmlStr(foundValueStr);
        retElements.add(e);
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
    return retElements;
  }

  private void test(ExtElement element) throws ApplicationException {
    String uid = element.getUid();
    String docId = element.getDocumentId();
    String xpath = element.getXpath();
    String pageNumber = element.getPageNumber();
    String xmlStr = element.getXmlString();
    if (uid == null)
      throw new ApplicationException("External object: no attribute \"uid\" specified in: " + xmlStr);
    if (docId == null)
      throw new ApplicationException("External object: no attribute \"documentId\" specified in: " + xmlStr);
    if (xpath == null)
      throw new ApplicationException("External object: no xpath in attribute \"xpointer\" specified in: " + xmlStr);
    if (pageNumber == null)
      throw new ApplicationException("External object: no attribute \"pageNumber\" specified in: " + xmlStr);
  }

  private void createDBExternalObject(ExtObject extObject) throws ApplicationException {
    try {
      test(extObject);
      Date now = new Date();
      extObject.setModificationDate(now);
      String type = extObject.getType();
      String uid = extObject.getUid();
      String docId = extObject.getDocumentId();
      if (docId == null || docId.isEmpty())
        docId = "-1";
      String keyStr = type + "###" + uid + "###" + docId;
      String valueStr = extObject.getXmlString();
      DatabaseEntry dbEntryKey = new DatabaseEntry(keyStr.getBytes("utf-8"));
      DatabaseEntry dbEntryValue = new DatabaseEntry(valueStr.getBytes("utf-8"));
      Database objectDB = dbEnvExternalObjects.getObjectDB();
      objectDB.put(null, dbEntryKey, dbEntryValue);
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private void updateDBExternalObject(ExtObject object) throws ApplicationException {
    test(object);
    String content = object.getContent();
    String elementXmlStr = object.getXmlString();
    if (content == null)
      throw new ApplicationException("External object: no content element specified in: " + elementXmlStr);
    Date modificationDate = object.getModificationDate();
    Date now = new Date();
    object.setModificationDate(now);
    String type = object.getType();
    String uid = object.getUid();
    String docId = object.getDocumentId();
    String hashKey = type + "###" + uid + "###" + docId;
    boolean updated = false;
    try {
      Database objectDB = dbEnvExternalObjects.getObjectDB();
      Transaction t = dbEnvExternalObjects.getEnv().beginTransaction(null, null);
      Cursor cursor = objectDB.openCursor(t, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS && ! updated) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtObject obj = object.getInstance(foundValueStr);
        Date objModificationDate = obj.getModificationDate();
        if (modificationDate.equals(objModificationDate)) {
          cursor.delete();
          byte[] elementXmlStrBytes = elementXmlStr.getBytes("utf-8");
          DatabaseEntry dbEntryValue = new DatabaseEntry(elementXmlStrBytes);
          cursor.put(dbEntryKey, dbEntryValue);
          updated = true;
          break;
        }
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
      t.commit();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private void deleteDBExternalObject(ExtObject object) throws ApplicationException {
    test(object);
    Date modificationDate = object.getModificationDate();
    Date now = new Date();
    object.setModificationDate(now);
    String type = object.getType();
    String uid = object.getUid();
    String docId = object.getDocumentId();
    String hashKey = type + "###" + uid + "###" + docId;
    try {
      Database objectDB = dbEnvExternalObjects.getObjectDB();
      Transaction t = dbEnvExternalObjects.getEnv().beginTransaction(null, null);
      Cursor cursor = objectDB.openCursor(t, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtObject obj = object.getInstance(foundValueStr);
        Date objModificationDate = obj.getModificationDate();
        if (modificationDate == null || modificationDate.equals(objModificationDate)) {
          cursor.delete();
        }
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
      t.commit();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
  }

  private ArrayList<ExtObject> readDBExternalObjects(ExtObject object) throws ApplicationException {
    ArrayList<ExtObject> retElements = new ArrayList<ExtObject>();
    String type = object.getType();
    String uid = object.getUid();
    String docId = object.getDocumentId();
    String hashKey = type + "###" + uid + "###" + docId;
    try {
      Database objectDB = dbEnvExternalObjects.getObjectDB();
      Cursor cursor = objectDB.openCursor(null, null);
      byte[] bHashKey = hashKey.getBytes("utf-8");
      DatabaseEntry dbEntryKey = new DatabaseEntry(bHashKey);
      DatabaseEntry foundValue = new DatabaseEntry();
      OperationStatus operationStatus = cursor.getSearchKey(dbEntryKey, foundValue, LockMode.DEFAULT);
      while (operationStatus == OperationStatus.SUCCESS) {
        byte[] foundValueBytes = foundValue.getData();
        String foundValueStr = new String(foundValueBytes, "utf-8");
        ExtObject obj = object.getInstance(foundValueStr);
        retElements.add(obj);
        operationStatus = cursor.getNextDup(dbEntryKey, foundValue, LockMode.DEFAULT);
      }
      cursor.close();
    } catch (DatabaseException e) {
      throw new ApplicationException(e);
    } catch (UnsupportedEncodingException e) {
      throw new ApplicationException(e);
    }
    return retElements;
  }
  
  private void test(ExtObject object) throws ApplicationException {
    String uid = object.getUid();
    String xmlStr = object.getXmlString();
    if (uid == null)
      throw new ApplicationException("External object: no attribute \"uid\" specified in: " + xmlStr);
  }


  
  private void init() throws ApplicationException {
    dbEnvExternalObjects = new DbEnvExternalObjects();
    dbEnvExternalObjects.setDataDir(DB_DIR_EXTERNAL_OBJECTS);
    dbEnvExternalObjects.init();
    dbEnvExternalObjects.openDatabases();
  }
  
  public static void main(String[] args) throws ApplicationException {
    getInstance();
    instance.beginOperation();
    System.out.print("Start ...");
    // instance.validateSampleDoc();
    // instance.deleteSampleData();
    // instance.createSampleData();
    // instance.updateSampleData();
    instance.readSampleData(); 
    instance.end();
    instance.endOperation();
    Double elapsedTime = new Util().getSecondWithMillisecondsBetween(instance.beginOfOperation, instance.endOfOperation);
    System.out.println("End.");
    System.out.println("Needed time: " + elapsedTime + " seconds");
  }

  private void validateSampleDoc() throws ApplicationException {
    SchemaHandler schemaHandler = new SchemaHandler();
    MpdlDocOperation docOp = new MpdlDocOperation("bla", "bla", "", "tei", "en", "Test_1789.xml");
    String localFileName = "/Users/jwillenborg/texts/mpdl/documents/tei/en/Test_1789.xml";
    schemaHandler.validate(localFileName, docOp);
  }
  
  private void deleteSampleData() throws ApplicationException {
    String xmlNodeId1 = "/archimedes[1]/text[1]/body[1]/chap[1]/p[1]/s[2]";
    String objectXmlStr1 = 
      "<object type=\"" + "element" + "\" " + 
              "uid=\"" + "joe" + "\" " + 
              "documentId=\"" + "/archimedes/it/l223.xml" + "\" " + 
              "xpointer=\"" + "#xpointer(id('page17')" + xmlNodeId1 + "\"" + 
              ">" +
       "</object>";
    ExtElement e1 = ExtElement.parseXmlStr(objectXmlStr1);
    String xmlNodeId2 = "/archimedes[1]/text[1]/body[1]/chap[1]/p[1]/s[4]";
    String objectXmlStr2 = 
      "<object type=\"" + "element" + "\" " + 
              "uid=\"" + "michael" + "\" " + 
              "documentId=\"" + "/archimedes/it/l223.xml" + "\" " + 
              "xpointer=\"" + "#xpointer(id('page17')" + xmlNodeId2 + "\"" + 
              ">" +
       "</object>";
    ExtElement e2 = ExtElement.parseXmlStr(objectXmlStr2);
    deleteExternalElement(e1);
    deleteExternalElement(e2);
    
    ExtQuery q = new ExtQuery();
    q.setUid("joe");
    q.setDocumentId("/archimedes/it/l223.xml");
    ArrayList<ExtObject> objects = readExternalObjects(q); 
    for (int i=0; i<objects.size(); i++) {
      ExtObject o = objects.get(i);
      deleteExternalObject(o);
    }

    ExtQuery q2 = new ExtQuery();
    q2.setUid("michael");
    q2.setDocumentId("/archimedes/it/l223.xml");
    objects = readExternalObjects(q2); 
    for (int i=0; i<objects.size(); i++) {
      ExtObject o = objects.get(i);
      deleteExternalObject(o);
    }
  }
  
  private void createSampleData() throws ApplicationException {
    Date now = new Date();

    String sId = "/archimedes[1]/text[1]/body[1]/chap[1]/p[1]/s[2]";
    ExtElement e = new ExtElement();
    e.setUid("joe");
    e.setModificationDate(now);
    e.setDocumentId("/archimedes/it/l223.xml");
    e.setPageNumber("17");
    e.setXpath(sId);
    e.setPoint(".1");
    e.setContent("<note>This is a test note to element " + sId + " with <ref target=\"http://slime.de\">this external link</ref>" + "</note>");
    createExternalElement(e);
    
    ExtElement e2 = new ExtElement();
    String sId2 = "/archimedes[1]/text[1]/body[1]/chap[1]/p[1]/s[4]";
    e2.setUid("michael");
    e2.setModificationDate(now);
    e2.setDocumentId("/archimedes/it/l223.xml");
    e2.setPageNumber("17");
    e2.setXpath(sId2);
    e2.setPoint("18");
    e2.setContent("<note>This is a test note to element " + sId2 + "</note>");
    createExternalElement(e2);
    
    ExtQuery q1 = new ExtQuery();
    q1.setUid("joe");
    q1.setDocumentId("/archimedes/it/l223.xml");
    q1.setQueryType("fulltext");
    q1.setQueryName("seminario");
    createExternalObject(q1);
    
    ExtQuery q2 = new ExtQuery();
    q2.setUid("michael");
    q2.setDocumentId("/archimedes/it/l223.xml");
    q2.setQueryType("url");
    String url = "http://mpdl-proto.mpiwg-berlin.mpg.de/mpdl/page-query-result.xql?document=/archimedes/it/l223.xml&pn=17&mode=text&query-type=fulltextMorph&query=seminario&query-result-pn=1";
    String urlDeresolved = StringUtilEscapeChars.deresolveXmlEntities(url);
    q2.setQueryName(urlDeresolved);
    createExternalObject(q2);
    
  }

  private void updateSampleData() throws ApplicationException {
    Date now = new Date();
    String xmlNodeId = "/archimedes[1]/text[1]/body[1]/chap[1]/p[1]/s[2]";
    String objectXmlStr = 
      "<object type=\"" + "element" + "\" " + 
              "uid=\"" + "joe" + "\" " + 
              "documentId=\"" + "/archimedes/it/l223.xml" + "\" " + 
              "xpointer=\"" + "#xpointer(id('page17')" + xmlNodeId + "\"" + 
              ">" +
          "<content>" + "<note>This is a test note to element " + xmlNodeId + " with <ref target=\"http://slime.de\">this external link</ref>" + "</note>" + "</content>" +
       "</object>";
    ExtElement e = ExtElement.parseXmlStr(objectXmlStr);
    e.setModificationDate(now);
    updateExternalElement(e);
  }
    
  private void readSampleData() throws ApplicationException {
    ExtElement elem = new ExtElement();
    elem.setDocumentId("/archimedes/it/l223.xml");
    elem.setPageNumber("17");
    ArrayList<ExtElement> elements = readExternalElements(elem); 
    System.out.println(elements);
    
    ExtQuery q1 = new ExtQuery();
    q1.setUid("joe");
    q1.setDocumentId("/archimedes/it/l223.xml");
    ArrayList<ExtObject> objects = readExternalObjects(q1); 
    System.out.println(objects);

    ExtQuery q2 = new ExtQuery();
    q2.setUid("michael");
    q2.setDocumentId("/archimedes/it/l223.xml");
    objects = readExternalObjects(q2); 
    System.out.println(objects);
  }
  
  private void end() throws ApplicationException {
    dbEnvExternalObjects.close();
  }

  private void beginOperation() {
    beginOfOperation = new Date();
  }

  private void endOperation() {
    endOfOperation = new Date();
  }

}