001package de.deepamehta.core.impl; 002 003import de.deepamehta.core.model.AssociationModel; 004import de.deepamehta.core.model.AssociationDefinitionModel; 005import de.deepamehta.core.model.AssociationRoleModel; 006import de.deepamehta.core.model.AssociationTypeModel; 007import de.deepamehta.core.model.ChildTopicsModel; 008import de.deepamehta.core.model.DeepaMehtaObjectModel; 009import de.deepamehta.core.model.IndexMode; 010import de.deepamehta.core.model.RelatedAssociationModel; 011import de.deepamehta.core.model.RelatedTopicModel; 012import de.deepamehta.core.model.RoleModel; 013import de.deepamehta.core.model.SimpleValue; 014import de.deepamehta.core.model.TopicModel; 015import de.deepamehta.core.model.TopicDeletionModel; 016import de.deepamehta.core.model.TopicReferenceModel; 017import de.deepamehta.core.model.TopicRoleModel; 018import de.deepamehta.core.model.TopicTypeModel; 019import de.deepamehta.core.model.TypeModel; 020import de.deepamehta.core.model.ViewConfigurationModel; 021import de.deepamehta.core.model.facets.FacetValueModel; 022import de.deepamehta.core.model.topicmaps.AssociationViewModel; 023import de.deepamehta.core.model.topicmaps.TopicViewModel; 024import de.deepamehta.core.model.topicmaps.ViewProperties; 025import de.deepamehta.core.service.ModelFactory; 026import de.deepamehta.core.util.DeepaMehtaUtils; 027 028import org.codehaus.jettison.json.JSONArray; 029import org.codehaus.jettison.json.JSONException; 030import org.codehaus.jettison.json.JSONObject; 031 032import java.util.ArrayList; 033import java.util.HashMap; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Map; 037 038 039 040// ### TODO: should methods return model *impl* objects? -> Yes! 041public class ModelFactoryImpl implements ModelFactory { 042 043 // ------------------------------------------------------------------------------------------------------- Constants 044 045 private static final String REF_ID_PREFIX = "ref_id:"; 046 private static final String REF_URI_PREFIX = "ref_uri:"; 047 private static final String DEL_ID_PREFIX = "del_id:"; 048 private static final String DEL_URI_PREFIX = "del_uri:"; 049 050 // ---------------------------------------------------------------------------------------------- Instance Variables 051 052 PersistenceLayer pl; 053 054 // -------------------------------------------------------------------------------------------------- Public Methods 055 056 057 058 // === TopicModel === 059 060 @Override 061 public TopicModelImpl newTopicModel(long id, String uri, String typeUri, SimpleValue value, 062 ChildTopicsModel childTopics) { 063 return new TopicModelImpl(newDeepaMehtaObjectModel(id, uri, typeUri, value, childTopics)); 064 } 065 066 @Override 067 public TopicModelImpl newTopicModel(ChildTopicsModel childTopics) { 068 return newTopicModel(-1, null, null, null, childTopics); 069 } 070 071 @Override 072 public TopicModelImpl newTopicModel(String typeUri) { 073 return newTopicModel(-1, null, typeUri, null, null); 074 } 075 076 @Override 077 public TopicModelImpl newTopicModel(String typeUri, SimpleValue value) { 078 return newTopicModel(-1, null, typeUri, value, null); 079 } 080 081 @Override 082 public TopicModelImpl newTopicModel(String typeUri, ChildTopicsModel childTopics) { 083 return newTopicModel(-1, null, typeUri, null, childTopics); 084 } 085 086 @Override 087 public TopicModelImpl newTopicModel(String uri, String typeUri) { 088 return newTopicModel(-1, uri, typeUri, null, null); 089 } 090 091 @Override 092 public TopicModelImpl newTopicModel(String uri, String typeUri, SimpleValue value) { 093 return newTopicModel(-1, uri, typeUri, value, null); 094 } 095 096 @Override 097 public TopicModelImpl newTopicModel(String uri, String typeUri, ChildTopicsModel childTopics) { 098 return newTopicModel(-1, uri, typeUri, null, childTopics); 099 } 100 101 @Override 102 public TopicModelImpl newTopicModel(long id) { 103 return newTopicModel(id, null, null, null, null); 104 } 105 106 @Override 107 public TopicModelImpl newTopicModel(long id, ChildTopicsModel childTopics) { 108 return newTopicModel(id, null, null, null, childTopics); 109 } 110 111 @Override 112 public TopicModelImpl newTopicModel(TopicModel topic) { 113 return new TopicModelImpl((TopicModelImpl) topic); 114 } 115 116 @Override 117 public TopicModelImpl newTopicModel(JSONObject topic) { 118 try { 119 return new TopicModelImpl(newDeepaMehtaObjectModel(topic)); 120 } catch (Exception e) { 121 throw new RuntimeException("Parsing TopicModel failed (JSONObject=" + topic + ")", e); 122 } 123 } 124 125 126 127 // === AssociationModel === 128 129 @Override 130 public AssociationModelImpl newAssociationModel(long id, String uri, String typeUri, RoleModel roleModel1, 131 RoleModel roleModel2, SimpleValue value, ChildTopicsModel childTopics) { 132 return new AssociationModelImpl(newDeepaMehtaObjectModel(id, uri, typeUri, value, childTopics), 133 (RoleModelImpl) roleModel1, (RoleModelImpl) roleModel2); 134 } 135 136 @Override 137 public AssociationModelImpl newAssociationModel(String typeUri, RoleModel roleModel1, RoleModel roleModel2) { 138 return newAssociationModel(-1, null, typeUri, roleModel1, roleModel2, null, null); 139 } 140 141 @Override 142 public AssociationModelImpl newAssociationModel(String typeUri, RoleModel roleModel1, RoleModel roleModel2, 143 ChildTopicsModel childTopics) { 144 return newAssociationModel(-1, null, typeUri, roleModel1, roleModel2, null, childTopics); 145 } 146 147 // ### TODO: don't leave the assoc uninitialized. Refactoring needed. See comment in TypeCache#put methods. 148 @Override 149 public AssociationModelImpl newAssociationModel() { 150 return newAssociationModel(-1, null, null, null, null, null, null); 151 } 152 153 // ### TODO: don't leave the assoc uninitialized. Refactoring needed. See comment in TypeCache#put methods. 154 @Override 155 public AssociationModelImpl newAssociationModel(ChildTopicsModel childTopics) { 156 return newAssociationModel(-1, null, null, null, null, null, childTopics); 157 } 158 159 @Override 160 public AssociationModelImpl newAssociationModel(long id, String uri, String typeUri, RoleModel roleModel1, 161 RoleModel roleModel2) { 162 return newAssociationModel(id, uri, typeUri, roleModel1, roleModel2, null, null); 163 } 164 165 @Override 166 public AssociationModelImpl newAssociationModel(AssociationModel assoc) { 167 return new AssociationModelImpl((AssociationModelImpl) assoc); 168 } 169 170 @Override 171 public AssociationModelImpl newAssociationModel(JSONObject assoc) { 172 try { 173 return new AssociationModelImpl(newDeepaMehtaObjectModel(assoc), 174 assoc.has("role_1") ? parseRole(assoc.getJSONObject("role_1")) : null, 175 assoc.has("role_2") ? parseRole(assoc.getJSONObject("role_2")) : null 176 ); 177 } catch (Exception e) { 178 throw new RuntimeException("Parsing AssociationModel failed (JSONObject=" + assoc + ")", e); 179 } 180 } 181 182 // --- 183 184 private RoleModelImpl parseRole(JSONObject roleModel) { 185 if (roleModel.has("topic_id") || roleModel.has("topic_uri")) { 186 return newTopicRoleModel(roleModel); 187 } else if (roleModel.has("assoc_id")) { 188 return newAssociationRoleModel(roleModel); 189 } else { 190 throw new RuntimeException("Parsing TopicRoleModel/AssociationRoleModel failed (JSONObject=" + 191 roleModel + ")"); 192 } 193 } 194 195 196 197 // === DeepaMehtaObjectModel === 198 199 /** 200 * @param id Optional (-1 is a valid value and represents "not set"). 201 * @param uri Optional (<code>null</code> is a valid value). 202 * @param typeUri Mandatory in the context of a create operation. 203 * Optional (<code>null</code> is a valid value) in the context of an update operation. 204 * @param value Optional (<code>null</code> is a valid value). 205 * @param childTopics Optional (<code>null</code> is a valid value and is transformed into an empty composite). 206 */ 207 DeepaMehtaObjectModelImpl newDeepaMehtaObjectModel(long id, String uri, String typeUri, SimpleValue value, 208 ChildTopicsModel childTopics) { 209 return new DeepaMehtaObjectModelImpl(id, uri, typeUri, value, (ChildTopicsModelImpl) childTopics, pl()); 210 } 211 212 DeepaMehtaObjectModelImpl newDeepaMehtaObjectModel(JSONObject object) throws JSONException { 213 return newDeepaMehtaObjectModel( 214 object.optLong("id", -1), 215 object.optString("uri", null), 216 object.optString("type_uri", null), 217 object.has("value") ? new SimpleValue(object.get("value")) : null, 218 object.has("childs") ? newChildTopicsModel(object.getJSONObject("childs")) : null 219 ); 220 } 221 222 223 224 // === ChildTopicsModel === 225 226 @Override 227 public ChildTopicsModelImpl newChildTopicsModel() { 228 return new ChildTopicsModelImpl(new HashMap(), this); 229 } 230 231 @Override 232 public ChildTopicsModelImpl newChildTopicsModel(JSONObject values) { 233 try { 234 Map<String, Object> childTopics = new HashMap(); 235 Iterator<String> i = values.keys(); 236 while (i.hasNext()) { 237 String assocDefUri = i.next(); 238 String childTypeUri = childTypeUri(assocDefUri); 239 Object value = values.get(assocDefUri); 240 if (!(value instanceof JSONArray)) { 241 childTopics.put(assocDefUri, createTopicModel(childTypeUri, value)); 242 } else { 243 JSONArray valueArray = (JSONArray) value; 244 List<RelatedTopicModel> topics = new ArrayList(); 245 childTopics.put(assocDefUri, topics); 246 for (int j = 0; j < valueArray.length(); j++) { 247 topics.add(createTopicModel(childTypeUri, valueArray.get(j))); 248 } 249 } 250 } 251 return new ChildTopicsModelImpl(childTopics, this); 252 } catch (Exception e) { 253 throw new RuntimeException("Parsing ChildTopicsModel failed (JSONObject=" + values + ")", e); 254 } 255 } 256 257 @Override 258 public String childTypeUri(String assocDefUri) { 259 return assocDefUri.split("#")[0]; 260 } 261 262 // --- 263 264 /** 265 * Creates a topic model from a JSON value. 266 * 267 * Both topic serialization formats are supported: 268 * 1) canonic format -- contains entire topic models. 269 * 2) simplified format -- contains the topic value only (simple or composite). 270 */ 271 private RelatedTopicModel createTopicModel(String childTypeUri, Object value) throws JSONException { 272 if (value instanceof JSONObject) { 273 JSONObject val = (JSONObject) value; 274 // we detect the canonic format by checking for mandatory topic properties 275 if (val.has("value") || val.has("childs")) { 276 // canonic format (topic or topic reference) 277 AssociationModel relatingAssoc = null; 278 if (val.has("assoc")) { 279 relatingAssoc = newAssociationModel(val.getJSONObject("assoc")); 280 } 281 if (val.has("value")) { 282 RelatedTopicModel topicRef = createReferenceModel(val.get("value"), relatingAssoc); 283 if (topicRef != null) { 284 return topicRef; 285 } 286 } 287 // 288 initTypeUri(val, childTypeUri); 289 // 290 TopicModel topic = newTopicModel(val); 291 if (relatingAssoc != null) { 292 return newRelatedTopicModel(topic, relatingAssoc); 293 } else { 294 return newRelatedTopicModel(topic); 295 } 296 } else { 297 // simplified format (composite topic) 298 return newRelatedTopicModel(newTopicModel(childTypeUri, newChildTopicsModel(val))); 299 } 300 } else { 301 // simplified format (simple topic or topic reference) 302 RelatedTopicModel topicRef = createReferenceModel(value, null); 303 if (topicRef != null) { 304 return topicRef; 305 } 306 // simplified format (simple topic) 307 return newRelatedTopicModel(newTopicModel(childTypeUri, new SimpleValue(value))); 308 } 309 } 310 311 private RelatedTopicModel createReferenceModel(Object value, AssociationModel relatingAssoc) { 312 if (value instanceof String) { 313 String val = (String) value; 314 if (val.startsWith(REF_ID_PREFIX)) { 315 long topicId = refTopicId(val); 316 if (relatingAssoc != null) { 317 return newTopicReferenceModel(topicId, relatingAssoc); 318 } else { 319 return newTopicReferenceModel(topicId); 320 } 321 } else if (val.startsWith(REF_URI_PREFIX)) { 322 String topicUri = refTopicUri(val); 323 if (relatingAssoc != null) { 324 return newTopicReferenceModel(topicUri, relatingAssoc); 325 } else { 326 return newTopicReferenceModel(topicUri); 327 } 328 } else if (val.startsWith(DEL_ID_PREFIX)) { 329 return newTopicDeletionModel(delTopicId(val)); 330 } else if (val.startsWith(DEL_URI_PREFIX)) { 331 return newTopicDeletionModel(delTopicUri(val)); 332 } 333 } 334 return null; 335 } 336 337 private void initTypeUri(JSONObject value, String childTypeUri) throws JSONException { 338 if (!value.has("type_uri")) { 339 value.put("type_uri", childTypeUri); 340 } else { 341 // sanity check 342 String typeUri = value.getString("type_uri"); 343 if (!typeUri.equals(childTypeUri)) { 344 throw new IllegalArgumentException("A \"" + childTypeUri + "\" topic model has type_uri=\"" + 345 typeUri + "\""); 346 } 347 } 348 } 349 350 // --- 351 352 private long refTopicId(String val) { 353 return Long.parseLong(val.substring(REF_ID_PREFIX.length())); 354 } 355 356 private String refTopicUri(String val) { 357 return val.substring(REF_URI_PREFIX.length()); 358 } 359 360 private long delTopicId(String val) { 361 return Long.parseLong(val.substring(DEL_ID_PREFIX.length())); 362 } 363 364 private String delTopicUri(String val) { 365 return val.substring(DEL_URI_PREFIX.length()); 366 } 367 368 369 370 // === TopicRoleModel === 371 372 @Override 373 public TopicRoleModelImpl newTopicRoleModel(long topicId, String roleTypeUri) { 374 return new TopicRoleModelImpl(topicId, roleTypeUri, pl()); 375 } 376 377 @Override 378 public TopicRoleModelImpl newTopicRoleModel(String topicUri, String roleTypeUri) { 379 return new TopicRoleModelImpl(topicUri, roleTypeUri, pl()); 380 } 381 382 @Override 383 public TopicRoleModelImpl newTopicRoleModel(JSONObject topicRoleModel) { 384 try { 385 long topicId = topicRoleModel.optLong("topic_id", -1); 386 String topicUri = topicRoleModel.optString("topic_uri", null); 387 String roleTypeUri = topicRoleModel.getString("role_type_uri"); 388 // 389 if (topicId == -1 && topicUri == null) { 390 throw new IllegalArgumentException("Neiter \"topic_id\" nor \"topic_uri\" is set"); 391 } 392 if (topicId != -1 && topicUri != null) { 393 throw new IllegalArgumentException("\"topic_id\" and \"topic_uri\" must not be set at the same time"); 394 } 395 // 396 if (topicId != -1) { 397 return newTopicRoleModel(topicId, roleTypeUri); 398 } else { 399 return newTopicRoleModel(topicUri, roleTypeUri); 400 } 401 } catch (Exception e) { 402 throw new RuntimeException("Parsing TopicRoleModel failed (JSONObject=" + topicRoleModel + ")", e); 403 } 404 } 405 406 407 408 // === AssociationRoleModel === 409 410 @Override 411 public AssociationRoleModelImpl newAssociationRoleModel(long assocId, String roleTypeUri) { 412 return new AssociationRoleModelImpl(assocId, roleTypeUri, pl()); 413 } 414 415 @Override 416 public AssociationRoleModelImpl newAssociationRoleModel(JSONObject assocRoleModel) { 417 try { 418 long assocId = assocRoleModel.getLong("assoc_id"); 419 String roleTypeUri = assocRoleModel.getString("role_type_uri"); 420 return newAssociationRoleModel(assocId, roleTypeUri); 421 } catch (Exception e) { 422 throw new RuntimeException("Parsing AssociationRoleModel failed (JSONObject=" + assocRoleModel + ")", e); 423 } 424 } 425 426 427 428 // === RelatedTopicModel === 429 430 @Override 431 public RelatedTopicModelImpl newRelatedTopicModel(long topicId) { 432 return new RelatedTopicModelImpl(newTopicModel(topicId), newAssociationModel()); 433 } 434 435 @Override 436 public RelatedTopicModelImpl newRelatedTopicModel(long topicId, AssociationModel relatingAssoc) { 437 return new RelatedTopicModelImpl(newTopicModel(topicId), (AssociationModelImpl) relatingAssoc); 438 } 439 440 @Override 441 public RelatedTopicModelImpl newRelatedTopicModel(String topicUri) { 442 return new RelatedTopicModelImpl(newTopicModel(topicUri, (String) null), newAssociationModel()); 443 // topicTypeUri=null 444 } 445 446 @Override 447 public RelatedTopicModelImpl newRelatedTopicModel(String topicUri, AssociationModel relatingAssoc) { 448 return new RelatedTopicModelImpl(newTopicModel(topicUri, (String) null), (AssociationModelImpl) relatingAssoc); 449 // topicTypeUri=null 450 } 451 452 @Override 453 public RelatedTopicModelImpl newRelatedTopicModel(String topicTypeUri, SimpleValue value) { 454 return new RelatedTopicModelImpl(newTopicModel(topicTypeUri, value), newAssociationModel()); 455 } 456 457 @Override 458 public RelatedTopicModelImpl newRelatedTopicModel(String topicTypeUri, ChildTopicsModel childTopics) { 459 return new RelatedTopicModelImpl(newTopicModel(topicTypeUri, childTopics), newAssociationModel()); 460 } 461 462 @Override 463 public RelatedTopicModelImpl newRelatedTopicModel(TopicModel topic) { 464 return new RelatedTopicModelImpl((TopicModelImpl) topic, newAssociationModel()); 465 } 466 467 @Override 468 public RelatedTopicModelImpl newRelatedTopicModel(TopicModel topic, AssociationModel relatingAssoc) { 469 return new RelatedTopicModelImpl((TopicModelImpl) topic, (AssociationModelImpl) relatingAssoc); 470 } 471 472 473 474 // === RelatedAssociationModel === 475 476 @Override 477 public RelatedAssociationModel newRelatedAssociationModel(AssociationModel assoc, AssociationModel relatingAssoc) { 478 return new RelatedAssociationModelImpl((AssociationModelImpl) assoc, (AssociationModelImpl) relatingAssoc); 479 } 480 481 482 483 // === TopicReferenceModel === 484 485 @Override 486 public TopicReferenceModel newTopicReferenceModel(long topicId) { 487 return new TopicReferenceModelImpl(newRelatedTopicModel(topicId)); 488 } 489 490 @Override 491 public TopicReferenceModel newTopicReferenceModel(long topicId, AssociationModel relatingAssoc) { 492 return new TopicReferenceModelImpl(newRelatedTopicModel(topicId, relatingAssoc)); 493 } 494 495 @Override 496 public TopicReferenceModel newTopicReferenceModel(String topicUri) { 497 return new TopicReferenceModelImpl(newRelatedTopicModel(topicUri)); 498 } 499 500 @Override 501 public TopicReferenceModel newTopicReferenceModel(String topicUri, AssociationModel relatingAssoc) { 502 return new TopicReferenceModelImpl(newRelatedTopicModel(topicUri, relatingAssoc)); 503 } 504 505 @Override 506 public TopicReferenceModel newTopicReferenceModel(long topicId, ChildTopicsModel relatingAssocChildTopics) { 507 return new TopicReferenceModelImpl( 508 newRelatedTopicModel(topicId, newAssociationModel(relatingAssocChildTopics)) 509 ); 510 } 511 512 @Override 513 public TopicReferenceModel newTopicReferenceModel(String topicUri, ChildTopicsModel relatingAssocChildTopics) { 514 return new TopicReferenceModelImpl( 515 newRelatedTopicModel(topicUri, newAssociationModel(relatingAssocChildTopics)) 516 ); 517 } 518 519 520 521 // === TopicDeletionModel === 522 523 @Override 524 public TopicDeletionModel newTopicDeletionModel(long topicId) { 525 return new TopicDeletionModelImpl(newRelatedTopicModel(topicId)); 526 } 527 528 @Override 529 public TopicDeletionModel newTopicDeletionModel(String topicUri) { 530 return new TopicDeletionModelImpl(newRelatedTopicModel(topicUri)); 531 } 532 533 534 535 // === TopicTypeModel === 536 537 @Override 538 public TopicTypeModelImpl newTopicTypeModel(TopicModel typeTopic, String dataTypeUri, 539 List<IndexMode> indexModes, List<AssociationDefinitionModel> assocDefs, 540 List<String> labelConfig, ViewConfigurationModel viewConfig) { 541 return new TopicTypeModelImpl(newTypeModel(typeTopic, dataTypeUri, indexModes, assocDefs, labelConfig, 542 (ViewConfigurationModelImpl) viewConfig)); 543 } 544 545 @Override 546 public TopicTypeModelImpl newTopicTypeModel(String uri, String value, String dataTypeUri) { 547 return new TopicTypeModelImpl(newTypeModel(uri, "dm4.core.topic_type", new SimpleValue(value), dataTypeUri)); 548 } 549 550 @Override 551 public TopicTypeModelImpl newTopicTypeModel(JSONObject topicType) { 552 try { 553 return new TopicTypeModelImpl(newTypeModel(topicType.put("type_uri", "dm4.core.topic_type"))); 554 } catch (Exception e) { 555 throw new RuntimeException("Parsing TopicTypeModel failed (JSONObject=" + topicType + ")", e); 556 } 557 } 558 559 560 561 // === AssociationTypeModel === 562 563 @Override 564 public AssociationTypeModelImpl newAssociationTypeModel(TopicModel typeTopic, String dataTypeUri, 565 List<IndexMode> indexModes, List<AssociationDefinitionModel> assocDefs, 566 List<String> labelConfig, ViewConfigurationModel viewConfig) { 567 return new AssociationTypeModelImpl(newTypeModel(typeTopic, dataTypeUri, indexModes, assocDefs, labelConfig, 568 (ViewConfigurationModelImpl) viewConfig)); 569 } 570 571 @Override 572 public AssociationTypeModelImpl newAssociationTypeModel(String uri, String value, String dataTypeUri) { 573 return new AssociationTypeModelImpl(newTypeModel(uri, "dm4.core.assoc_type", new SimpleValue(value), 574 dataTypeUri)); 575 } 576 577 @Override 578 public AssociationTypeModelImpl newAssociationTypeModel(JSONObject assocType) { 579 try { 580 return new AssociationTypeModelImpl(newTypeModel(assocType.put("type_uri", "dm4.core.assoc_type"))); 581 } catch (Exception e) { 582 throw new RuntimeException("Parsing AssociationTypeModel failed (JSONObject=" + assocType + ")", e); 583 } 584 } 585 586 587 588 // === TypeModel === 589 590 TypeModelImpl newTypeModel(TopicModel typeTopic, String dataTypeUri, List<IndexMode> indexModes, 591 List<AssociationDefinitionModel> assocDefs, List<String> labelConfig, 592 ViewConfigurationModelImpl viewConfig) { 593 return new TypeModelImpl((TopicModelImpl) typeTopic, dataTypeUri, indexModes, assocDefs, labelConfig, 594 viewConfig); 595 } 596 597 TypeModelImpl newTypeModel(String uri, String typeUri, SimpleValue value, String dataTypeUri) { 598 return new TypeModelImpl(newTopicModel(uri, typeUri, value), dataTypeUri, 599 new ArrayList(), new ArrayList(), new ArrayList(), newViewConfigurationModel() 600 ); 601 } 602 603 TypeModelImpl newTypeModel(JSONObject typeModel) throws JSONException { 604 TopicModelImpl typeTopic = newTopicModel(typeModel); 605 return new TypeModelImpl(typeTopic, 606 typeModel.optString("data_type_uri", null), 607 parseIndexModes(typeModel.optJSONArray("index_mode_uris")), 608 parseAssocDefs(typeModel.optJSONArray("assoc_defs"), typeTopic.getUri()), 609 parseLabelConfig(typeModel.optJSONArray("label_config")), 610 newViewConfigurationModel(typeModel.optJSONArray("view_config_topics")) 611 ); 612 } 613 614 // --- 615 616 private List<IndexMode> parseIndexModes(JSONArray indexModeUris) { 617 try { 618 List<IndexMode> indexModes = new ArrayList(); 619 if (indexModeUris != null) { 620 for (int i = 0; i < indexModeUris.length(); i++) { 621 indexModes.add(IndexMode.fromUri(indexModeUris.getString(i))); 622 } 623 } 624 return indexModes; 625 } catch (Exception e) { 626 throw new RuntimeException("Parsing index modes failed (JSONArray=" + indexModeUris + ")", e); 627 } 628 } 629 630 private List<AssociationDefinitionModel> parseAssocDefs(JSONArray assocDefs, String parentTypeUri) throws 631 JSONException { 632 List<AssociationDefinitionModel> _assocDefs = new ArrayList(); 633 if (assocDefs != null) { 634 for (int i = 0; i < assocDefs.length(); i++) { 635 JSONObject assocDef = assocDefs.getJSONObject(i) 636 .put("parent_type_uri", parentTypeUri); 637 _assocDefs.add(newAssociationDefinitionModel(assocDef)); 638 } 639 } 640 return _assocDefs; 641 } 642 643 private List<String> parseLabelConfig(JSONArray labelConfig) { 644 return labelConfig != null ? DeepaMehtaUtils.toList(labelConfig) : new ArrayList(); 645 } 646 647 648 649 // === AssociationDefinitionModel === 650 651 @Override 652 public AssociationDefinitionModelImpl newAssociationDefinitionModel( 653 long id, String uri, String assocTypeUri, String customAssocTypeUri, 654 String parentTypeUri, String childTypeUri, 655 String parentCardinalityUri, String childCardinalityUri, 656 ViewConfigurationModel viewConfig) { 657 return new AssociationDefinitionModelImpl( 658 newAssociationModel(id, uri, assocTypeUri, parentRole(parentTypeUri), childRole(childTypeUri), 659 null, childTopics(customAssocTypeUri) 660 ), 661 parentCardinalityUri, childCardinalityUri, (ViewConfigurationModelImpl) viewConfig 662 ); 663 } 664 665 @Override 666 public AssociationDefinitionModelImpl newAssociationDefinitionModel(String assocTypeUri, 667 String parentTypeUri, String childTypeUri, 668 String parentCardinalityUri, String childCardinalityUri) { 669 return newAssociationDefinitionModel(-1, null, assocTypeUri, null, parentTypeUri, childTypeUri, 670 parentCardinalityUri, childCardinalityUri, null); 671 } 672 673 @Override 674 public AssociationDefinitionModelImpl newAssociationDefinitionModel(String assocTypeUri, String customAssocTypeUri, 675 String parentTypeUri, String childTypeUri, 676 String parentCardinalityUri, String childCardinalityUri) { 677 return newAssociationDefinitionModel(-1, null, assocTypeUri, customAssocTypeUri, parentTypeUri, childTypeUri, 678 parentCardinalityUri, childCardinalityUri, null); 679 } 680 681 /** 682 * @param assoc the underlying association. 683 * IMPORTANT: the association must identify its players <i>by URI</i> (not by ID). ### still true? 684 */ 685 @Override 686 public AssociationDefinitionModelImpl newAssociationDefinitionModel(AssociationModel assoc, 687 String parentCardinalityUri, String childCardinalityUri, 688 ViewConfigurationModel viewConfig) { 689 return new AssociationDefinitionModelImpl((AssociationModelImpl) assoc, parentCardinalityUri, 690 childCardinalityUri, (ViewConfigurationModelImpl) viewConfig); 691 } 692 693 @Override 694 public AssociationDefinitionModelImpl newAssociationDefinitionModel(JSONObject assocDef) { 695 try { 696 AssociationModelImpl assoc = newAssociationModel(assocDef.optLong("id", -1), null, 697 assocDef.getString("assoc_type_uri"), 698 parentRole(assocDef.getString("parent_type_uri")), 699 childRole(assocDef.getString("child_type_uri")), 700 null, childTopics(assocDef) 701 ); 702 // 703 if (!assocDef.has("parent_cardinality_uri") && !assoc.getTypeUri().equals("dm4.core.composition_def")) { 704 throw new RuntimeException("\"parent_cardinality_uri\" is missing"); 705 } 706 // 707 return new AssociationDefinitionModelImpl(assoc, 708 assocDef.optString("parent_cardinality_uri", "dm4.core.one"), 709 assocDef.getString("child_cardinality_uri"), 710 newViewConfigurationModel(assocDef.optJSONArray("view_config_topics")) 711 ); 712 } catch (Exception e) { 713 throw new RuntimeException("Parsing AssociationDefinitionModel failed (JSONObject=" + assocDef + ")", e); 714 } 715 } 716 717 // --- 718 719 private TopicRoleModel parentRole(String parentTypeUri) { 720 return newTopicRoleModel(parentTypeUri, "dm4.core.parent_type"); 721 } 722 723 private TopicRoleModel childRole(String childTypeUri) { 724 return newTopicRoleModel(childTypeUri, "dm4.core.child_type"); 725 } 726 727 // --- 728 729 private ChildTopicsModel childTopics(JSONObject assocDef) throws JSONException { 730 // Note: getString() called on a key with JSON null value would return the string "null" 731 return childTopics(assocDef.isNull("custom_assoc_type_uri") ? null : 732 assocDef.getString("custom_assoc_type_uri")); 733 } 734 735 private ChildTopicsModel childTopics(String customAssocTypeUri) { 736 if (customAssocTypeUri != null) { 737 if (customAssocTypeUri.startsWith(DEL_URI_PREFIX)) { 738 return newChildTopicsModel().putDeletionRef("dm4.core.assoc_type#dm4.core.custom_assoc_type", 739 delTopicUri(customAssocTypeUri)); 740 } else { 741 return newChildTopicsModel().putRef("dm4.core.assoc_type#dm4.core.custom_assoc_type", 742 customAssocTypeUri); 743 } 744 } else { 745 return null; 746 } 747 } 748 749 750 751 // === ViewConfigurationModel === 752 753 @Override 754 public ViewConfigurationModelImpl newViewConfigurationModel() { 755 return new ViewConfigurationModelImpl(new HashMap()); 756 } 757 758 @Override 759 public ViewConfigurationModelImpl newViewConfigurationModel(Iterable<? extends TopicModel> configTopics) { 760 Map<String, TopicModelImpl> _configTopics = new HashMap(); 761 for (TopicModel configTopic : configTopics) { 762 _configTopics.put(configTopic.getTypeUri(), (TopicModelImpl) configTopic); 763 } 764 return new ViewConfigurationModelImpl(_configTopics); 765 } 766 767 /** 768 * @param configurable A topic type, an association type, or an association definition. ### FIXDOC 769 */ 770 @Override 771 public ViewConfigurationModelImpl newViewConfigurationModel(JSONArray configTopics) { 772 try { 773 Map<String, TopicModelImpl> _configTopics = new HashMap(); 774 if (configTopics != null) { 775 for (int i = 0; i < configTopics.length(); i++) { 776 TopicModelImpl configTopic = newTopicModel(configTopics.getJSONObject(i)); 777 _configTopics.put(configTopic.getTypeUri(), configTopic); 778 } 779 } 780 return new ViewConfigurationModelImpl(_configTopics); 781 } catch (Exception e) { 782 throw new RuntimeException("Parsing ViewConfigurationModel failed (JSONArray=" + configTopics + ")", e); 783 } 784 } 785 786 787 788 // === Topicmaps === 789 790 @Override 791 public TopicViewModel newTopicViewModel(TopicModel topic, ViewProperties viewProps) { 792 return new TopicViewModelImpl((TopicModelImpl) topic, viewProps); 793 } 794 795 @Override 796 public AssociationViewModel newAssociationViewModel(AssociationModel assoc) { 797 return new AssociationViewModelImpl((AssociationModelImpl) assoc); 798 } 799 800 801 802 // === Facets === 803 804 @Override 805 public FacetValueModel newFacetValueModel(String childTypeUri) { 806 return new FacetValueModelImpl(childTypeUri, this); 807 } 808 809 @Override 810 public FacetValueModel newFacetValueModel(JSONObject facetValue) { 811 try { 812 ChildTopicsModelImpl childTopics = newChildTopicsModel(facetValue); 813 if (childTopics.size() != 1) { 814 throw new RuntimeException("There are " + childTopics.size() + " child topic entries (expected is 1)"); 815 } 816 return new FacetValueModelImpl(childTopics); 817 } catch (Exception e) { 818 throw new RuntimeException("Parsing FacetValueModel failed (JSONObject=" + facetValue + ")", e); 819 } 820 } 821 822 // ------------------------------------------------------------------------------------------------- Private Methods 823 824 private PersistenceLayer pl() { 825 if (pl == null) { 826 throw new RuntimeException("before using the ModelFactory a PersistenceLayer must be set"); 827 } 828 return pl; 829 } 830}