view src/main/java/org/mpi/openmind/repository/bo/Entity.java @ 26:5e24413d355b

Fixed bug that deleted all attributes in the system if a relation had id=null :-(
author Robert Casties <casties@mpiwg-berlin.mpg.de>
date Fri, 05 Aug 2016 22:02:18 +0200
parents c23ae718fdd3
children e52f593f9e0d
line wrap: on
line source

package org.mpi.openmind.repository.bo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Transient;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.mpi.openmind.cache.WrapperService;
import org.mpi.openmind.repository.utils.AttributeMap;
import org.mpi.openmind.repository.utils.OMUtils;

import cl.maps.duplex.DuplexKey;

/**
 *
 * @author jurzua
 */
@javax.persistence.Entity
@DiscriminatorValue("ENTITY")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class Entity extends Node implements Serializable, Cloneable, Comparable<Entity> {
	
	private static final long serialVersionUID = 3498561370603862745L;

	private static Logger logger = Logger.getLogger(Entity.class);
	
    public Entity() {
    }

    /**
     * 
     * @param type could be either Node.TYPE_ABOX (for assertions) or Node.TYPE_TBOX (for definitions).
     * @param lightweight
     */
    public Entity(String type, Boolean lightweight) {
    	if(StringUtils.isEmpty(type) || (!Node.TYPE_ABOX.equals(type) && !Node.TYPE_TBOX.equals(type))){
    		try {
				throw new Exception("Creating a Entity. Type=" + type + 
						" is invalid. Type could be either ABOX (for assertions) or TBOX (for definitions). " +
						"See  org.mpi.openmind.repository.bo.Node");
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
    	}
    	this.setLightweight(lightweight);
        this.setType(type);
        
    }
    
    /**
     * 
     * @param type could be either Node.TYPE_ABOX (for assertions) or Node.TYPE_TBOX (for definitions).
     * @param objectClass
     * @param lightweight
     */
    public Entity(String type, String objectClass, Boolean lightweight) {
    	if(StringUtils.isEmpty(type) || (!Node.TYPE_ABOX.equals(type) && !Node.TYPE_TBOX.equals(type))){
    		try {
				throw new Exception("Creating a Entity. Type=" + type + 
						" is invalid. Type could be either ABOX (for assertions) or TBOX (for definitions). " +
						"See  org.mpi.openmind.repository.bo.Node");
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
    	}
    	this.setLightweight(lightweight);
        this.setObjectClass(objectClass);
    	this.setType(type);
    }
    
    @Transient
    private Boolean lightweight;
    @Transient
    private List<Attribute> attributes = new ArrayList<Attribute>();
    @Transient
    private List<Relation> sourceRelations = new ArrayList<Relation>();
    @Transient
    private List<Relation> targetRelations = new ArrayList<Relation>();

    /**
     * <p>This method returns the relations which were loaded from the DB. </p>
     * <p>If the content of this entity was not loaded, it means is lightweight, the output will not be valid</p>
     * @param ownValue
     * @return
     */
    public Relation getSourceRelationByOwnValue(String ownValue){
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Relation relation : this.getSourceRelations()) {
                if (relation.getOwnValue().equals(ownValue)) {
                    return relation;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return null;
    }
    

    public boolean containsSourceRelation(String relationName, Long targetId){
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Relation relation : this.getSourceRelations()) {
                if (relation.getOwnValue().equals(relationName) && 
                		OMUtils.equals(relation.getTargetId(), targetId)) {
                    return true;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return false;
    }
    
    public boolean containsTargetRelation(String relationName, Long sourceId){
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Relation relation : this.getTargetRelations()) {
                if (relation.getOwnValue().equals(relationName) &&
                		OMUtils.equals(relation.getSourceId(), sourceId)) {
                    return true;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return false;
    }
    
	public boolean equals(Long l1, Long l2){
		if(l1 != null && l2 != null){
			return l1.equals(l2);
		}
		return false;
	}
    
    public List<Relation> getSourceRelations(String relationName, String tarObjClass){
    	List<Relation> list = new ArrayList<Relation>();
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Relation relation : this.getSourceRelations()) {
                if (relation.getOwnValue().equals(relationName) && relation.getTargetObjectClass().equals(tarObjClass)) {
                    list.add(relation);
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return list;
    }
    
    public List<Relation> getTargetRelations(String relationName, String srcObjClass){
    	List<Relation> list = new ArrayList<Relation>();
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Relation relation : this.getTargetRelations()) {
                if (relation.getOwnValue().equals(relationName) && relation.getSourceObjectClass().equals(srcObjClass)) {
                    list.add(relation);
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return list;
    }

    public Boolean isConcept() {
        if (this.getType().equals(Node.TYPE_TBOX)) {
            return true;
        }
        return false;
    }

    public Boolean isAssertion() {
        if (this.getType().equals(Node.TYPE_ABOX)) {
            return true;
        }
        return false;
    }

    public void setConcept(Entity concept) throws Exception {
        if (this.getType().equals(Node.TYPE_TBOX)) {
            throw new IllegalStateException("A concept can not belong to a concept");
        }
        Relation toRemove = this.getSourceRelationByOwnValue(WrapperService.IS_TYPE_OF);
        if (toRemove != null) {
            this.getSourceRelations().remove(toRemove);
        }
        Relation isTypeOf = new Relation(this, concept);
        isTypeOf.setOwnValue(WrapperService.IS_TYPE_OF);
        isTypeOf.setType(this.getType());
        this.setObjectClass(concept.getOwnValue());
    }

    public void addAttribute(Attribute att) {
    	this.testLightweightState();
    	if(!lightweight){
    		if(att != null){
        		att.setType(this.getType());
        		att.setSourceId(this.getId());
        		att.setSourceModif(this.getModificationTime());
        		att.setSourceObjectClass(this.getObjectClass());
        		if(Node.TYPE_TBOX.equals(this.getType())){
        			att.setObjectClass(Node.TYPE_TBOX);
                }
                this.attributes.add(att);	
        	}	
    	}
    }
    
    public void replaceTargetRelation(Entity newSrc, String srcObjClass, String relName){
    	this.testLightweightState();
    	if(!lightweight){
    		if(newSrc == null || !newSrc.isValid()){
            	this.removeAllTargetRelations(relName, srcObjClass);
            }else{
            	boolean found = false;
            	
            	for(Relation rel : new ArrayList<Relation>(getTargetRelations(relName, srcObjClass))){
            		if(rel.getSourceId().equals(newSrc.getId())){
            			found = true;
            		}else{
            			this.targetRelations.remove(rel);
            		}
            	}
            	
            	if(!found){
            		this.removeAllTargetRelations(relName, srcObjClass);
            		Relation rel = new Relation(newSrc, this);
    				rel.setOwnValue(relName);
            	}
            }
    	}
    }
    
    /**
     * This methods should be used for relation one-to-many 
     * like witness->is_part_of->codex.
     * 
     * @param newTar
     * @param tarObjClass
     * @param relName
     */
    public void replaceSourceRelation(Entity newNonLwTar, String tarObjClass, String relName){
    	testLightweightState();
    	if(!lightweight){
    		
    		if(newNonLwTar == null || !newNonLwTar.isValid()){
            	this.removeAllSourceRelations(relName, tarObjClass);
            }else{
            	
            	boolean found = false;
            	for(Relation rel : new ArrayList<Relation>(getSourceRelations(relName, tarObjClass))){
            		if(rel.getTargetId().equals(newNonLwTar.getId())){
            			found = true;
            		}else{
            			this.sourceRelations.remove(rel);
            		}
            	}
            	
            	if(!found){
            		this.removeAllSourceRelations(relName, tarObjClass);
            		this.addSourceRelation(relName, newNonLwTar);
            		//Relation rel = new Relation(this, newTar);
    				//rel.setOwnValue(relName);
            	}
            }
    		
    	}
    }

    public void addSourceRelation(String relName, Entity tar){
    	if(!containsSourceRelation(relName, tar.getId()) &&
    			!tar.containsTargetRelation(relName, this.getId())){
    		new Relation(this, tar, relName);
    	}else if(!containsSourceRelation(relName, tar.getId())){
    		Relation rel = tar.getTargetRelation(relName, this.getId());
    		if(rel != null){
    			this.sourceRelations.add(rel);
    		}
    	}else if(!tar.containsTargetRelation(relName, this.getId())){
    		Relation rel = this.getSourceRelation(relName, tar.getId());
    		if(rel != null){
    			tar.getTargetRelations().add(rel);
    		}
    	}
    }
    
    public void addTargetRelation(String relName, Entity src){
    	if(!containsTargetRelation(relName, src.getId()) &&
    			!src.containsSourceRelation(relName, getId())){
    		new Relation(src, this, relName);
    	}else if(!containsTargetRelation(relName, src.getId())){
    		Relation rel = src.getSourceRelation(relName, getId());
    		if(rel != null){
    			this.targetRelations.add(rel);
    		}
    	}else if(!src.containsSourceRelation(relName, getId())){
    		Relation rel = this.getTargetRelation(relName, src.getId());
    		if(rel != null){
    			src.getSourceRelations().add(rel);
    		}
    	}
    }
    
    public Relation getTargetRelation(String relName, Long srcId){
    	for(Relation rel : getTargetRelations()){
    		if(rel.getOwnValue().equals(relName) && rel.getSourceId().equals(srcId)){
    			return rel;
    		}
    	}
    	return null;
    }
    
    public Relation getSourceRelation(String relName, Long tarId){
    	for(Relation rel : getSourceRelations()){
    		if(rel.getOwnValue().equals(relName) && rel.getTargetId().equals(tarId)){
    			return rel;
    		}
    	}
    	return null;
    }
    
    public void addSourceRelation(Relation srcRel) {
    	//@TODO
    	 /*  big problem definition:
    	 * example TEXT is_version_of TEXT
    	 * the relation is_version_of is saved twice in the DB
    	 */
    	Relation oldRel = this.containsSrcRel(srcRel);
    	if(oldRel != null){
    		
    		Exception ex = new Exception(
    				"This entity has already this (source) relation [\n" +
					toString() + "\n" +
					"NewRel=" + srcRel + "\n" +
					"OldRel=" + oldRel + "]");
    		logger.error(ex.getMessage(), ex);
    		//logger.error(ex.getMessage());
    		this.removeSourceRelation(srcRel.getOwnValue(), srcRel.getTargetId());
    	}
    	srcRel.setType(getType());
        this.sourceRelations.add(srcRel);
    }
    
    public void addTargetRelation(Relation tarRel) {
    	Relation oldRel = this.containsTarRel(tarRel);
    	if(oldRel != null){
    		Exception ex = new Exception(
    				"This entity has already this (target) relation [\n" +
					toString() + "\n" +
					"NewRel=" + tarRel + "\n" +
					"OldRel=" + oldRel + "]");
    		logger.error(ex.getMessage(), ex);
    		//logger.error(ex.getMessage());
    		this.removeTargetRelation(tarRel.getOwnValue(), tarRel.getSourceId());
    	}
    	tarRel.setType(this.getType());
        this.targetRelations.add(tarRel);
        
    }
    
    private void testLightweightState(Entity ent){
    	try {
        	if (ent.lightweight) {
        		throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB. " + ent);
	        }
        }catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
    }
    
    private void testLightweightState(){
    	try {
        	if (this.lightweight) {
        		throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB. " + this.toString());
	        }
        }catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
    }

    public List<Relation> getSourceRelations() {
    	this.testLightweightState();
        return sourceRelations;
    }

    public void setSourceRelations(List<Relation> sourceRelations) {
        this.sourceRelations = sourceRelations;
    }

    public List<Relation> getTargetRelations() {
    	testLightweightState();
        return targetRelations;
    }

    public void setTargetRelations(List<Relation> targetRelations) {
        this.targetRelations = targetRelations;
    }

    public List<Attribute> getAttributes() {
    	testLightweightState();
        return attributes;
    }

    public void setAttributes(List<Attribute> attributes) {
        this.attributes = attributes;
    }

    /**
     * <p>This method sets the object class for the current entity and 
     * for the entityObjectClass of its attributes.</p> 
     * <p>The field entityObjectClass is added to the attributes 
     * to be used to performance some specific types of searchs.</p>
     */
    @Override
	public void setObjectClass(String objectClass) {
		super.setObjectClass(objectClass);
		for(Attribute att : this.attributes){
			att.setSourceObjectClass(objectClass);
		}
		for(Relation rel : this.sourceRelations){
			rel.setSourceObjectClass(objectClass);
		}
		for(Relation rel : this.targetRelations){
			rel.setTargetObjectClass(objectClass);
		}
		if(!Node.TYPE_TBOX.equals(objectClass)){
			//OJO
			//this.setType(TYPE_ABOX);
		}
	}
    
    @Override
    public void setUser(String user){
    	super.setUser(user);
    	if(this.lightweight.equals(false)){
        	for(Attribute att : this.getAttributes()){
    			att.setUser(user);
    		}
    		for(Relation rel : this.getSourceRelations()){
    			rel.setUser(user);
    			for(Attribute att : rel.getAttributes()){
    				att.setUser(user);
    			}
    		}
    		for(Relation rel : this.getTargetRelations()){
    			rel.setUser(user);
    			for(Attribute att : rel.getAttributes()){
    				att.setUser(user);
    			}
    		}    		
    	}
    }
    
    /*
     * Methods needing to the integration
     *
     */
    public void removeAllSourceRelationsByName(String name) {
        try {
        	if (this.lightweight) {
        		throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
	        }
        	
	        for (Relation rel : new ArrayList<Relation>(this.getSourceRelations())) {
	            if (rel.getOwnValue() != null && rel.getOwnValue().equals(name)) {
	            	this.getSourceRelations().remove(rel);
	            }
	        }
	        
	        
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
    }
    
    /**
     * <p>Removes transiently all relations from this entity, which conform the given input.</p> 
     * <p>It could be made persistent using ontology service.</p>
     * @param nameRelation
     * @param objClassSource
     * @return
     */
    public void removeAllTargetRelations(String nameRelation, String objClassSource){
    	testLightweightState();
    	if(!lightweight){
    		for(Relation rel : new ArrayList<Relation>(getTargetRelations())){
            	if(rel.getOwnValue().equals(nameRelation) && rel.getSourceObjectClass().equals(objClassSource)){
            		this.targetRelations.remove(rel);
            	}
            }	
    	}
    }
    
    /**
     * <p>Removes transiently all relations from this entity, which conform the given input.</p> 
     * <p>It could be made persistent using ontology service.</p>
     * @param nameRelation
     * @param objClassSource
     * @return
     */
    public void removeAllSourceRelations(String nameRelation, String objClassTarget){
    	testLightweightState();
    	if(!lightweight){
    		for(Relation rel : new ArrayList<Relation>(getSourceRelations())){
            	if(rel.getOwnValue().equals(nameRelation) && rel.getTargetObjectClass().equals(objClassTarget)){
            		this.sourceRelations.remove(rel);
            	}
            }	
    	}
    }
    
    /**
     * 
     * <p>The changes executed by this method are transiently</p>
     * 
     * <p>Two source relations are not unique for the perspective of this entity, 
     * if they have the same 'relationName' and 'target object class' (one-to-many relations).</p>
     * 
     * <p>This method create a source relation, if it does not exist, 
     * otherwise the first source relation will be updated with the new entity target.</p>
     * 
     * <p>Attention: if already there is more than one relation with same 'relationName' and 'target object class', 
     * only the first one found will be updated with the new target entity.</p>
     * 
     * @param relName
     * @param source
     */
    public void setAsUniqueSourceRelation(String relName, Entity target){
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
        	
            Relation srcRel = null;
            for(Relation rel : getSourceRelations()){
            	if(rel.getOwnValue().equals(relName) && rel.getSourceObjectClass().equals(target.getObjectClass())){
            		srcRel = rel;
            	}
            }
            
            if(srcRel == null){
            	srcRel = new Relation(this, target, relName);
            }else{
            	srcRel.setTarget(this);
            }
        	
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
    }
    
    /**
     * <p>The changes executed by this method are transiently</p>
     * 
     * <p>Two target relations are not unique for the perspective of this entity, 
     * if they have the same 'relationName' and 'source object class' (many-to-one relations).</p>
     * 
     * <p>This method create a target relation, if it does not exist, 
     * otherwise the first target relation will be updated with the new entity source.</p>
     * 
     * <p>Attention: if already there is more than one relation with same 'relationName' and 'source object class', 
     * only the first one found will be updated with the new source entity.</p>
     * 
     * @param relName
     * @param source
     */
    public void setAsUniqueTargetRelation(String relName, Entity source){
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
        	
            Relation tarRel = null;
            for(Relation rel : getTargetRelations()){
            	if(rel.getOwnValue().equals(relName) && rel.getSourceObjectClass().equals(source.getObjectClass())){
            		tarRel = rel;
            	}
            }
            
            if(tarRel == null){
            	tarRel = new Relation(source, this, relName);
            }else{
            	tarRel.setTarget(this);
            }
        	
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
    }
    
    /**
     * Removes transiently the relation  from this entity. 
     * It could be made persistent using ontology service
     * @param name
     * @param target
     * @return true if the relation was found and removed
     */
    public boolean removeSourceRelation(String relName, Long tarId){
    	for(Relation rel : new ArrayList<Relation>(getSourceRelations())){
    		if(StringUtils.equals(rel.getOwnValue(), relName) &&
    				rel.getTargetId().equals(tarId)){
    			this.sourceRelations.remove(rel);
    			return true;
    		}
    	}
    	return false;
    }
    
    /**
     * 
     * @return true if this entity can be made persistent, otherwise false.
     */
    public boolean isValid(){
    	if(StringUtils.isNotEmpty(getType()) && (getType().equals(Node.TYPE_ABOX) || getType().equals(Node.TYPE_TBOX))){
    		if(StringUtils.isNotEmpty(getObjectClass())){
    			return true;
    		}
    	}
    	return false;
    }
    
    /**
     * Removes transiently the relation from this entity. 
     * It could be made persistent using ontology service
     * @param name
     * @param target
     * @return true if the relation was found and removed
     */
    public boolean removeTargetRelation(String relName, Long srcId){
    	for(Relation rel : new ArrayList<Relation>(getTargetRelations())){
    		if(StringUtils.equals(rel.getOwnValue(), relName) &&
    				rel.getSourceId().equals(srcId)){
    			this.targetRelations.remove(rel);
    			return true;
    		}
    	}
    	return false;
    }

    /**
     * Removes transiently the first target relation found, which match the given name.
     * change: now delete all relation by name
     * @param name ownValue of the relation.
     */
    public void removeAllTargetRelationsByName(String name){
        
    	try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            List<Relation> removeList = new ArrayList<Relation>();
	        for (Relation rel : this.getTargetRelations()) {
	            if (rel.getOwnValue() != null && rel.getOwnValue().equals(name)) {
	                removeList.add(rel);
	            }
	        }
	        for(Relation r : removeList){
	        	this.getTargetRelations().remove(r);	
	        }
    	} catch (Exception e) {
    		logger.error(e.getMessage(), e);
        }
    }

    public AttributeMap getAttributeMap(){
    	return new AttributeMap(this);
    }
    
    public Attribute getAttributeByName(String name) {
        try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Attribute attribute : this.getAttributes()) {
                if (attribute.getObjectClass().equals(name) /*|| attribute.getObjectClass().equals(name)*/) {
                    return attribute;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return null;
    }
    
    public Attribute getAttributeByOwnValue(String ow) {
        try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Attribute attribute : this.getAttributes()) {
                if (attribute.getOwnValue().equals(ow) /*|| attribute.getObjectClass().equals(name)*/) {
                    return attribute;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
        }
        return null;
    }

    public boolean containsAttribute(String name) {
        try {
            if (this.lightweight) {
                throw new IllegalAccessException("This Entity is lightweight, so its relations and attributes were not loaded from the DB.");
            }
            for (Attribute attribute : this.getAttributes()) {
                if (attribute.getObjectClass().equals(name)) {
                    return true;
                }
            }
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
            return false;
        }
        return false;
    }

    @Override
    public void increaseVersion() {
        super.increaseVersion();
        for (Attribute att : this.attributes) {
            att.increaseVersion();
        }
        for (Relation rel : this.sourceRelations) {
            rel.increaseVersion();
            for(Attribute att : rel.getAttributes()){
            	att.increaseVersion();
            }
        }
        for (Relation rel : this.targetRelations) {
            rel.increaseVersion();
            for(Attribute att : rel.getAttributes()){
            	att.increaseVersion();
            }
        }
        for (View view : this.getViews()) {
            view.increaseVersion();
        }
    }

    /**
     * deletes the value of rowId for the entity and all associated elements.
     * As consequence of this method, when the entity is saved, it will be saved as a new row.
     */
    public void resetRowId() {
        this.setRowId(null);
        for (Attribute att : this.attributes) {
            att.setRowId(null);
        }
        for (Relation rel : this.sourceRelations) {
            rel.setRowId(null);
            for(Attribute att : rel.getAttributes()){
            	att.setRowId(null);
            }
        }
        for (Relation rel : this.targetRelations) {
            rel.setRowId(null);
            for(Attribute att : rel.getAttributes()){
            	att.setRowId(null);
            }
        }
        for (View view : this.getViews()) {
            view.setRowId(null);
        }
    }
    
    public void resetId() {
        this.setId(null);
        for (Attribute att : this.attributes) {
            att.setId(null);
            att.setSourceId(null);
            att.setSourceModif(null);
            att.setSourceObjectClass(null);
        }
        for (Relation rel : this.sourceRelations) {
            rel.setId(null);
            for(Attribute att : rel.getAttributes()){
            	att.setId(null);
            }
        }
        for (Relation rel : this.targetRelations) {
            rel.setId(null);
            for(Attribute att : rel.getAttributes()){
            	att.setId(null);
            }
        }
        for (View view : this.getViews()) {
            view.setId(null);
        }
    }

    @Override
    public void setType(String type) {
        super.setType(type);
        for (Attribute attribute : this.attributes) {
            attribute.setType(type);
        }
        for (Relation rel : this.sourceRelations) {
            rel.setType(type);
            for(Attribute att : rel.getAttributes()){
            	att.setType(type);
            }
        }
        for (Relation rel : this.targetRelations) {
            rel.setType(type);
            for(Attribute att : rel.getAttributes()){
            	att.setType(type);
            }
        }

    }

    @Override
    public void setModificationTime(Long time) {
        super.setModificationTime(time);
        for (Attribute attribute : this.getAttributes()) {
            attribute.setModificationTime(time);
            attribute.setSourceModif(time);            
        }
        for (Relation rel : this.getSourceRelations()) {
            //rel.setModificationTime(time);
            rel.setSourceModif(time);
            rel.setModificationTime(time);
            for(Attribute att : rel.getAttributes()){
            	att.setModificationTime(time);
            }
            if(this.getId() != null && this.getId().equals(rel.getTargetId())){
            	rel.setTargetModif(time);            	
            }
        }
        for (Relation rel : this.getTargetRelations()) {
            //rel.setModificationTime(time);
            rel.setTargetModif(time);
            rel.setModificationTime(time);
            for(Attribute att : rel.getAttributes()){
            	att.setModificationTime(time);
            }
            if(this.getId() != null && this.getId().equals(rel.getSourceId())){
            	rel.setSourceModif(time);            	
            }
        }
    }
    
    @Override
	public void setIsPublic(Boolean isPublic) {
		super.setIsPublic(isPublic);
		if(!this.isLightweight()){
			for (Attribute attribute : this.getAttributes()) {
	            attribute.setIsPublic(isPublic);
	                        
	        }
	        for (Relation rel : this.getSourceRelations()) {
	            rel.setIsPublic(isPublic);
	            for(Attribute att : rel.getAttributes()){
	            	att.setIsPublic(isPublic);
	            }
	            
	        }
	        for (Relation rel : this.getTargetRelations()) {
	            rel.setIsPublic(isPublic);
	            for(Attribute att : rel.getAttributes()){
	            	att.setIsPublic(isPublic);
	            }
	        }	
		}
	}

    @Override
    public Object clone() {
        try {
            Entity clone = (Entity) super.clone(); 
            clone.setAttributes(new ArrayList<Attribute>());
            clone.setSourceRelations(new ArrayList<Relation>());
            clone.setTargetRelations(new ArrayList<Relation>());
            
            if(!clone.isLightweight()){
            	for (Attribute attribute : this.attributes) {
                    clone.addAttribute((Attribute) attribute.clone());
                }
                for (Relation srcRelation : this.sourceRelations) {
                	Relation clonRelation = (Relation) srcRelation.clone();
                	clonRelation.setAttributes(new ArrayList<Attribute>());
                	for(Attribute att : srcRelation.getAttributes()){
                		clonRelation.getAttributes().add((Attribute)att.clone());
                	}
                    clone.addSourceRelation(clonRelation);
                }
                for (Relation targetRelation : this.targetRelations) {
                	Relation clonRelation = (Relation) targetRelation.clone();
                	clonRelation.setAttributes(new ArrayList<Attribute>());
                	for(Attribute att : targetRelation.getAttributes()){
                		clonRelation.getAttributes().add((Attribute)att.clone());
                	}
                    clone.addTargetRelation((Relation) targetRelation.clone());
                }	
            }

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

    @Override
    public void setSystemStatus(String status) {
        super.setSystemStatus(status);
        if(!lightweight){
        	for (Attribute attribute : this.getAttributes()) {
                attribute.setSystemStatus(status);
            }
            //really does matter if the system status is or no
            //Current for a relation
            for (Relation rel : this.getSourceRelations()) {
                rel.setSystemStatus(status);
                for(Attribute att : rel.getAttributes()){
                	att.setSystemStatus(status);
                }
            }
            for (Relation rel : this.getTargetRelations()) {
                rel.setSystemStatus(status);
                for(Attribute att : rel.getAttributes()){
                	att.setSystemStatus(status);
                }
            }	
        }        
    }

    public DuplexKey<String, Long> getKey(){
    	return new DuplexKey<String, Long>(this.getObjectClass(), this.getId());
    }
    
    public Boolean isLightweight() {
    	if(lightweight == null)
    		this.lightweight = true;
        return lightweight;
    }

    public void setLightweight(Boolean lightweight) {
        this.lightweight = lightweight;
    }

    public String toSmallString() {
        String rowIdString = (this.getRowId() == null) ? "" : "rowId=" + this.getRowId() + ", ";
        String idString = (this.getId() == null) ? "" : "id=" + getId() + ", ";

        return "Entity[" + rowIdString + idString + "objClass=" + this.getObjectClass() +  ", ownValue=" + this.getOwnValue() + "]";
    }
    
    @Override
    public String toString() {
        String rowIdString = (this.getRowId() == null) ? "" : "rowId=" + this.getRowId() + ", ";
        String idString = (this.getId() == null) ? "" : "id=" + getId() + ", ";

        
        
        return "Entity[" + rowIdString + idString + "oc=" + this.getObjectClass() +  ", ov=" + this.getOwnValue() + ", user=" + getUser() +  ", sysStatus=" + this.getSystemStatus() +
                ", type=" + this.getType() + " att.size=" + this.attributes.size() + "]";
    }

    public String getShortString(){
    	return "[" + this.getId() + "] " + this.getOwnValue();
    }
    
	@Override
	public int compareTo(Entity e) {
		if(e == null)
			return 1;
		if(StringUtils.isNotEmpty(this.getOwnValue()))
			return this.getOwnValue().compareTo(e.getOwnValue());
		else return 0;
	}
	
	public Relation containsSrcRel(Relation other){
		
		for(Relation ownRel : getSourceRelations()){
			if(ownRel.equalsContent(other)){
				return ownRel;
			}
		}
		return null;
	}
	
	public Relation containsTarRel(Relation other){
		for(Relation ownRel : getTargetRelations()){
			if(ownRel.equalsContent(other)){
				return ownRel;
			}
		}		
		return null;
	}
	
	public boolean equalsContent(Entity other) throws Exception{
		
		if(this.isLightweight() || other.isLightweight()){
			throw new Exception(" It is not possible to comparate the content of two lightWeight entities.");
		}
		
		if(this.getAttributes().size() != other.getAttributes().size() ||
				this.sourceRelations.size() != other.sourceRelations.size() ||
				this.targetRelations.size() != other.targetRelations.size()){
			return false;
		}
			
		for(Attribute att : this.getAttributes()){
			Attribute otherAtt = other.getAttributeByName(att.getName());
			if(!att.equalsContent(otherAtt)){
				return false;
			}
		}
		
		for(Relation rel : other.getSourceRelations()){
			if(containsSrcRel(rel) == null){
				return false;
			}
		}
		
		for(Relation rel : other.getTargetRelations()){
			if(this.containsTarRel(rel) == null){
				return false;
			}
		}
		
		
		return true;
	}
	
	public void refreshEnt(Entity other, WrapperService ws) throws Exception{
		
		//Attributes
		for(Attribute otherAtt : other.getAttributes()){
			Attribute rootAtt = this.getAttributeByName(otherAtt.getName());
			if(rootAtt == null){
				Attribute newAtt = new Attribute(otherAtt.getName(), otherAtt.getContentType(), otherAtt.getValue());
				this.addAttribute(newAtt);
				logger.info("Adding " + newAtt);
			}else if(!rootAtt.equalsContent(otherAtt)){
				String oldValue = rootAtt.getOwnValue();
				rootAtt.setValue(otherAtt.getValue());
				logger.info("Refreshing " + rootAtt + "\n" + oldValue + "\n");
			}			
		}
		
		for(Attribute rootAtt : new ArrayList<Attribute>(this.getAttributes())){
			if(other.getAttributeByName(rootAtt.getName()) == null){
				this.getAttributes().remove(rootAtt);
			}
		}
		
		//Source Relations
		for(Relation otherRel : other.getSourceRelations()){
			if(this.containsSrcRel(otherRel) == null){
				//create
				Relation rel = Relation.entRelation(otherRel, ws);
				this.addSourceRelation(rel);
			}
		}
		
		for(Relation rootRel : new ArrayList<Relation>(this.getSourceRelations())){
			if(other.containsSrcRel(rootRel) == null){
				this.getSourceRelations().remove(rootRel);
			}
		}
		
		//Target relations
		for(Relation otherRel : other.getTargetRelations()){
			if(this.containsTarRel(otherRel) == null){
				//create
				Relation rel = Relation.entRelation(otherRel, ws);
				this.addTargetRelation(rel);
			}
		}
		
		for(Relation rootRel : new ArrayList<Relation>(this.getTargetRelations())){
			if(other.containsTarRel(rootRel) == null){
				this.getTargetRelations().remove(rootRel);
			}
		}
				
	}
}