Package org.openntf.domino.graph2.impl

Source Code of org.openntf.domino.graph2.impl.DElement

package org.openntf.domino.graph2.impl;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javolution.util.FastMap;
import javolution.util.FastSet;
import javolution.util.function.Equalities;

import org.openntf.domino.Document;
import org.openntf.domino.graph.DominoVertex;
import org.openntf.domino.types.Null;
import org.openntf.domino.utils.TypeUtils;

public abstract class DElement implements org.openntf.domino.graph2.DElement, Serializable {
  private static final Logger log_ = Logger.getLogger(DElement.class.getName());
  private static final long serialVersionUID = 1L;
  public static final String TYPE_FIELD = "_OPEN_GRAPHTYPE";

  public static enum Deferred {
    INSTANCE;
  }

  protected transient org.openntf.domino.graph2.DGraph parent_;
  private String delegateKey_;
  private transient Map<String, Object> delegate_;

  public DElement(final org.openntf.domino.graph2.DGraph parent) {
    parent_ = parent;
  }

  protected org.openntf.domino.graph2.impl.DGraph getParent() {
    return (org.openntf.domino.graph2.impl.DGraph) parent_;
  }

  private FastSet<String> changedProperties_;

  private FastSet<String> getChangedPropertiesInt() {
    if (changedProperties_ == null) {
      changedProperties_ = new FastSet<String>(Equalities.LEXICAL_CASE_INSENSITIVE).atomic();
    }
    return changedProperties_;
  }

  private FastSet<String> removedProperties_;

  private FastSet<String> getRemovedPropertiesInt() {
    if (removedProperties_ == null) {
      removedProperties_ = new FastSet<String>(Equalities.LEXICAL_CASE_INSENSITIVE).atomic();
    }
    return removedProperties_;
  }

  private FastMap<String, Object> props_;

  private FastMap<String, Object> getProps() {
    if (props_ == null) {
      FastMap<String, Object> localProps = new FastMap<String, Object>(Equalities.LEXICAL_CASE_INSENSITIVE);
      for (String key : getDelegate().keySet()) {
        localProps.put(key, Deferred.INSTANCE);
      }
      props_ = localProps.atomic();
    }
    return props_;
  }

  @Override
  public <T> T getProperty(final String propertyName, final Class<?> T) {
    Object result = null;
    Map<String, Object> props = getProps();
    result = props.get(propertyName);
    if (result == null || Deferred.INSTANCE.equals(result)) {
      try {
        Map<String, Object> delegate = getDelegate();
        if (delegate instanceof Document) {
          Document doc = (Document) delegate;
          result = doc.getItemValue(propertyName, T);
        } else {
          result = T.cast(delegate.get(propertyName));
        }
        if (result == null) {
          props.put(propertyName, Null.INSTANCE);
        } else if (result instanceof Serializable) {
          props.put(propertyName, result);
        } else {
          log_.log(Level.FINE, "Got a value from the document but it's not Serializable. It's a " + result.getClass().getName());
          props.put(propertyName, result);
        }
      } catch (Exception e) {
        log_.log(Level.WARNING, "Exception occured attempting to get value from document for " + propertyName
            + " so we cannot return a value", e);
      }
    } else if (result == Null.INSTANCE) {

    } else {
      if (result != null && !T.isAssignableFrom(result.getClass())) {
        try {
          Map<String, Object> delegate = getDelegate();
          if (delegate instanceof Document) {
            Document doc = (Document) delegate;
            result = doc.getItemValue(propertyName, T);
          } else {
            Object chk = delegate.get(propertyName);
            if (chk != null) {
              result = T.cast(delegate.get(propertyName));
            }
          }
          if (result == null) {
            props.put(propertyName, Null.INSTANCE);
          } else if (result instanceof Serializable) {
            props.put(propertyName, result);
          } else {
            log_.log(Level.FINE, "Got a value from the document but it's not Serializable. It's a "
                + result.getClass().getName());
            props.put(propertyName, result);
          }
        } catch (Exception e) {
          log_.log(Level.WARNING, "Exception occured attempting to get value from document for " + propertyName
              + " but we have a value in the cache.", e);
        }
      }
    }
    if (result == Null.INSTANCE) {
      result = null;
    }
    return (T) result;
  }

  @Override
  public <T> T getProperty(final String key) {
    return getProperty(key, java.lang.Object.class);
  }

  @Override
  public Set<String> getPropertyKeys() {
    return getProps().keySet().unmodifiable();
  }

