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