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.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.jugile.daims.anno.ConnectionNN;
import org.jugile.util.Buffer;
import org.jugile.util.CsvTokenizer;
import org.jugile.util.DBConnection;
import org.jugile.util.DBQueue;
import org.jugile.util.Jugile;
import org.jugile.util.Msg;
/**
* <i>"this is verse"</i> <b>()</b>
*
* <br/>==========<br/>
*
* here is doc
*
* @author jukka.rahkonen@iki.fi
*
*/
public class DomainData extends Jugile {
static Logger log = Logger.getLogger(DomainData.class);
// private boolean writeThrough = false;
// protected void setWriteThrough() { writeThrough = true; }
// protected boolean isWriteThrough() { return writeThrough; }
private DomainCore domain = null;
protected DomainData(DomainCore domain) { this.domain = domain; }
protected DomainCore d() { return domain; }
protected BoCollection<Bo> getBoCollection(Class<Bo> cl) {
BoCollection<Bo> bc = (BoCollection<Bo>)Jugile.instantiateObject(cl.getName()+"Collection");
bc.origin = map(cl); // set coredata collection to its origin
return bc;
}
protected Bo getOrCreate(Class<Bo> cl, String idstr) {
return getOrCreate(cl, parseLongSafe(idstr));
}
protected Bo getOrCreate(Class<Bo> cl, long id) {
return map(cl).getOrCreateOld(id);
}
private Bo get(Class<Bo> cl, long id) {
return map(cl).getOriginal(id);
}
private void remove(Class<Bo> cl, long id) {
map(cl).remove(id);
}
// ----------- data maps -----------
private Map<Class<Bo>,BoMap<Bo>> maps = new HashMap<Class<Bo>,BoMap<Bo>>();
private BoMap<Bo> map(Class<Bo> cl) {
BoMap<Bo> m = maps.get(cl);
if (m == null) {
m = createBoMap(cl);
maps.put(cl,m);
}
return m;
}
private BoMap<Bo> createBoMap(Class<Bo> cl) {
BoMap<Bo> bm = new BoMap<Bo>(cl,this);
return bm;
}
// ---------- persistence ----------
protected int modifyDomain(CsvTokenizer t) throws Exception {
int count = 0;
List<String> headers = null;
boolean mapping = false;
Class<Bo> clo = null;
String cn1 = null;
//Proxy ddp = new Proxy(_dd());
while (t.readLine()) {
if ((count+1)%1000 == 0) log.info("modify domain: " + (count+1));
if (t.col(0).startsWith(Bo.HEADERSTART)) {
// headerline
String cname = t.col(0).substring(1);
clo = (Class<Bo>)getClassByName(cname);
headers = new ArrayList<String>();
for (String hdr : t.getCols()) headers.add(hdr);
mapping = false;
continue;
}
if (t.col(0).equals(Bo.MAPSTART)) {
// n-n mapping
clo = (Class<Bo>)getClassByName(t.col(1));
cn1 = t.col(2);
mapping = true;
continue;
}
if (mapping) {
if (t.col(0).equals(Bo.MAPSTART+"D")) {
//log.debug("MAP DELETE");
Bo o = get(clo, parseLongSafe(t.col(1)));
if (o == null) {
// this is not necessarily error case: if object is
// just deleted and its n-n connection are put
// in n-n delete list, the object DEL can come first,
// then this is not found anymore, but its not an error.
//fail("n-n object not found: " + clo + " " + t.col(1));
continue;
}
for (int i = 2; i < t.cols(); i++) {
o.removeOriginNN(cn1, parseLongSafe(t.col(i)));
}
} else {
Bo o = get(clo, parseLongSafe(t.col(0)));
if (o == null) fail("n-n object not found: " + clo + " " + t.col(0));
Class<Bo> clo2 = o.getOtherEndClass(cn1);
for (int i = 1; i < t.cols(); i++) {
Bo o2 = getOrCreate(clo2,t.col(i));
o.addOriginNN(cn1, o2);
}
}
} else {
// dataline
if (Bo.DEL.equals(t.col(0))) {
//print("DELETE: " + t.col(1));
try {
// call onDeleteEvent
Bo o = get(clo,parseLongSafe(t.col(1)));
if (o != null) {
o.onDeleteEvent();
// cleanup all neighbour collections
o.cleanUpOriginConnections();
}
} catch (Exception e) {}
remove(clo,parseLongSafe(t.col(1))); // just remove from map
} else {
Bo o = (Bo)getOrCreate(clo,t.col(0));
if (o == null) fail("invalid object: "+ clo + " "+ t.col(0));
o.parse(this, headers, t.getCols());
//log.debug("Bo parsed: "+ o);
}
}
count++;
}
return count;
}
protected void saveToCsv(Writer out) throws Exception {
for (Class<Bo> cl : maps.keySet()) {
//log.debug("writing csv: " + cl.getName());
out.write(map(cl).csv());
out.write(map(cl).nncsv());
}
out.close();
}
protected int saveToDB(DBConnection c) throws Exception {
int count = 0;
for (Class<Bo> cl : maps.keySet()) {
log.info("writing db: " + cl.getName());
int i = map(cl).writeAllToDB(c);
log.info(" wrote rows: " + i);
count += i;
}
return count;
}
protected int loadFromDB(DBConnection c, Class<Bo>[] cls) throws Exception {
int count = 0;
for (Class<Bo> cl : cls) {
log.debug("load table: " + cl);
Bo o = (Bo)cl.newInstance(); // just for template
BoInfo bi = o.bi();
c.prepare("select "+o._getSelectFlds()+" from "+o.table()+" where archived=0");
for (List<Object> row : c.select()) {
long id = (Integer)row.get(0);
o = getOrCreate(cl,id);
o._setState(this,bi,row);
//log.debug("row: " + o);
count++;
if ((count%1000)==0) log.info("load " + bi.table + " "+ count);
}
// n-n connections
for (Field f : bi.nns) {
String nntable = f.getAnnotation(ConnectionNN.class).table();
Class<Bo> cl2 = o.getOtherEndClass(f.getName());
c.prepare("select o1,o2 from " + nntable);
for (List<Object> row : c.select()) {
long id1 = (Integer)row.get(0);
long id2 = (Integer)row.get(1);
// Bo o1 = getOrCreate(cl,id1);
// Bo o2 = getOrCreate(cl2,id2);
// log.debug("NN: " + nntable + " " + o1 + " - " + o2);
Bo o1 = getOrCreate(cl,id2); // SWAP - ANG needs this
Bo o2 = getOrCreate(cl2,id1);
o1.addOriginNN(f.getName(), o2);
//log.debug("added NN: " + o1 + " --- " + o2);
}
}
}
return count;
}
protected int readDeltasFromQueue(String node, int max) throws Exception {
int count = 0;
for (Msg m : DBQueue.getMessages(node, max)) {
String delta = m.getMsg();
CsvTokenizer t = CsvTokenizer.parseString(delta,Bo.CSVDELIMITER);
modifyDomain(t);
count++;
}
return count;
}
protected void dump(Buffer buf) throws Exception {
buf.ln("DomainData:");
buf.ln("===========");
for (BoMap m : maps.values()) m.dump(buf);
}
protected void stats(Stats st) {
for (Class cl : st.classes()) {
map(cl).stats(st);
}
}
}