001package systems.dmx.contacts.migrations;
002
003import systems.dmx.core.Topic;
004import systems.dmx.core.model.AssociationDefinitionModel;
005import systems.dmx.core.model.AssociationTypeModel;
006import systems.dmx.core.model.ChildTopicsModel;
007import systems.dmx.core.service.Migration;
008
009import java.util.ArrayList;
010import java.util.List;
011import java.util.logging.Logger;
012
013
014
015/**
016 * Changes Contacts model and converts content.
017 * Runs only in UPDATE mode.
018 * <p>
019 * Part of DM 4.6
020 */
021public class Migration2 extends Migration {
022
023    // ---------------------------------------------------------------------------------------------- Instance Variables
024
025    private List<Entry> phoneEntries = new ArrayList();
026    private List<Entry> addressEntries = new ArrayList();
027
028    private Logger logger = Logger.getLogger(getClass().getName());
029
030    // -------------------------------------------------------------------------------------------------- Public Methods
031
032    @Override
033    public void run() {
034        logger.info("########## Converting Phone Entry and Address Entry topics");
035        //
036        // 1) prepare
037        //
038        bufferContentAndDeleteTypes();
039        //
040        // 2) change model
041        //
042        dmx.createAssociationType(mf.newAssociationTypeModel("dmx.contacts.phone_entry", "Phone Entry",
043            "dmx.core.identity")
044            .addAssocDef(mf.newAssociationDefinitionModel("dmx.core.aggregation_def",
045            "dmx.contacts.phone_entry", "dmx.contacts.phone_label", "dmx.core.many", "dmx.core.one")));
046        dmx.createAssociationType(mf.newAssociationTypeModel("dmx.contacts.address_entry", "Address Entry",
047            "dmx.core.identity")
048            .addAssocDef(mf.newAssociationDefinitionModel("dmx.core.aggregation_def",
049            "dmx.contacts.address_entry", "dmx.contacts.address_label", "dmx.core.many", "dmx.core.one")));
050        dmx.getTopicType("dmx.contacts.person")
051            .addAssocDefBefore(
052                mf.newAssociationDefinitionModel("dmx.core.composition_def", "dmx.contacts.phone_entry", false, false,
053                "dmx.contacts.person", "dmx.contacts.phone_number", "dmx.core.one", "dmx.core.many"),
054            "dmx.contacts.email_address")
055            .addAssocDefBefore(
056                mf.newAssociationDefinitionModel("dmx.core.composition_def", "dmx.contacts.address_entry", false, false,
057                "dmx.contacts.person", "dmx.contacts.address", "dmx.core.one", "dmx.core.many"),
058            "dmx.contacts.notes");
059        dmx.getTopicType("dmx.contacts.institution")
060            .addAssocDefBefore(
061                mf.newAssociationDefinitionModel("dmx.core.composition_def", "dmx.contacts.phone_entry", false, false,
062                "dmx.contacts.institution", "dmx.contacts.phone_number", "dmx.core.one", "dmx.core.many"),
063            "dmx.contacts.email_address")
064            .addAssocDefBefore(
065                mf.newAssociationDefinitionModel("dmx.core.composition_def", "dmx.contacts.address_entry", false, false,
066                "dmx.contacts.institution", "dmx.contacts.address", "dmx.core.one", "dmx.core.many"),
067            "dmx.contacts.notes");
068        //
069        // 3) convert content
070        //
071        for (Entry entry : phoneEntries)   convertPhoneEntry(entry);
072        for (Entry entry : addressEntries) convertAddressEntry(entry);
073        //
074        logger.info("########## Converting Phone Entry and Address Entry topics complete\n    " +
075            "Phone entries converted: " + phoneEntries.size() + "\n    " +
076            "Address entries converted: " + addressEntries.size());
077    }
078
079    // ------------------------------------------------------------------------------------------------- Private Methods
080
081    private void bufferContentAndDeleteTypes() {
082        //
083        // 1) buffer entry topic content in memory
084        //
085        // Note: the actual conversion (as performed later) relies on the buffered content
086        for (Topic phoneEntry   : dmx.getTopicsByType("dmx.contacts.phone_entry"))   bufferPhoneEntry(phoneEntry);
087        for (Topic addressEntry : dmx.getTopicsByType("dmx.contacts.address_entry")) bufferAddressEntry(addressEntry);
088        //
089        // 2) temporarily change entry types
090        //
091        // Note: we change comp_def to aggr_def to avoid deleting childs when deleting the entry topics (next step).
092        // The childs are the Phone and Address topics we want keep and reassign later (while the actual conversion).
093        dmx.getTopicType("dmx.contacts.phone_entry").getAssocDef("dmx.contacts.phone_number")
094            .setTypeUri("dmx.core.aggregation_def");
095        dmx.getTopicType("dmx.contacts.address_entry").getAssocDef("dmx.contacts.address")
096            .setTypeUri("dmx.core.aggregation_def");
097        //
098        // 3) delete entry topics
099        //
100        // Note: deleting the entry types (next step) requires to delete all instances before.
101        for (Entry entry : phoneEntries)   entry.topic.delete();
102        for (Entry entry : addressEntries) entry.topic.delete();
103        //
104        // 4) delete entry types
105        //
106        // Note: the entry topic types must be deleted as they are recreated as association types with the same URI.
107        dmx.deleteTopicType("dmx.contacts.phone_entry");
108        dmx.deleteTopicType("dmx.contacts.address_entry");
109    }
110
111    // ---
112
113    private void bufferPhoneEntry(Topic phoneEntry) {
114        Topic parent = phoneEntry.getRelatedTopic("dmx.core.composition", "dmx.core.child", "dmx.core.parent", null);
115        Topic phoneLabel  = phoneEntry.getChildTopics().getTopic("dmx.contacts.phone_label");
116        Topic phoneNumber = phoneEntry.getChildTopics().getTopic("dmx.contacts.phone_number");
117        phoneEntries.add(new Entry(phoneEntry, parent, phoneLabel.getId(), phoneNumber.getId()));
118    }
119
120    private void bufferAddressEntry(Topic addressEntry) {
121        Topic parent = addressEntry.getRelatedTopic("dmx.core.composition", "dmx.core.child", "dmx.core.parent", null);
122        Topic addressLabel = addressEntry.getChildTopics().getTopic("dmx.contacts.address_label");
123        Topic address      = addressEntry.getChildTopics().getTopic("dmx.contacts.address");
124        addressEntries.add(new Entry(addressEntry, parent, addressLabel.getId(), address.getId()));
125    }
126
127    // ---
128
129    private void convertPhoneEntry(Entry entry) {
130        entry.parent.getChildTopics().addRef("dmx.contacts.phone_number", entry.objectId, mf.newChildTopicsModel()
131            .putRef("dmx.contacts.phone_label", entry.labelId));
132    }
133
134    private void convertAddressEntry(Entry entry) {
135        entry.parent.getChildTopics().addRef("dmx.contacts.address", entry.objectId, mf.newChildTopicsModel()
136            .putRef("dmx.contacts.address_label", entry.labelId));
137    }
138
139    // ---
140
141    private class Entry {
142
143        private Topic topic;
144        private Topic parent;
145        private long labelId;
146        private long objectId;
147
148        private Entry(Topic topic, Topic parent, long labelId, long objectId) {
149            this.topic = topic;
150            this.parent = parent;
151            this.labelId = labelId;
152            this.objectId = objectId;
153        }
154    }
155}