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.ChildTopicsModel;
010    import de.deepamehta.core.model.RelatedAssociationModel;
011    import de.deepamehta.core.model.RelatedTopicModel;
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            _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    }