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    // ---
157
158    @Override
159    final DeepaMehtaEvent getPreUpdateEvent() {
160        return CoreEvent.PRE_UPDATE_TOPIC;
161    }
162
163    @Override
164    final DeepaMehtaEvent getPostUpdateEvent() {
165        return CoreEvent.POST_UPDATE_TOPIC;
166    }
167
168    @Override
169    final DeepaMehtaEvent getPreDeleteEvent() {
170        return CoreEvent.PRE_DELETE_TOPIC;
171    }
172
173    @Override
174    final DeepaMehtaEvent getPostDeleteEvent() {
175        return CoreEvent.POST_DELETE_TOPIC;
176    }
177
178    // ---
179
180    @Override
181    final Directive getUpdateDirective() {
182        return Directive.UPDATE_TOPIC;
183    }
184
185    @Override
186    final Directive getDeleteDirective() {
187        return Directive.DELETE_TOPIC;
188    }
189
190
191
192    // === Core Internal Hooks ===
193
194    @Override
195    void preDelete() {
196        if (typeUri.equals("dm4.core.topic_type") || typeUri.equals("dm4.core.assoc_type")) {
197            throw new RuntimeException("Tried to delete a type with a generic delete-topic call. " +
198                "Use a delete-type call instead.");
199        }
200    }
201
202
203
204    // ===
205
206    TopicModelImpl findChildTopic(String topicTypeUri) {
207        try {
208            if (typeUri.equals(topicTypeUri)) {
209                return this;
210            }
211            //
212            for (AssociationDefinitionModel assocDef : getType().getAssocDefs()) {
213                String assocDefUri    = assocDef.getAssocDefUri();
214                String cardinalityUri = assocDef.getChildCardinalityUri();
215                TopicModelImpl childTopic = null;
216                if (cardinalityUri.equals("dm4.core.one")) {
217                    childTopic = childTopics.getTopicOrNull(assocDefUri);                                // no DB access
218                } else if (cardinalityUri.equals("dm4.core.many")) {
219                    List<RelatedTopicModelImpl> _childTopics = childTopics.getTopicsOrNull(assocDefUri); // no DB access
220                    if (_childTopics != null && !_childTopics.isEmpty()) {
221                        childTopic = _childTopics.get(0);
222                    }
223                } else {
224                    throw new RuntimeException("\"" + cardinalityUri + "\" is an unexpected cardinality URI");
225                }
226                // Note: topics just created have no child topics yet
227                if (childTopic == null) {
228                    continue;
229                }
230                // recursion
231                childTopic = childTopic.findChildTopic(topicTypeUri);
232                if (childTopic != null) {
233                    return childTopic;
234                }
235            }
236            return null;
237        } catch (Exception e) {
238            throw new RuntimeException("Searching topic " + id + " for \"" + topicTypeUri + "\" failed", e);
239        }
240    }
241
242
243
244    // ------------------------------------------------------------------------------------------------- Private Methods
245
246    private void reassignInstantiation() {
247        // remove current assignment
248        fetchInstantiation().delete();
249        // create new assignment
250        pl.createTopicInstantiation(id, typeUri);
251    }
252
253    // Note: this method works only for instances, not for types.
254    // This is because a type is not of type "dm4.core.topic_type" but of type "dm4.core.meta_type".
255    private AssociationModelImpl fetchInstantiation() {
256        RelatedTopicModelImpl topicType = getRelatedTopic("dm4.core.instantiation", "dm4.core.instance",
257            "dm4.core.type", "dm4.core.topic_type");
258        //
259        if (topicType == null) {
260            throw new RuntimeException("Topic " + id + " is not associated to a topic type");
261        }
262        //
263        return topicType.getRelatingAssociation();
264    }
265}