001package de.deepamehta.core.impl;
002
003import de.deepamehta.core.Association;
004import de.deepamehta.core.RelatedAssociation;
005import de.deepamehta.core.RelatedTopic;
006import de.deepamehta.core.Topic;
007import de.deepamehta.core.TopicType;
008import de.deepamehta.core.model.AssociationModel;
009import de.deepamehta.core.model.ChildTopicsModel;
010import de.deepamehta.core.model.RelatedAssociationModel;
011import de.deepamehta.core.model.RelatedTopicModel;
012import de.deepamehta.core.model.TopicModel;
013import de.deepamehta.core.service.Directive;
014import de.deepamehta.core.service.Directives;
015import de.deepamehta.core.service.ResultList;
016
017import java.util.List;
018import java.util.logging.Logger;
019
020
021
022/**
023 * A topic that is attached to the {@link DeepaMehtaService}.
024 */
025class AttachedTopic extends AttachedDeepaMehtaObject implements Topic {
026
027    // ---------------------------------------------------------------------------------------------- Instance Variables
028
029    private Logger logger = Logger.getLogger(getClass().getName());
030
031    // ---------------------------------------------------------------------------------------------------- Constructors
032
033    AttachedTopic(TopicModel model, EmbeddedService dms) {
034        super(model, dms);
035    }
036
037    // -------------------------------------------------------------------------------------------------- Public Methods
038
039
040
041    // ******************************************
042    // *** AttachedDeepaMehtaObject Overrides ***
043    // ******************************************
044
045
046
047    // === Updating ===
048
049    @Override
050    public void update(TopicModel model) {
051        _update(model);
052        //
053        dms.fireEvent(CoreEvent.POST_UPDATE_TOPIC_REQUEST, this);
054    }
055
056
057
058    // === Deletion ===
059
060    @Override
061    public void delete() {
062        try {
063            dms.fireEvent(CoreEvent.PRE_DELETE_TOPIC, this);
064            //
065            // delete sub-topics and associations
066            super.delete();
067            // delete topic itself
068            logger.info("Deleting " + this);
069            Directives.get().add(Directive.DELETE_TOPIC, this);
070            dms.storageDecorator.deleteTopic(getId());
071            //
072            dms.fireEvent(CoreEvent.POST_DELETE_TOPIC, this);
073        } catch (Exception e) {
074            throw new RuntimeException("Deleting topic failed (" + this + ")", e);
075        }
076    }
077
078
079
080    // ****************************
081    // *** Topic Implementation ***
082    // ****************************
083
084
085
086    @Override
087    public Topic loadChildTopics() {
088        return (Topic) super.loadChildTopics();
089    }
090
091    @Override
092    public Topic loadChildTopics(String childTypeUri) {
093        return (Topic) super.loadChildTopics(childTypeUri);
094    }
095
096    // ---
097
098    @Override
099    public TopicModel getModel() {
100        return (TopicModel) super.getModel();
101    }
102
103
104
105    // ***************************************
106    // *** DeepaMehtaObject Implementation ***
107    // ***************************************
108
109
110
111    // === Traversal ===
112
113    // --- Topic Retrieval ---
114
115    @Override
116    public ResultList<RelatedTopic> getRelatedTopics(List assocTypeUris, String myRoleTypeUri, String othersRoleTypeUri,
117                                                     String othersTopicTypeUri, int maxResultSize) {
118        ResultList<RelatedTopicModel> topics = dms.storageDecorator.fetchTopicRelatedTopics(getId(),
119            assocTypeUris, myRoleTypeUri, othersRoleTypeUri, othersTopicTypeUri, maxResultSize);
120        return dms.instantiateRelatedTopics(topics);
121    }
122
123    // --- Association Retrieval ---
124
125    @Override
126    public RelatedAssociation getRelatedAssociation(String assocTypeUri, String myRoleTypeUri,
127                                                    String othersRoleTypeUri, String othersAssocTypeUri) {
128        RelatedAssociationModel assoc = dms.storageDecorator.fetchTopicRelatedAssociation(getId(),
129            assocTypeUri, myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri);
130        return assoc != null ? dms.instantiateRelatedAssociation(assoc) : null;
131    }
132
133    @Override
134    public ResultList<RelatedAssociation> getRelatedAssociations(String assocTypeUri, String myRoleTypeUri,
135                                                                 String othersRoleTypeUri, String othersAssocTypeUri) {
136        ResultList<RelatedAssociationModel> assocs = dms.storageDecorator.fetchTopicRelatedAssociations(getId(),
137            assocTypeUri, myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri);
138        return dms.instantiateRelatedAssociations(assocs);
139    }
140
141    // ---
142
143    @Override
144    public Association getAssociation(String assocTypeUri, String myRoleTypeUri, String othersRoleTypeUri,
145                                                                                   long othersTopicId) {
146        AssociationModel assoc = dms.storageDecorator.fetchAssociation(assocTypeUri, getId(), othersTopicId,
147            myRoleTypeUri, othersRoleTypeUri);
148        return assoc != null ? dms.instantiateAssociation(assoc) : null;
149    }
150
151    @Override
152    public List<Association> getAssociations() {
153        return dms.instantiateAssociations(dms.storageDecorator.fetchTopicAssociations(getId()));
154    }
155
156
157
158    // === Properties ===
159
160    @Override
161    public void setProperty(String propUri, Object propValue, boolean addToIndex) {
162        dms.storageDecorator.storeTopicProperty(getId(), propUri, propValue, addToIndex);
163    }
164
165    @Override
166    public void removeProperty(String propUri) {
167        dms.storageDecorator.removeTopicProperty(getId(), propUri);
168    }
169
170
171
172    // ----------------------------------------------------------------------------------------- Package Private Methods
173
174    /**
175     * Low-level update method which does not fire the POST_UPDATE_TOPIC_REQUEST event.
176     * <p>
177     * Called multiple times while updating the child topics (see AttachedChildTopics).
178     * POST_UPDATE_TOPIC_REQUEST on the other hand must be fired only once (per update request).
179     */
180    void _update(TopicModel model) {
181        logger.info("Updating topic " + getId() + " (new " + model + ")");
182        //
183        dms.fireEvent(CoreEvent.PRE_UPDATE_TOPIC, this, model);
184        //
185        TopicModel oldModel = getModel().clone();
186        super.update(model);
187        //
188        dms.fireEvent(CoreEvent.POST_UPDATE_TOPIC, this, model, oldModel);
189    }
190
191
192
193    // === Implementation of the abstract methods ===
194
195    @Override
196    String className() {
197        return "topic";
198    }
199
200    @Override
201    void updateChildTopics(ChildTopicsModel childTopics) {
202        update(new TopicModel(childTopics));
203    }
204
205    @Override
206    Directive getUpdateDirective() {
207        return Directive.UPDATE_TOPIC;
208    }
209
210    @Override
211    final void storeUri() {
212        dms.storageDecorator.storeTopicUri(getId(), getUri());
213    }
214
215    @Override
216    final void storeTypeUri() {
217        reassignInstantiation();
218        dms.storageDecorator.storeTopicTypeUri(getId(), getTypeUri());
219    }
220
221    // ---
222
223    @Override
224    final RelatedTopicModel fetchRelatedTopic(String assocTypeUri, String myRoleTypeUri,
225                                              String othersRoleTypeUri, String othersTopicTypeUri) {
226        return dms.storageDecorator.fetchTopicRelatedTopic(getId(), assocTypeUri, myRoleTypeUri, othersRoleTypeUri,
227            othersTopicTypeUri);
228    }
229
230    @Override
231    final ResultList<RelatedTopicModel> fetchRelatedTopics(String assocTypeUri, String myRoleTypeUri,
232                                                           String othersRoleTypeUri, String othersTopicTypeUri,
233                                                           int maxResultSize) {
234        return dms.storageDecorator.fetchTopicRelatedTopics(getId(), assocTypeUri, myRoleTypeUri, othersRoleTypeUri,
235            othersTopicTypeUri, maxResultSize);
236    }
237
238    // ---
239
240    @Override
241    TopicType getType() {
242        return dms.getTopicType(getTypeUri());
243    }
244
245
246
247    // ------------------------------------------------------------------------------------------------- Private Methods
248
249    private void reassignInstantiation() {
250        // remove current assignment
251        fetchInstantiation().delete();
252        // create new assignment
253        dms.createTopicInstantiation(getId(), getTypeUri());
254    }
255
256    // Note: this method works only for instances, not for types.
257    // This is because a type is not of type "dm4.core.topic_type" but of type "dm4.core.meta_type".
258    private Association fetchInstantiation() {
259        RelatedTopic topicType = getRelatedTopic("dm4.core.instantiation", "dm4.core.instance", "dm4.core.type",
260            "dm4.core.topic_type");
261        //
262        if (topicType == null) {
263            throw new RuntimeException("Topic " + getId() + " is not associated to a topic type");
264        }
265        //
266        return topicType.getRelatingAssociation();
267    }
268}