package net.methodyne.bellvue.store; import java.io.IOException; import java.util.Collection; import java.util.Vector; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import com.jamonapi.*; import net.methodyne.bellvue.system.User; import net.methodyne.bellvue.system.Group; import net.methodyne.bellvue.core.Sdata; import net.methodyne.bellvue.core.Finder; /** * The datastore functions for inserting, update, delete and locking are accessible by this. * *@author Andreas Reiss *@version 1.0 * <br>Date: 11.08.2003 * <br>Time: 15:54:20 * <br> copyright Methodyne GmbH, Zug - Switzerland. */ public class DataLayer { String pkg; String objects; public MemStore memStore ; /** * Creates and initialises a new in memory datastore * @param dir the directory to persist data on disk */ public DataLayer(String dir) { pkg = "net.methodyne.bellvue.system"; objects = pkg + ".User," + pkg + ".Group," + pkg + ".Application," + pkg + ".BClass," + pkg + ".Bulk";// + pkg + ".ClipObject" ; try { memStore = new MemStore(new DataKeeper(objects), dir ,3 ); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("DataLayer:new DataLayer!"); Sdata sd = new Sdata(); sd.user = new User(); Group g = new Group(); g.groupname = "admin"; sd.user.groups.add(g); new DataInit().createSystem( sd, this, objects); init(); } /** * Initialise supporting Hashes */ public void init(){ memStore.system().initMaps(); } /** * Used by the bulk object only - do not use this in your application! * @param sd * @param x * @param bulk */ public void store(Sdata sd, Object x, boolean bulk) { System.out.println("DataLayer:insert:bulk"); try { long currentid = ( memStore.system()).getId(sd, x.getClass().getName() ); //System.out.println("new Id: " + newid); long xid = x.getClass().getField("id").getLong(x); if( currentid <= xid ){ memStore.executeCommand(sd, new DataSetIdCommand( x.getClass().getName() , xid )); } memStore.executeCommand(sd, new DataInsertCommand( x )); } catch (Exception e) { e.printStackTrace(); } } /** * Store an object without setting a lock. * @param sd * @param x */ public void storeUnlocked(Sdata sd, Object x) { System.out.println("DataLayer:storeUnlocked"); try { if( x.getClass().getField("id").getLong(x) < 0 ){ // object needs valid id long newid = ( memStore.system()).getId(sd, x.getClass().getName() ); //System.out.println("new Id: " + newid); x.getClass().getField("id").setLong(x, newid); memStore.executeCommand(sd, new DataSetIdCommand( x.getClass().getName() , newid )); memStore.executeCommand(sd, new StoreUnlockedCommand(x)); } else{ // object has valid id memStore.executeCommand(sd, new DataUpdateCommand(x)); } } catch (Exception e) { e.printStackTrace(); } } /** * Store an object and set the lock for the user in sd.user * @param sd * @param x */ public void store(Sdata sd, Object x) { Monitor store = MonitorFactory.start("DataLayer:insert"); //System.out.println("DataLayer:insert"); try { if( x.getClass().getField("id").getLong(x) < 0 ){ // object needs valid id long newid = ( memStore.system()).getId(sd, x.getClass().getName() ); //System.out.println("new Id: " + newid); x.getClass().getField("id").setLong(x, newid); memStore.executeCommand(sd, new DataSetIdCommand( x.getClass().getName() , newid )); memStore.executeCommand(sd, new DataInsertCommand(x)); } else{ // object has valid id memStore.executeCommand(sd, new DataUpdateCommand(x)); } } catch (Exception e) { e.printStackTrace(); } store.stop(); } /** * Delete * @param sd * @param x */ public void delete(Sdata sd, Object x) { Monitor del = MonitorFactory.start("DataLayer:del"); try { memStore.executeCommand(sd, new DataDeleteCommand(x)); } catch (Exception e) { e.printStackTrace(); } del.stop(); } /** * Retrieve data from the store via the given Finder * @param x * @param sd * @return the given finder */ public Finder fetch(Finder x, Sdata sd){ Monitor fet = MonitorFactory.start("DataLayer:fetch"); Finder dd = ( memStore.system()).fetch(x, sd); fet.stop(); return dd; } /** * Retrieves an object without locking it. * @param sd the session data * @param name of the Bclass * @param reference the id * @param unlocked * @return The object with the given reference (id) or null. */ public Object retrieve(Sdata sd, String name, long reference, boolean unlocked){ return getRefObjects(( memStore.system()).retrieve(sd, name,reference, unlocked),sd); } /** * Retrieves an object and locks it. Like a get by id * @param sd * @param name * @param reference * @return The object with the given reference (id) or null. */ public Object retrieve(Sdata sd, String name, long reference){ Monitor ret = MonitorFactory.start("DataLayer:retrieve"); Object o = ( memStore.system()).retrieve(sd, name,reference); ret.stop(); return getRefObjects(o, sd); } /** * To enable navigation from one object to the next in store. * @param sd * @param x * @return the object with the next higher id */ public Object retrieveNext(Sdata sd, Object x){ Monitor retrieveNext = MonitorFactory.start("DataLayer:retrieveNext"); Object o = ( memStore.system()).retrieveNext(sd, x); retrieveNext.stop(); return getRefObjects(o, sd); } /** * To enable navigation from one object to the next in store. * @param sd * @param x * @return the object with the next lower id */ public Object retrievePrevious(Sdata sd, Object x){ Monitor retrievePrevious = MonitorFactory.start("DataLayer:retrievePrevious"); Object o = ( memStore.system()).retrievePrevious(sd, x); retrievePrevious.stop(); return getRefObjects(o, sd); } public void addAll(Sdata sd, Collection c, String name ){ ( memStore.system()).addAll(sd, c, name); } public void repAll(Sdata sd, Collection c, String name ){ ( memStore.system()).repAll(sd, c, name); } /** * Dumps the data from memory to disk. This gets done periodically by default. * <br> The interval can be configured in web.xml with StateWriteScheduleSeconds in the MainServlet section. * <br>The data gets serialized and compressed with gzip on the fly for efficiency. */ public void takeState() { Monitor takeState = MonitorFactory.start("DataLayer: write state"); try { //System.out.println( new Date() + " Taking state"); memStore.writeState(); } catch (IOException iox) { System.out.println("Write State failed: " + iox.getMessage());} takeState.stop(); } /** * Count all objects in the Store * @return */ public long getObjectCount() { return ( memStore.system()).getObjectCount(); } /** * Checks is the user in sd.user is allowed to access the Bclass given by name * @param sd session data * @param name Bclass name * @return true if permitted, false otherwise */ public boolean permitted(Sdata sd, String name) { return memStore.system().permitted(sd, name); } /** * Explicitly unlocks an object. This has to be called when finished with an object or * it will be locked for others. * @param o object to unlock * @param sd the session data */ public void unlock(Object o, Sdata sd) { memStore.system().doLock(o, sd, false); } /** This attempts to put a lock for this object and returns the locktype * * @param y object to check * @param sd * @return * <br> 0 EXRW locker = this user locked it in mode exclusive read and write * <br> 1 EXRW other = object is locked by another user * <br> 2 EXW locker = this user locked it in mode exclusive write * <br> 3 EXW other = object is locked by another user * <br> 4 OFF = locking is turned off for this bclass * <br> 5 unknown object type */ public int lockType(Object y, Sdata sd) { return memStore.system().lockType( y,sd ); } /** * Used to restore the referenced objects in collections or references. * @param x * @param sd * @return the given object */ public Object getRefObjects(Object x, Sdata sd) { if(x == null) return null; Field[] f = x.getClass().getFields(); if (x.getClass().getName().endsWith(".Finder")) { fetch((Finder) x, sd); } else { for (int i = 0; i < f.length; i++) { try { String name = f[i].getName(); if (f[i].getType().getName().endsWith(".Vector") && (!name.startsWith("reference"))) { //System.out.println(name); String type = invoke(x, typeName(name)); Vector r = (Vector) x.getClass().getField(refName(name)).get(x); if (r.size() > 0) { Vector v = new Vector(); for (int j = 0; j < r.size(); j++) { Object a = r.elementAt(j); if (a.getClass().getName().endsWith("Long")) { Object d = retrieve(sd, type, ((Long) a).longValue(),true); if (d != null) { v.add(d); } else { r.removeElementAt(j); } } } x.getClass().getField(name).set(x, v); } } else if (f[i].getType().getName().endsWith(".Object") && (!name.startsWith("reference"))) { //System.out.println(name); String type = invoke(x, typeName(name)); Object a = x.getClass().getField(refName(name)).get(x); if (a != null) { Object d = retrieve(sd, type, ((Long) a).longValue(), true); if (d != null) { x.getClass().getField(name).set(x, d); } else { x.getClass().getField(refName(name)).set(x, null); } } } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } } return x; } private String invoke(Object x, String sn) { String doit = ""; try { doit = (String) x.getClass().getMethod(sn, null).invoke(x, null); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } return doit; } String typeName(String name) { return "type" + name.substring(0, 1).toUpperCase() + name.substring(1); } String refName(String name) { return "reference" + name.substring(0, 1).toUpperCase() + name.substring(1); } }