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 }