001package de.deepamehta.core.impl;
002
003import de.deepamehta.core.AssociationDefinition;
004import de.deepamehta.core.DeepaMehtaObject;
005import de.deepamehta.core.DeepaMehtaType;
006import de.deepamehta.core.RelatedTopic;
007import de.deepamehta.core.model.ChildTopicsModel;
008import de.deepamehta.core.model.DeepaMehtaObjectModel;
009import de.deepamehta.core.model.RelatedTopicModel;
010import de.deepamehta.core.model.SimpleValue;
011
012import org.codehaus.jettison.json.JSONObject;
013
014import java.util.List;
015
016
017
018/**
019 * A DeepaMehta object model that is attached to the DB.
020 *
021 * Method name conventions and semantics:
022 *  - getXX()           Reads from memory (model).
023 *  - setXX(arg)        Writes to memory (model) and DB. Elementary operation.
024 *  - updateXX(arg)     Compares arg with current value (model) and calls setXX() method(s) if required.
025 *                      Can be called with arg=null which indicates no update is requested.
026 *                      Typically returns nothing.
027 *  - fetchXX()         Fetches value from DB.              ### FIXDOC
028 *  - storeXX()         Stores current value (model) to DB. ### FIXDOC
029 */
030abstract class DeepaMehtaObjectImpl implements DeepaMehtaObject {
031
032    // ---------------------------------------------------------------------------------------------- Instance Variables
033
034    DeepaMehtaObjectModelImpl model;    // underlying model
035
036    PersistenceLayer pl;
037    ModelFactoryImpl mf;
038
039    // ---------------------------------------------------------------------------------------------------- Constructors
040
041    DeepaMehtaObjectImpl(DeepaMehtaObjectModelImpl model, PersistenceLayer pl) {
042        this.model = model;
043        this.pl = pl;
044        this.mf = pl.mf;
045    }
046
047    // -------------------------------------------------------------------------------------------------- Public Methods
048
049
050
051    // ***************************************
052    // *** DeepaMehtaObject Implementation ***
053    // ***************************************
054
055
056
057    // === Model ===
058
059    // --- ID ---
060
061    @Override
062    public final long getId() {
063        return model.getId();
064    }
065
066    // --- URI ---
067
068    @Override
069    public final String getUri() {
070        return model.getUri();
071    }
072
073    @Override
074    public final void setUri(String uri) {
075        model.updateUri(uri);
076    }
077
078    // --- Type URI ---
079
080    @Override
081    public final String getTypeUri() {
082        return model.getTypeUri();
083    }
084
085    @Override
086    public final void setTypeUri(String typeUri) {
087        model.updateTypeUri(typeUri);
088    }
089
090    // --- Simple Value ---
091
092    @Override
093    public final SimpleValue getSimpleValue() {
094        return model.getSimpleValue();
095    }
096
097    // ---
098
099    @Override
100    public final void setSimpleValue(String value) {
101        setSimpleValue(new SimpleValue(value));
102    }
103
104    @Override
105    public final void setSimpleValue(int value) {
106        setSimpleValue(new SimpleValue(value));
107    }
108
109    @Override
110    public final void setSimpleValue(long value) {
111        setSimpleValue(new SimpleValue(value));
112    }
113
114    @Override
115    public final void setSimpleValue(boolean value) {
116        setSimpleValue(new SimpleValue(value));
117    }
118
119    @Override
120    public final void setSimpleValue(SimpleValue value) {
121        model.updateSimpleValue(value);
122    }
123
124    // --- Child Topics ---
125
126    @Override
127    public final ChildTopicsImpl getChildTopics() {
128        return new ChildTopicsImpl(model.childTopics, model, pl);
129    }
130
131    // ### FIXME: no UPDATE directive for *this* object is added. No UPDATE event for *this* object is fired.
132    // We should call the abstract updateWithChildTopics() instead.
133    @Override
134    public final void setChildTopics(ChildTopicsModel childTopics) {
135        try {
136            model._updateChildTopics((ChildTopicsModelImpl) childTopics);
137        } catch (Exception e) {
138            throw new RuntimeException("Setting the child topics failed (" + childTopics + ")", e);
139        }
140    }
141
142    // ---
143
144    @Override
145    public DeepaMehtaObject loadChildTopics() {
146        model.loadChildTopics();
147        return this;
148    }
149
150    @Override
151    public DeepaMehtaObject loadChildTopics(String assocDefUri) {
152        model.loadChildTopics(assocDefUri);
153        return this;
154    }
155
156    // ---
157
158    @Override
159    public final DeepaMehtaType getType() {
160        return model.getType().instantiate();
161    }
162
163    @Override
164    public DeepaMehtaObjectModelImpl getModel() {
165        return model;
166    }
167
168
169
170    // === Updating ===
171
172    @Override
173    public final void update(DeepaMehtaObjectModel updateModel) {
174        model.update((DeepaMehtaObjectModelImpl) updateModel);     // ### FIXME: call through pl for access control
175    }
176
177    // ---
178
179    // ### FIXME: no UPDATE directive for *this* object is added. No UPDATE event for *this* object is fired.
180    // Directives/events is handled only in the high-level update() method.
181    // Here however we need to call the low-level updateChildTopics() method in order to pass an arbitrary assoc def.
182    @Override
183    public final void updateChildTopic(RelatedTopicModel newChildTopic, AssociationDefinition assocDef) {
184        model.updateChildTopics((RelatedTopicModelImpl) newChildTopic, null, assocDef.getModel());
185                                                                                                // newChildTopics=null
186    }
187
188    // ### FIXME: no UPDATE directive for *this* object is added. No UPDATE event for *this* object is fired.
189    // Directives/events is handled only in the high-level update() method.
190    // Here however we need to call the low-level updateChildTopics() method in order to pass an arbitrary assoc def.
191    @Override
192    public final void updateChildTopics(List<? extends RelatedTopicModel> newChildTopics,
193                                                                                       AssociationDefinition assocDef) {
194        model.updateChildTopics(null, (List<RelatedTopicModelImpl>) newChildTopics, assocDef.getModel());
195                                                                                                // newChildTopic=null
196    }
197
198
199
200    // === Deletion ===
201
202    @Override
203    public final void delete() {
204        model.delete();     // ### FIXME: call through pl for access control
205    }
206
207
208
209    // === Traversal ===
210
211    // --- Topic Retrieval ---
212
213    @Override
214    public final RelatedTopic getRelatedTopic(String assocTypeUri, String myRoleTypeUri,
215                                              String othersRoleTypeUri, String othersTopicTypeUri) {
216        RelatedTopicModelImpl topic = model.getRelatedTopic(assocTypeUri, myRoleTypeUri, othersRoleTypeUri,
217            othersTopicTypeUri);
218        return topic != null ? pl.<RelatedTopic>checkReadAccessAndInstantiate(topic) : null;
219    }
220
221    @Override
222    public final List<RelatedTopic> getRelatedTopics(String assocTypeUri) {
223        return getRelatedTopics(assocTypeUri, null, null, null);
224    }
225
226    @Override
227    public final List<RelatedTopic> getRelatedTopics(String assocTypeUri, String myRoleTypeUri,
228                                                     String othersRoleTypeUri, String othersTopicTypeUri) {
229        List<RelatedTopicModelImpl> topics = model.getRelatedTopics(assocTypeUri, myRoleTypeUri, othersRoleTypeUri,
230            othersTopicTypeUri);
231        return pl.checkReadAccessAndInstantiate(topics);
232    }
233
234    // Note: this method is implemented in the subclasses (this is an abstract class):
235    //     getRelatedTopics(List assocTypeUris, ...)
236
237    // --- Association Retrieval ---
238
239    // Note: these methods are implemented in the subclasses (this is an abstract class):
240    //     getAssociation(...)
241    //     getAssociations()
242
243
244
245    // === Properties ===
246
247    @Override
248    public final Object getProperty(String propUri) {
249        return pl.fetchProperty(getId(), propUri);
250    }
251
252    @Override
253    public final boolean hasProperty(String propUri) {
254        return pl.hasProperty(getId(), propUri);
255    }
256
257    @Override
258    public final void setProperty(String propUri, Object propValue, boolean addToIndex) {
259        model.storeProperty(propUri, propValue, addToIndex);
260    }
261
262    @Override
263    public final void removeProperty(String propUri) {
264        model.removeProperty(propUri);
265    }
266
267
268
269    // === Misc ===
270
271    @Override
272    public final Object getDatabaseVendorObject() {
273        return pl.getDatabaseVendorObject(getId());
274    }
275
276
277
278    // **********************************
279    // *** JSONEnabled Implementation ***
280    // **********************************
281
282
283
284    @Override
285    public final JSONObject toJSON() {
286        return model.toJSON();
287    }
288
289
290
291    // ****************
292    // *** Java API ***
293    // ****************
294
295
296
297    @Override
298    public final boolean equals(Object o) {
299        return ((DeepaMehtaObjectImpl) o).model.equals(model);
300    }
301
302    @Override
303    public final int hashCode() {
304        return model.hashCode();
305    }
306
307    @Override
308    public final String toString() {
309        return model.toString();
310    }
311
312
313
314    // ----------------------------------------------------------------------------------------- Package Private Methods
315
316    final String className() {
317        return model.className();
318    }
319}