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