Package org.jugile.daims

Source Code of org.jugile.daims.BoMapDelta$BoMapIterator

package org.jugile.daims;

/*

Copyright (C) 2011-2011 Jukka Rahkonen  email: jukka.rahkonen@iki.fi

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/

import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;
import org.jugile.daims.anno.Connection1N;
import org.jugile.daims.anno.ConnectionNN;
import org.jugile.util.Buffer;
import org.jugile.util.DBConnection;
import org.jugile.util.Jugile;

/**
* <i>"For this is what the LORD says — he who created the heavens, he is God;
* he who fashioned and made the earth, he founded it;
* he did not create it to be empty, but formed it to be inhabited — he says:
* 'I am the LORD, and there is no other.'"</i> <b>(Isaiah 45:18)</b>
*
* <br/>==========<br/>
*
* here is doc
* @author jukka.rahkonen@iki.fi
*
*/
public class BoMapDelta<E extends Bo> extends Jugile {
  static Logger log = Logger.getLogger(BoMapDelta.class);

  private UnitOfWork uow() { return DomainCore.getUnitOfWork(); }

  protected Map<Long,E> items = new HashMap<Long,E>(2);
  protected Map<Long,E> removed = new HashMap<Long,E>(2);
  protected Map<Long,Object> props = null;

  protected void reset() {
    items = new HashMap<Long,E>(2);
    removed = new HashMap<Long,E>(2);
    props = null;
    size = 0;
  }
 
  protected BoMap<E> origin;
  public BoMapDelta(BoMap<E> origin) {
    this.origin = origin;
  }
  public BoMapDelta(Class<E> cl) {
    origin = new BoMap<E>(cl,null);
  }
 
  public Object getProp(long id) {
    if (props == null) return null;
    return props.get(id);
  }
  public Object getProp(E o) {
    if (o == null) return null;
    return getProp(o.id());
  }
 
  public final void remove(E o) { remove(o,true); }
  public final void remove(E o, boolean cleanup) {
    if (o == null) return;
    //log.debug("remove: " + o);
    if (contains(o.id())) {
      //log.debug("  it contains it");
      // contains() test is needed to keep correct size count
      if (!removed.containsKey(o.id())) {
        // NOTE: do not touch items here: it causes concurrent modification exception
        removed.put(o.id(),o);
        size--;
        if (cleanup) try { o.cleanUpConnections(); } catch (Exception e) {fail(e);}
        if (props != null) props.remove(o.id());
      }
    } else {
      //log.debug("  it didnt contain it");
    }
  }
 
 
//  protected void removeAll() {
//    log.debug("removeAll");
//    for (E o : (BoCollection<E>)this) {
//      log.debug("  removing: " + o);
//      remove(o,false);
//    }
//  }
 
  public final boolean contains(long id) {
    if (removed.containsKey(id)) return false;
    if (items.containsKey(id)) return true;
    if (origin.contains(id)) return true;
    return false;
  }
 
 
  private int size = 0;
 
  public final void add(E o) { add(o,null); }
  public final void add(E o, Object vo) {
    if (o == null) return;
    // remove removed
    if (removed.remove(o.id()) != null) {
      //log.debug("add(o) removed: " + o);
      if (items.containsKey(o.id())) size++; // for case of re-adding
    }
    if (!items.containsKey(o.id())) {
      //log.debug("add: " + o);
      items.put(o.id(),o);
      size++;
      if (vo != null) {
        if (props == null) props = new HashMap<Long,Object>();
        props.put(o.id(), vo);
      }
    }
  }
 
  public final void add(List<E> lst) { for (E o : lst) add(o); }
  //public final void add(BoMapDelta<E> map) { for (E o : map) add(o); }

  public final int getSize() {
    return origin.size() + size;
  }
 
  // allways gets a copy of original or new from delta
  public final E get(long id) {
    if (removed.containsKey(id)) return null;
    E o = items.get(id);
    if (o != null && !o.isRef()) { // check if this is lazyloaded reference
      return o;
    }
    o = origin.getCopy(id);
    if (o == null) {
      //fail("original object not found: " + origin.getClazz().getName() + ": " + id);
      // empty collections ( new BoCollection(); ) in app have no original items
      return null;
    }
    items.put(o.id(),o);
    return o;
  }
 
  protected final E createNewBo() {
    E o = (E)Bo.createNew(origin.getClazz());
    items.put(o.id(),o);
    size++;
    return o;
  }
 
  protected final boolean isRemoved(E o) {
    if (removed.containsKey(o.id())) return true;
    return false;
  }
 
  public class BoMapIterator implements Iterator<E> {
    BoMapDelta<E> bm = null;
    Iterator<E> i = null;
    Iterator<E> oi = null;
    public BoMapIterator(BoMapDelta<E> bm) {
      this.bm = bm;
      i = bm.items.values().iterator();
      if (bm.origin != null) {
        oi = bm.origin.iterator();
      }
      next = getNext(); // find first next
    }
   
