Package org.openntf.domino.helpers

Source Code of org.openntf.domino.helpers.DocumentSyncHelper

/*
* Copyright 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.openntf.domino.helpers;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.openntf.domino.Database;
import org.openntf.domino.Database.ModifiedDocClass;
import org.openntf.domino.DateTime;
import org.openntf.domino.Document;
import org.openntf.domino.DocumentCollection;
import org.openntf.domino.Item;
import org.openntf.domino.Session;
import org.openntf.domino.View;
import org.openntf.domino.transactions.DatabaseTransaction;

/**
* DocumentSyncHelper class
*
* This class provides a quick and easy way to sync fields or formulas from a DocumentCollection to related documents, e.g. from Companies
* to Contacts for those companies, or States to Contacts for those states.
*
* <ol>
* <li>Create a map of updates to make to related documents
* <ul>
* <li>Key is Item to pull from source document or formula to be processed against source document</li>
* <li>Value is Item name to wrote to on target documents
* <li>
* </ul>
* </li>
* <li>Create a new instance of DocumentSyncHelper
* <li>
* <li>Either in constructor or separately, define the strategy to apply when updating target documents</li>
* <li>Either in constructor or separately, load in the map</li>
* <li>Either in constructor or separately, define target server</li>
* <li>Either in constructor or separately, define target database</li>
* <li>Either in constructor or separately, define target view name</li>
* <li>Either in constructor or separately, define field in source to use as a key for target view</li>
* <li>Get a DocumentCollection of source document(s)</li>
* <li>Pass to DocumentSyncHelper.process method</li>
* </ol>
*
* Example:<br/>
* <code>
* Database currDb = XSPUtil.getCurrentDatabase();
* java.util.Map<Object, String> syncMap = new java.util.HashMap<Object, String>();
* syncMap.put("Key", "State");
* syncMap.put("Name", "StateName");
* syncMap.put("@Now", "LastSync");
* DocumentSyncHelper helper = new DocumentSyncHelper(DocumentSyncHelper.Strategy.CREATE_AND_REPLACE, syncMap,
*       currDb.getServer(), currDb.getFilePath(), "AllContactsByState", "Key");
* View states = currDb.getView("AllStates");
* DocumentCollection sourceCollection = states.getAllDocuments();
* helper.process(sourceCollection);
* </code>
*
* Alternatively, sync settings can be held in a control document. Use a Map<Controls, String> to map DocumentSyncHelper properties to Item
* names on the control document, e.g.
*
* Map has key Controls.TARGET_SERVER=ServerName will look for an Item called ServerName on the control document to retrieve the server name
* to use in the DocumentSyncHelper
*/
public class DocumentSyncHelper {

  /** The Constant log_. */
  @SuppressWarnings("unused")
  private static final Logger log_ = Logger.getLogger(DocumentSyncHelper.class.getName());

  /**
   * The Enum Strategy.
   *
   * Strategy to apply when updating target documents
   *
   * @since org.openntf.domino 1.0.0
   */
  public static enum Strategy {

    /** The replace if newer. */
    REPLACE_IF_NEWER,
    /** The create and replace. */
    CREATE_AND_REPLACE,
    /** The replace only. */
    REPLACE_ONLY
  }

  /**
   * The TransactionRule enum.
   *
   * The strategy to apply transactions
   *
   * @since org.openntf.domino 1.0.0
   */
  public static enum TransactionRule {
    NO_TRANSACTION, COMMIT_EVERY_SOURCE, COMMIT_AT_END
  }

  /**
   * The Enum Controls.
   *
   * Provides standard access to map properties of the DocumentSyncHelper to Item names in a control document from the control Map
   *
   * @since org.openntf.domino 1.0.0
   */
  public static enum Controls {

    /** The target server. */
    TARGET_SERVER,
    /** The target filepath. */
    TARGET_FILEPATH,
    /** The target lookup view. */
    TARGET_LOOKUP_VIEW,
    /** The source key formula. */
    SOURCE_KEY_FORMULA,
    /** The strategy. */
    STRATEGY,
    /** The sync source field. */
    SYNC_SOURCE_FIELD,
    /** The sync target field. */
    SYNC_TARGET_FIELD;
  }

