001package systems.dmx.core.impl;
002
003import systems.dmx.core.model.RelatedTopicModel;
004import systems.dmx.core.model.SimpleValue;
005import systems.dmx.core.model.TopicModel;
006import systems.dmx.core.model.TopicReferenceModel;
007
008import java.util.List;
009
010
011
012class TopicReferenceModelImpl extends RelatedTopicModelImpl implements TopicReferenceModel {
013
014    // ---------------------------------------------------------------------------------------------------- Constructors
015
016    TopicReferenceModelImpl(RelatedTopicModelImpl relatedTopic) {
017        super(relatedTopic);
018    }
019
020    // -------------------------------------------------------------------------------------------------- Public Methods
021
022    @Override
023    public boolean isReferenceById() {
024        return getId() != -1;
025    }
026
027    @Override
028    public boolean isReferenceByUri() {
029        return getUri() != null && !getUri().equals("");
030    }
031
032    @Override
033    public boolean isEmptyRef() {
034        return !isReferenceById() && !isReferenceByUri();
035    }
036
037    // ---
038
039    @Override
040    public boolean isReferingTo(TopicModel topic) {
041        if (isReferenceById()) {
042            return getId() == topic.getId();
043        } else if (isReferenceByUri()) {
044            return getUri().equals(topic.getUri());
045        } else {
046            throw new RuntimeException("Invalid " + this);
047        }
048    }
049
050    @Override
051    public RelatedTopicModelImpl findReferencedTopic(List<? extends RelatedTopicModel> topics) {
052        for (RelatedTopicModel topic : topics) {
053            if (isReferingTo(topic)) {
054                return (RelatedTopicModelImpl) topic;
055            }
056        }
057        return null;
058    }
059
060    // ----------------------------------------------------------------------------------------- Package Private Methods
061
062    @Override
063    String className() {
064        return "topic reference";
065    }
066
067    // ---
068
069    /**
070     * Resolves this reference and replaces it by the resolved topic.
071     *
072     * TODO: don't manipulate in-place?
073     *
074     * @throws  RuntimeException    if retrieval of the refered topic fails
075     * @throws  RuntimeException    if this reference refers to nothing
076     */
077    TopicModelImpl resolve() {
078        try {
079            TopicModelImpl topic;
080            // Note: the resolved topic must be fetched including its child topics.
081            // They might be required for label calculation and/or at client-side. ### TODO?
082            if (isReferenceById()) {
083                topic = pl.fetchTopic(id);    // .loadChildTopics();  // TODO?
084            } else if (isReferenceByUri()) {
085                topic = pl.fetchTopic("uri", new SimpleValue(uri));
086                if (topic == null) {
087                    throw new RuntimeException("Topic with URI \"" + uri + "\" not found");
088                }
089                // .loadChildTopics();  // TODO?
090            } else {
091                throw new RuntimeException("Invalid " + this);
092            }
093            // TODO: why is set() required?
094            // Without it the custom assoc type refs in the type cache are unresolved (ID=-1) after bootstrap
095            this.set(topic);
096            return topic;
097        } catch (Exception e) {
098            throw new RuntimeException("Resolving a topic reference failed (" + this + ")", e);
099        }
100    }
101}