Package com.findwise.hydra.mongodb

Source Code of com.findwise.hydra.mongodb.MongoDocument

package com.findwise.hydra.mongodb;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.bson.BSONObject;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.findwise.hydra.DatabaseDocument;
import com.findwise.hydra.DatabaseQuery;
import com.findwise.hydra.Document;
import com.findwise.hydra.DocumentID;
import com.findwise.hydra.JsonException;
import com.findwise.hydra.local.LocalDocument;
import com.findwise.tools.Comparator;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;


public class MongoDocument implements DBObject, DatabaseDocument<MongoType> {
  private DBObject documentMap;
 
  private static Logger logger = LoggerFactory.getLogger(MongoDocument.class);
 
  private boolean actionTouched = false;
 
  private Set<String> touchedContent;
  private Set<String> touchedMetadata;
 
  public static final String MONGO_ID_KEY = "_id";
  private boolean partialObject = false;
 
  public MongoDocument() {
    setup();
  }
 
  public MongoDocument(String json) throws JsonException {
    this();
    fromJson(json);
  }
 
  private void setup() {
    touchedContent = new HashSet<String>();
    touchedMetadata = new HashSet<String>();
    documentMap = new BasicDBObject();
    documentMap.put(METADATA_KEY, new BasicDBObject());
    documentMap.put(CONTENTS_KEY, new BasicDBObject());
  }

 
  private DBObject getContents() {
    return (DBObject) documentMap.get(CONTENTS_KEY);
  }
 
  private DBObject getMetadata() {
    return (DBObject) documentMap.get(METADATA_KEY);
  }
 
  @Override
  public Action getAction() {
    Object o = documentMap.get(ACTION_KEY);
    if(o!=null) {
      return Action.valueOf((String)o);
    }
    return null;
  }
 
  @Override
  public void setAction(Action action) {
    actionTouched = true;
    if(action==null) {
      documentMap.put(ACTION_KEY, null);
    } else {
      documentMap.put(ACTION_KEY, action.toString());
    }
  }

  @Override
  public final void putAll(BSONObject o) {
    documentMap.putAll(o.toMap());
  }

  @Override
  public Object get(String key) {
    return documentMap.get(key);
  }

  @SuppressWarnings("unchecked")
  @Override
  public Map<String, Object> toMap() {
    return documentMap.toMap();
  }

  @Override
  public Object removeField(String key) {
    return documentMap.removeField(key);
  }

  @Override
  public boolean hasErrors() {
    return getMetadata().containsField(ERROR_METADATA_KEY);
  }
 
  @Override
  public void addError(String from, Throwable t) {
    if(!hasErrors()) {
      getMetadata().put(ERROR_METADATA_KEY, new BasicDBObject());
    }
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    t.printStackTrace(pw);
   
    ((BasicDBObject)getMetadata().get(ERROR_METADATA_KEY)).put(from, sw.toString());
    touchedMetadata.add(ERROR_METADATA_KEY);
  }
 
  @Override
  @Deprecated
  public boolean containsKey(String s) {
    return containsField(s);
  }

  @Deprecated
  @Override
  /**
   * This method will in most cases only return true for keys "_id", "metadata" and "content".
   * Use containsMetadataField or containsContentField instead to look inside those maps.
   */
  public boolean containsField(String key) {
    return documentMap.containsKey(key);
  }
 
  @Override
  public boolean hasMetadataField(String key) {
    return getMetadataField(key)!=null;
  }
 
  @Override
  public boolean hasContentField(String key) {
    return getContents().containsField(key);
  }

  @Override
  public void markAsPartialObject() {
    partialObject = true;
  }

  @Override
  public boolean isPartialObject() {
    return partialObject;
  }

  @Override
  @Deprecated
  public Object put(String key, Object v) {
    return documentMap.put(key, v);
  }
 
  @Override
  public final Object putContentField(String key, Object v) {
    touchedContent.add(key);
    return getContents().put(key, v);
  }

  @Override
  public Object getContentField(String key) {
    return getContents().get(key);
  }

  @Override
  public Object getMetadataField(String key) {
    return getMetadata().get(key);
  }
 
