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