View Javadoc

1   package cz.cuni.amis.pogamut.multi.communication.worldview.property;
2   
3   import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
4   import cz.cuni.amis.pogamut.multi.agent.ITeamId;
5   import cz.cuni.amis.pogamut.multi.communication.translator.event.ISharedPropertyUpdateResult;
6   import cz.cuni.amis.pogamut.multi.communication.translator.event.ISharedPropertyUpdatedEvent;
7   import cz.cuni.amis.pogamut.multi.communication.translator.event.ISharedPropertyUpdateResult.Result;
8   import cz.cuni.amis.pogamut.multi.communication.worldview.object.ISharedProperty;
9   import cz.cuni.amis.utils.HashCode;
10  import cz.cuni.amis.utils.NullCheck;
11  import cz.cuni.amis.utils.SafeEquals;
12  import cz.cuni.amis.utils.exception.PogamutException;
13  
14  /**
15   * Abstract implementation of the ISharedProperty object,
16   * this class manages the methods every ISharedProperty needs to have, regardless of its type.
17   * <p>SharedProperties are generally derived from bot's subjective observation of the world (local properties). If the local properties, which are used to derive the
18   * value of the sharedProperty are dated, the sharedProperty is considered "dirty", because the value <i>might</i> be wrong, the team that owns this property only 
19   * <i>assumes</i> the value.</p> 
20   * @author srlok
21   *
22   */
23  public abstract class AbstractSharedProperty<TYPE> implements ISharedProperty<TYPE> {
24  	
25  	protected PropertyId propertyId = null;
26  	protected boolean dirty = false;
27  	protected Class<?> compositeClass = null;
28  	protected TYPE value;
29  	private int hashCode;
30  		
31  	@Override
32  	public boolean nullOverrides()
33  	{
34  		return false;
35  	}
36  	
37  	/**
38  	 * Every descendant must implement this by calling value.clone() or otherwise returning a new copy of value.
39  	 * @return
40  	 */
41  	protected abstract TYPE cloneValue();
42  	
43  	public AbstractSharedProperty(WorldObjectId objId, String identifier, TYPE value, Class<?> compositeClass)
44  	{
45  		this.propertyId = PropertyId.get(objId, identifier);
46  		this.compositeClass = compositeClass;
47  		this.value = value;
48  		HashCode hc = new HashCode();
49  		hc.add(propertyId);
50  		this.hashCode = hc.getHash();
51  	}
52  	
53  	/**
54  	 * Used in copy-constructors,
55  	 * when writing a copy constructor for a descendant class, you must add a clone for value.
56  	 * @param source
57  	 */
58  	public AbstractSharedProperty(AbstractSharedProperty source)
59  	{
60  		this.hashCode = source.hashCode;
61  		this.propertyId = source.propertyId;
62  		this.dirty = source.dirty;
63  		this.compositeClass = source.compositeClass;
64  		this.value = (TYPE) source.cloneValue();
65  	}
66  	
67  	/**
68  	 * Used in propertyConstructors from data.
69  	 * @param objectId
70  	 * @param identifier
71  	 * @param compositeClass
72  	 */
73  	public AbstractSharedProperty( WorldObjectId objectId, String identifier, Class compositeClass)
74  	{
75  		this(objectId, identifier, (TYPE)null, compositeClass);
76  	}
77  		
78  	@Override
79  	public int hashCode() {
80  		return hashCode;
81  	}
82  	
83  	@Override
84  	public boolean equals(Object another) {
85  		if (another == null) return false;		
86  		if (!(another instanceof ISharedProperty)) { return false; }
87  		ISharedProperty other = (ISharedProperty)another;
88  		if (!getPropertyValueClass().isAssignableFrom(other.getPropertyValueClass())) return false;
89  		return ((this.isDirty() == other.isDirty()) && (SafeEquals.equals(this.getValue(), other.getValue()))) && this.getPropertyId().equals(other.getPropertyId());
90  	}
91  	
92  	@Override
93  	public abstract ISharedProperty<TYPE> clone();
94  	
95  	@Override
96  	public TYPE getValue() {
97  		return value;
98  	}
99  	
100 	@Override
101 	public void setValue(TYPE value) {
102 		this.value = value;
103 	}
104 
105 	@Override
106 	public Class getCompositeClass()
107 	{
108 		return compositeClass;
109 	}
110 	
111 	@Override
112 	public boolean isDirty()
113 	{
114 		return dirty;
115 	}
116 	
117 	public void setDirty(boolean value)
118 	{
119 		this.dirty = value;
120 	}
121 	
122 	@Override
123 	public WorldObjectId getObjectId()
124 	{
125 		return this.propertyId.getWorldObjectId();
126 	}
127 	
128 	@Override
129 	public PropertyId getPropertyId()
130 	{
131 		return this.propertyId;
132 	}
133 	
134 	@Override
135 	public ISharedPropertyUpdatedEvent createUpdateEvent(long time, ITeamId teamId)
136 	{
137 		return new GenericPropertyUpdate(this, time, teamId);
138 	}
139 	
140 	public static class GenericPropertyUpdate implements ISharedPropertyUpdatedEvent
141 	{
142 
143 		private ISharedProperty data;
144 		private long time;
145 		private ITeamId teamId;
146 		
147 		public GenericPropertyUpdate(ISharedProperty data, long time, ITeamId teamId)
148 		{
149 			this.data = data;
150 			NullCheck.check(this.data, "data");
151 			this.time = time;
152 			this.teamId = teamId;
153 		}
154 		
155 		@Override
156 		public long getSimTime() {
157 			return time;
158 		}
159 
160 		@Override
161 		public WorldObjectId getObjectId() {
162 			return data.getObjectId();
163 		}
164 
165 		@Override
166 		public PropertyId getPropertyId() {
167 			return data.getPropertyId();
168 		}
169 
170 		@Override
171 		public ITeamId getTeamId() {
172 			return this.teamId;
173 		}
174 
175 		@Override
176 		public ISharedPropertyUpdateResult update(ISharedProperty property) {
177 			if ( property == null )
178 			{
179 				//created event;
180 				data = data.clone(); //make sure we are returning new instance
181 				return new ISharedPropertyUpdateResult.SharedPropertyUpdateResult(Result.CREATED, data);
182 			}
183 
184 			if (!data.getPropertyValueClass().isAssignableFrom(property.getPropertyValueClass())) {
185 				// BAD UPDATE! CLASSES DOES NOT MATCH
186 				throw new PogamutException("Unexpected object type provided for update, expected value class " + data.getPropertyValueClass() + " got data with value class " + property.getPropertyValueClass(), this);
187 			}
188 			
189 			ISharedProperty original = property;
190 			boolean updated = false;
191 			if ( !SafeEquals.equals(original.getValue(), data.getValue()) )
192 			{	
193 				if ( property.nullOverrides() )
194 				{
195 					updated = true;
196 					original.setValue(data.getValue());
197 				}
198 				else if ( data.getValue() != null )
199 				{
200 					updated = true;
201 					original.setValue(data.getValue());
202 				}
203 			}
204 			this.data = original;
205 			
206 			if (updated)
207 			{
208 				return new ISharedPropertyUpdateResult.SharedPropertyUpdateResult(Result.UPDATED, original);
209 			}
210 			return new ISharedPropertyUpdateResult.SharedPropertyUpdateResult(Result.SAME, original);
211 			
212 			
213 		}
214 	}
215 	
216 }