  /** The target server_. */
  private String targetServer_;

  /** The target filepath_. */
  private String targetFilepath_;

  /** The target lookup view_. */
  private String targetLookupView_;

  /** The source key formula_. */
  // private String sourceKeyFormula_;

  private Formula sourceKeyFormula_;

  /** The strategy_. */
  private Strategy strategy_;

  private TransactionRule transactionRule_;

  /** The sync map_. */
  private Map<Formula, String> syncMap_;

  /**
   * Instantiates a new document sync helper.
   *
   * @since org.openntf.domino 1.0.0
   */
  public DocumentSyncHelper() {
    // TODO allow for constructor arguments to configure
  }

  /**
   * Instantiates a new DocumentSyncHelper with a Document of sync settings and a Map of field names for each setting in the control doc
   *
   * @param controlDoc
   *            Document with Items for relevant settings for the DocumentSyncHelper
   * @param controlMap
   *            Map<Controls, String> of Item names to use to retrieve DocumentSyncHelper settings from the control doc
   * @since org.openntf.domino 1.0.0
   */
  public DocumentSyncHelper(final Document controlDoc, Map<Controls, String> controlMap) {
    if (controlMap == null)
      controlMap = new HashMap<Controls, String>();
    if (controlMap.containsKey(Controls.TARGET_SERVER)) {
      setTargetServer(controlDoc.getItemValueString(controlMap.get(Controls.TARGET_SERVER)));
    } else if (controlDoc.hasItem(Controls.TARGET_SERVER.toString())) {
      setTargetServer(controlDoc.getItemValueString(Controls.TARGET_SERVER.toString()));
    } else {
      setTargetServer(controlDoc.getParentDatabase().getServer());
    }
    if (controlMap.containsKey(Controls.TARGET_FILEPATH)) {
      setTargetFilepath(controlDoc.getItemValueString(controlMap.get(Controls.TARGET_FILEPATH)));
    } else if (controlDoc.hasItem(Controls.TARGET_FILEPATH.toString())) {
      setTargetFilepath(controlDoc.getItemValueString(Controls.TARGET_FILEPATH.toString()));
    } else {
      setTargetFilepath(controlDoc.getParentDatabase().getFilePath());
    }
    if (controlMap.containsKey(Controls.TARGET_LOOKUP_VIEW)) {
      setTargetLookupView(controlDoc.getItemValueString(controlMap.get(Controls.TARGET_LOOKUP_VIEW)));
    } else if (controlDoc.hasItem(Controls.TARGET_LOOKUP_VIEW.toString())) {
      setTargetLookupView(controlDoc.getItemValueString(Controls.TARGET_LOOKUP_VIEW.toString()));
    } else {
      setTargetLookupView("TARGET_LOOKUP_VIEW");
    }
    if (controlMap.containsKey(Controls.SOURCE_KEY_FORMULA)) {
      setSourceKeyFormula(controlDoc.getItemValueString(controlMap.get(Controls.SOURCE_KEY_FORMULA)));
    } else if (controlDoc.hasItem(Controls.SOURCE_KEY_FORMULA.toString())) {
      setSourceKeyFormula(controlDoc.getItemValueString(Controls.SOURCE_KEY_FORMULA.toString()));
    } else {
      setSourceKeyFormula("SOURCE_KEY_FORMULA"); // this would be the name of the field on the source document used for the lookup
    }
    if (controlMap.containsKey(Controls.STRATEGY)) {
      setStrategy(Strategy.valueOf(controlDoc.getItemValueString(controlMap.get(Controls.STRATEGY))));
    } else if (controlDoc.hasItem(Controls.STRATEGY.toString())) {
      setStrategy(Strategy.valueOf(controlDoc.getItemValueString(Controls.STRATEGY.toString())));
    } else {
      setStrategy(Strategy.CREATE_AND_REPLACE);
    }
    Map<Object, String> syncMap = new HashMap<Object, String>();
    if (controlMap.containsKey(Controls.SYNC_SOURCE_FIELD) && controlMap.containsKey(Controls.SYNC_TARGET_FIELD)) {
      java.util.Vector<Object> keyVec = controlDoc.getItemValue(controlMap.get(Controls.SYNC_SOURCE_FIELD));
      java.util.Vector<Object> valueVec = controlDoc.getItemValue(controlMap.get(Controls.SYNC_TARGET_FIELD));
      int i = 0;
      for (Object key : keyVec) {
        Formula Fkey = new Formula();
        Fkey.setExpression((String) key);
        syncMap.put(Fkey, (String) valueVec.get(i));
        i++;
      }
    } else if (controlDoc.hasItem(Controls.SYNC_SOURCE_FIELD.toString()) && controlDoc.hasItem(Controls.SYNC_TARGET_FIELD.toString())) {
      java.util.Vector<Object> keyVec = controlDoc.getItemValue(Controls.SYNC_SOURCE_FIELD.toString());
      java.util.Vector<Object> valueVec = controlDoc.getItemValue(Controls.SYNC_TARGET_FIELD.toString());
      int i = 0;
      for (Object key : keyVec) {
        Formula Fkey = new Formula();
        Fkey.setExpression((String) key);
        syncMap.put(Fkey, (String) valueVec.get(i));
        i++;
      }
    } else {
      // TODO some default sync mappping, perhaps dynamic
    }
    setSyncMap(syncMap);
  }

