view src/main/java/org/mpi/openmind/repository/services/AbstractPersistenceService.java @ 80:4c9ceb28cfd0

fix some NPEs with refreshRelations
author Robert Casties <casties@mpiwg-berlin.mpg.de>
date Fri, 16 Jun 2017 15:41:39 +0200
parents e0be7c0030f5
children 4845dff46ad9
line wrap: on
line source

package org.mpi.openmind.repository.services;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.mpi.openmind.configuration.ConfigurationService;
import org.mpi.openmind.repository.bo.Attribute;
import org.mpi.openmind.repository.bo.Entity;
import org.mpi.openmind.repository.bo.Node;
import org.mpi.openmind.repository.bo.Relation;
import org.mpi.openmind.repository.bo.View;
import org.mpi.openmind.repository.bo.utils.Sequence;
import org.mpi.openmind.repository.utils.HibernateUtil;
import org.mpi.openmind.repository.utils.OwnValueGenerator;

/**
 * 
 * @author jurzua
 */
public abstract class AbstractPersistenceService {

    private ConfigurationService configurationService;

	private OwnValueGenerator ownValueGenerator;

	private final static String NODE_SEQUENCE = "nodeSequence";

	private static Logger logger = Logger.getLogger(AbstractPersistenceService.class);
	
    public static final String TRANSACTION_LOGGER = "openmind.transactionlog";

    private static Logger txLog = Logger.getLogger(TRANSACTION_LOGGER);

	private boolean importMode = false;

	public AbstractPersistenceService() {
	}

	public String generateOwnValue(Entity entity) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		String ownValue = null;

		try {
			session.getTransaction().begin();
			ownValue = this.ownValueGenerator.generateOwnValue(entity, session);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		} finally {
			session.getTransaction().commit();
		}

