001 package de.deepamehta.core.impl; 002 003 import de.deepamehta.core.Association; 004 import de.deepamehta.core.AssociationDefinition; 005 import de.deepamehta.core.DeepaMehtaObject; 006 import de.deepamehta.core.RelatedTopic; 007 import de.deepamehta.core.Topic; 008 import de.deepamehta.core.Type; 009 import de.deepamehta.core.model.ChildTopicsModel; 010 import de.deepamehta.core.model.DeepaMehtaObjectModel; 011 import de.deepamehta.core.model.RelatedTopicModel; 012 import de.deepamehta.core.model.SimpleValue; 013 import de.deepamehta.core.model.TopicModel; 014 import de.deepamehta.core.service.ResultList; 015 016 import org.codehaus.jettison.json.JSONObject; 017 018 import java.util.List; 019 import java.util.logging.Logger; 020 021 022 023 /** 024 * A DeepaMehta object model that is attached to the DB. 025 * 026 * Method name conventions and semantics: 027 * - getXX() Reads from memory (model). 028 * - setXX(arg) Writes to memory (model) and DB. Elementary operation. 029 * - updateXX(arg) Compares arg with current value (model) and calls setXX() method(s) if required. 030 * Can be called with arg=null which indicates no update is requested. 031 * Typically returns nothing. 032 * - fetchXX() Fetches value from DB. ### FIXDOC 033 * - storeXX() Stores current value (model) to DB. ### FIXDOC 034 */ 035 abstract class AttachedDeepaMehtaObject implements DeepaMehtaObject { 036 037 // ---------------------------------------------------------------------------------------------- Instance Variables 038 039 private DeepaMehtaObjectModel model; // underlying model 040 041 private AttachedChildTopics childTopics; // attached object cache 042 043 protected final EmbeddedService dms; 044 045 private Logger logger = Logger.getLogger(getClass().getName()); 046 047 // ---------------------------------------------------------------------------------------------------- Constructors 048 049 AttachedDeepaMehtaObject(DeepaMehtaObjectModel model, EmbeddedService dms) { 050 this.model = model; 051 this.dms = dms; 052 this.childTopics = new AttachedChildTopics(model.getChildTopicsModel(), this, dms); 053 } 054 055 // -------------------------------------------------------------------------------------------------- Public Methods 056 057 058 059 // *************************************** 060 // *** DeepaMehtaObject Implementation *** 061 // *************************************** 062 063 064 065 // === Model === 066 067 // --- ID --- 068 069 @Override 070 public long getId() { 071 return model.getId(); 072 } 073 074 // --- URI --- 075 076 @Override 077 public String getUri() { 078 return model.getUri(); 079 } 080 081 @Override 082 public void setUri(String uri) { 083 // update memory 084 model.setUri(uri); 085 // update DB 086 storeUri(); // abstract 087 } 088 089 // --- Type URI --- 090 091 @Override 092 public String getTypeUri() { 093 return model.getTypeUri(); 094 } 095 096 @Override 097 public void setTypeUri(String typeUri) { 098 // update memory 099 model.setTypeUri(typeUri); 100 // update DB 101 storeTypeUri(); // abstract 102 } 103 104 // --- Simple Value --- 105 106 @Override 107 public SimpleValue getSimpleValue() { 108 return model.getSimpleValue(); 109 } 110 111 // --- 112 113 @Override 114 public void setSimpleValue(String value) { 115 setSimpleValue(new SimpleValue(value)); 116 } 117 118 @Override 119 public void setSimpleValue(int value) { 120 setSimpleValue(new SimpleValue(value)); 121 } 122 123 @Override 124 public void setSimpleValue(long value) { 125 setSimpleValue(new SimpleValue(value)); 126 } 127 128 @Override 129 public void setSimpleValue(boolean value) { 130 setSimpleValue(new SimpleValue(value)); 131 } 132 133 @Override 134 public void setSimpleValue(SimpleValue value) { 135 dms.valueStorage.setSimpleValue(getModel(), value); 136 } 137 138 // --- Child Topics --- 139 140 @Override 141 public AttachedChildTopics getChildTopics() { 142 return childTopics; 143 } 144 145 @Override 146 public void setChildTopics(ChildTopicsModel childTopics) { 147 try { 148 getChildTopics().update(childTopics); 149 } catch (Exception e) { 150 throw new RuntimeException("Setting the child topics failed (" + childTopics + ")", e); 151 } 152 } 153 154 // --- 155 156 @Override 157 public DeepaMehtaObject loadChildTopics() { 158 getChildTopics().loadChildTopics(); 159 return this; 160 } 161 162 @Override 163 public DeepaMehtaObject loadChildTopics(String childTypeUri) { 164 getChildTopics().loadChildTopics(childTypeUri); 165 return this; 166 } 167 168 // --- 169 170 @Override 171 public DeepaMehtaObjectModel getModel() { 172 return model; 173 } 174 175 176 177 // === Updating === 178 179 @Override 180 public void update(DeepaMehtaObjectModel newModel) { 181 updateUri(newModel.getUri()); 182 updateTypeUri(newModel.getTypeUri()); 183 updateValue(newModel); 184 } 185 186 // --- 187 188 @Override 189 public void updateChildTopic(TopicModel newChildTopic, AssociationDefinition assocDef) { 190 getChildTopics().updateChildTopics(newChildTopic, null, assocDef); 191 } 192 193 @Override 194 public void updateChildTopics(List<TopicModel> newChildTopics, AssociationDefinition assocDef) { 195 getChildTopics().updateChildTopics(null, newChildTopics, assocDef); 196 } 197 198 199 200 // === Deletion === 201 202 /** 203 * Deletes all sub-topics of this DeepaMehta object (associated via "dm4.core.composition", recursively) and 204 * deletes all the remaining direct associations of this DeepaMehta object. 205 * <p> 206 * Note: deletion of the object itself is up to the subclasses. 207 */ 208 @Override 209 public void delete() { 210 // 1) recursively delete sub-topics 211 ResultList<RelatedTopic> childTopics = getRelatedTopics("dm4.core.composition", 212 "dm4.core.parent", "dm4.core.child", null, 0); 213 for (Topic childTopic : childTopics) { 214 childTopic.delete(); 215 } 216 // 2) delete direct associations 217 for (Association assoc : getAssociations()) { // getAssociations() is abstract 218 assoc.delete(); 219 } 220 } 221 222 223 224 // === Traversal === 225 226 // --- Topic Retrieval --- 227 228 @Override 229 public RelatedTopic getRelatedTopic(String assocTypeUri, String myRoleTypeUri, String othersRoleTypeUri, 230 String othersTopicTypeUri) { 231 RelatedTopicModel topic = fetchRelatedTopic(assocTypeUri, myRoleTypeUri, othersRoleTypeUri, othersTopicTypeUri); 232 // fetchRelatedTopic() is abstract 233 return topic != null ? dms.instantiateRelatedTopic(topic) : null; 234 } 235 236 @Override 237 public ResultList<RelatedTopic> getRelatedTopics(String assocTypeUri, int maxResultSize) { 238 return getRelatedTopics(assocTypeUri, null, null, null, maxResultSize); 239 } 240 241 @Override 242 public ResultList<RelatedTopic> getRelatedTopics(String assocTypeUri, String myRoleTypeUri, 243 String othersRoleTypeUri, String othersTopicTypeUri, int maxResultSize) { 244 ResultList<RelatedTopicModel> topics = fetchRelatedTopics(assocTypeUri, myRoleTypeUri, othersRoleTypeUri, 245 othersTopicTypeUri, maxResultSize); // fetchRelatedTopics() is abstract 246 return dms.instantiateRelatedTopics(topics); 247 } 248 249 // Note: this method is implemented in the subclasses (this is an abstract class): 250 // getRelatedTopics(List assocTypeUris, ...) 251 252 // --- Association Retrieval --- 253 254 // Note: these methods are implemented in the subclasses (this is an abstract class): 255 // getAssociation(...); 256 // getAssociations(); 257 258 259 260 // === Misc === 261 262 @Override 263 public Object getDatabaseVendorObject() { 264 return dms.storageDecorator.getDatabaseVendorObject(getId()); 265 } 266 267 268 269 // ********************************** 270 // *** JSONEnabled Implementation *** 271 // ********************************** 272 273 274 275 @Override 276 public JSONObject toJSON() { 277 return model.toJSON(); 278 } 279 280 281 282 // **************** 283 // *** Java API *** 284 // **************** 285 286 287 288 @Override 289 public boolean equals(Object o) { 290 return ((AttachedDeepaMehtaObject) o).model.equals(model); 291 } 292 293 @Override 294 public int hashCode() { 295 return model.hashCode(); 296 } 297 298 @Override 299 public String toString() { 300 return model.toString(); 301 } 302 303 304 305 // ----------------------------------------------------------------------------------------- Package Private Methods 306 307 abstract String className(); 308 309 // ### TODO: Directive getUpdateDirective() 310 abstract void addUpdateDirective(); 311 312 abstract void storeUri(); 313 314 abstract void storeTypeUri(); 315 316 // --- 317 318 abstract RelatedTopicModel fetchRelatedTopic(String assocTypeUri, String myRoleTypeUri, 319 String othersRoleTypeUri, String othersTopicTypeUri); 320 321 abstract ResultList<RelatedTopicModel> fetchRelatedTopics(String assocTypeUri, String myRoleTypeUri, 322 String othersRoleTypeUri, String othersTopicTypeUri, int maxResultSize); 323 324 // --- 325 326 // ### TODO: add to public interface 327 Type getType() { 328 return dms.valueStorage.getType(getModel()); 329 } 330 331 // ------------------------------------------------------------------------------------------------- Private Methods 332 333 334 335 // === Update === 336 337 private void updateUri(String newUri) { 338 // abort if no update is requested 339 if (newUri == null) { 340 return; 341 } 342 // 343 String uri = getUri(); 344 if (!uri.equals(newUri)) { 345 logger.info("### Changing URI of " + className() + " " + getId() + 346 " from \"" + uri + "\" -> \"" + newUri + "\""); 347 setUri(newUri); 348 } 349 } 350 351 private void updateTypeUri(String newTypeUri) { 352 // abort if no update is requested 353 if (newTypeUri == null) { 354 return; 355 } 356 // 357 String typeUri = getTypeUri(); 358 if (!typeUri.equals(newTypeUri)) { 359 logger.info("### Changing type URI of " + className() + " " + getId() + 360 " from \"" + typeUri + "\" -> \"" + newTypeUri + "\""); 361 setTypeUri(newTypeUri); 362 } 363 } 364 365 private void updateValue(DeepaMehtaObjectModel newModel) { 366 if (getType().getDataTypeUri().equals("dm4.core.composite")) { 367 getChildTopics().update(newModel.getChildTopicsModel()); 368 } else { 369 updateSimpleValue(newModel.getSimpleValue()); 370 } 371 } 372 373 private void updateSimpleValue(SimpleValue newValue) { 374 // abort if no update is requested 375 if (newValue == null) { 376 return; 377 } 378 // 379 SimpleValue value = getSimpleValue(); 380 if (!value.equals(newValue)) { 381 logger.info("### Changing simple value of " + className() + " " + getId() + 382 " from \"" + value + "\" -> \"" + newValue + "\""); 383 setSimpleValue(newValue); 384 } 385 } 386 }