  /**
   * Instantiates a new document sync helper passing in a sync map
   *
   * @param strategy
   *            the strategy
   * @param syncMap
   *            the sync map
   * @param args
   *            the args, up to four, each in order is:
   *            <ol>
   *            <li>target server</li>
   *            <li>target filepath</li>
   *            <li>target lookup view</li>
   *            <li>formula to apply to each source document to get key for target documents. E.g. "ContactID" = use ContactID field of
   *            source document as key value to apply to target lookup view to get the collection to update
   *            </ol>
   * @since org.openntf.domino 1.0.0
   */
  public DocumentSyncHelper(final Strategy strategy, final Map<Object, String> syncMap, final String... args) {
    setStrategy(strategy);
    setSyncMap(syncMap);
    if (args.length >= 1) {
      setTargetServer(args[0]);
    }
    if (args.length >= 2) {
      setTargetFilepath(args[1]);
    }
    if (args.length >= 3) {
      setTargetLookupView(args[2]);
    }
    if (args.length >= 4) {
      setSourceKeyFormula(args[3]);
    }

  }

  /**
   * Extended method to process, allowing the developer to define to only process source documents modified since a given Java date
   *
   * @param sourceDb
   *            Database source documents are in
   * @param sinceDate
   *            Date since when documents should have been modified
   * @since org.openntf.domino 1.0.0
   */
  public void processSince(final Database sourceDb, final Date sinceDate) {
    DateTime dt = sourceDb.getAncestorSession().createDateTime(sinceDate);
    DocumentCollection sourceCollection = sourceDb.getModifiedDocuments(dt, ModifiedDocClass.DATA);
    process(sourceCollection);
  }

  /**
   * Extended method to process, allowing the developer to define to only process source documents modified since a given Java date
   *
   * @param sourceDb
   *            Database source documents are in
   * @param sinceDate
   *            Date since when documents should have been modified
   * @param formName
   *            String form name to restrict DocumentCollection to
   * @since org.openntf.domino 1.0.0
   */
  public void processSince(final Database sourceDb, final Date sinceDate, final String formName) {
    DateTime dt = sourceDb.getAncestorSession().createDateTime(sinceDate);
    DocumentCollection sourceCollection = sourceDb.getModifiedDocuments(dt, ModifiedDocClass.DATA);
    sourceCollection.FTSearch("[Form] = \"" + formName + "\"");
    process(sourceCollection);
  }

