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