  @SuppressWarnings("rawtypes")
  @Override
  public void setProperty(final String key, final Object value) {
    boolean isEqual = false;
    Map<String, Object> props = getProps();
    if (props != null) {
      if (key != null) {
        Object current = getProperty(key);
        //        if (key.startsWith(DominoVertex.IN_PREFIX) && value instanceof java.util.Collection) {
        //          isEdgeCollection = true;
        //        }
        if (current == null && value == null) {
          return;
        }
        //NTF The standard equality check has a fast out based on array size, so I think it's safe to use here...
        /*if (key.startsWith(DominoVertex.IN_PREFIX) || key.startsWith(DominoVertex.OUT_PREFIX)) {
          isEqual = false;  //NTF ALWAYS set edge collections. Checking them can be expensive
        } else*/if (value != null && current != null) {
          if (!(value instanceof java.util.Collection) && !(value instanceof java.util.Map) && !value.getClass().isArray()) {
            isEqual = value.equals(current);
          }
          if (value instanceof java.util.Collection && current instanceof java.util.Collection) {
            Object[] vArray = ((java.util.Collection) value).toArray();
            Object[] cArray = ((java.util.Collection) current).toArray();
            isEqual = Arrays.deepEquals(vArray, cArray);
          }
          if (value.getClass().isArray() && current.getClass().isArray()) {
            Object[] vArray = (Object[]) value;
            Object[] cArray = (Object[]) current;
            isEqual = Arrays.deepEquals(vArray, cArray);
          }
        }
        if (isEqual) {
          log_.log(Level.FINE, "Not setting property " + key + " because the new value is equal to the existing value");
        }
        if (value instanceof Serializable) {
          if (current == null || Null.INSTANCE.equals(current)) {
            getParent().startTransaction(this);
            getChangedPropertiesInt().add(key);
          } else if (!isEqual) {
            getParent().startTransaction(this);
            getChangedPropertiesInt().add(key);
          } else {
          }
        } else if (value == null) {
          if (!Null.INSTANCE.equals(current)) {
            getParent().startTransaction(this);
            getChangedPropertiesInt().add(key);
          }
        } else {
          log_.log(Level.FINE, "Attempted to set property " + key + " to a non-serializable value: " + value.getClass().getName());
          if (current == null || Null.INSTANCE.equals(current)) {
            getParent().startTransaction(this);
            getChangedPropertiesInt().add(key);
          } else if (!isEqual) {
            getParent().startTransaction(this);
            getChangedPropertiesInt().add(key);
          } else {
          }
        }
      } else {
        log_.log(Level.WARNING, "propertyName is null on a setProperty request?");
      }
    } else {
      log_.log(Level.WARNING, "Properties are null for element!");
    }
  }

  @Override
  public <T> T removeProperty(final String key) {
    getParent().startTransaction(this);
    T result = getProperty(key);
    Map<String, Object> props = getProps();
    props.remove(key);
    Map<String, Object> source = getDelegate();
    source.remove(key);
    getRemovedPropertiesInt().add(key);
    return result;
  }

  @Override
  public abstract void remove();

  void _remove() {
    getParent().startTransaction(this);
    getParent().removeDelegate(this);
  }

  @Override
  public Object getId() {
    return delegateKey_;
  }

  @Override
  public boolean hasProperty(final String key) {
    return getPropertyKeys().contains(key);
  }

  @Override
  public <T> T getProperty(final String key, final Class<?> T, final boolean allowNull) {
    T result = getProperty(key, T);
    if (allowNull) {
      return result;
    } else {
      if (result == null || Null.INSTANCE == result) {
        return TypeUtils.getDefaultInstance(T);
      } else {
        return result;
      }
    }
  }

  @Override
  public int incrementProperty(final String key) {
    // TODO NTF it would be really great to figure out a way to use primitives here
    Integer result = getProperty(key, Integer.class);
    if (result == null)
      result = 0;
    setProperty(key, ++result);
    return result;
  }

  @Override
  public int decrementProperty(final String key) {
    // TODO NTF it would be really great to figure out a way to use primitives here
    Integer result = getProperty(key, Integer.class);
    if (result == null)
      result = 0;
    setProperty(key, --result);
    return result;
  }

  @Override
  public Map<String, Object> getDelegate() {
    if (delegate_ == null) {
      delegate_ = getParent().findDelegate(delegateKey_);
    }
    return delegate_;
  }

  @Override
  public void setDelegate(final Map<String, Object> delegate) {
    delegate_ = delegate;
  }

  @Override
  public Map<String, Object> toMap(final String[] props) {
    FastMap<String, Object> result = new FastMap<String, Object>();
    for (String prop : props) {
      result.put(prop, getProperty(prop));
    }
    return result.unmodifiable();
  }

  @Override
  public Map<String, Object> toMap(final Set<String> props) {
    return toMap(props.toArray(TypeUtils.DEFAULT_STR_ARRAY));
  }

  @Override
  public void fromMap(final Map<String, Object> map) {
    // TODO Auto-generated method stub

  }

  protected void applyChanges() {
    Map<String, Object> props = getProps();
    Map<String, Object> delegate = getDelegate();
    if (!props.isEmpty()) {
      for (String s : getChangedPropertiesInt()) {
        String key = s;
        Object v = props.get(key);
        if (s.startsWith(DominoVertex.IN_PREFIX) || s.startsWith(DominoVertex.OUT_PREFIX)) {
          if (delegate instanceof Document) {
            ((Document) delegate).replaceItemValue(s, v, false);
          } else {
            delegate.put(s, v);
          }
        } else {
          delegate.put(s, v);
        }
      }
      getChangedPropertiesInt().clear();
    }
    for (String key : getRemovedPropertiesInt()) {
      delegate.remove(key);
    }
    getRemovedPropertiesInt().clear();
  }

  @Override
  public void rollback() {
    getProps().clear();
    getChangedPropertiesInt().clear();
    getRemovedPropertiesInt().clear();
  }

  @Override
  public void commit() {

  }

}
TOP

Related Classes of org.openntf.domino.graph2.impl.DElement

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.