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 TypeModel 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 return this; 122 } 123 124 public void updateAssocDef(AssociationDefinitionModel assocDef) { 125 assocDefs.put(assocDef.getChildTypeUri(), assocDef); 126 } 127 128 public AssociationDefinitionModel removeAssocDef(String childTypeUri) { 129 // error check 130 getAssocDef(childTypeUri); 131 // 132 return assocDefs.remove(childTypeUri); 133 } 134 135 public void removeAllAssocDefs() { 136 assocDefs.clear(); 137 } 138 139 // === Label Configuration === 140 141 public List<String> getLabelConfig() { 142 return labelConfig; 143 } 144 145 public void setLabelConfig(List<String> labelConfig) { 146 this.labelConfig = labelConfig; 147 } 148 149 // === View Configuration === 150 151 public ViewConfigurationModel getViewConfigModel() { 152 return viewConfig; 153 } 154 155 // FIXME: server-side operations on the view config settings possibly suggest they are not acually 156 // view config settings but part of the topic type model. Possibly this method should be dropped. 157 public Object getViewConfig(String typeUri, String settingUri) { 158 return viewConfig.getSetting(typeUri, settingUri); 159 } 160 161 public void setViewConfig(ViewConfigurationModel viewConfig) { 162 this.viewConfig = viewConfig; 163 } 164 165 166 167 // **************************** 168 // *** TopicModel Overrides *** 169 // **************************** 170 171 172 173 @Override 174 public JSONObject toJSON() { 175 try { 176 JSONObject o = super.toJSON(); 177 // 178 o.put("data_type_uri", getDataTypeUri()); 179 IndexMode.toJSON(indexModes, o); 180 AssociationDefinitionModel.toJSON(assocDefs.values(), o); 181 o.put("label_config", DeepaMehtaUtils.stringsToJson(getLabelConfig())); 182 getViewConfigModel().toJSON(o); 183 // 184 return o; 185 } catch (Exception e) { 186 throw new RuntimeException("Serialization failed (" + this + ")", e); 187 } 188 } 189 190 191 192 // **************** 193 // *** Java API *** 194 // **************** 195 196 197 198 @Override 199 public String toString() { 200 return "id=" + id + ", uri=\"" + uri + "\", value=\"" + value + "\", typeUri=\"" + typeUri + 201 "\", dataTypeUri=\"" + getDataTypeUri() + "\", indexModes=" + getIndexModes() + ", assocDefs=" + 202 getAssocDefs() + ", labelConfig=" + getLabelConfig() + ", " + getViewConfigModel(); 203 } 204 205 206 207 // ------------------------------------------------------------------------------------------------- Private Methods 208 209 private List<String> parseLabelConfig(JSONObject typeModel) throws Exception { 210 if (typeModel.has("label_config")) { 211 return DeepaMehtaUtils.toList(typeModel.getJSONArray("label_config")); 212 } 213 return new ArrayList(); 214 } 215 216 private void parseAssocDefs(JSONObject typeModel) throws Exception { 217 JSONArray assocDefs = typeModel.optJSONArray("assoc_defs"); 218 if (assocDefs != null) { 219 for (int i = 0; i < assocDefs.length(); i++) { 220 JSONObject assocDef = assocDefs.getJSONObject(i); 221 addAssocDef(AssociationDefinitionModel.fromJSON(assocDef, this.uri)); 222 } 223 } 224 } 225 }