  /**
   * Process a specific DocumentCollection.
   *
   * WARNING: Does not currently check that all properties of the SyncHelper have been set up
   *
   * @param coll
   *            DocumentCollection of source documents
   * @since org.openntf.domino 1.0.0
   */
  public void process(final DocumentCollection coll) {
    // TODO Check to make sure properties are all set up before running
    Session session = coll.getAncestorSession();
    Database targetDb = session.getDatabase(getTargetServer(), getTargetFilepath());
    View targetView = targetDb.getView(getTargetLookupView());
    Strategy strategy = getStrategy();
    DatabaseTransaction txn = null;
    if (getTransactionRule() == TransactionRule.COMMIT_AT_END) {
      txn = targetDb.startTransaction();
    }
    for (Document source : coll) {
      if (getTransactionRule() == TransactionRule.COMMIT_EVERY_SOURCE) {
        txn = targetDb.startTransaction();
      }
      DateTime sourceLastMod = source.getLastModified();
      // Object lookupKey = Factory.wrappedEvaluate(session, getSourceKeyFormula(), source);
      Object lookupKey = getSourceKeyFormula().getValue(source);
      DocumentCollection targetColl = targetView.getAllDocumentsByKey(lookupKey, true);
      for (Document target : targetColl) {
        // boolean targetDirty = false;
        for (Map.Entry<Formula, String> entry : getSyncMap().entrySet()) {
          String targetItemName = entry.getValue();
          java.util.Vector<?> sourceValue = entry.getKey().getValue(source);
          // Factory.wrappedEvaluate(session, entry.getKey(), source);
          if (strategy == Strategy.CREATE_AND_REPLACE) {
            target.replaceItemValue(targetItemName, sourceValue);
            // targetDirty = true;
          } else {
            Item targetItem = target.getFirstItem(targetItemName);
            if (strategy == Strategy.REPLACE_IF_NEWER) {
              DateTime itemLastMod = targetItem.getLastModified();
              if (sourceLastMod.isAfter(itemLastMod)) {
                targetItem.setValues(sourceValue);
                // targetDirty = true;
              }
            } else if (strategy == Strategy.REPLACE_ONLY) {
              if (targetItem != null) {
                targetItem.setValues(sourceValue);
                // targetDirty = true;
              }
            }
          }
        }
        if (getTransactionRule() == TransactionRule.NO_TRANSACTION || txn == null) {
          target.save();
        }
      }
      if (getTransactionRule() == TransactionRule.COMMIT_EVERY_SOURCE && txn != null) {
        txn.commit();
        txn = null;
      }
    }
    if (getTransactionRule() == TransactionRule.COMMIT_AT_END && txn != null) {
      txn.commit();
      txn = null;
    }
  }

  /**
   * Sets the target View (and so also Database and Server) from which to retrieve documents
   *
   * @param view
   *            View to find documents to update
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetView(final org.openntf.domino.View view) {
    setTargetLookupView(view.getName());
    setTargetDatabase(view.getAncestorDatabase());
  }

  /**
   * Sets the target Database (and so also Server) from which to retrieve documents
   *
   * @param db
   *            Database to find documents to update
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetDatabase(final Database db) {
    setTargetServer(db.getServer());
    setTargetFilepath(db.getFilePath());
  }

  /**
   * Sets the target Database (and so also Server) and View from which to retrieve documents
   *
   * @param db
   *            Database to find documents to update
   * @param viewName
   *            String view name to find documents to update
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetDatabase(final Database db, final String viewName) {
    setTargetServer(db.getServer());
    setTargetFilepath(db.getFilePath());
    setTargetLookupView(viewName);
  }

  /**
   * Gets the target server.
   *
   * @return String the target server
   * @since org.openntf.domino 1.0.0
   */
  public String getTargetServer() {
    return targetServer_;
  }