  @SuppressWarnings("unchecked")
  public Map<String, Object> getMetadataMap() {
    return getMetadata().toMap();
  }

 
  @SuppressWarnings("unchecked")
  @Override
  public Map<String, Object> getContentMap() {
    return getContents().toMap();
  }
 
  @Override
  public final Object putMetadataField(String key, Object v) {
    touchedMetadata.add(key);
    return getMetadata().put(key, v);
  }
 
  @Override
  public final Object removeContentField(String key) {
    touchedContent.add(key);
    return getContents().removeField(key);
  }
 
  @Override
  public MongoDocumentID getID() {
    if(get(MONGO_ID_KEY) == null) {
      return null;
    }
    return new MongoDocumentID((ObjectId) get(MONGO_ID_KEY));
  }

  public String getIDKey() {
    return MONGO_ID_KEY;
  }

  @SuppressWarnings({ "rawtypes" })
  @Override
  public final void putAll(Map m) {
    documentMap.putAll(m);
  }

  @Override
  public final void putAll(Document<?> d) {
    if(d==null) {
      logger.warn("null passed to MongoDocument.putAll(), doing nothing.");
      return;
    }
   
    if(d.getID() == null) {
      //Do nothing.
    }
    else if(d.getID() instanceof MongoDocumentID) {
      documentMap.put(MONGO_ID_KEY, d.getID().getID());
    } else {
      try {
        ObjectId id = MongoDocumentID.getObjectId(d.getID().toJSON());
        documentMap.put(MONGO_ID_KEY, id);
      } catch (JsonException e) {
        logger.error("Unable to convert ID of type "+d.getID().getClass()+ " to MongoDucumentID", e);
        return;
      }
    }
   
   
    if(d.getAction()!=null) {
      setAction(d.getAction());
    }
   
    for(Map.Entry<String, Object> e : d.getMetadataMap().entrySet()) {
      putMetadataField(e.getKey(), e.getValue());
    }
   
    for(Map.Entry<String, Object> e : d.getContentMap().entrySet()) {
      putContentField(e.getKey(), e.getValue());
    }
  }

  @Override
  public Set<String> keySet() {
    return documentMap.keySet();
  }
 
  public String toString() {
    return documentMap.toString();
  }
 
  public boolean isActionTouched() {
    return actionTouched;
  }

  public Set<String> getTouchedContent() {
    return touchedContent;
  }

  public Set<String> getTouchedMetadata() {
    return touchedMetadata;
  }

  private Set<String> getMetadataFields() {
    return getMetadata().keySet();
  }

  @Override
  public Set<String> getContentFields() {
    return getContents().keySet();
  }

  @Override
  public boolean isEqual(Document<?> d) {
    if(d.getID()!=null) {
      if(!d.getID().getID().equals(getID().getID())) {
        return false;
      }
    }
    else {
      if(getID()!=null) {
        return false;
      }
    }
   
    if(d.getAction()!=getAction()) {
      return false;
    }

    if(equalMetadata(d) && equalContent(d)) {
      return true;
    }
   
    return false;
  }
 
  private boolean equalMetadata(Document<?> d) {
    Set<String> metadata = d.getMetadataMap().keySet();
    if(metadata.size()!=getMetadataFields().size()) {
      return false;
    }
   
    for(String s : metadata) {
      if(!getMetadataFields().contains(s)) {
        return false;
      }
     
      if(!Comparator.equals(getMetadataField(s), d.getMetadataMap().get(s))) {
        return false;
      }
    }

    return true;
  }
 
  private boolean equalContent(Document<?> d) {
    Set<String> content = d.getContentFields();
    if(content.size()!=getContentFields().size()) {
      return false;
    }
   
    for(String s : content) {
      if(!getContentFields().contains(s)) {
        return false;
      }
     
      if(!Comparator.equals(getContentField(s), d.getContentField(s))) {
        return false;
      }
    }

    return true;
  }
 
  @Override
  public final void fromJson(String json) throws JsonException {
    clear();
    putAll(new LocalDocument(json));
  }
 
  @Override
  public String toJson() {
    LocalDocument ld = new LocalDocument();
    ld.putAll(this);
    return ld.toJson();
  }
 