		return ownValue;
	}

	public int dropAssertions() {
		int row = 0;
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.beginTransaction();
			String sql = "DELETE FROM Node WHERE type = 'ABox'";
			Query query = session.createQuery(sql);
			row = query.executeUpdate();

			logger.info("Drop assertions - rows deleted= " + row);

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
		return row;
	}

	public int dropDefinitions() {
		int row = 0;
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.beginTransaction();
			String sql = "DELETE FROM Node WHERE type = 'TBox'";
			Query query = session.createQuery(sql);
			row = query.executeUpdate();

			logger.info("Drop definitions - rows deleted= " + row);

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
		return row;
	}

	public void saveOrUpdateObject(Object obj) {
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();
			session.saveOrUpdate(obj);
			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	private void saveNode0(Session session, Node node, Sequence idSequence){
		node.autoNormalize();
		node.setSystemStatus(Node.SYS_STATUS_CURRENT_VERSION);
		
		if(node.getModificationTime() == null){
			node.setModificationTime(System.currentTimeMillis());
		}	
		if(node.getVersion() == null){
			node.increaseVersion();
		}
		
		if (node.getId() == null){
			node.setId(idSequence.generateId());
		}	
		
		if (node.getRowId() == null){
		    logger.debug("Save node: "+node.toString());
		    txLog.info("save node: "+node.toEncString());
			session.save(node);
		}else{
            txLog.info("merge node: "+node.toEncString());
			session.merge(node);
		}
			
		logger.info("Saved node\t" + node);
	}

	public void saveNode(Node node) throws Exception {

		logger.info("Saving node\t" + node);

		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();

		Sequence idSequence = this.getIdSequence(session);

		this.saveNode0(session, node, idSequence);
		
		session.save(idSequence);

		session.getTransaction().commit();
		logger.info("Node saved\t" + node);
	}

	public void saveNodeList(List<Node> nodeList) throws Exception{

		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();

		Sequence idSequence = this.getIdSequence(session);
		/*
		long start = System.currentTimeMillis();
		DecimalFormat df = new DecimalFormat("#.##");
		int counter = 0;
		*/
		logger.info("##### Saving Node List: " + nodeList.size() + " #####");

		for (Node node : nodeList) {
			this.saveNode0(session, node, idSequence);
			/*
			double percent = ((double) counter / (double) nodeList.size()) * 100.0;
			long diff = System.currentTimeMillis() - start;
			double min = (double) diff / (double) (60 * 1000);

			if ((percent % 10) < 0.005) {
				logger.debug("\n[" + df.format(percent) + " %] counter: "
						+ counter + " / " + nodeList.size());

				logger.debug("Tempo: " + (double) counter / min);
			}
			counter++;
			*/
		}

		session.save(idSequence);
		session.getTransaction().commit();
	}

	/**
	 * This method delete the nodes and its history.
	 * 
	 * @param nodeList
	 */
	public void removeNode(Node node) {
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			this.removeNodesById(node.getId(), session);

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
	}

	/**
	 * This method delete the nodes and its history.
	 * 
	 * @param nodeList
	 */
	public void removeNodeList(List<Node> nodeList) {
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			logger.debug("##### Deleting Node List: " + nodeList.size()
					+ " #####");

			for (Node node : nodeList) {
				this.removeNodesById(node.getId(), session);
			}

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
	}

	/**
	 * Save every part of the entity but not generate new versions nor ownValue
	 * 
	 * @param nodeList
	 */
	public void saveEntityListAsNode(List<Entity> entList) {
		int entitiesSize = 0;
		int nodeSize = 0;
		long start = System.currentTimeMillis();
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			Sequence idSequence = this.getIdSequence(session);

			DecimalFormat df = new DecimalFormat("#.##");
			int counter = 0;

			List<Node> nodeList = generateNodeList(entList);
			logger.debug("##### Saving Node List #####");
			logger.debug("Entities: " + entList.size() + " #####");
			logger.debug("Nodes: " + nodeList.size() + " #####");

			entitiesSize = entList.size();
			nodeSize = nodeList.size();

			for (Node node : nodeList) {

				node.autoNormalize();
				
				if (node.getId() == null)
					node.setId(idSequence.generateId());
                if (node.getRowId() == null) {
                    logger.debug("Save node from EntityListAsNode: "+node);
                    txLog.info("save node: "+node.toEncString());
                    session.save(node);
                } else {
                    txLog.info("merge node: "+node.toEncString());
                    session.merge(node);

                }

				double percent = ((double) counter / (double) nodeList.size()) * 100.0;
				long diff = System.currentTimeMillis() - start;
				double min = (double) diff / (double) (60 * 1000);

				if ((percent % 10) < 0.005) {
					logger.debug("\n[" + df.format(percent) + " %] counter: "
							+ counter + " / " + nodeList.size());

					logger.debug("Tempo: " + (double) counter / min);
				}
				counter++;
			}

			session.save(idSequence);
			session.getTransaction().commit();

			StringBuilder sb = new StringBuilder();
			sb.append("\n\t#### saveEntityListAsNode ####\n");
			sb.append("\tentitiesSize=\t" + entitiesSize + "\n");
			sb.append("\tnodeSize=\t" + nodeSize + "\n");
			sb.append("\ttime[ms]=\t" + (System.currentTimeMillis() - start)
					+ "\n");
			logger.info(sb.toString());

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			e.printStackTrace();
		}
	}

	private List<Node> generateNodeList(List<Entity> list) {
		List<Node> list0 = new ArrayList<Node>();
		for (Entity ent : list) {
			list0.add(ent);
			for (Attribute att : ent.getAttributes()) {
				list0.add(att);
			}
			for (Relation rel : ent.getSourceRelations()) {
				list0.add(rel);
			}
			for (Relation rel : ent.getTargetRelations()) {
				list0.add(rel);
			}
		}
		return list0;
	}

	/**
	 * Saves all given entities without attributes and relations without creating new versions.
	 * 
	 * @param nodeList
	 */
    public void saveEntityListAsNodeWithoutContent(List<Entity> nodeList) throws Exception {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.getTransaction().begin();
            Sequence idSequence = this.getIdSequence(session);
            
            logger.debug("START saving Node list of size " + nodeList.size());

            for (Entity node : nodeList) {
                node.autoNormalize();
                if (node.getId() == null) {
                    node.setId(idSequence.generateId());
                }
                if (node.getRowId() == null) {
                    // node is new
                    logger.debug("Saving node from EntityListAsNodeWithoutContent: " + node);
                    txLog.info("save node: " + node.toEncString());
                    session.save(node);
                } else {
                    txLog.info("merge node: " + node.toEncString());
                    session.merge(node);
                }
            }
            // update sequence
            session.save(idSequence);
            
            logger.debug("END saving Node list.");
            
        } catch (Exception e) {
            logger.error(e);
        } finally {
            session.getTransaction().commit();
        }
	}

	public void deleteEntityList(List<Entity> entities) {
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			for (Entity ent : entities) {
				this.removePersistenceEntity(ent, session);
			}

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
	}

	public void saveEntityList(List<Entity> entities) throws Exception {		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();

		for (Entity entity : entities) {
			saveEntity0(session, entity);
		}

		session.getTransaction().commit();		
	}
	
	public Map<Long, Long> saveEntityListAsNew(List<Entity> entities,
			Map<Long, Long> idMap) throws Exception {

		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		Sequence idSequence = this.getIdSequence(session);

		for (Entity entity : entities) {

			Long oldId = entity.getId();
			entity.resetId();
			entity.resetRowId();
			this.saveEntity0(session, entity);
			idMap.put(oldId, entity.getId());
		}

		session.save(idSequence);
		session.getTransaction().commit();
		return idMap;
	}

	/**
	 * <p>
	 * This method deletes all entities by type (TBox/ABox), it means the method
	 * deletes either all concepts or all assertions.
	 * </p>
	 * <p>
	 * The history of every deleted entity will be removed too.
	 * </p>
	 * 
	 * @param type
	 *            Node.TYPE_TBOX or Node.TYPE_ABOX
	 */
	@Deprecated
	public void deleteEntities(Long id, String type, Boolean deleteHistory) {
		if (!(Node.TYPE_ABOX.equals(type) || Node.TYPE_TBOX.equals(type))) {
			throw new IllegalArgumentException(
					"The parameter 'type' should be either: " + Node.TYPE_ABOX
							+ " or " + Node.TYPE_TBOX + ", but was: " + type);
		}

		List<Entity> entList = this.getEntities(id,
				Node.SYS_STATUS_CURRENT_VERSION, type, null);

		// loading previous versions
		List<Entity> historyEntList = new ArrayList<Entity>();
		if (deleteHistory) {
			for (Entity ent : entList) {
				historyEntList.addAll(this.getEntities(ent.getId(),
						Node.SYS_STATUS_PREVIOUS_VERSION, type, null));
			}
		}

		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			for (Entity ent : entList) {
				this.removePersistenceEntity(ent, session);
			}
			if (deleteHistory) {
				for (Entity ent : historyEntList) {
					this.removePersistenceEntity(ent, session);
				}
			}

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
	}

	/**
	 * This deleting is made using JDBC and not hibernate. The history is too
	 * removed by this method. TODO test what could happen with the hibernate
	 * cache
	 * 
	 * @param ent
	 * @param session
	 */
	private void removePersistenceEntity(Entity ent, Session session) {
		for (Attribute att : ent.getAttributes()) {
			// session.delete(att);
			removeNodesById(att.getId(), session);
			for (View view : att.getViews()) {
				// session.delete(view);
				removeNodesById(view.getId(), session);
			}
		}
		for (Relation rel : ent.getSourceRelations()) {
			// session.delete(rel);
			removeNodesById(rel.getId(), session);
			for (View view : rel.getViews()) {
				// session.delete(view);
				removeNodesById(view.getId(), session);
			}
		}
		for (Relation rel : ent.getTargetRelations()) {
			// session.delete(rel);
			removeNodesById(rel.getId(), session);
			for (View view : rel.getViews()) {
				// session.delete(view);
				removeNodesById(view.getId(), session);
			}
		}
		for (View view : ent.getViews()) {
			// session.delete(view);
			removeNodesById(view.getId(), session);
		}
		// session.delete(ent);
		removeNodesById(ent.getId(), session);
	}

	private int removeNodesById(Long id, Session session) {
		String sql = "DELETE FROM Node WHERE id = :id";
		Query query = session.createQuery(sql);
		query.setLong("id", id);
		return query.executeUpdate();
	}

	/**
	 * <p>
	 * Changes the system status of the entity from CURRENT_VERSION to
	 * PREVIOUS_VERSION.
	 * </p>
	 * 
	 * <p>
	 * It means, the entity will stay in the DB, but the it will not be visible
	 * by the ordinary methods.
	 * </p>
	 * 
	 * @param entity
	 */
    public void removeEntCurrentVersion(Long entId, String type) throws Exception {
        logger.info("Deleting entity [ID=" + entId + ", type=" + type + "]. But keeping history in DB.");
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.getTransaction().begin();

            if (entId != null) {
                /*
                 * this method get the current version. Related to the relation,
                 * the time_modification is not consider, because it it
                 * producing problems.
                 */
                List<Entity> previousEntityList = this.getEntities(session, entId, Node.SYS_STATUS_CURRENT_VERSION,
                        type, null, false);
                if (previousEntityList.size() > 0) {
                    if (previousEntityList.size() > 1) {
                        logger.error("Found more than one current entities!");
                    }
                    Entity previousEntity = previousEntityList.get(0);
                    logger.info("Saving previous entity: " + previousEntity);
                    this.persistEntityAsPrevious(session, previousEntity);
                }
            }
        } catch (Exception e) {
            logger.error(e);
        } finally {
            session.getTransaction().commit();
        }
    }

	/**
	 * Save the entity to the database.
	 * 
	 * Creates a new version of the entity. Runs in a transaction.
	 * 
	 * @param entity
	 * @return
	 */
	public void saveEntity(Entity entity) throws Exception {
	    // start transaction
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		// save entity
		saveEntity0(session, entity);
		// end transaction
		session.getTransaction().commit();
	}

	/**
	 * Save the entity to the database using the given session.
	 * 
	 * Creates a new version and sets the existing entity to PREVIOUS_VERSION.
	 * 
	 * @param session
	 * @param entity
	 * @throws Exception
	 */
	private void saveEntity0(Session session, Entity entity) throws Exception {
		if (entity.getId() != null) {
		    // get the still current entity(s)
			List<Entity> previousEntityList = this.getEntities(session, entity.getId(), Node.SYS_STATUS_CURRENT_VERSION, entity.getType(), null, false);
			if (previousEntityList.size() > 0) {
				if (previousEntityList.size() > 1) {
					logger.error("Found more than one current entities!");
				}
				// set the first current entity as previous 
				Entity previousEntity = previousEntityList.get(0);
				// compare old and new entity
				if (! previousEntity.equalsStructure(entity)) {
				    logger.warn("Entity to save has different structure! old="+previousEntity+" new="+entity);
				}
				logger.info("Saving previous entity: " + previousEntity);
				this.persistEntityAsPrevious(session, previousEntity);
			}
		}
		this.saveCurrentEntity(session, entity, null);
	}

	/**
	 * Save the entity as (new) current version using the given session.
	 * 
	 * Sets system_status to CURRENT_VERSION and updates row_id, version, modification_time,
	 * etc.
	 * 
	 * @param session
	 * @param entity
	 * @param idSequence
	 * @throws Exception
	 */
	private void saveCurrentEntity(Session session, Entity entity, Sequence idSequence) throws Exception {
		Long time = System.currentTimeMillis();
		refreshEntityRelations(session, entity);
		entity.setSystemStatus(Node.SYS_STATUS_CURRENT_VERSION);
		entity.resetRowId();
		entity.increaseVersion();
		entity.setObjectClass(entity.getObjectClass());
		entity.setModificationTime(time);
		entity.setType(entity.getType());
		entity.setUser(entity.getUser());
		entity.autoNormalize();
		// generating of id, connecting rels, atts and views to the entity
		this.prepareEntity(session, entity, idSequence);
		this.persistEntity(session, entity);
	}
	
	/**
	 * Updates the endpoints of the relations of this entity.
	 * 
	 * This class must be called, 
	 * because sometimes the current entity is related to other entities that 
	 * have been changed in parallel to the edition of this entity.
	 * For this reason, some relations of the current entity can have old information of the related entities (like the modification time).
	 * This method updates the relations of the current entities getting the actual information of the related entities directly from the DB.
	 * 
	 * @author jurzua 
	 * 
	 * @param session
	 * @param entity
	 * @throws Exception
	 */
	private void refreshEntityRelations(Session session, Entity entity) throws Exception {
		for(Relation rel : entity.getSourceRelations()){
			refreshRelationTarget(session, rel);
		}
		
		for(Relation rel : entity.getTargetRelations()){
			refreshRelationSource(session, rel);
		}
	}
	
	/**
	 * Update the target of the relation.
	 * 
     * @author jurzua 
     * 
	 * @param session
	 * @param rel
	 * @throws Exception
	 */
	private void refreshRelationTarget(Session session, Relation rel) throws Exception {
		if(rel.getTargetId() == null){
			throw new Exception("Refreshing entity " + rel.getSourceId() + ", the system found a relation with empty target.");
		}
		StringBuilder sb = new StringBuilder("refreshTarget of " + rel.toString() + " to "+rel.printTarget());
		List<Entity> entityList = this.getEntities(session, rel.getTargetId(), Node.SYS_STATUS_CURRENT_VERSION, rel.getType(), null, false);
		if(entityList.isEmpty()){
			throw new Exception("Refreshing entity " + rel.getSourceId() + ", the system found a relation without target. " + rel.toString());
		}
		Entity target = entityList.get(0);
		long targetModifOld = rel.getTargetModif();
		rel.setTarget(target);
		sb.append(" new "+rel.printTarget());
		// the refresh is logged only if we detect a difference between the relation and the target entity.
		if(targetModifOld != rel.getTargetModif()){
			logger.warn(sb.toString());
		}
	}
	
	/**
	 * Update the source of the relation.
	 * 
     * @author jurzua 
     * 
	 * @param session
	 * @param rel
	 * @throws Exception
	 */
	private void refreshRelationSource(Session session, Relation rel) throws Exception {
		if(rel.getSourceId() ==  null){
			throw new Exception("Refreshing entity " + rel.getTargetId() + ", the system found a relation with emtpy source.");
		}
		StringBuilder sb = new StringBuilder("refreshSource of " + rel.toString() + " to "+rel.printSource());
		List<Entity> entityList = this.getEntities(session, rel.getSourceId(), Node.SYS_STATUS_CURRENT_VERSION, rel.getType(), null, false);
		if(entityList.isEmpty()){
			throw new Exception("Refreshing entity " + rel.getTargetId() + ", the system found a relation without source. " + rel.toString());
		}
		Entity source = entityList.get(0);
		long sourceModifOld = rel.getSourceModif();
		rel.setSource(source);
		sb.append(" new "+rel.printSource());
		// the refresh is logged only if we detect a difference between the relation and the source entity.
		if(sourceModifOld != rel.getSourceModif()){
			logger.warn(sb.toString());
		}
	}

	/**
	 * Update the entity to prepare it for persistence using the session.
	 * 
	 * If the ID is null new IDs will be assigned for the entity and its 
	 * attributes and relations.
	 * The modification time is propagated from the entity to its
	 * attributes and relations.
	 * Own-values are normalized.
	 * 
	 * @param session
	 * @param entity
	 * @return
	 */
	private Entity prepareEntity(Session session, Entity entity, Sequence idSequence) {

	    /*
	     * update id
	     */
		if (entity.getId() == null) {
			if (idSequence == null)
				entity.setId(this.generateId(session));
			else
				entity.setId(idSequence.generateId());
		}

		/* 
		 * update attributes
		 */
		for (Attribute att : entity.getAttributes()) {
			if (att.getId() == null) {
				if (idSequence == null)
					att.setId(this.generateId(session));
				else
					att.setId(idSequence.generateId());
			}
			att.setSourceId(entity.getId());
			att.setSourceModif(entity.getModificationTime());
			att.setSourceObjectClass(entity.getObjectClass());
			att.autoNormalize();
		}

		/*
		 * update source relations
		 */
		for (Relation rel : entity.getSourceRelations()) {
			if (rel.getId() == null) {
				if (idSequence == null)
					rel.setId(this.generateId(session));
				else
					rel.setId(idSequence.generateId());
			}
			rel.setSourceId(entity.getId());
			rel.setSourceModif(entity.getModificationTime());
			rel.setSourceObjectClass(entity.getObjectClass());
			// TODO: update relation target too?
			rel.autoNormalize(); // TODO: normalize relation?
			if(StringUtils.equals(entity.getType(), Node.TYPE_ABOX)) {
				rel.setObjectClass(rel.getOwnValue());				
			} else if(StringUtils.equals(entity.getType(), Node.TYPE_TBOX)) {
				rel.setObjectClass(Node.TYPE_TBOX);
			}
			
			/*
			 * update attributes for relations
			 */
			for (Attribute att : rel.getAttributes()) {
				if (att.getId() == null) {
					if (idSequence == null)
						att.setId(this.generateId(session));
					else
						att.setId(idSequence.generateId());
				}
				att.setSourceId(rel.getId());
				att.setSourceModif(rel.getModificationTime());
				att.setSourceObjectClass(rel.getOwnValue());
				att.autoNormalize();
			}
		}

		/*
		 * update target relations
		 */
		for (Relation rel : entity.getTargetRelations()) {
			if (rel.getId() == null) {
				if (idSequence == null)
					rel.setId(this.generateId(session));
				else
					rel.setId(idSequence.generateId());
			}
			rel.setTargetId(entity.getId());
			rel.setTargetModif(entity.getModificationTime());
			rel.setTargetObjectClass(entity.getObjectClass());
			// TODO: update relation source too?
			rel.autoNormalize(); // TODO: normalize?
			if(StringUtils.equals(entity.getType(), Node.TYPE_ABOX)){
				rel.setObjectClass(rel.getOwnValue());				
			}else if(StringUtils.equals(entity.getType(), Node.TYPE_TBOX)){
				rel.setObjectClass(Node.TYPE_TBOX);
			}
			/*
			 * update relation attributes
			 */
			for (Attribute att : rel.getAttributes()) {
				if (att.getId() == null) {
					if (idSequence == null)
						att.setId(this.generateId(session));
					else
						att.setId(idSequence.generateId());
				}
				att.setSourceId(rel.getId());
				att.setSourceModif(rel.getModificationTime());
				att.setSourceObjectClass(rel.getOwnValue());
				att.autoNormalize();
			}
		}
		
		/*
		 * update views(?)
		 */
		for (View view : entity.getViews()) {
			if (view.getId() == null) {
				if (idSequence == null)
					view.setId(this.generateId(session));
				else
					view.setId(idSequence.generateId());
			}
			view.setSourceId(entity.getId());
			view.setSourceModif(entity.getModificationTime());
			view.setSourceObjectClass(entity.getObjectClass());
			view.autoNormalize();
		}
		
		return entity;
	}

	/**
	 * Set an entities' system state to PREVIOUS_VERSION and persist it.
	 * 
	 * Also persists the entities' attributes and relations.
	 * 
	 * @param session
	 * @param entity
	 */
	private void persistEntityAsPrevious(Session session, Entity entity) {
		entity.setSystemStatus(Node.SYS_STATUS_PREVIOUS_VERSION);
        txLog.debug("* START save previous entity...");
        txLog.info("save previous entity: "+entity.toEncString());
		session.save(entity);
		for (Attribute attribute : entity.getAttributes()) {
            txLog.info("save previous entity attribute: "+attribute.toEncString());
			session.save(attribute);
		}
		for (Relation rel : entity.getSourceRelations()) {
	        txLog.info("save previous source relation: "+rel.toEncString());
			session.save(rel);
			for (Attribute att : rel.getAttributes()) {
                txLog.info("save previous source relation attribute: "+att.toEncString());
				session.save(att);
			}
		}
		for (Relation rel : entity.getTargetRelations()) {
            txLog.info("save previous target relation: "+rel.toEncString());
			session.save(rel);
            for (Attribute att : rel.getAttributes()) {
                txLog.info("save previous target relation attribute: "+att.toEncString());
                session.save(att);
            }
		}
		for (View view : entity.getViews()) {
			session.save(view);
		}
        txLog.debug("* END ...save previous entity");
	}

	/**
	 * Persist a (current) entity and its attributes and relations using the session.
	 * 
	 * @param session
	 * @param entity
	 * @throws Exception
	 */
	private void persistEntity(Session session, Entity entity) throws Exception {
		txLog.info("* START save entity...");
        txLog.info("save entity: "+entity.toEncString());
		session.save(entity);
		for (Attribute attribute : entity.getAttributes()) {
		    txLog.info("save entity attribute: "+attribute.toEncString());
			session.save(attribute);
		}
		for (Relation rel : entity.getSourceRelations()) {
			rel.setSource(entity);
			if (rel.getSourceId() == null || rel.getTargetId() == null) {
				throw new IllegalStateException(
						"Either the sourceId or the targetId was not initialized to the source relation: "
								+ rel.getOwnValue());
			}
	        txLog.info("save source relation: "+rel.toEncString());
			session.save(rel);
			for (Attribute att : rel.getAttributes()) {
	            txLog.info("save source relation attribute: "+att.toEncString());
				session.save(att);
			}
		}
		for (Relation rel : entity.getTargetRelations()) {
			rel.setTarget(entity);
			if (rel.getSourceId() == null || rel.getTargetId() == null) {
				throw new IllegalStateException(
						"Either the sourceId or the targetId was not initialized to the target relation: "
								+ rel.getOwnValue());
			}
            txLog.info("save target relation: "+rel.toEncString());
			session.save(rel);
            for (Attribute att : rel.getAttributes()) {
                txLog.info("save target relation attribute: "+att.toEncString());
                session.save(att);
            }
		}

		// Call of ownValue Generator.
		if (!isImportMode()) {
			String ownValue = this.getOwnValueGenerator().generateOwnValue(entity, session);
			if (StringUtils.isNotEmpty(ownValue)) {
				entity.setOwnValue(ownValue);
				entity.autoNormalize();
				txLog.info("save entity (new ov): "+entity.toEncString());
				session.save(entity);
			}
		}
        txLog.debug("* ...END save entity");
	}

	public OwnValueGenerator getOwnValueGenerator() {
		return ownValueGenerator;
	}

	public void setOwnValueGenerator(OwnValueGenerator ownValueGenerator) {
		this.ownValueGenerator = ownValueGenerator;
	}

	/**
	 * Returns entities with their content from the database using the session.
	 * 
	 * If a parameter is null then the condition is omitted from the query
	 * returning all entities matching the remaining conditions.
	 * 
	 * @param session
	 * @param id
	 * @param systemStatus
	 * @param type
	 * @param ownValue
	 * @param considerTimeModif
	 * @return
	 */
	private List<Entity> getEntities(Session session, Long id,
			String systemStatus, String type, String ownValue, boolean considerTimeModif) {

        if (!(systemStatus.equals(Node.SYS_STATUS_PREVIOUS_VERSION)
                || systemStatus.equals(Node.SYS_STATUS_CURRENT_VERSION))) {
            throw new IllegalArgumentException("Invalid input systemStatus: " + systemStatus);
        }

		if (StringUtils.isNotEmpty(type)
				&& !(type.equals(Node.TYPE_ABOX) || type.equals(Node.TYPE_TBOX))) {
			throw new IllegalArgumentException("Invalid input type: " + type);
		}

		List<Entity> entities;

		String hqlEntities = "from Entity where systemStatus = :systemStatus";

		if (StringUtils.isNotEmpty(type)) {
			hqlEntities += " AND type = :type";
		}

		if (id != null) {
			hqlEntities += " AND id = :id";
		}

		if (StringUtils.isNotEmpty(ownValue)) {
			hqlEntities += " AND ownValue = :ownValue";
		}

		Query queryEntities = session.createQuery(hqlEntities);
		queryEntities.setString("systemStatus", systemStatus);

		if (StringUtils.isNotEmpty(type)) {
			queryEntities.setString("type", type);
		}

		if (StringUtils.isNotEmpty(ownValue)) {
			queryEntities.setString("ownValue", ownValue);
		}

		if (id != null) {
			queryEntities.setLong("id", id);
		}
		entities = queryEntities.list();

		for (Entity entity : entities) {
			entity.setLightweight(true);
			entity = this.getEntityContent(session, entity, considerTimeModif);
		}

		return entities;
	}

	/**
	 * Returns entities with their content from the database.
	 * 
     * If a parameter is null then the condition is omitted from the query
     * returning all entities matching the remaining conditions.
     * 
	 * @param id
	 * @param systemStatus
	 * @param type
	 * @param ownValue
	 * @return
	 */
	public List<Entity> getEntities(Long id, String systemStatus, String type, String ownValue) {
		// logger.debug("GET ENTITIES Entities [id=" + id + ", type=" + type + ", ownValue=" + ownValue + "]");

		if (!(systemStatus.equals(Node.SYS_STATUS_PREVIOUS_VERSION) || systemStatus
				.equals(Node.SYS_STATUS_CURRENT_VERSION))) {
			throw new IllegalArgumentException("Invalid input systemStatus: "
					+ systemStatus);
		}

		if (StringUtils.isNotEmpty(type)
				&& !(type.equals(Node.TYPE_ABOX) || type.equals(Node.TYPE_TBOX))) {
			throw new IllegalArgumentException("Invalid input type: " + type);
		}

		List<Entity> entities = null;
		Session session = null;
		try {
			//long start = System.currentTimeMillis();
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			session.getTransaction().begin();

			entities = this.getEntities(session, id, systemStatus, type, ownValue, true);

			/* long dif = System.currentTimeMillis() - start;
			String s = "Found=\n";
			for (Entity e : entities) {
				s += e.toString() + "\n";
			}
			s += "time used= " + dif + "[ms]\n\n";
			logger.debug(s); */

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		} finally {
			session.getTransaction().commit();
		}
		return entities;
	}

	private String whereUpdate(String where) {
		if (StringUtils.isEmpty(where))
			where = " where ";
		else
			where += " AND ";
		return where;
	}

	/**
	 * Returns a list of Nodes.
     *
     * If a parameter is null then the condition is omitted from the query
     * returning all entities matching the remaining conditions.
	 * 
	 * @param session
	 * @param id
	 * @param systemStatus
	 * @param sourceId
	 * @param srcModif
	 * @param targetId
	 * @param tarModif
	 * @return
	 */
	public List<Node> getNodes(Session session, Long id, String systemStatus,
			Long sourceId, Long srcModif, Long targetId, Long tarModif) {
		List<Node> nodes = null;

		/*
		 * create HQL query string
		 */
		String from = "from Node ";
		String where = "";

		if (id != null) {
			where = this.whereUpdate(where);
			where += " id = :id ";
		}

		if (StringUtils.isNotEmpty(systemStatus)) {
			where = this.whereUpdate(where);
			where += " systemStatus = :systemStatus ";
		}
		
		if (sourceId != null) {
			where = this.whereUpdate(where);
			where += " sourceId = :sourceId ";
		}
		
		if (srcModif != null) {
			where = this.whereUpdate(where);
			where += " sourceModif = :sourceModif ";
		}

		if (targetId != null) {
			where = this.whereUpdate(where);
			where += " targetId = :targetId ";
		}
		
		if (tarModif != null) {
			where = this.whereUpdate(where);
			where += " targetModif = :targetModif ";
		}

		String hql = from + where;
		// create query object
		Query query = session.createQuery(hql);

		/*
		 * add query parameters
		 */
		if (id != null)
			query.setLong("id", id);
		
		if (StringUtils.isNotEmpty(systemStatus))
			query.setString("systemStatus", systemStatus);

		if (sourceId != null)
			query.setLong("sourceId", sourceId);
		
		if (srcModif != null)
			query.setLong("sourceModif", srcModif);

		if (targetId != null)
			query.setLong("targetId", targetId);
		
		if (tarModif != null)
			query.setLong("targetModif", tarModif);

		/*
		 *  run the query
		 */
		nodes = query.list();

		return nodes;
	}

	/**
	 * Populate a lightweight entity with attributes and relations.
	 *  
	 * @param session
	 * @param entity
	 * @param considerTimeModif
	 * @return
	 */
	private Entity getEntityContent(Session session, Entity entity, boolean considerTimeModif) {
		if (entity != null && entity.isLightweight()) {
			entity.setLightweight(false);
			entity.setAttributes(new ArrayList<Attribute>());
			entity.setSourceRelations(new ArrayList<Relation>());
			entity.setTargetRelations(new ArrayList<Relation>());

            /*
             * Danger: getNodes finds all attributes in the db and tries to attach them to 
             * this entity if id=null!
             */
            if (entity.getId() == null) {
                logger.error("Entity with id=null! Abort loading attributes.");
                return entity;
            }
			
			/*
			 * get all nodes with source_id = entity.id
			 * i.e. Attributes and SourceRelations.
			 */
			List<Node> nodes = null; 					
			if (considerTimeModif) {
				nodes = this.getNodes(session, null,
						entity.getSystemStatus(), entity.getId(),
						entity.getModificationTime(), null, null);
			} else {
				nodes = this.getNodes(session, null,
						entity.getSystemStatus(), entity.getId(),
						null, null, null);
			}
					
			/*
			 * add Attributes and SourceRelations
			 */
			for (Node node : nodes) {
				if (node instanceof Attribute) {
					entity.addAttribute((Attribute) node);
					
				} else if (node instanceof Relation) {
					Relation rel = (Relation) node;
		            /*
		             * Danger: getNodes finds all attributes in the db and tries to attach them to 
		             * this relation if id=null!
		             */
		            if (rel.getId() == null) {
		                logger.error("Relation with id=null! Abort loading attributes.");
		                continue;
		            }
		            /*
		             * get all nodes with source_id = rel.id
		             * i.e. relation Attributes
		             */
					List<Node> attrs = this.getNodes(session, null,
							rel.getSystemStatus(), rel.getId(),
							rel.getModificationTime(), null, null);
					for (Node attNode : attrs) {
						if (attNode instanceof Attribute) {
							rel.addAttribute((Attribute) attNode);
						}
					}
					// TODO: ???
					if (considerTimeModif) {
						entity.addSourceRelation(rel);	
					} else {
						entity.getSourceRelations().add(rel);
					}
					
				} else if (node instanceof View) {
					entity.getViews().add((View) node);
					
				} else {
					throw new IllegalArgumentException("Invalid node found: " + node);
				}
			}

			/*
			 * get all nodes with target_id = entity.id
			 * i.e. TargetRelations
			 */
			List<Node> tarRels = null;
			
			if (considerTimeModif) {
				tarRels = this.getNodes(session, null,
						entity.getSystemStatus(), null, null, entity.getId(),
						entity.getModificationTime());
			} else {
				tarRels = this.getNodes(session, null,
						entity.getSystemStatus(), null, null, entity.getId(),
						null);
			}
			
			/*
			 * add TargetRelations
			 */
			for (Node node : tarRels) {
				if (node instanceof Relation) {
					Relation rel = (Relation) node;
		            /*
		             * Danger: getNodes finds all attributes in the db and tries to attach them to 
		             * this relation if id=null!
		             */
		            if (rel.getId() == null) {
		                logger.error("Relation with id=null! Abort loading attributes.");
		                continue;
		            }
                    /*
                     * get all nodes with source_id = rel.id
                     * i.e. relation Attributes
                     */
					List<Node> attrs = this.getNodes(session, null,
							rel.getSystemStatus(), rel.getId(),
							rel.getModificationTime(), null, null);
					for (Node attNode : attrs) {
						if (attNode instanceof Attribute) {
							rel.addAttribute((Attribute) attNode);
						}
					}
					// TODO: ???
					if (considerTimeModif) {
						entity.addTargetRelation(rel);
					} else {
						entity.getTargetRelations().add(rel);
					}
					
				} else {
					throw new IllegalArgumentException("Invalid node found: " + node);
				}
			}
		}
		return entity;
	}

    /**
     * Populate a lightweight entity with attributes and relations.
     *  
     * @param entity
     * @return
     */
    public Entity getEntityContent(Entity entity) {
        if (entity != null && entity.isLightweight()) {
            Session session = null;
            try {
                /* logger.debug("GET ENTITY CONTENT [objClass=" + entity.getObjectClass() + ", id=" + entity.getId()
                        + ", ownValue=" + entity.getOwnValue() + "]"); */
                //long start = System.currentTimeMillis();
                
                // start transaction
                session = HibernateUtil.getSessionFactory().getCurrentSession();
                session.getTransaction().begin();
                // get entity content
                entity = this.getEntityContent(session, entity, true);
                
                /* long diff = System.currentTimeMillis() - start;
                logger.debug("Time to get content=" + diff + "(s)"); */
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                session.getTransaction().commit();
            }
        }
        return entity;
    }

	public List<String> getObjecClassSuggestion(String objectClass, Class nodeClass, int maxResults) {
		objectClass += "%";
		try {

			List<String> suggestions = new ArrayList<String>();
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();
			String hql = "from ";
			if (nodeClass.equals(Entity.class)) {
				hql += "Entity ";
			}
			if (nodeClass.equals(Relation.class)) {
				hql += "Relation ";
			}
			if (nodeClass.equals(Attribute.class)) {
				hql += "Attribute ";
			}
			if (nodeClass.equals(Node.class)) {
				hql += "Node ";
			}
			if (nodeClass.equals(View.class)) {
				hql += "View ";
			}
			hql += " where objectClass like :objectClass "
					+ "group by objectClass";

			Query query = session.createQuery(hql);
			query.setString("objectClass", objectClass);
			query.setMaxResults(maxResults);
			List<Node> list = query.list();
			for (Node node : list) {
				suggestions.add(node.getObjectClass());
			}
			return suggestions;

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
		return null;
	}

	public List<String> getOwnValueSuggestion(String ownValue, Class nodeClass, int maxResults) {
		ownValue += "%";
		try {

			List<String> suggestions = new ArrayList<String>();
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();
			String hql = "from ";
			if (nodeClass.equals(Entity.class)) {
				hql += "Entity ";
			}
			if (nodeClass.equals(Relation.class)) {
				hql += "Relation ";
			}
			if (nodeClass.equals(Attribute.class)) {
				hql += "Attribute ";
			}
			if (nodeClass.equals(Node.class)) {
				hql += "Node ";
			}
			if (nodeClass.equals(View.class)) {
				hql += "View ";
			}
			hql += " where ownValue like :ownValue " + "group by ownValue";

			Query query = session.createQuery(hql);
			query.setString("ownValue", ownValue);
			query.setMaxResults(maxResults);
			List<Node> list = query.list();
			for (Node node : list) {
				suggestions.add(node.getOwnValue());
			}
			return suggestions;

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
		return null;
	}

	public Entity loadEntitiesForTargetRelation(Entity entity) {
		try {
			// where parent_id = :parent_id AND type = :type
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.getTransaction().begin();

			for (Relation rel : entity.getTargetRelations()) {
				List<Entity> entities = this.getEntities(session,
						rel.getSourceId(), Node.SYS_STATUS_CURRENT_VERSION,
						null, null, true);
				if (entities.size() > 0) {
					Entity source = entities.get(0);
					rel.setSource(source);
				}
			}

			session.getTransaction().commit();
			return entity;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// e.printStackTrace();
		}
		return entity;
	}

	/**
	 * Return all (lightweight) entities matching the query.
     * 
     * Any parameter that is null is omitted as a query condition matching
     * all values in this parameter.
     * 
     * Own value is searched as substring if ownValueSubString=true.
     * 
	 * @param session
	 * @param systemStatus
	 * @param id
	 * @param type
	 * @param objectClass
	 * @param ownValue
	 * @param ownValueSubString
	 * @param maxResult
	 * @return
	 */
    protected List<Entity> getLightweightEntities(Session session, String systemStatus, Long id, String type,
            String objectClass, String ownValue, boolean ownValueSubString, int maxResult) {

        /*
         * build query string
         */
        String hqlEntities = "from Entity where ";
        if (StringUtils.isNotEmpty(ownValue)) {
            if (ownValueSubString)
                hqlEntities += "ownValue like :ownValue AND ";
            else
                hqlEntities += "ownValue = :ownValue AND ";
        }
        if (id != null) {
            hqlEntities += "id = :id AND ";
        }
        if (StringUtils.isNotEmpty(objectClass)) {
            hqlEntities += "objectClass = :objectClass AND ";
        }
        if (StringUtils.isNotEmpty(type)) {
            hqlEntities += "type = :type AND ";
        }

        hqlEntities += "systemStatus = :systemStatus ";

        /* 
         * create query object
         */
        Query queryEntities = session.createQuery(hqlEntities);
        
        /*
         * add query parameters
         */
        queryEntities.setString("systemStatus", systemStatus);
        if (StringUtils.isNotEmpty(ownValue)) {
            if (ownValueSubString) {
                // substring search
                queryEntities.setString("ownValue", "%" + ownValue + "%");
                //logger.debug("ownValue=%" + ownValue + "%");
            } else {
                queryEntities.setString("ownValue", ownValue);
                //logger.debug("ownValue=" + ownValue);
            }
        }
        if (maxResult > 0) {
            queryEntities.setMaxResults(maxResult);
        }

        if (StringUtils.isNotEmpty(type)) {
            queryEntities.setString("type", type);
        }
        if (id != null) {
            queryEntities.setLong("id", id);
        }
        if (StringUtils.isNotEmpty(objectClass)) {
            queryEntities.setString("objectClass", objectClass);
        }
        
        /*
         * run query and return results
         */
        List<Entity> entities = queryEntities.list();

        for (Entity ent : entities) {
            ent.setLightweight(true);
        }

        return entities;
    }

	/**
	 * Return all (lightweight) entities matching the query.
	 * 
     * Any parameter that is null is omitted as a query condition matching
     * all values in this parameter.
     * 
	 * Own value is searched as substring if ownValueSubString=true.
	 * 
     * @param systemStatus
     * @param id
     * @param type
     * @param objectClass
     * @param ownValue
     * @param ownValueSubString
     * @param maxResult
     * @return
     */
    public List<Entity> getLightweightEntities(String systemStatus, Long id, String type, String objectClass,
            String ownValue, boolean ownValueSubString, int maxResult) {
        //logger.debug("GET LW ENTITIES [type=" + type + " id=" + id + ", objectClass=" + objectClass + ", ownValue="
        //        + ownValue + "]");

        List<Entity> entities = new ArrayList<Entity>();
        /*
         * check inputs
         */
        if (!(systemStatus.equals(Node.SYS_STATUS_PREVIOUS_VERSION)
                || systemStatus.equals(Node.SYS_STATUS_CURRENT_VERSION))) {
            throw new IllegalArgumentException("Invalid input systemStatus: " + systemStatus);
        }
        if (StringUtils.isNotEmpty(type) && !(type.equals(Node.TYPE_ABOX) || type.equals(Node.TYPE_TBOX))) {
            throw new IllegalArgumentException("Invalid input type: " + type);
        }

        /*
         * call getLightweightEntities with transaction
         */
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.getTransaction().begin();

            entities = this.getLightweightEntities(session, systemStatus, id, type, objectClass, ownValue,
                    ownValueSubString, maxResult);

        } catch (Exception e) {
            logger.error(e);
        } finally {
            session.getTransaction().commit();
        }
        return entities;
    }

	private Sequence getIdSequence(Session session) {
		Sequence sequence = null;
		String hqlJoin = "from Sequence where name = :name";
		Query query = session.createQuery(hqlJoin);
		query.setString("name", NODE_SEQUENCE);
		List<Sequence> sequences = query.list();
		if (sequences.size() > 0)
			sequence = sequences.get(0);
		if (sequence == null) {
			sequence = new Sequence(NODE_SEQUENCE, new Long(0));
		}
		return sequence;
	}

	protected Long generateId(Session session) {
		Long id = null;
		Sequence sequence = null;
		String hqlJoin = "from Sequence where name = :name";
		Query query = session.createQuery(hqlJoin);
		query.setString("name", NODE_SEQUENCE);
		List<Sequence> sequences = query.list();
		if (sequences.size() > 0) {
			sequence = sequences.get(0);
		} else {
			sequence = new Sequence(NODE_SEQUENCE, new Long(0));
		}
		id = sequence.generateId();
		session.save(sequence);
		return id;
	}

	public ConfigurationService getConfigurationService() {
		return configurationService;
	}

	public void setConfigurationService(
			ConfigurationService configurationService) {
		this.configurationService = configurationService;
	}

	public boolean isImportMode() {
		return importMode;
	}

	public void setImportModus(boolean importModus) {
		this.importMode = importModus;
	}

    /**
     * Returns all definition relations.
     * 
     * @return
     * @throws Exception
     */
	public List<Relation> getDefRelations() {
		List<Relation> list = new ArrayList<Relation>();
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		try {
			session.getTransaction().begin();

			String hql = "from Relation where systemStatus = :systemStatus and type = :type";
			Query query = session.createQuery(hql);

			query.setString("systemStatus", Node.SYS_STATUS_CURRENT_VERSION);
			query.setString("type", Node.TYPE_TBOX);

			list = query.list();
		} catch (Exception e) {
			logger.error(e);
		} finally {
			session.getTransaction().commit();
		}
		return list;
	}

    /**
     * Returns all definition attributes.
     * 
     * @return
     * @throws Exception
     */
	public List<Attribute> getDefAttributes() {
		List<Attribute> list = new ArrayList<Attribute>();
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		try {
			session.getTransaction().begin();

			String hql = "from Attribute where systemStatus = :systemStatus and type = :type";
			Query query = session.createQuery(hql);

			query.setString("systemStatus", Node.SYS_STATUS_CURRENT_VERSION);
			query.setString("type", Node.TYPE_TBOX);

			list = query.list();

		} catch (Exception e) {
			logger.error(e);
		} finally {
			session.getTransaction().commit();
		}
		return list;
	}

	/**
	 * Returns all (lightweight) definition entities.
	 * 
	 * @return
	 * @throws Exception
	 */
    public List<Entity> getLWDefinitions() throws Exception {
        List<Entity> list = new ArrayList<Entity>();
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.getTransaction().begin();

            String hql = "from Entity where systemStatus = :systemStatus and type = :type";
            Query query = session.createQuery(hql);

            query.setString("systemStatus", Node.SYS_STATUS_CURRENT_VERSION);
            query.setString("type", Node.TYPE_TBOX);

            list = query.list();
            for (Entity def : list) {
                def.setLightweight(true);
            }
        } catch (Exception e) {
            logger.error(e);
        } finally {
            session.getTransaction().commit();
        }

        return list;
    }

	// #################################################################
	// #################################################################
	// #################################################################

	/**
	 * Returns the number of Entities of the given objectClass in the database.
	 * 
	 * Returns the number of all Entities if objectClass==null.
	 * 
	 * @param objectClass
	 * @return
	 */
	public Long getEntityCount(String objectClass) {
		Long count = null;
		try {
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();
			session.getTransaction().begin();

			String hql = "select count(*) from Entity where ";

			if (StringUtils.isNotEmpty(objectClass)) {
				hql += "objectClass = :objectClass AND ";
			} else {
				hql += "objectClass != :objectClass AND ";
			}
			hql += "systemStatus = :systemStatus ";

			Query query = session.createQuery(hql);
			query.setString("systemStatus", Node.SYS_STATUS_CURRENT_VERSION);
			if (StringUtils.isNotEmpty(objectClass)) {
				query.setString("objectClass", objectClass);
			} else {
				query.setString("objectClass", Node.TYPE_TBOX);
			}
			count = (Long) query.uniqueResult();

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e);
		}
		return count;
	}

	/**
	 * Returns all Entities of the given objectClass in the database 
	 * between startRecord and endRecord.
	 * 
	 * @param objectClass
	 *            if it is null, all entities are returned (except
	 *            definitions). To get the definitions objectClass should be:
	 *            Node.TYPE_TBOX
	 * @param startRecord
	 * @param endRecord
	 * @return
	 */
	public List<Entity> getEntityPage(String objectClass, final int startRecord, final int endRecord) {

		List<Entity> entities = new ArrayList<Entity>();
		try {
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();
			session.getTransaction().begin();

			String hql = "from Entity where ";

			if (StringUtils.isNotEmpty(objectClass)) {
				// real objectClass
				hql += "objectClass = :objectClass AND ";
			} else {
				// objectClass == null -- match object_class != 'TBox'
				hql += "objectClass != :objectClass AND ";
			}

			hql += "systemStatus = :systemStatus order by ownValue";

			Query query = session.createQuery(hql);
			// use Hibernate's result paging
			query.setFirstResult(startRecord);
			query.setMaxResults(endRecord);
			// add query params
			query.setString("systemStatus", Node.SYS_STATUS_CURRENT_VERSION);
			if (StringUtils.isNotEmpty(objectClass)) {
				// real objectClass
				query.setString("objectClass", objectClass);
			} else {
				// objectClass == null -- match object_class != 'TBox'
				query.setString("objectClass", Node.TYPE_TBOX);
			}
			// fetch Entities
			entities = query.list();

			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error(e);
		}
		return entities;
	}

	public static void main(String[] args) {
		/*
		 * ServiceRegistry sr = new ServiceRegistry(); Long count =
		 * sr.getPersistenceService().getEntityCount("CODEX");
		 * logger.info("count codex " + count);
		 * 
		 * List<Entity> list = sr.getPersistenceService().getEntityPage("CODEX",
		 * count.intValue() - 100, count.intValue() - 50); for(Entity e : list){
		 * logger.info(e.toString()); }
		 */
	}

}