    private E next = null;
    public E getNext() {
      // iterate own items
      while (i.hasNext()) {
        E o = i.next();
        // is it removed
        if (!removed.containsKey(o.id())) {
          return o;
        }
      }
     
      // iterate origin items
      while (oi.hasNext()) {
        E o = oi.next();
        if (removed.containsKey(o.id())) {
          continue;
        }
        if (items.containsKey(o.id())) {
          continue; // allready visited
        }
        return o;
      }
      return null; // not found, end reached
    }
   
    public boolean hasNext() { return next != null; }
    public E next() {
      E res = next;
      next = getNext();
      if (!uow().isReadOnly())
        if (res != null && res.isOrigin()) res = (E)res.getUowCopy();
      return res;
    }

    public void remove() { fail("remove not supported");}   
  }

  // no iterator() named method for avoiding accidentaly using this iterator
  // instead of inherited BoCollection's iterator.
  // TODO: change this name later back to iterator() when everything works.
  public final Iterator<E> deltaIterator() {
    return new BoMapIterator(this);
  }
 
  /**
   * Locally remove added / modified
   */
  private void localRemove() {
    Iterator<Long> i = removed.keySet().iterator();
    while (i.hasNext()) {
      long id = i.next();
      Bo o = items.remove(id);
      if (o != null)
        if (o.isNew()) // only new items should be removed from delete list
          i.remove();
    }
  }
 

  public int getCommitSize() {
    int cs = removed.size();
    cs += items.size();
    return cs;
  }
 
  public void delta(Writer out) throws Exception {
    if (getCommitSize() == 0) return; // empty set
   
    // header row
    //log.debug("delta. first: " + _first());
    out.write(_first()._headerRow() + "\n");
   
    // 1. add added and merge modified
    Iterator<E> i2 = items.values().iterator();
    while (i2.hasNext()) {
      E o = i2.next();
      if (o.isModified() || o.isNew())
        out.write(o._delta() + "\n");
    }
   
    // TODO: local cleanup: remove locally removed
    // 2. remove deleted ( if same transaction creates and deletes)
    Iterator<E> i = removed.values().iterator();
    while (i.hasNext()) {
      E o = i.next();
      out.write(o._deleteRow() + "\n");
    }
  }
 
 
  // TODO: clean up - combine with BoMap.nncsv()
  public void nndelta(Writer out) throws Exception {
    if (getCommitSize() == 0) return; // empty set
    //log.debug("nndelta. first: " + _first());
    for (Field f : bi().nns) {
      String cn1 = f.getName();
      print("====== :" +cn1);
      // iterate all items and add changes on n-n collection
      if (items.size() > 0) {
        out.write(_first()._nnHeader(f) + "\n");
        Iterator<E> i2 = items.values().iterator();
        while (i2.hasNext()) {
          E o = i2.next();
          BoMapDelta<E> m = (BoMapDelta<E>)o.getBoCollection(cn1);
          List<E> localItems = m.getLocalItems();
          if (localItems.size() > 0) {
            out.write(((Bo)o).getId());
            for (Bo bo : localItems) {
              // items() of n-n collection, added
              out.write(Bo.CSVDELIMITER + bo.getId());
            }
            out.write("\n");           
          }
          List<E> deletedItems = m.getDeletedItems();
          if (deletedItems.size() > 0) {
            out.write(Bo.MAPSTART+"D"+Bo.CSVDELIMITER+((Bo)o).getId());
            for (Bo bo : deletedItems) {
              // items() of n-n collection, added
              out.write(Bo.CSVDELIMITER + bo.getId());
            }
            out.write("\n");           
          }
        }
      }
    }
  }

  private E _first = null;
  private E _first() {
    // instantiate
    if (_first != null) return _first;
    try {
      _first = origin.getClazz().newInstance();
      return _first;
    } catch (Exception e) { fail(e); return null; }
  }
  protected E getProto() { return _first(); }

  private List<E> getLocalItems() {
    List<E> res = new ArrayList<E>();
    Iterator<E> i = items.values().iterator();
    while (i.hasNext()) {
      E o = i.next();
      res.add(o);
    }
    return res;
  }

  private List<E> getDeletedItems() {
    List<E> res = new ArrayList<E>();
    Iterator<E> i = removed.values().iterator();
    while (i.hasNext()) {
      E o = i.next();
      res.add(o);
    }
    return res;
  }

  private BoInfo bi;
  protected BoInfo bi() {
    if (bi == null) bi = _first().bi();
    return bi;
  }
 
