1 57 package org.opencrx.kernel.layer.persistence; 58 59 import java.text.DecimalFormat ; 60 import java.text.NumberFormat ; 61 import java.util.Arrays ; 62 import java.util.Iterator ; 63 import java.util.List ; 64 65 import org.opencrx.kernel.generic.OpenCrxException; 66 import org.openmdx.base.exception.ServiceException; 67 import org.openmdx.compatibility.base.application.configuration.Configuration; 68 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSelectors; 69 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject; 70 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0; 71 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderOperations; 72 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderReply; 73 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest; 74 import org.openmdx.compatibility.base.dataprovider.cci.Directions; 75 import org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader; 76 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes; 77 import org.openmdx.compatibility.base.dataprovider.layer.persistence.jdbc.Database_1; 78 import org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0; 79 import org.openmdx.compatibility.base.naming.Path; 80 import org.openmdx.compatibility.base.query.FilterOperators; 81 import org.openmdx.compatibility.base.query.FilterProperty; 82 import org.openmdx.compatibility.base.query.Quantors; 83 import org.openmdx.kernel.exception.BasicException; 84 85 88 public class ObjectMapping_1 89 extends Database_1 { 90 91 public void activate( 93 short id, 94 Configuration configuration, 95 Layer_1_0 delegation 96 ) throws Exception , ServiceException { 97 98 super.activate( 99 id, 100 configuration, 101 delegation 102 ); 103 104 int activityNumberLength = 7; 106 if(configuration.values(ConfigurationKeys.ACTIVITY_NUMBER_LENGTH).size() > 0) { 107 activityNumberLength = new Integer (configuration.getFirstValue(ConfigurationKeys.ACTIVITY_NUMBER_LENGTH)).intValue(); 108 } 109 this.activityNumberFormatter = new DecimalFormat ("00000000000000000000".substring(0, activityNumberLength)); 110 111 int depotPositionQualifierLength = 13; 113 if(configuration.values(ConfigurationKeys.INVENTORY_BOOKING_QUALIFIER_LENGTH).size() > 0) { 114 depotPositionQualifierLength = new Integer (configuration.getFirstValue(ConfigurationKeys.INVENTORY_BOOKING_QUALIFIER_LENGTH)).intValue(); 115 } 116 this.contractPositionNumberFormatter = new DecimalFormat ("00000000000000000000".substring(0, depotPositionQualifierLength)); 117 118 } 119 120 private DataproviderObject retrieveObject( 122 ServiceHeader header, 123 Path identity 124 ) throws ServiceException { 125 return super.get( 126 header, 127 new DataproviderRequest( 128 new DataproviderObject(identity), 129 DataproviderOperations.OBJECT_RETRIEVAL, 130 AttributeSelectors.ALL_ATTRIBUTES, 131 null 132 ) 133 ).getObject(); 134 } 135 136 private DataproviderObject[] findObjects( 138 ServiceHeader header, 139 Path reference, 140 short attributeSelector, 141 FilterProperty[] attributeFilter 142 ) throws ServiceException { 143 return super.find( 144 header, 145 new DataproviderRequest( 146 new DataproviderObject(reference), 147 DataproviderOperations.ITERATION_START, 148 attributeFilter, 149 0, Integer.MAX_VALUE, 150 Directions.ASCENDING, 151 attributeSelector, 152 null 153 ) 154 ).getObjects(); 155 } 156 157 private DataproviderObject replaceObject( 159 ServiceHeader header, 160 DataproviderObject object 161 ) throws ServiceException { 162 return super.replace( 163 header, 164 new DataproviderRequest( 165 object, 166 DataproviderOperations.OBJECT_REPLACEMENT, 167 AttributeSelectors.ALL_ATTRIBUTES, 168 null 169 ) 170 ).getObject(); 171 } 172 173 179 private void assertSingleValues( 180 DataproviderObject_1_0 object, 181 List excludeAttributes 182 ) { 183 for( 184 Iterator i = object.attributeNames().iterator(); 185 i.hasNext(); 186 ) { 187 String attributeName = (String )i.next(); 188 if( 189 !"owner".equals(attributeName) && 190 ((excludeAttributes == null) || !excludeAttributes.contains(attributeName)) 191 ) { 192 if( 193 (object.getValues(attributeName) != null) && 194 (object.values(attributeName).size() > 1) 195 ) { 196 Object v = object.values(attributeName).get(0); 197 object.clearValues(attributeName).add(v); 198 } 199 } 200 } 201 } 202 203 private DataproviderReply completeReply( 205 ServiceHeader header, 206 DataproviderRequest request, 207 DataproviderReply reply 208 ) throws ServiceException { 209 for( 210 int i = 0; 211 i < reply.getObjects().length; 212 i++ 213 ) { 214 DataproviderObject object = reply.getObjects()[i]; 215 String objectClass = (String )object.values(SystemAttributes.OBJECT_CLASS).get(0); 216 Path accessPath = object.path(); 217 218 220 if( 222 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:activity1:Activity") && 223 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.activity1/provider/:*/segment/:*/activity/:*")) 224 ) { 225 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 226 new Path("xri:@openmdx:org.opencrx.kernel.activity1").getDescendant( 227 new String []{ 228 "provider", 229 object.path().get(2), 230 "segment", 231 object.path().get(4), 232 "activity", 233 object.path().getBase() 234 } 235 ).toXri() 236 ); 237 this.assertSingleValues(object, null); 238 } 239 else if( 241 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:Product") && 242 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.product1/provider/:*/segment/:*/product/:*")) 243 ) { 244 String id = object.path().getBase(); 245 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 246 new Path("xri:@openmdx:org.opencrx.kernel.product1").getDescendant( 247 new String []{ 248 "provider", 249 object.path().get(2), 250 "segment", 251 object.path().get(4), 252 "product", 253 id.substring(id.indexOf("~") + 1) 254 } 255 ).toXri() 256 ); 257 this.assertSingleValues(object, null); 258 } 259 else if( 261 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:ProductOffering") && 262 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.product1/provider/:*/segment/:*/productOffering/:*")) 263 ) { 264 String id = object.path().getBase(); 265 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 266 new Path("xri:@openmdx:org.opencrx.kernel.product1").getDescendant( 267 new String []{ 268 "provider", 269 object.path().get(2), 270 "segment", 271 object.path().get(4), 272 "productOffering", 273 id.substring(id.indexOf("~") + 1) 274 } 275 ).toXri() 276 ); 277 this.assertSingleValues(object, null); 278 } 279 else if( 281 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:ProductBundleType") && 282 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.product1/provider/:*/segment/:*/productBundleType/:*")) 283 ) { 284 String id = object.path().getBase(); 285 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 286 new Path("xri:@openmdx:org.opencrx.kernel.product1").getDescendant( 287 new String []{ 288 "provider", 289 object.path().get(2), 290 "segment", 291 object.path().get(4), 292 "productBundleType", 293 id.substring(id.indexOf("~") + 1) 294 } 295 ).toXri() 296 ); 297 this.assertSingleValues(object, null); 298 } 299 else if( 301 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:ProductBundle") && 302 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.product1/provider/:*/segment/:*/productOffering/:*/productBundle/:*")) 303 ) { 304 String id = object.path().getBase(); 305 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 306 new Path("xri:@openmdx:org.opencrx.kernel.product1").getDescendant( 307 new String []{ 308 "provider", 309 object.path().get(2), 310 "segment", 311 object.path().get(4), 312 "productOffering", 313 id.substring(0, id.indexOf("~")), 314 "productBundle", 315 id.substring(id.indexOf("~") + 1) 316 } 317 ).toXri() 318 ); 319 this.assertSingleValues(object, null); 320 } 321 else if( 323 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:BundledProduct") && 324 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.product1/provider/:*/segment/:*/productBundleType/:*/bundledProduct/:*")) 325 ) { 326 String id = object.path().getBase(); 327 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 328 new Path("xri:@openmdx:org.opencrx.kernel.product1").getDescendant( 329 new String []{ 330 "provider", 331 object.path().get(2), 332 "segment", 333 object.path().get(4), 334 "productBundleType", 335 id.substring(0, id.indexOf("~")), 336 "bundledProduct", 337 id.substring(id.indexOf("~") + 1) 338 } 339 ).toXri() 340 ); 341 this.assertSingleValues(object, null); 342 } 343 else if( 345 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:account1:Account") && 346 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.account1/provider/:*/segment/:*/account/:*")) 347 ) { 348 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 349 new Path("xri:@openmdx:org.opencrx.kernel.account1").getDescendant( 350 new String []{ 351 "provider", 352 object.path().get(2), 353 "segment", 354 object.path().get(4), 355 "account", 356 object.path().getBase() 357 } 358 ).toXri() 359 ); 360 this.assertSingleValues(object, null); 361 } 362 else if( 364 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:account1:SearchIndexEntry") 365 ) { 366 this.assertSingleValues(object, null); 367 } 368 else if( 370 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:activity1:ActivityLinkFrom") 371 ) { 372 this.assertSingleValues(object, null); 373 } 374 else if( 376 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:product1:PriceListEntry") 377 ) { 378 this.assertSingleValues( 379 object, 380 Arrays.asList(new String []{"usage"}) 381 ); 382 } 383 else if( 385 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:ContractRole") 386 ) { 387 this.assertSingleValues(object, null); 388 } 389 else if( 391 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:activity1:ActivityFollowUp") && 392 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.activity1/provider/:*/segment/:*/activity/:*/followUp/:*")) 393 ) { 394 String id = object.path().getBase(); 395 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 396 new Path("xri:@openmdx:org.opencrx.kernel.activity1").getDescendant( 397 new String []{ 398 "provider", 399 object.path().get(2), 400 "segment", 401 object.path().get(4), 402 "activity", 403 id.substring(0, id.indexOf("~")), 404 "followUp", 405 id.substring(id.indexOf("~") + 1) 406 } 407 ).toXri() 408 ); 409 this.assertSingleValues(object, null); 410 } 411 else if( 413 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:Lead") && 414 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/lead/:*")) 415 ) { 416 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 417 new Path("xri:@openmdx:org.opencrx.kernel.contract1").getDescendant( 418 new String []{ 419 "provider", 420 object.path().get(2), 421 "segment", 422 object.path().get(4), 423 "lead", 424 object.path().getBase() 425 } 426 ).toXri() 427 ); 428 this.assertSingleValues(object, null); 429 } 430 else if( 432 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:Opportunity") && 433 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/opportunity/:*")) 434 ) { 435 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 436 new Path("xri:@openmdx:org.opencrx.kernel.contract1").getDescendant( 437 new String []{ 438 "provider", 439 object.path().get(2), 440 "segment", 441 object.path().get(4), 442 "opportunity", 443 object.path().getBase() 444 } 445 ).toXri() 446 ); 447 this.assertSingleValues(object, null); 448 } 449 else if( 451 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:Quote") && 452 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/quote/:*")) 453 ) { 454 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 455 new Path("xri:@openmdx:org.opencrx.kernel.contract1").getDescendant( 456 new String []{ 457 "provider", 458 object.path().get(2), 459 "segment", 460 object.path().get(4), 461 "quote", 462 object.path().getBase() 463 } 464 ).toXri() 465 ); 466 this.assertSingleValues(object, null); 467 } 468 else if( 470 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:SalesOrder") && 471 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/salesOrder/:*")) 472 ) { 473 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 474 new Path("xri:@openmdx:org.opencrx.kernel.contract1").getDescendant( 475 new String []{ 476 "provider", 477 object.path().get(2), 478 "segment", 479 object.path().get(4), 480 "salesOrder", 481 object.path().getBase() 482 } 483 ).toXri() 484 ); 485 this.assertSingleValues(object, null); 486 } 487 else if( 489 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:Invoice") && 490 !accessPath.isLike(new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/invoice/:*")) 491 ) { 492 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 493 new Path("xri:@openmdx:org.opencrx.kernel.contract1").getDescendant( 494 new String []{ 495 "provider", 496 object.path().get(2), 497 "segment", 498 object.path().get(4), 499 "invoice", 500 object.path().getBase() 501 } 502 ).toXri() 503 ); 504 this.assertSingleValues(object, null); 505 } 506 else if( 508 this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:activity1:WorkReportEntry") 509 ) { 510 this.assertSingleValues(object, null); 511 } 512 else if( 514 object.path().isLike(PATTERN_ACTIVITY_TRACKER_CONTAINS_ACTIVITY_NOTE) 515 ) { 516 String id = object.path().getBase(); 517 object.clearValues(SystemAttributes.OBJECT_IDENTITY).add( 518 new Path("xri:@openmdx:org.opencrx.kernel.activity1").getDescendant( 519 new String []{ 520 "provider", 521 object.path().get(2), 522 "segment", 523 object.path().get(4), 524 "activity", 525 id.substring(0, id.indexOf("~")), 526 "note", 527 id.substring(id.indexOf("~")+1) 528 } 529 ).toXri() 530 ); 531 this.assertSingleValues(object, null); 532 } 533 } 534 return reply; 535 } 536 537 private DataproviderRequest prepareFindRequest( 539 ServiceHeader header, 540 DataproviderRequest request 541 ) { 542 return request; 543 } 544 545 private void setActivityNumber( 547 ServiceHeader header, 548 DataproviderRequest request, 549 Path existingIdentity 550 ) throws ServiceException { 551 if(request.path().isLike(PATTERN_ACTIVITY)) { 552 DataproviderObject activitySegment = this.retrieveObject( 554 header, 555 request.path().getParent().getParent() 556 ); 557 long currentActivityNumber = activitySegment.getValues("currentActivityNumber") != null 558 ? ((Number )activitySegment.getValues("currentActivityNumber").get(0)).longValue() 559 : 0; 560 boolean activitySegmentModified = false; 561 562 String suppliedActivityNumber = request.object().getValues("activityNumber") != null 564 ? (String )request.object().values("activityNumber").get(0) 565 : null; 566 567 DataproviderObject existing = existingIdentity == null 569 ? null 570 : this.retrieveObject(header, existingIdentity); 571 String existingActivityNumber = (existing != null) && (existing.getValues("activityNumber") != null) 572 ? (String )existing.values("activityNumber").get(0) 573 : null; 574 575 if(suppliedActivityNumber == null) { 577 if(existingActivityNumber == null) { 578 Long nextActivityNumber = new Long (currentActivityNumber + 1); 579 request.object().clearValues("activityNumber").add(this.activityNumberFormatter.format(nextActivityNumber.longValue())); 580 activitySegment.clearValues("currentActivityNumber").add(nextActivityNumber); 581 activitySegmentModified = true; 582 } 583 } 584 585 else { 588 DataproviderObject[] activities = this.findObjects( 589 header, 590 request.path().getParent(), 591 AttributeSelectors.NO_ATTRIBUTES, 592 new FilterProperty[]{ 593 new FilterProperty( 594 Quantors.THERE_EXISTS, 595 "activityNumber", 596 FilterOperators.IS_IN, 597 new String []{suppliedActivityNumber} 598 ) 599 } 600 ); 601 if(activities.length > 0) { 603 if((activities.length == 1) && !activities[0].path().equals(request.path())) { 604 throw new ServiceException( 605 OpenCrxException.DOMAIN, 606 OpenCrxException.ASSERTION_FAILURE, 607 new BasicException.Parameter[]{ 608 new BasicException.Parameter("param0", "activityNumber"), 609 new BasicException.Parameter("param1", suppliedActivityNumber) 610 }, 611 "Duplicate activity number" 612 ); 613 } 614 } 615 else { 616 try { 617 long numberAsLong = new Long (suppliedActivityNumber).longValue(); 618 activitySegment.clearValues("currentActivityNumber").add( 619 new Long (java.lang.Math.max(numberAsLong, currentActivityNumber)) 620 ); 621 activitySegmentModified = true; 622 } 623 catch(NumberFormatException e) {} 624 } 625 } 626 if(activitySegmentModified) { 627 this.replaceObject(header, activitySegment); 628 } 629 } 630 } 631 632 636 private void setContractPositionNumber( 637 ServiceHeader header, 638 DataproviderRequest request, 639 Path existingIdentity 640 ) throws ServiceException { 641 if( 642 request.path().isLike(PATTERN_OPPORTUNITY_POSITION) || 643 request.path().isLike(PATTERN_QUOTE_POSITION) || 644 request.path().isLike(PATTERN_SALESORDER_POSITION) || 645 request.path().isLike(PATTERN_INVOICE_POSITION) 646 ) { 647 DataproviderObject contractSegment = this.retrieveObject( 649 header, 650 request.path().getPrefix(5) 651 ); 652 long currentContractPositionNumber = contractSegment.getValues("currentPositionNumber") != null 653 ? ((Number )contractSegment.getValues("currentPositionNumber").get(0)).longValue() 654 : 0; 655 boolean contractSegmentModified = false; 656 657 String suppliedContractPositionNumber = request.object().getValues("positionNumber") != null 659 ? (String )request.object().values("positionNumber").get(0) 660 : null; 661 DataproviderObject existing = existingIdentity == null 663 ? null 664 : this.retrieveObject(header, existingIdentity); 665 String existingContractPositionNumber = (existing != null) && (existing.getValues("positionNumber") != null) 666 ? (String )existing.values("positionNumber").get(0) 667 : null; 668 if(suppliedContractPositionNumber == null) { 670 if(existingContractPositionNumber == null) { 671 Long nextContractPositionNumber = new Long (currentContractPositionNumber + 1); 672 request.object().clearValues("positionNumber").add(this.contractPositionNumberFormatter.format(nextContractPositionNumber.longValue())); 673 contractSegment.clearValues("currentPositionNumber").add(nextContractPositionNumber); 674 contractSegmentModified = true; 675 } 676 } 677 else { 679 try { 680 long numberAsLong = new Long (suppliedContractPositionNumber).longValue(); 681 contractSegment.clearValues("currentPositionNumber").add( 682 new Long (java.lang.Math.max(numberAsLong, currentContractPositionNumber)) 683 ); 684 contractSegmentModified = true; 685 } 686 catch(NumberFormatException e) {} 687 } 688 if(contractSegmentModified) { 689 this.replaceObject(header, contractSegment); 690 } 691 } 692 } 693 694 public DataproviderReply get( 696 ServiceHeader header, 697 DataproviderRequest request 698 ) throws ServiceException { 699 return this.completeReply( 700 header, 701 request, 702 super.get(header, request) 703 ); 704 } 705 706 public DataproviderReply find( 708 ServiceHeader header, 709 DataproviderRequest request 710 ) throws ServiceException { 711 return this.completeReply( 712 header, 713 request, 714 super.find(header, this.prepareFindRequest(header, request)) 715 ); 716 } 717 718 public DataproviderReply create( 720 ServiceHeader header, 721 DataproviderRequest request 722 ) throws ServiceException { 723 724 this.setActivityNumber( 725 header, 726 request, 727 null 728 ); 729 this.setContractPositionNumber( 730 header, 731 request, 732 null 733 ); 734 return super.create(header, request); 735 } 736 737 public DataproviderReply replace( 739 ServiceHeader header, 740 DataproviderRequest request 741 ) throws ServiceException { 742 this.setActivityNumber( 743 header, 744 request, 745 request.path() 746 ); 747 this.setContractPositionNumber( 748 header, 749 request, 750 request.path() 751 ); 752 return super.replace(header, request); 753 } 754 755 static private final Path PATTERN_ACTIVITY_TRACKER_CONTAINS_ACTIVITY_NOTE_REF = 759 new Path("xri:@openmdx:org.opencrx.kernel.activity1/provider/:*/segment/:*/activityTracker/:*/activityNote"); 760 static private final Path PATTERN_ACTIVITY_TRACKER_CONTAINS_ACTIVITY_NOTE = 761 PATTERN_ACTIVITY_TRACKER_CONTAINS_ACTIVITY_NOTE_REF.getChild(":*"); 762 763 static private final Path PATTERN_ACTIVITY = 764 new Path("xri:@openmdx:org.opencrx.kernel.activity1/provider/:*/segment/:*/activity/:*"); 765 static private final Path PATTERN_OPPORTUNITY_POSITION = 766 new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/opportunity/:*/position/:*"); 767 static private final Path PATTERN_QUOTE_POSITION = 768 new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/quote/:*/position/:*"); 769 static private final Path PATTERN_SALESORDER_POSITION = 770 new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/salesOrder/:*/position/:*"); 771 static private final Path PATTERN_INVOICE_POSITION = 772 new Path("xri:@openmdx:org.opencrx.kernel.contract1/provider/:*/segment/:*/invoice/:*/position/:*"); 773 774 private NumberFormat activityNumberFormatter = null; 775 private NumberFormat contractPositionNumberFormatter = null; 776 777 } 778 779 | Popular Tags |