001package de.deepamehta.core.impl;
002
003import de.deepamehta.core.Topic;
004import de.deepamehta.core.model.AssociationDefinitionModel;
005import de.deepamehta.core.model.ChildTopicsModel;
006import de.deepamehta.core.model.IndexMode;
007import de.deepamehta.core.model.RoleModel;
008import de.deepamehta.core.model.TopicModel;
009import de.deepamehta.core.model.TopicTypeModel;
010import de.deepamehta.core.model.TypeModel;
011import de.deepamehta.core.service.DeepaMehtaEvent;
012import de.deepamehta.core.service.Directive;
013
014import java.util.List;
015
016
017
018class TopicModelImpl extends DeepaMehtaObjectModelImpl implements TopicModel {
019
020    // ---------------------------------------------------------------------------------------------------- Constructors
021
022    TopicModelImpl(DeepaMehtaObjectModelImpl object) {
023        super(object);
024    }
025
026    // -------------------------------------------------------------------------------------------------- Public Methods
027
028
029
030    // === Implementation of the abstract methods ===
031
032    @Override
033    public RoleModel createRoleModel(String roleTypeUri) {
034        return mf.newTopicRoleModel(id, roleTypeUri);
035    }
036
037
038
039    // === Java API ===
040
041    @Override
042    public TopicModel clone() {
043        try {
044            return (TopicModel) super.clone();
045        } catch (Exception e) {
046            throw new RuntimeException("Cloning a TopicModel failed", e);
047        }
048    }
049
050    @Override
051    public String toString() {
052        return "topic (" + super.toString() + ")";
053    }
054
055
056
057    // ----------------------------------------------------------------------------------------- Package Private Methods
058
059    @Override
060    String className() {
061        return "topic";
062    }
063
064    @Override
065    TopicImpl instantiate() {
066        return new TopicImpl(this, pl);
067    }
068
069    @Override
070    final TopicModelImpl createModelWithChildTopics(ChildTopicsModel childTopics) {
071        return mf.newTopicModel(childTopics);
072    }
073
074    // ---
075
076    @Override
077    final TopicTypeModelImpl getType() {
078        return pl.typeStorage.getTopicType(typeUri);
079    }
080
081    @Override
082    final List<AssociationModelImpl> getAssociations() {
083        return pl.fetchTopicAssociations(id);
084    }
085
086    // ---
087
088    @Override
089    final RelatedTopicModelImpl getRelatedTopic(String assocTypeUri, String myRoleTypeUri, String othersRoleTypeUri,
090                                                                                           String othersTopicTypeUri) {
091        return pl.fetchTopicRelatedTopic(id, assocTypeUri, myRoleTypeUri, othersRoleTypeUri, othersTopicTypeUri);
092    }
093
094    @Override
095    final List<RelatedTopicModelImpl> getRelatedTopics(String assocTypeUri, String myRoleTypeUri,
096                                                                                           String othersRoleTypeUri,
097                                                                                           String othersTopicTypeUri) {
098        return pl.fetchTopicRelatedTopics(id, assocTypeUri, myRoleTypeUri, othersRoleTypeUri, othersTopicTypeUri);
099    }
100
101    @Override
102    final List<RelatedTopicModelImpl> getRelatedTopics(List assocTypeUris, String myRoleTypeUri,
103                                                                                           String othersRoleTypeUri,
104                                                                                           String othersTopicTypeUri) {
105        return pl.fetchTopicRelatedTopics(id, assocTypeUris, myRoleTypeUri, othersRoleTypeUri, othersTopicTypeUri);
106    }
107
108    // ---
109
110    @Override
111    final void storeUri() {
112        pl.storeTopicUri(id, uri);
113    }
114
115    @Override
116    final void storeTypeUri() {
117        reassignInstantiation();
118        pl.storeTopicTypeUri(id, typeUri);
119    }
120
121    @Override
122    final void storeSimpleValue() {
123        TypeModel type = getType();
124        pl.storeTopicValue(id, value, type.getIndexModes(), type.getUri(), getIndexValue());
125    }
126
127    @Override
128    final void indexSimpleValue(IndexMode indexMode) {
129        pl.indexTopicValue(id, indexMode, typeUri, getIndexValue());
130    }
131
132    @Override
133    final void storeProperty(String propUri, Object propValue, boolean addToIndex) {
134        pl.storeTopicProperty(id, propUri, propValue, addToIndex);
135    }
136
137    @Override
138    final void removeProperty(String propUri) {
139        pl.removeTopicProperty(id, propUri);
140    }
141
142    // ---
143
144    @Override
145    final void _delete() {
146        pl._deleteTopic(id);
147    }
148
149    // ---
150
151    @Override
152    final void checkReadAccess() {
153        pl.checkTopicReadAccess(id);
154    }
155
156    @Override
157    final void checkWriteAccess() {
158        pl.checkTopicWriteAccess(id);
159    }
160
161    // ---
162
163    @Override
164    final DeepaMehtaEvent getPreUpdateEvent() {
165        return CoreEvent.PRE_UPDATE_TOPIC;
166    }
167
168    @Override
169    final DeepaMehtaEvent getPostUpdateEvent() {
170        return CoreEvent.POST_UPDATE_TOPIC;
171    }
172
173    @Override
174    final DeepaMehtaEvent getPreDeleteEvent() {
175        return CoreEvent.PRE_DELETE_TOPIC;
176    }
177
178    @Override
179    final DeepaMehtaEvent getPostDeleteEvent() {
180        return CoreEvent.POST_DELETE_TOPIC;
181    }
182
183    // ---
184
185    @Override
186    final Directive getUpdateDirective() {
187        return Directive.UPDATE_TOPIC;
188    }
189
190    @Override
191    final Directive getDeleteDirective() {
192        return Directive.DELETE_TOPIC;
193    }
194
195
196
197    // === Core Internal Hooks ===
198
199    @Override
200    void preDelete() {
201        if (typeUri.equals("dm4.core.topic_type") || typeUri.equals("dm4.core.assoc_type")) {
202            throw new RuntimeException("Tried to delete a type with a generic delete-topic call. " +
203                "Use a delete-type call instead.");
204        }
205    }
206
207
208
209    // ===
210
211    TopicModelImpl findChildTopic(String topicTypeUri) {
212        try {
213            if (typeUri.equals(topicTypeUri)) {
214                return this;
215            }
216            //
217            for (AssociationDefinitionModel assocDef : getType().getAssocDefs()) {
218                String assocDefUri    = assocDef.getAssocDefUri();
219                String cardinalityUri = assocDef.getChildCardinalityUri();
220                TopicModelImpl childTopic = null;
221                if (cardinalityUri.equals("dm4.core.one")) {
222                    childTopic = childTopics.getTopicOrNull(assocDefUri);                                // no DB access
223                } else if (cardinalityUri.equals("dm4.core.many")) {
224                    List<RelatedTopicModelImpl> _childTopics = childTopics.getTopicsOrNull(assocDefUri); // no DB access
225                    if (_childTopics != null && !_childTopics.isEmpty()) {
226                        childTopic = _childTopics.get(0);
227                    }
228                } else {
229                    throw new RuntimeException("\"" + cardinalityUri + "\" is an unexpected cardinality URI");
230                }
231                // Note: topics just created have no child topics yet
232                if (childTopic == null) {
233                    continue;
234                }
235                // recursion
236                childTopic = childTopic.findChildTopic(topicTypeUri);
237                if (childTopic != null) {
238                    return childTopic;
239                }
240            }
241            return null;
242        } catch (Exception e) {
243            throw new RuntimeException("Searching topic " + id + " for \"" + topicTypeUri + "\" failed", e);
244        }
245    }
246
247
248
249    // ------------------------------------------------------------------------------------------------- Private Methods
250
251    private void reassignInstantiation() {
252        // remove current assignment
253        fetchInstantiation().delete();
254        // create new assignment
255        pl.createTopicInstantiation(id, typeUri);
256    }
257
258    // Note: this method works only for instances, not for types.
259    // This is because a type is not of type "dm4.core.topic_type" but of type "dm4.core.meta_type".
260    private AssociationModelImpl fetchInstantiation() {
261        RelatedTopicModelImpl topicType = getRelatedTopic("dm4.core.instantiation", "dm4.core.instance",
262            "dm4.core.type", "dm4.core.topic_type");
263        //
264        if (topicType == null) {
265            throw new RuntimeException("Topic " + id + " is not associated to a topic type");
266        }
267        //
268        return topicType.getRelatingAssociation();
269    }
270}