001 package de.deepamehta.core.model; 002 003 import de.deepamehta.core.util.DeepaMehtaUtils; 004 005 import org.codehaus.jettison.json.JSONObject; 006 import org.codehaus.jettison.json.JSONArray; 007 008 import java.util.ArrayList; 009 import java.util.Collection; 010 import java.util.LinkedHashMap; 011 import java.util.List; 012 import java.util.Map; 013 import java.util.logging.Logger; 014 015 016 017 public abstract class TypeModel extends TopicModel { 018 019 // ---------------------------------------------------------------------------------------------- Instance Variables 020 021 private String dataTypeUri; 022 private List<IndexMode> indexModes; 023 private Map<String, AssociationDefinitionModel> assocDefs; // is never null, may be empty 024 private List<String> labelConfig; // is never null, may be empty 025 private ViewConfigurationModel viewConfig; // is never null 026 027 private Logger logger = Logger.getLogger(getClass().getName()); 028 029 // ---------------------------------------------------------------------------------------------------- Constructors 030 031 public TypeModel(String uri, String topicTypeUri, SimpleValue value, String dataTypeUri) { 032 super(uri, topicTypeUri, value); 033 this.dataTypeUri = dataTypeUri; 034 this.indexModes = new ArrayList(); 035 this.assocDefs = new LinkedHashMap(); 036 this.labelConfig = new ArrayList(); 037 this.viewConfig = new ViewConfigurationModel(); 038 } 039 040 public TypeModel(TopicModel topic, String dataTypeUri, List<IndexMode> indexModes, 041 List<AssociationDefinitionModel> assocDefs, List<String> labelConfig, 042 ViewConfigurationModel viewConfig) { 043 super(topic); 044 this.dataTypeUri = dataTypeUri; 045 this.indexModes = indexModes; 046 this.assocDefs = new LinkedHashMap(); 047 for (AssociationDefinitionModel assocDef : assocDefs) { 048 addAssocDef(assocDef); 049 } 050 this.labelConfig = labelConfig; 051 this.viewConfig = viewConfig; 052 } 053 054 public TypeModel(JSONObject typeModel, String typeUri) { 055 super(typeModel, typeUri); 056 try { 057 this.dataTypeUri = typeModel.getString("data_type_uri"); 058 this.indexModes = IndexMode.parse(typeModel); 059 this.assocDefs = new LinkedHashMap(); 060 this.labelConfig = parseLabelConfig(typeModel); 061 this.viewConfig = new ViewConfigurationModel(typeModel); 062 parseAssocDefs(typeModel); 063 } catch (Exception e) { 064 throw new RuntimeException("Parsing TypeModel failed (JSONObject=" + typeModel + ")", e); 065 } 066 } 067 068 // -------------------------------------------------------------------------------------------------- Public Methods 069 070 // === Data Type === 071 072 public String getDataTypeUri() { 073 return dataTypeUri; 074 } 075 076 public void setDataTypeUri(String dataTypeUri) { 077 this.dataTypeUri = dataTypeUri; 078 } 079 080 // === Index Modes === 081 082 public List<IndexMode> getIndexModes() { 083 return indexModes; 084 } 085 086 public void addIndexMode(IndexMode indexMode) { 087 indexModes.add(indexMode); 088 } 089 090 // === Association Definitions === 091 092 public Collection<AssociationDefinitionModel> getAssocDefs() { 093 return assocDefs.values(); 094 } 095 096 public AssociationDefinitionModel getAssocDef(String childTypeUri) { 097 AssociationDefinitionModel assocDef = assocDefs.get(childTypeUri); 098 if (assocDef == null) { 099 throw new RuntimeException("Schema violation: association definition \"" + 100 childTypeUri + "\" not found in " + this); 101 } 102 return assocDef; 103 } 104 105 public void addAssocDef(AssociationDefinitionModel assocDef) { 106 // error check ### FIXME: drop this check or provide proper feedback to the type editor user 107 if (!getDataTypeUri().equals("dm4.core.composite")) { 108 throw new RuntimeException("Association definitions can only be added to composite topic types. " + 109 "Topic type \"" + getUri() + "\" is of data type \"" + getDataTypeUri() + "\". (" + assocDef + ")"); 110 } 111 // error check 112 String childTypeUri = assocDef.getChildTypeUri(); 113 AssociationDefinitionModel existing = assocDefs.get(childTypeUri); 114 if (existing != null) { 115 throw new RuntimeException("Schema ambiguity: topic type \"" + uri + 116 "\" has more than one association definitions with uri \"" + childTypeUri + "\""); 117 } 118 // 119 updateAssocDef(assocDef); 120 } 121 122 public void updateAssocDef(AssociationDefinitionModel assocDef) { 123 assocDefs.put(assocDef.getChildTypeUri(), assocDef); 124 } 125 126 public AssociationDefinitionModel removeAssocDef(String childTypeUri) { 127 // error check 128 getAssocDef(childTypeUri); 129 // 130 return assocDefs.remove(childTypeUri); 131 } 132 133 public void removeAllAssocDefs() { 134 assocDefs.clear(); 135 } 136 137 // === Label Configuration === 138 139 public List<String> getLabelConfig() { 140 return labelConfig; 141 } 142 143 public void setLabelConfig(List<String> labelConfig) { 144 this.labelConfig = labelConfig; 145 } 146 147 // === View Configuration === 148 149 public ViewConfigurationModel getViewConfigModel() { 150 return viewConfig; 151 } 152 153 // FIXME: server-side operations on the view config settings possibly suggest they are not acually 154 // view config settings but part of the topic type model. Possibly this method should be dropped. 155 public Object getViewConfig(String typeUri, String settingUri) { 156 return viewConfig.getSetting(typeUri, settingUri); 157 } 158 159 public void setViewConfig(ViewConfigurationModel viewConfig) { 160 this.viewConfig = viewConfig; 161 } 162 163 164 165 // **************************** 166 // *** TopicModel Overrides *** 167 // **************************** 168 169 170 171 @Override 172 public JSONObject toJSON() { 173 try { 174 JSONObject o = super.toJSON(); 175 // 176 o.put("data_type_uri", getDataTypeUri()); 177 IndexMode.toJSON(indexModes, o); 178 AssociationDefinitionModel.toJSON(assocDefs.values(), o); 179 o.put("label_config", DeepaMehtaUtils.stringsToJson(getLabelConfig())); 180 getViewConfigModel().toJSON(o); 181 // 182 return o; 183 } catch (Exception e) { 184 throw new RuntimeException("Serialization failed (" + this + ")", e); 185 } 186 } 187 188 189 190 // **************** 191 // *** Java API *** 192 // **************** 193 194 195 196 @Override 197 public String toString() { 198 return "id=" + id + ", uri=\"" + uri + "\", value=\"" + value + "\", typeUri=\"" + typeUri + 199 "\", dataTypeUri=\"" + getDataTypeUri() + "\", indexModes=" + getIndexModes() + ", assocDefs=" + 200 getAssocDefs() + ", labelConfig=" + getLabelConfig() + ", " + getViewConfigModel(); 201 } 202 203 204 205 // ------------------------------------------------------------------------------------------------- Private Methods 206 207 private List<String> parseLabelConfig(JSONObject typeModel) throws Exception { 208 if (typeModel.has("label_config")) { 209 return DeepaMehtaUtils.toList(typeModel.getJSONArray("label_config")); 210 } 211 return new ArrayList(); 212 } 213 214 private void parseAssocDefs(JSONObject typeModel) throws Exception { 215 JSONArray assocDefs = typeModel.optJSONArray("assoc_defs"); 216 if (assocDefs != null) { 217 for (int i = 0; i < assocDefs.length(); i++) { 218 JSONObject assocDef = assocDefs.getJSONObject(i); 219 addAssocDef(AssociationDefinitionModel.fromJSON(assocDef, this.uri)); 220 } 221 } 222 } 223 }