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