  /**
   * Sets the target server.
   *
   * @param targetServer
   *            String the new target server
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetServer(final String targetServer) {
    targetServer_ = targetServer;
  }

  /**
   * Gets the target filepath.
   *
   * @return String the target filepath
   * @since org.openntf.domino 1.0.0
   */
  public String getTargetFilepath() {
    return targetFilepath_;
  }

  /**
   * Sets the target filepath.
   *
   * @param targetFilepath
   *            String the new target filepath
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetFilepath(final String targetFilepath) {
    targetFilepath_ = targetFilepath;
  }

  /**
   * Gets the target lookup view.
   *
   * @return String the target lookup view name
   * @since org.openntf.domino 1.0.0
   */
  public String getTargetLookupView() {
    return targetLookupView_;
  }

  /**
   * Sets the target lookup view.
   *
   * @param targetLookupView
   *            String the new target lookup view name
   * @since org.openntf.domino 1.0.0
   */
  public void setTargetLookupView(final String targetLookupView) {
    targetLookupView_ = targetLookupView;
  }

  /**
   * Gets the source key using an Item name or Formula.
   *
   * @return String the source key formula
   * @since org.openntf.domino 1.0.0
   */
  public Formula getSourceKeyFormula() {
    if (sourceKeyFormula_ == null) {
      sourceKeyFormula_ = new Formula();
    }
    return sourceKeyFormula_;
  }

  /**
   * Sets the source key using an Item name of Formula.
   *
   * @param sourceKeyFormula
   *            String the new source key formula
   * @since org.openntf.domino 1.0.0
   */
  public void setSourceKeyFormula(final String sourceKeyFormula) {
    if (sourceKeyFormula_ == null) {
      sourceKeyFormula_ = new Formula();
    }
    sourceKeyFormula_.setExpression(sourceKeyFormula);
  }

  /**
   * Gets the strategy.
   *
   * @return Strategy to apply
   * @since org.openntf.domino 1.0.0
   */
  public Strategy getStrategy() {
    return strategy_;
  }

  /**
   * Gets the transaction rule.
   *
   * @return TransactionRule to apply
   * @since org.openntf.domino 1.0.0
   */
  public TransactionRule getTransactionRule() {
    if (transactionRule_ == null) {
      transactionRule_ = TransactionRule.NO_TRANSACTION;
    }
    return transactionRule_;
  }

  /**
   * Sets the strategy.
   *
   * @param strategy
   *            Strategy to apply
   * @since org.openntf.domino 1.0.0
   */
  public void setStrategy(final Strategy strategy) {
    strategy_ = strategy;
  }

  /**
   * Sets the transaction rule.
   *
   * @param rule
   *            TransactionRule to apply
   * @since org.openntf.domino 1.0.0
   */
  public void setTransactionRule(final TransactionRule rule) {
    transactionRule_ = rule;
  }

  /**
   * Gets the sync map of Item names or Formulas to apply to the source document and Item names on the target documents into which to
   * store the result
   *
   * @return Map<Formula, String> the sync map
   * @since org.openntf.domino 1.0.0
   */
  public Map<Formula, String> getSyncMap() {
    return syncMap_;
  }

  /**
   * Sets the sync mapof Item names or Formulas to apply to the source document and Item names on the target documents into which to store
   * the result
   *
   * @param syncMap
   *            Map<Formula, String> the sync map
   * @since org.openntf.domino 1.0.0
   */
  public void setSyncMap(final Map<java.lang.Object, String> syncMap) {
    Map<Formula, String> formulaMap = new HashMap<Formula, String>();
    for (Map.Entry<Object, String> entry : syncMap.entrySet()) {
      if (entry.getKey() instanceof Formula) {
        formulaMap.put((Formula) entry.getKey(), entry.getValue());
      }
      Formula Fkey = new Formula();
      Fkey.setExpression(String.valueOf(entry.getKey()));
      formulaMap.put(Fkey, entry.getValue());
    }
    syncMap_ = formulaMap;
  }

}
TOP

Related Classes of org.openntf.domino.helpers.DocumentSyncHelper

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.