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 ViewConfigurationModel viewConfig) { 541 return new TopicTypeModelImpl(newTypeModel(typeTopic, dataTypeUri, indexModes, assocDefs, 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 ViewConfigurationModel viewConfig) { 567 return new AssociationTypeModelImpl(newTypeModel(typeTopic, dataTypeUri, indexModes, assocDefs, 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, ViewConfigurationModelImpl viewConfig) { 592 return new TypeModelImpl((TopicModelImpl) typeTopic, dataTypeUri, indexModes, assocDefs, viewConfig); 593 } 594 595 TypeModelImpl newTypeModel(String uri, String typeUri, SimpleValue value, String dataTypeUri) { 596 return new TypeModelImpl(newTopicModel(uri, typeUri, value), dataTypeUri, new ArrayList(), new ArrayList(), 597 newViewConfigurationModel()); 598 } 599 600 TypeModelImpl newTypeModel(JSONObject typeModel) throws JSONException { 601 TopicModelImpl typeTopic = newTopicModel(typeModel); 602 return new TypeModelImpl(typeTopic, 603 typeModel.optString("data_type_uri", null), 604 parseIndexModes(typeModel.optJSONArray("index_mode_uris")), // optJSONArray may return null 605 parseAssocDefs(typeModel.optJSONArray("assoc_defs"), typeTopic.getUri()), // optJSONArray may return null 606 newViewConfigurationModel(typeModel.optJSONArray("view_config_topics"))); // optJSONArray may return null 607 } 608 609 // --- 610 611 private List<IndexMode> parseIndexModes(JSONArray indexModeUris) { 612 try { 613 List<IndexMode> indexModes = new ArrayList(); 614 if (indexModeUris != null) { 615 for (int i = 0; i < indexModeUris.length(); i++) { 616 indexModes.add(IndexMode.fromUri(indexModeUris.getString(i))); 617 } 618 } 619 return indexModes; 620 } catch (Exception e) { 621 throw new RuntimeException("Parsing index modes failed (JSONArray=" + indexModeUris + ")", e); 622 } 623 } 624 625 private List<AssociationDefinitionModel> parseAssocDefs(JSONArray assocDefs, String parentTypeUri) throws 626 JSONException { 627 List<AssociationDefinitionModel> _assocDefs = new ArrayList(); 628 if (assocDefs != null) { 629 for (int i = 0; i < assocDefs.length(); i++) { 630 JSONObject assocDef = assocDefs.getJSONObject(i) 631 .put("parent_type_uri", parentTypeUri); 632 _assocDefs.add(newAssociationDefinitionModel(assocDef)); 633 } 634 } 635 return _assocDefs; 636 } 637 638 639 640 // === AssociationDefinitionModel === 641 642 @Override 643 public AssociationDefinitionModelImpl newAssociationDefinitionModel(String assocTypeUri, 644 String parentTypeUri, String childTypeUri, 645 String parentCardinalityUri, String childCardinalityUri) { 646 return newAssociationDefinitionModel(-1, null, assocTypeUri, null, false, parentTypeUri, childTypeUri, 647 parentCardinalityUri, childCardinalityUri, null); 648 } 649 650 @Override 651 public AssociationDefinitionModelImpl newAssociationDefinitionModel(String assocTypeUri, 652 String customAssocTypeUri, boolean includeInLabel, 653 String parentTypeUri, String childTypeUri, 654 String parentCardinalityUri, String childCardinalityUri) { 655 return newAssociationDefinitionModel(-1, null, assocTypeUri, customAssocTypeUri, includeInLabel, 656 parentTypeUri, childTypeUri, parentCardinalityUri, childCardinalityUri, null); 657 } 658 659 /** 660 * @param assoc the underlying association. 661 * IMPORTANT: the association must identify its players <i>by URI</i> (not by ID). ### still true? 662 */ 663 @Override 664 public AssociationDefinitionModelImpl newAssociationDefinitionModel(AssociationModel assoc, 665 String parentCardinalityUri, String childCardinalityUri, 666 ViewConfigurationModel viewConfig) { 667 return new AssociationDefinitionModelImpl((AssociationModelImpl) assoc, parentCardinalityUri, 668 childCardinalityUri, (ViewConfigurationModelImpl) viewConfig); 669 } 670 671 @Override 672 public AssociationDefinitionModelImpl newAssociationDefinitionModel(JSONObject assocDef) { 673 try { 674 AssociationModelImpl assoc = newAssociationModel(assocDef.optLong("id", -1), null, 675 assocDef.getString("assoc_type_uri"), 676 parentRole(assocDef.getString("parent_type_uri")), 677 childRole(assocDef.getString("child_type_uri")), 678 null, childTopics(assocDef) 679 ); 680 // 681 if (!assocDef.has("parent_cardinality_uri") && !assoc.getTypeUri().equals("dm4.core.composition_def")) { 682 throw new RuntimeException("\"parent_cardinality_uri\" is missing"); 683 } 684 // 685 return new AssociationDefinitionModelImpl(assoc, 686 assocDef.optString("parent_cardinality_uri", "dm4.core.one"), 687 assocDef.getString("child_cardinality_uri"), 688 newViewConfigurationModel(assocDef.optJSONArray("view_config_topics")) 689 ); 690 } catch (Exception e) { 691 throw new RuntimeException("Parsing AssociationDefinitionModel failed (JSONObject=" + assocDef + ")", e); 692 } 693 } 694 695 /** 696 * Internal. 697 */ 698 AssociationDefinitionModelImpl newAssociationDefinitionModel(long id, String uri, String assocTypeUri, 699 String customAssocTypeUri, boolean includeInLabel, 700 String parentTypeUri, String childTypeUri, 701 String parentCardinalityUri, String childCardinalityUri, 702 ViewConfigurationModel viewConfig) { 703 return new AssociationDefinitionModelImpl( 704 newAssociationModel(id, uri, assocTypeUri, parentRole(parentTypeUri), childRole(childTypeUri), 705 null, childTopics(customAssocTypeUri, includeInLabel) // value=null 706 ), 707 parentCardinalityUri, childCardinalityUri, 708 (ViewConfigurationModelImpl) viewConfig); 709 } 710 711 /** 712 * Internal. 713 */ 714 AssociationDefinitionModelImpl newAssociationDefinitionModel(ChildTopicsModel childTopics) { 715 return new AssociationDefinitionModelImpl(newAssociationModel(childTopics)); 716 } 717 718 // --- 719 720 private TopicRoleModel parentRole(String parentTypeUri) { 721 return newTopicRoleModel(parentTypeUri, "dm4.core.parent_type"); 722 } 723 724 private TopicRoleModel childRole(String childTypeUri) { 725 return newTopicRoleModel(childTypeUri, "dm4.core.child_type"); 726 } 727 728 // --- 729 730 private ChildTopicsModel childTopics(JSONObject assocDef) throws JSONException { 731 // Note: getString()/optString() on a key with JSON null value would return the string "null" 732 String customAssocTypeUri = assocDef.isNull("custom_assoc_type_uri") ? null : 733 assocDef.getString("custom_assoc_type_uri"); 734 boolean includeInLabel = assocDef.optBoolean("include_in_label"); 735 // 736 return childTopics(customAssocTypeUri, includeInLabel); 737 } 738 739 private ChildTopicsModel childTopics(String customAssocTypeUri, boolean includeInLabel) { 740 ChildTopicsModel childTopics = newChildTopicsModel(); 741 // 742 childTopics.put("dm4.core.include_in_label", includeInLabel); 743 // 744 if (customAssocTypeUri != null) { 745 if (customAssocTypeUri.startsWith(DEL_URI_PREFIX)) { 746 childTopics.putDeletionRef("dm4.core.assoc_type#dm4.core.custom_assoc_type", 747 delTopicUri(customAssocTypeUri)); 748 } else { 749 childTopics.putRef("dm4.core.assoc_type#dm4.core.custom_assoc_type", 750 customAssocTypeUri); 751 } 752 } 753 // 754 return childTopics; 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 configTopics may be null 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}