  @Override
  public String contentFieldsToJson(Iterable<String> contentFields) {
    LocalDocument ld = new LocalDocument();
    ld.putAll(this);
    return ld.contentFieldsToJson(contentFields);
  }
 
  @Override
  public String metadataFieldsToJson(Iterable<String> metadataFields) {
    LocalDocument ld = new LocalDocument();
    ld.putAll(this);
    return ld.metadataFieldsToJson(metadataFields);
  }
 
  @Override
  public final void clear() {
    setup();
  }

  @Override
  public Status getStatus() {
    if(getMetadataMap().containsKey(FAILED_METADATA_FLAG)) {
      return Status.FAILED;
    }
    if(getMetadataMap().containsKey(DISCARDED_METADATA_FLAG)) {
      return Status.DISCARDED;
    }
    if(getMetadataMap().containsKey(PENDING_METADATA_FLAG)) {
      return Status.PENDING;
    }
    if(getMetadataMap().containsKey(PROCESSED_METADATA_FLAG)) {
      return Status.PROCESSED;
    }
    return Status.PROCESSING;
  }
 
  /**
   * nullsafe
   */
  @SuppressWarnings("unchecked")
  private Map<String, Object> getMetadataSubMap(String key) {
    if(getMetadataMap().containsKey(key)) {
      return (Map<String, Object>) getMetadataMap().get(key);
    }
    return new HashMap<String, Object>();
  }
 
  @Override
  public boolean touchedBy(String stage) {
    return getMetadataSubMap(TOUCHED_METADATA_TAG).containsKey(stage);
  }

  @Override
  public boolean fetchedBy(String stage) {
    return getMetadataSubMap(FETCHED_METADATA_TAG).containsKey(stage);
  }

  @Override
  public boolean removeFetchedBy(String stage) {
    if(fetchedBy(stage)) {
      touchedMetadata.add(FETCHED_METADATA_TAG);
      return getMetadataSubMap(FETCHED_METADATA_TAG).remove(stage)!=null;
    }
    return false;
  }
 
  @SuppressWarnings("unchecked")
  @Override
  public boolean removeTouchedBy(String stage) {
    touchedMetadata.add(TOUCHED_METADATA_TAG);
    return ((Map<String,Object>)getMetadataMap().get(TOUCHED_METADATA_TAG)).remove(stage)!=null;
  }

  @Override
  public Set<String> getTouchedBy() {
    return getMetadataSubMap(TOUCHED_METADATA_TAG).keySet();
  }

  @Override
  public Set<String> getFetchedBy() {
    return getMetadataSubMap(FETCHED_METADATA_TAG).keySet();
  }

  @Override
  public Date getTouchedTime(String stage) {
    return (Date) getMetadataSubMap(TOUCHED_METADATA_TAG).get(stage);
  }

  @Override
  public Date getFetchedTime(String stage) {
    return (Date) getMetadataSubMap(FETCHED_METADATA_TAG).get(stage);
  }

  @Override
  public Date getCompletedTime() {
    return getDoneTag().date;
  }

  @Override
  public String getCompletedBy() {
    return getDoneTag().tag;
  }
 
  private class DoneTuple {
    private Date date;
    private String tag;
  }
 
  private DoneTuple getDoneTag() {
    DoneTuple done = new DoneTuple();
   
    if(getMetadataMap().containsKey(FAILED_METADATA_FLAG)) {
      done.date = (Date) getMetadataSubMap(FAILED_METADATA_FLAG).get(DATE_METADATA_SUBKEY);
      done.tag = (String) getMetadataSubMap(FAILED_METADATA_FLAG).get(STAGE_METADATA_SUBKEY);
    }
    else if(getMetadataMap().containsKey(DISCARDED_METADATA_FLAG)) {
      done.date = (Date) getMetadataSubMap(DISCARDED_METADATA_FLAG).get(DATE_METADATA_SUBKEY);
      done.tag = (String) getMetadataSubMap(DISCARDED_METADATA_FLAG).get(STAGE_METADATA_SUBKEY);
    }
    else if(getMetadataMap().containsKey(PENDING_METADATA_FLAG)) {
      done.date = (Date) getMetadataSubMap(PENDING_METADATA_FLAG).get(DATE_METADATA_SUBKEY);
      done.tag = (String) getMetadataSubMap(PENDING_METADATA_FLAG).get(STAGE_METADATA_SUBKEY);
    }
    else if(getMetadataMap().containsKey(PROCESSED_METADATA_FLAG)) {
      done.date = (Date) getMetadataSubMap(PROCESSED_METADATA_FLAG).get(DATE_METADATA_SUBKEY);
      done.tag = (String) getMetadataSubMap(PROCESSED_METADATA_FLAG).get(STAGE_METADATA_SUBKEY);
    }
    return done;
  }

