001    package de.deepamehta.plugins.contacts.migrations;
002    
003    import de.deepamehta.core.Topic;
004    import de.deepamehta.core.model.AssociationDefinitionModel;
005    import de.deepamehta.core.model.AssociationTypeModel;
006    import de.deepamehta.core.model.ChildTopicsModel;
007    import de.deepamehta.core.service.Migration;
008    
009    import java.util.ArrayList;
010    import java.util.List;
011    import 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     */
021    public 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            dms.createAssociationType(new AssociationTypeModel("dm4.contacts.phone_entry", "Phone Entry",
043                "dm4.core.composite")
044                .addAssocDef(new AssociationDefinitionModel("dm4.core.aggregation_def",
045                "dm4.contacts.phone_entry", "dm4.contacts.phone_label", "dm4.core.many", "dm4.core.one")));
046            dms.createAssociationType(new AssociationTypeModel("dm4.contacts.address_entry", "Address Entry",
047                "dm4.core.composite")
048                .addAssocDef(new AssociationDefinitionModel("dm4.core.aggregation_def",
049                "dm4.contacts.address_entry", "dm4.contacts.address_label", "dm4.core.many", "dm4.core.one")));
050            dms.getTopicType("dm4.contacts.person")
051                .addAssocDefBefore(new AssociationDefinitionModel("dm4.core.composition_def", "dm4.contacts.phone_entry",
052                "dm4.contacts.person", "dm4.contacts.phone_number", "dm4.core.one", "dm4.core.many"),
053                "dm4.contacts.email_address")
054                .addAssocDefBefore(new AssociationDefinitionModel("dm4.core.composition_def", "dm4.contacts.address_entry",
055                "dm4.contacts.person", "dm4.contacts.address", "dm4.core.one", "dm4.core.many"),
056                "dm4.contacts.notes");
057            dms.getTopicType("dm4.contacts.institution")
058                .addAssocDefBefore(new AssociationDefinitionModel("dm4.core.composition_def", "dm4.contacts.phone_entry",
059                "dm4.contacts.institution", "dm4.contacts.phone_number", "dm4.core.one", "dm4.core.many"),
060                "dm4.contacts.email_address")
061                .addAssocDefBefore(new AssociationDefinitionModel("dm4.core.composition_def", "dm4.contacts.address_entry",
062                "dm4.contacts.institution", "dm4.contacts.address", "dm4.core.one", "dm4.core.many"),
063                "dm4.contacts.notes");
064            //
065            // 3) convert content
066            //
067            for (Entry entry : phoneEntries)   convertPhoneEntry(entry);
068            for (Entry entry : addressEntries) convertAddressEntry(entry);
069            //
070            logger.info("########## Converting Phone Entry and Address Entry topics complete.\n    " +
071                "Phone entries converted: " + phoneEntries.size() + "\n    " +
072                "Address entries converted: " + addressEntries.size());
073        }
074    
075        // ------------------------------------------------------------------------------------------------- Private Methods
076    
077        private void bufferContentAndDeleteTypes() {
078            //
079            // 1) buffer entry topic content in memory
080            //
081            // Note: the actual conversion (as performed later) relies on the buffered content
082            for (Topic phoneEntry   : dms.getTopics("dm4.contacts.phone_entry", 0))   bufferPhoneEntry(phoneEntry);
083            for (Topic addressEntry : dms.getTopics("dm4.contacts.address_entry", 0)) bufferAddressEntry(addressEntry);
084            //
085            // 2) temporarily change entry types
086            //
087            // Note: we change comp_def to aggr_def to avoid deleting childs when deleting the entry topics (next step).
088            // The childs are the Phone and Address topics we want keep and reassign later (while the actual conversion).
089            dms.getTopicType("dm4.contacts.phone_entry").getAssocDef("dm4.contacts.phone_number")
090                .setTypeUri("dm4.core.aggregation_def");
091            dms.getTopicType("dm4.contacts.address_entry").getAssocDef("dm4.contacts.address")
092                .setTypeUri("dm4.core.aggregation_def");
093            //
094            // 3) delete entry topics
095            //
096            // Note: deleting the entry types (next step) requires to delete all instances before.
097            for (Entry entry : phoneEntries)   entry.topic.delete();
098            for (Entry entry : addressEntries) entry.topic.delete();
099            //
100            // 4) delete entry types
101            //
102            // Note: the entry topic types must be deleted as they are recreated as association types with the same URI.
103            dms.deleteTopicType("dm4.contacts.phone_entry");
104            dms.deleteTopicType("dm4.contacts.address_entry");
105        }
106    
107        // ---
108    
109        private void bufferPhoneEntry(Topic phoneEntry) {
110            Topic parent = phoneEntry.getRelatedTopic("dm4.core.composition", "dm4.core.child", "dm4.core.parent", null);
111            Topic phoneLabel  = phoneEntry.getChildTopics().getTopic("dm4.contacts.phone_label");
112            Topic phoneNumber = phoneEntry.getChildTopics().getTopic("dm4.contacts.phone_number");
113            phoneEntries.add(new Entry(phoneEntry, parent, phoneLabel.getId(), phoneNumber.getId()));
114        }
115    
116        private void bufferAddressEntry(Topic addressEntry) {
117            Topic parent = addressEntry.getRelatedTopic("dm4.core.composition", "dm4.core.child", "dm4.core.parent", null);
118            Topic addressLabel = addressEntry.getChildTopics().getTopic("dm4.contacts.address_label");
119            Topic address      = addressEntry.getChildTopics().getTopic("dm4.contacts.address");
120            addressEntries.add(new Entry(addressEntry, parent, addressLabel.getId(), address.getId()));
121        }
122    
123        // ---
124    
125        private void convertPhoneEntry(Entry entry) {
126            entry.parent.getChildTopics().addRef("dm4.contacts.phone_number", entry.objectId, new ChildTopicsModel()
127                .putRef("dm4.contacts.phone_label", entry.labelId));
128        }
129    
130        private void convertAddressEntry(Entry entry) {
131            entry.parent.getChildTopics().addRef("dm4.contacts.address", entry.objectId, new ChildTopicsModel()
132                .putRef("dm4.contacts.address_label", entry.labelId));
133        }
134    
135        // ---
136    
137        private class Entry {
138    
139            private Topic topic;
140            private Topic parent;
141            private long labelId;
142            private long objectId;
143    
144            private Entry(Topic topic, Topic parent, long labelId, long objectId) {
145                this.topic = topic;
146                this.parent = parent;
147                this.labelId = labelId;
148                this.objectId = objectId;
149            }
150        }
151    }