001    package de.deepamehta.core.model;
002    
003    import org.codehaus.jettison.json.JSONObject;
004    
005    import java.util.ArrayList;
006    import java.util.Collection;
007    import java.util.List;
008    import java.util.Map;
009    import java.util.logging.Logger;
010    
011    
012    
013    /**
014     * Definition of an association between 2 topic types -- part of DeepaMehta's type system,
015     * like an association in a class diagram. Used to represent both, aggregations and compositions.
016     * ### FIXDOC: also assoc types have assoc defs
017     *
018     * @author <a href="mailto:jri@deepamehta.de">Jörg Richter</a>
019     */
020    public class AssociationDefinitionModel extends AssociationModel {
021    
022        // ---------------------------------------------------------------------------------------------- Instance Variables
023    
024        private String instanceLevelAssocTypeUri;       // derived, not serialized
025    
026        private String parentTypeUri;                   // derived, not serialized
027        private String childTypeUri;                    // derived, not serialized
028    
029        private String parentCardinalityUri;
030        private String childCardinalityUri;
031    
032        private ViewConfigurationModel viewConfigModel; // is never null
033    
034        private Logger logger = Logger.getLogger(getClass().getName());
035    
036        // ---------------------------------------------------------------------------------------------------- Constructors
037    
038        public AssociationDefinitionModel(String typeUri, String parentTypeUri, String childTypeUri,
039                                                          String parentCardinalityUri, String childCardinalityUri) {
040            this(-1, null, typeUri, parentTypeUri, childTypeUri, parentCardinalityUri, childCardinalityUri, null);
041        }
042    
043        public AssociationDefinitionModel(long id, String uri, String typeUri, String parentTypeUri, String childTypeUri,
044                                                               String parentCardinalityUri, String childCardinalityUri,
045                                                               ViewConfigurationModel viewConfigModel) {
046            super(id, uri, typeUri, parentRoleModel(parentTypeUri), childRoleModel(childTypeUri));
047            //
048            this.instanceLevelAssocTypeUri = instanceLevelAssocTypeUri(typeUri);
049            //
050            this.parentTypeUri = parentTypeUri;
051            this.childTypeUri = childTypeUri;
052            //
053            this.parentCardinalityUri = parentCardinalityUri;
054            this.childCardinalityUri = childCardinalityUri;
055            //
056            this.viewConfigModel = viewConfigModel != null ? viewConfigModel : new ViewConfigurationModel();
057        }
058    
059        // -------------------------------------------------------------------------------------------------- Public Methods
060    
061        public String getInstanceLevelAssocTypeUri() {
062            return instanceLevelAssocTypeUri;
063        }
064    
065        public String getParentTypeUri() {
066            return parentTypeUri;
067        }
068    
069        public String getChildTypeUri() {
070            return childTypeUri;
071        }
072    
073        public String getParentCardinalityUri() {
074            return parentCardinalityUri;
075        }
076    
077        public String getChildCardinalityUri() {
078            return childCardinalityUri;
079        }
080    
081        public ViewConfigurationModel getViewConfigModel() {
082            return viewConfigModel;
083        }
084    
085        // ---
086    
087        @Override
088        public void setTypeUri(String typeUri) {
089            super.setTypeUri(typeUri);
090            this.instanceLevelAssocTypeUri = instanceLevelAssocTypeUri(typeUri);
091        }
092    
093        public void setParentCardinalityUri(String parentCardinalityUri) {
094            this.parentCardinalityUri = parentCardinalityUri;
095        }
096    
097        public void setChildCardinalityUri(String childCardinalityUri) {
098            this.childCardinalityUri = childCardinalityUri;
099        }
100    
101        public void setViewConfigModel(ViewConfigurationModel viewConfigModel) {
102            this.viewConfigModel = viewConfigModel;
103        }
104    
105        // ---
106    
107        public JSONObject toJSON() {
108            try {
109                JSONObject o = super.toJSON();
110                o.put("parent_cardinality_uri", parentCardinalityUri);
111                o.put("child_cardinality_uri", childCardinalityUri);
112                viewConfigModel.toJSON(o);
113                return o;
114            } catch (Exception e) {
115                throw new RuntimeException("Serialization failed (" + this + ")", e);
116            }
117        }
118    
119        // ---
120    
121        @Override
122        public String toString() {
123            return "\n    association definition (" + super.toString() +
124                ",\n        parent cardinality=\"" + parentCardinalityUri +
125                "\",\n        child cardinality=\"" + childCardinalityUri +
126                "\",\n        " + viewConfigModel + ")\n";
127        }
128    
129        // ----------------------------------------------------------------------------------------- Package Private Methods
130    
131        static AssociationDefinitionModel fromJSON(JSONObject assocDef, String parentTypeUri) {
132            try {
133                long id             = assocDef.optLong("id", -1);
134                String uri          = null;
135                String typeUri      = assocDef.getString("assoc_type_uri");
136                String childTypeUri = assocDef.getString("child_type_uri");
137                //
138                if (!assocDef.has("parent_cardinality_uri") && !typeUri.equals("dm4.core.composition_def")) {
139                    throw new RuntimeException("\"parent_cardinality_uri\" is missing");
140                }
141                String parentCardinalityUri = assocDef.optString("parent_cardinality_uri", "dm4.core.one");
142                String childCardinalityUri  = assocDef.getString("child_cardinality_uri");
143                //
144                ViewConfigurationModel viewConfigModel = new ViewConfigurationModel(assocDef);
145                //
146                return new AssociationDefinitionModel(id, uri, typeUri, parentTypeUri, childTypeUri,
147                    parentCardinalityUri, childCardinalityUri, viewConfigModel);
148            } catch (Exception e) {
149                throw new RuntimeException("Parsing AssociationDefinitionModel failed (JSONObject=" + assocDef + ")", e);
150            }
151        }
152    
153        static void toJSON(Collection<AssociationDefinitionModel> assocDefs, JSONObject o) throws Exception {
154            List assocDefList = new ArrayList();
155            for (AssociationDefinitionModel assocDef : assocDefs) {
156                assocDefList.add(assocDef.toJSON());
157            }
158            o.put("assoc_defs", assocDefList);
159        }
160    
161        // ------------------------------------------------------------------------------------------------- Private Methods
162    
163        private static TopicRoleModel parentRoleModel(String parentTypeUri) {
164            return new TopicRoleModel(parentTypeUri, "dm4.core.parent_type");
165        }
166    
167        private static TopicRoleModel childRoleModel(String childTypeUri) {
168            return new TopicRoleModel(childTypeUri,  "dm4.core.child_type");
169        }
170    
171        // ---
172    
173        private String instanceLevelAssocTypeUri(String typeUri) {
174            if (typeUri.equals("dm4.core.aggregation_def")) {
175                return "dm4.core.aggregation";
176            } else if (typeUri.equals("dm4.core.composition_def")) {
177                return "dm4.core.composition";
178            } else {
179                throw new RuntimeException("Unexpected association type URI: \"" + typeUri + "\"");
180            }
181        }
182    }