  protected int writeToDB(DBConnection c) throws Exception {
    if (getCommitSize() == 0) return 0; // empty set
    int count = 0;
   
    String table = bi().table;
   
    // local cleanup - remove removed
    localRemove();
   
    // remove deleted
    //print("============ writeToDB: " + this);
    Iterator<E> i3 = removed.values().iterator();
    while (i3.hasNext()) {
      E o = i3.next();
      if (o.id() == 0 || o.version() <= 0) {
        log.warn("tried to remove ghost object: " + o);
        continue;
      }
      if (o.isArchived()) continue;
      c.prepare("delete from " + table + " where id_f=? AND vers=?");
      print("DELETE: " + o);
      //c.prepare("delete from " + table + " where id_f=?");
      c.param(o.id());
      c.param(o.version());
      //print("delete: " + o.id() + "," + o.version());
      int del = c.execute();
      if (del != 1) {
        fail("could not delete: " + o);
      }
      removeAllNN(c,o); // remove all n-n references from db
      count++;
    }
   
    // add added and merge modified
    Iterator<E> i2 = items.values().iterator();
    while (i2.hasNext()) {
      E o = i2.next();
      // handle n-n updates
      updateNN(c,o);
      if (o.isModified() || o.isNew()) {
        o._dbWriteFlds(c,bi());
        count++;
      }
    }     
    return count;
  }

  private void removeAllNN(DBConnection c, Bo o) throws Exception {
    // all n-n connections
    int i = 0;
    for (Field f : bi().nns) {
      String nntable = bi().nntables.get(i++);
      //c.prepare("delete from " + nntable + " where o1=?");
      c.prepare("delete from " + nntable + " where o2=?"); // ang swap
      c.param(o.id());
      c.execute();
    }
  }
 
  private void updateNN(DBConnection c, Bo o) throws Exception {
    // all n-n connections
    int i = 0;
    for (Field f : bi().nns) {
      String nntable = bi().nntables.get(i++);
      BoMapDelta<Bo> m = o.getBoCollection(f.getName());
      List<Bo> localItems = m.getLocalItems();
      if (localItems.size() > 0) {
        long oid1 = o.id();
        for (Bo bo : localItems) {
          // items() of n-n collection, added
          long oid2 = bo.id();
          c.prepare("replace into " + nntable + " set o1=?,o2=?");
          c.param(oid2); // swap needed to ang?
          c.param(oid1);
//          c.param(oid1);
//          c.param(oid2);
          c.execute();
        }
      }
      List<Bo> deletedItems = m.getDeletedItems();
      if (deletedItems.size() > 0) {
        long oid1 = o.id();
        for (Bo bo : deletedItems) {
          // items() of n-n collection, deleted
          long oid2 = bo.id();
          c.prepare("delete from " + nntable + " where o1=? AND o2=?");
          c.param(oid2); // swap needed to ang?
          c.param(oid1);
//          c.param(oid1);
//          c.param(oid2);
          c.execute();
        }
      }
    }
  }
 
  public String status() {
    Buffer buf = new Buffer();
    buf.nl();
    buf.ln("removed: " + removed.size());
    buf.ln("items: " + items.size());
    if (origin != null) {
      buf.ln("origin: " + origin.size());
    }
    return buf.toString();
  }

  public String toString() {
    String res = "[Delta " + getClassName(origin.getClazz()) + " " +
        hex(hashCode()) + " del:" + removed.size() + " items:"
        + items.size() + " origin:"+origin.size() + "] ";
    return res;
  }
 
  protected void dumpDeleted(Buffer buf) throws Exception {
    //    deleted:
    //        5430D082 Person
    //        5430D082 Person
    //        5430D082 Family
    buf.incrIndent();
    for (Bo o : this.getDeletedItems()) {
      buf.ln(o.toRefStr());
    }
    buf.decrIndent();
  }
 
  protected void dumpItems(Buffer buf) throws Exception {
    //    items:
    //        5430D082 Person (2,1,0,-,p1,-)  ->  5430D082
    //            family: 5430D082  Family (ref)
    //            family: 5430D082  Family (2,1,0) ->  5430D082 
    buf.incrIndent();
    for (Bo o : this.getLocalItems()) {
      o.dump(buf);
      buf.ln();
    }
    buf.decrIndent();
  }

  protected void dumpShort(Buffer buf) throws Exception {
    //      persons( 5430D082 -> 5430D082 ):
    //          items: 5430D082, 5430D082, 5430D082, 5430D082
    //          deleted: 5430D082, 5430D082 
    buf.ind().add("items: ");
    int ind = 0;
    for (Bo o : getLocalItems()) {
      if (ind++ > 0) buf.add(", ");
      buf.add(o.realHash());
    }
    buf.nl();
   
    buf.ind().add("deleted: ");
    ind = 0;
    for (Bo o : getDeletedItems()) {
      if (ind++ > 0) buf.add(", ");
      buf.add(o.realHash());
    }
    buf.nl();
  }
 
 


}
TOP

Related Classes of org.jugile.daims.BoMapDelta$BoMapIterator

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.