  @Override
  public void setID(DocumentID<MongoType> id) {
    documentMap.put(ID_KEY, id.getID());
  }

  @Override
  public boolean matches(DatabaseQuery<MongoType> query) {
    MongoQuery mq = (MongoQuery) query;
   
    for(String s : mq.getTouchedBy()) {
      if(!touchedBy(s)) {
        return false;
      }
    }
    for(String s : mq.getNotTouchedBy()) {
      if(touchedBy(s)) {
        return false;
      }
    }
   
    if(mq.getAction() != null && mq.getAction() != getAction()) {
      return false;
    }
   
    for(Map.Entry<String, Object> e : mq.getContentsEquals().entrySet()) {
      if(!hasContentField(e.getKey()) || !getContentField(e.getKey()).equals(e.getValue())) {
        return false;
      }
    }
   
    for(Map.Entry<String, Object> e : mq.getContentsNotEquals().entrySet()) {
      if(hasContentField(e.getKey()) && getContentField(e.getKey()).equals(e.getValue())) {
        return false;
      }
    }
   
    for(String s : mq.getContentsExists()) {
      if(!hasContentField(s)) {
        return false;
      }
    }
   
    for(String s : mq.getContentsNotExists()) {
      if(hasContentField(s)) {
        return false;
      }
    }
   

    for(String s : mq.getFetchedBy()) {
      if(!fetchedBy(s)) {
        return false;
      }
    }
   
    for(String s : mq.getNotFetchedBy()) {
      if(fetchedBy(s)) {
        return false;
      }
    }
   
    for(String s : mq.getMetadataExists()) {
      if(!hasMetadataField(s)) {
        return false;
      }
    }
   
    for(String s : mq.getMetadataNotExists()) {
      if(hasMetadataField(s)) {
        return false;
      }
    }
   
    for(Map.Entry<String, Object> e : mq.getMetadataEquals().entrySet()) {
      if(!hasMetadataField(e.getKey()) || !getMetadataMap().get(e.getKey()).equals(e.getValue())) {
        return false;
      }
    }
   
    for(Map.Entry<String, Object> e : mq.getMetadataNotEquals().entrySet()) {
      if(hasMetadataField(e.getKey()) && getMetadataMap().get(e.getKey()).equals(e.getValue())) {
        return false;
      }
    }
   
    if(mq.getRequiredID() != null && !getID().equals(mq.getRequiredID())) {
      return false;
    }
   
    return true;
  }
 
  public final void setFetchedBy(String stage, Date date) {
    touchedMetadata.add(FETCHED_METADATA_TAG);
    if(!getMetadata().containsField(FETCHED_METADATA_TAG)) {
      getMetadata().put(FETCHED_METADATA_TAG, BasicDBObjectBuilder.start(stage, date).get());
    } else {
      ((DBObject) getMetadata().get(FETCHED_METADATA_TAG)).put(stage, date);
    }
  }
 
  public final void setTouchedBy(String stage, Date date) {
    touchedMetadata.add(TOUCHED_METADATA_TAG);
    if(!getMetadata().containsField(TOUCHED_METADATA_TAG)) {
      getMetadata().put(TOUCHED_METADATA_TAG, BasicDBObjectBuilder.start(stage, date).get());
    } else {
      ((DBObject) getMetadata().get(TOUCHED_METADATA_TAG)).put(stage, date);
    }
  }
 
  public MongoDocument copy() {
    MongoDocument m = new MongoDocument();
    m.putAll((Document<MongoType>)this);
    return m;
  }
}
TOP

Related Classes of com.findwise.hydra.mongodb.MongoDocument

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.