1 56 package org.opencrx.kernel.layer.application; 57 58 import java.beans.XMLDecoder ; 59 import java.io.ByteArrayInputStream ; 60 import java.io.ByteArrayOutputStream ; 61 import java.io.IOException ; 62 import java.io.InputStream ; 63 import java.io.OutputStream ; 64 import java.io.OutputStreamWriter ; 65 import java.io.PrintStream ; 66 import java.io.PrintWriter ; 67 import java.util.ArrayList ; 68 import java.util.Arrays ; 69 import java.util.HashMap ; 70 import java.util.HashSet ; 71 import java.util.Iterator ; 72 import java.util.List ; 73 import java.util.Map ; 74 import java.util.Set ; 75 import java.util.StringTokenizer ; 76 import java.util.TreeSet ; 77 import java.util.Map.Entry; 78 import java.util.zip.ZipEntry ; 79 import java.util.zip.ZipOutputStream ; 80 81 import org.openmdx.application.log.AppLog; 82 import org.openmdx.base.exception.ServiceException; 83 import org.openmdx.base.query.Filter; 84 import org.openmdx.base.text.conversion.Base64; 85 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject; 86 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0; 87 import org.openmdx.compatibility.base.dataprovider.cci.RequestCollection; 88 import org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader; 89 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes; 90 import org.openmdx.compatibility.base.dataprovider.exporter.TraversalHandler; 91 import org.openmdx.compatibility.base.dataprovider.exporter.XMLExportHandler; 92 import org.openmdx.compatibility.base.dataprovider.exporter.XmlContentHandler; 93 import org.openmdx.compatibility.base.dataprovider.exporter.XmlExporter; 94 import org.openmdx.compatibility.base.dataprovider.importer.xml.XmlImporter; 95 import org.openmdx.compatibility.base.naming.Path; 96 import org.openmdx.kernel.exception.BasicException; 97 import org.openmdx.model1.accessor.basic.cci.ModelElement_1_0; 98 import org.openmdx.model1.accessor.basic.cci.Model_1_0; 99 import org.openmdx.model1.code.Multiplicities; 100 import org.xml.sax.SAXException ; 101 import org.xml.sax.SAXParseException ; 102 103 public class Xml { 104 105 class Importer extends XmlImporter { 107 108 public Importer( 109 RequestCollection target, 110 RequestCollection reader, 111 List errors, 112 List report 113 ) throws ServiceException { 114 super(target, reader, false, true); 115 this.errors = errors; 116 this.report = report; 117 } 118 119 private void addError( 120 String message 121 ) { 122 if(this.errors.size() < 5) { 123 this.errors.add(message); 124 } 125 } 126 127 private void addError( 128 SAXParseException e 129 ) { 130 this.addError("[" + this.getLocationString(e) + "]: " + e.getMessage()); 131 } 132 133 public void beginObject( 134 DataproviderObject object, 135 String operation 136 ) throws ServiceException { 137 if( 138 (object.path().size() > 5) && 139 ((this.mainObject == null) || (object.path().size() < this.mainObject.path().size())) 140 ) { 141 this.mainObject = object; 142 } 143 } 144 145 public void endObject( 146 DataproviderObject object, 147 String operation 148 ) throws ServiceException { 149 try { 150 if(!"null".equals(operation)) { 151 try { 152 DataproviderObject test = new DataproviderObject( 154 Xml.this.plugin.retrieveObjectForModification(object.path()) 155 ); 156 test.addClones( 157 object, 158 true 159 ); 160 Xml.this.model.verifyObject( 161 test, 162 test.values(SystemAttributes.OBJECT_CLASS).get(0), 163 Multiplicities.SINGLE_VALUE, 164 "create".equals(operation) 165 ); 166 167 Xml.this.removeForeignAndDerivedAttributes(object); 169 Xml.this.plugin.retrieveObjectForModification(object.path()).addClones( 170 object, 171 true 172 ); 173 } catch(Exception e) { 174 Xml.this.model.verifyObject( 175 object, 176 object.values(SystemAttributes.OBJECT_CLASS).get(0), 177 Multiplicities.SINGLE_VALUE, 178 "create".equals(operation) 179 ); 180 Xml.this.removeForeignAndDerivedAttributes(object); 181 Xml.this.target.addCreateRequest(object); 182 } 183 this.report.add(operation); 184 } 185 } 186 catch(ServiceException e) { 187 e.log(); this.addError(e.getMessage() + " at object " + object.path()); 189 } 190 } 191 192 public void error( 193 SAXParseException e 194 ) throws SAXException { 195 this.addError(e); 196 super.error(e); 197 } 198 199 public void fatalError( 200 SAXParseException e 201 ) throws SAXException { 202 this.addError(e); 203 super.fatalError(e); 204 } 205 206 public void warning( 207 SAXParseException e 208 ) { 209 this.report.add(e.getMessage()); 210 super.warning(e); 211 } 212 213 public void process( 214 InputStream [] is 215 ) { 216 try { 217 super.process(is); 218 } 219 catch(ServiceException e) { 220 BasicException be = e.getStackedException(0); 221 this.errors.add(be.getDescription() + " (" + Arrays.asList(be.getParameters()) + ")"); 222 } 223 } 224 225 public DataproviderObject getMainObject( 226 ) { 227 return this.mainObject; 228 } 229 230 private DataproviderObject mainObject = null; 231 private final List errors; 232 private final List report; 233 } 234 235 class Exporter extends XmlExporter { 237 238 public Exporter( 240 ServiceHeader header, 241 RequestCollection reader, 242 PrintStream exportStream, 243 Model_1_0 model, 244 Map exportedCodes 245 ) { 246 super( 247 header, 248 reader, 249 exportStream, 250 model, 251 "UTF-8" 252 ); 253 this.referencedObjects = new HashSet (); 254 this.exportedObjects = new HashSet (); 255 this.exportedCodes = exportedCodes; 256 } 257 258 public Set getReferencedObjects( 259 ) { 260 return this.referencedObjects; 261 } 262 263 public Set getExportedObjects( 264 ) { 265 return this.exportedObjects; 266 } 267 268 void updateReferencedObjects( 269 DataproviderObject_1_0 object 270 ) { 271 Xml.this.plugin.collectReferencedObjects( 272 object, 273 Xml.this.referenceFilter, 274 this.referencedObjects 275 ); 276 } 277 278 protected TraversalHandler setupTraversalHandler( 279 ) throws ServiceException { 280 this.setupContentHandler( 281 this.exportStream 282 ); 283 TaggingXMLExportHandler exportHandler = new TaggingXMLExportHandler( 284 this.model, 285 "http://www.w3.org/2001/XMLSchema-instance", 286 this.schemaString, 287 this.exportedCodes 288 ); 289 exportHandler.setContentHandler( 290 this.setupContentHandler(this.exportStream) 291 ); 292 return exportHandler; 293 } 294 295 protected XmlContentHandler setupContentHandler( 296 PrintStream target 297 ) throws ServiceException { 298 return new NonClosingXmlContentHandler( 299 target 300 ); 301 } 302 303 public void export( 305 List startPoints, 306 List referenceFilters, 307 Map attributeFilters, 308 String schemaString, 309 int maxObjects 310 ) throws ServiceException { 311 super.export( 312 startPoints, 313 referenceFilters, 314 attributeFilters, 315 schemaString 316 ); 317 } 318 319 class TaggingXMLExportHandler 321 extends XMLExportHandler { 322 323 public TaggingXMLExportHandler( 324 Model_1_0 model, 325 String schemaInstance, 326 String schemaLocation, 327 Map exportedCodes 328 ) { 329 super(model, schemaInstance, schemaLocation); 330 this.exportedCodes = exportedCodes; 331 } 332 333 339 public Map getAttributeTags( 340 DataproviderObject_1_0 object 341 ) throws ServiceException { 342 Map attributeTags = new HashMap (); 343 String objectClassName = (String )object.values(SystemAttributes.OBJECT_CLASS).get(0); 344 if(objectClassName != null) { 345 ModelElement_1_0 objectClass = this.model.getElement(objectClassName); 346 if(objectClass != null) { 347 for(Iterator i = object.attributeNames().iterator(); i.hasNext(); ) { 348 String attributeName = (String )i.next(); 349 for(Iterator j = objectClass.values("allSupertype").iterator(); j.hasNext(); ) { 351 ModelElement_1_0 supertype = this.model.getElement(j.next()); 352 String qualifiedClassName = (String )supertype.values("qualifiedName").get(0); 353 String qualifiedAttributeName = qualifiedClassName + ":" + attributeName; 354 DataproviderObject_1_0 codeValueContainer = Xml.this.plugin.getCodes().getCodeValueContainerByName(qualifiedAttributeName); 355 if(codeValueContainer != null) { 357 String codeValueContainerName = codeValueContainer.path().getBase(); 358 attributeTags.put( 359 attributeName, 360 "@see CodeValueContainer name=\"" + codeValueContainerName + "\"" 361 ); 362 Set codes = null; 364 if((codes = (Set )this.exportedCodes.get(codeValueContainerName)) == null) { 365 this.exportedCodes.put( 366 codeValueContainerName, 367 codes = new HashSet () 368 ); 369 } 370 try { 372 for(Iterator k = object.values(attributeName).iterator(); k.hasNext(); ) { 373 codes.add(new Integer (((Number )k.next()).intValue())); 374 } 375 } 376 catch(Exception e) { 377 AppLog.error("Exception occurred while retrieving codes for attribute", attributeName); 378 new ServiceException(e).log(); 379 } 380 break; 381 } 382 } 383 } 384 } 385 } 386 return attributeTags; 387 } 388 389 public boolean featureComplete( 390 DataproviderObject_1_0 object 391 ) throws ServiceException { 392 Exporter.this.updateReferencedObjects(object); 393 if((object.getValues(SystemAttributes.OBJECT_CLASS) != null) && (object.path().size() > 5)) { 395 Exporter.this.exportedObjects.add(object.path()); 396 } 397 return super.featureComplete( 398 object 399 ); 400 } 401 402 private final Map exportedCodes; 403 } 404 405 class NonClosingXmlContentHandler 407 extends XmlContentHandler { 408 409 public NonClosingXmlContentHandler( 410 PrintStream stream 411 ) { 412 super(stream); 413 } 414 415 public void endDocument( 416 ) throws ServiceException { 417 super.endDocument(false); 418 } 419 } 420 421 int currentEntryId = 0; 422 423 final Set referencedObjects; 424 final Set exportedObjects; 425 final Map exportedCodes; 428 } 429 430 static class NullOutputStream 432 extends OutputStream { 433 434 public NullOutputStream() { 435 } 436 public void close() throws IOException { 437 } 438 public void flush() throws IOException { 439 } 440 public void write(byte[] b, int off, int len) throws IOException { 441 } 442 public void write(byte[] b) throws IOException { 443 } 444 public void write(int b) throws IOException { 445 } 446 } 447 448 public Xml( 450 OpenCrxKernel_1 plugin, 451 RequestCollection target, 452 RequestCollection reader, 453 Model_1_0 model 454 ) { 455 this.plugin = plugin; 456 this.target = target; 457 this.reader = reader; 458 this.model = model; 459 this.header = null; 460 } 461 462 public Xml( 464 OpenCrxKernel_1 plugin, 465 ServiceHeader header, 466 RequestCollection reader, 467 Model_1_0 model 468 ) { 469 this.plugin = plugin; 470 this.header = header; 471 this.model = model; 472 this.target = null; 473 this.reader = reader; 474 } 475 476 void removeForeignAndDerivedAttributes( 478 DataproviderObject object 479 ) throws ServiceException { 480 481 ModelElement_1_0 typeDef = this.model.getElement(object.values(SystemAttributes.OBJECT_CLASS).get(0)); 483 if(this.model.isClassType(typeDef)) { 484 Map attributeDefs = this.model.getAttributeDefs( 485 typeDef, false, true 486 ); 487 for( 488 Iterator i = object.attributeNames().iterator(); 489 i.hasNext(); 490 ) { 491 boolean isDerived = false; 492 boolean isChangeable = true; 493 boolean isForeign = true; 494 495 String featureName = (String )i.next(); 496 497 if(featureName.indexOf(':') < 0) { 499 ModelElement_1_0 featureDef = (ModelElement_1_0) attributeDefs.get(featureName); 500 501 if (featureDef != null) { 502 isDerived = 503 (featureDef.values("isDerived").size() > 0) && 504 ((Boolean )featureDef.values("isDerived").get(0)).booleanValue(); 505 isChangeable = 506 (featureDef.values("isChangeable").size() > 0) && 507 ((Boolean )featureDef.values("isChangeable").get(0)).booleanValue(); 508 isForeign = false; 509 } 510 boolean isSystemAttribute = 511 SystemAttributes.OBJECT_CLASS.equals(featureName) 512 || SystemAttributes.CREATED_AT.equals(featureName) 513 || SystemAttributes.MODIFIED_AT.equals(featureName) 514 || SystemAttributes.CREATED_BY.equals(featureName) 515 || SystemAttributes.MODIFIED_BY.equals(featureName); 516 517 if((isDerived || !isChangeable || isForeign) && !isSystemAttribute) { 518 i.remove(); 519 } 520 } 521 } 522 } 523 } 524 525 private void exportItem( 527 ZipOutputStream zip, 528 PrintStream ps, 529 List startPoints, 530 Set exportedObjects, 531 Map exportedCodes, 532 int level 533 ) throws IOException , ServiceException { 534 if(level >= 0) { 535 List referencedObjects = new ArrayList (); 536 for( 537 Iterator i = startPoints.iterator(); 538 i.hasNext(); 539 ) { 540 Path startPoint = (Path)i.next(); 541 if(!exportedObjects.contains(startPoint)) { 542 zip.putNextEntry( 543 new ZipEntry ("data-" + (this.currentEntryId++) + ".xml") 544 ); 545 546 String qualifiedModelName = startPoint.get(0); 548 String namespace = qualifiedModelName.substring(0, qualifiedModelName.lastIndexOf(":")); 549 String modelName = qualifiedModelName.substring(qualifiedModelName.lastIndexOf(":") + 1); 550 Exporter exporter = new Exporter( 551 this.header, 552 this.reader, 553 ps, 554 this.model, 555 exportedCodes 556 ); 557 exporter.export( 558 Arrays.asList(new Path[]{startPoint}), 559 this.referenceFilter, 560 this.attributeFilter, 561 "xri:+resource/" + namespace.replace(':', '/') + "/" + modelName + "/xmi/" + modelName + ".xsd" 562 ); 563 564 referencedObjects.addAll( 566 exporter.getReferencedObjects() 567 ); 568 exportedObjects.addAll( 569 exporter.getExportedObjects() 570 ); 571 } 572 } 573 this.exportItem( 574 zip, 575 ps, 576 referencedObjects, 577 exportedObjects, 578 exportedCodes, 579 level-1 580 ); 581 } 582 } 583 584 public byte[] exportItem( 586 DataproviderObject_1_0 startFrom, 587 DataproviderObject_1_0 param 588 ) throws ServiceException { 589 590 try { 591 592 String referenceFilter = (String )param.values("referenceFilter").get(0); 594 if(referenceFilter == null) { 595 referenceFilter = ":*"; 596 } 597 this.referenceFilter = new ArrayList (); 598 StringTokenizer tokenizer = new StringTokenizer (referenceFilter, " ;,", false); 599 while(tokenizer.hasMoreTokens()) { 600 this.referenceFilter.add( 601 new Path(startFrom.path().toXri() + "/" + tokenizer.nextToken()) 602 ); 603 } 604 605 String attributeFilter = (String )param.values("attributeFilter").get(0); 607 this.attributeFilter = new HashMap (); 608 if(attributeFilter != null) { 609 tokenizer = new StringTokenizer (attributeFilter, " ;,", false); 610 while(tokenizer.hasMoreTokens()) { 611 String filterDefinition = tokenizer.nextToken(); 612 int pos = 0; 613 if((pos = filterDefinition.indexOf("=")) >= 0) { 614 Path reference = new Path(startFrom.path().toXri() + "/" + filterDefinition.substring(0, pos)); 615 Filter filter = null; 616 if(!"*".equals(filterDefinition.substring(pos+1))) { 617 try { 618 XMLDecoder decoder = new XMLDecoder ( 619 new ByteArrayInputStream (Base64.decode(filterDefinition.substring(pos+1))) 620 ); 621 filter = (Filter)decoder.readObject(); 622 decoder.close(); 623 } 624 catch(Exception e) {} 625 } 626 if(filter != null) { 627 this.attributeFilter.put( 628 reference, 629 filter 630 ); 631 } 632 } 633 } 634 } 635 636 Set exportedObjects = new TreeSet (); 637 638 642 ZipOutputStream zip = new ZipOutputStream (new NullOutputStream()); 644 PrintStream ps = new PrintStream (zip); 645 Map exportedCodes = new HashMap (); 646 exportedCodes.put( 648 LOCALE_CODE_TABLE_ID, 649 null 650 ); 651 this.currentEntryId = 0; 652 this.exportItem( 653 zip, 654 ps, 655 Arrays.asList(new Path[]{startFrom.path()} 656 ), 657 exportedObjects, 658 exportedCodes, 659 MAX_LEVELS 660 ); 661 662 Path last = null; 665 for( 666 Iterator i = exportedObjects.iterator(); 667 i.hasNext(); 668 ) { 669 Path current = (Path)i.next(); 670 if((last != null) && (current.startsWith(last))) { 671 i.remove(); 672 } 673 else { 674 last = current; 675 } 676 } 677 678 List exportedObjectsAsList = new ArrayList (exportedObjects); 682 exportedObjectsAsList.remove(startFrom.path()); 683 684 ByteArrayOutputStream bs = new ByteArrayOutputStream (); 686 zip = new ZipOutputStream (bs); 687 ps = new PrintStream (zip); 688 exportedCodes = new HashMap (); 689 exportedCodes.put( 690 LOCALE_CODE_TABLE_ID, 691 null 692 ); 693 this.currentEntryId = 0; 695 this.exportItem( 696 zip, 697 ps, 698 Arrays.asList(new Path[]{startFrom.path()}), 699 new TreeSet (), 700 exportedCodes, 701 0 702 ); 703 this.exportItem( 705 zip, 706 ps, 707 exportedObjectsAsList, 708 new TreeSet (), 709 exportedCodes, 710 0 711 ); 712 713 zip.putNextEntry( 715 new ZipEntry ("codes.xml") 716 ); 717 PrintWriter writer = new PrintWriter ( 718 new OutputStreamWriter (ps, "UTF-8"), 719 true 720 ); 721 writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 722 writer.println("<org.openmdx.base.Authority xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"org:opencrx:kernel:code1\" xsi:noNamespaceSchemaLocation=\"xri:+resource/org/opencrx/kernel/code1/xmi/code1.xsd\">"); 723 writer.println(" <_object/>"); 724 writer.println(" <_content>"); 725 writer.println(" <provider>"); 726 writer.println(" <org.openmdx.base.Provider qualifiedName=\"CRX\" _operation=\"null\">"); 727 writer.println(" <_object/>"); 728 writer.println(" <_content>"); 729 writer.println(" <segment>"); 730 writer.println(" <org.opencrx.kernel.code1.Segment qualifiedName=\"Root\" _operation=\"null\">"); 731 writer.println(" <_object/>"); 732 writer.println(" <_content>"); 733 writer.println(" <valueContainer>"); 734 for(Iterator j = exportedCodes.entrySet().iterator(); j.hasNext(); ) { 735 Entry e = (Entry)j.next(); 736 String codeValueContainerId = (String )e.getKey(); 737 Set codes = (Set )e.getValue(); 738 List codeEntries = this.plugin.getCodes().getCodeEntriesById(codeValueContainerId); 739 if(((codes == null) || (codes.size() > 0)) && (codeEntries != null)) { 740 writer.println(" <org.opencrx.kernel.code1.CodeValueContainer name=\"" + codeValueContainerId + "\" _operation=\"null\">"); 741 writer.println(" <_object/>"); 742 writer.println(" <_content>"); 743 writer.println(" <entry>"); 744 for(Iterator k = codeEntries.iterator(); k.hasNext(); ) { 745 DataproviderObject_1_0 codeEntry = (DataproviderObject_1_0)k.next(); 746 Number code = new Integer (codeEntry.path().getBase()); 747 if((codes == null) || (codes.contains(code))) { 748 writer.println(" <org.opencrx.kernel.code1.CodeValueEntry code=\"" + code + "\" _operation=\"null\">"); 749 writer.println(" <_object>"); 750 751 writer.println(" <shortText>"); 753 int ll = 0; 754 for( 755 Iterator l = codeEntry.values("shortText").iterator(); 756 l.hasNext(); 757 ll++ 758 ) { 759 String text = (String )l.next(); 760 if(text == null) { 761 writer.println(" <_item />"); 762 } 763 else { 764 writer.println(" <_item>" + text + "</_item>"); 765 } 766 } 767 writer.println(" </shortText>"); 768 769 writer.println(" <longText>"); 771 ll = 0; 772 for( 773 Iterator l = codeEntry.values("longText").iterator(); 774 l.hasNext(); 775 ll++ 776 ) { 777 String text = (String )l.next(); 778 if(text == null) { 779 writer.println(" <_item />"); 780 } 781 else { 782 writer.println(" <_item>" + text + "</_item>"); 783 } 784 } 785 writer.println(" </longText>"); 786 787 writer.println(" </_object>"); 788 writer.println(" <_content/>"); 789 writer.println(" </org.opencrx.kernel.code1.CodeValueEntry>"); 790 } 791 } 792 writer.println(" </entry>"); 793 writer.println(" </_content>"); 794 writer.println(" </org.opencrx.kernel.code1.CodeValueContainer>"); 795 } 796 } 797 writer.println(" </valueContainer>"); 798 writer.println(" </_content>"); 799 writer.println(" </org.opencrx.kernel.code1.Segment>"); 800 writer.println(" </segment>"); 801 writer.println(" </_content>"); 802 writer.println(" </org.openmdx.base.Provider>"); 803 writer.println(" </provider>"); 804 writer.println(" </_content>"); 805 writer.println("</org.openmdx.base.Authority>"); 806 zip.closeEntry(); 807 808 ps.close(); 809 return bs.toByteArray(); 810 } 811 catch(IOException e) { 812 throw new ServiceException(e); 813 } 814 } 815 816 public DataproviderObject importItem( 818 byte[] item, 819 short locale, 820 List errors, 821 List report 822 ) throws ServiceException { 823 Importer importer = new Importer( 824 this.target, 825 this.reader, 826 errors, 827 report 828 ); 829 importer.process( 830 new InputStream []{new ByteArrayInputStream (item)} 831 ); 832 return importer.getMainObject(); 833 } 834 835 public static final String MIME_TYPE = "text/xml"; 839 public static final int MIME_TYPE_CODE = 2; 840 public static final String LOCALE_CODE_TABLE_ID = "locale"; 841 protected static final int MAX_LEVELS = 4; 842 843 protected int currentEntryId = 0; 844 protected final OpenCrxKernel_1 plugin; 845 protected final Model_1_0 model; 846 protected final RequestCollection target; 847 protected final RequestCollection reader; 848 protected final ServiceHeader header; 849 protected List referenceFilter = null; 850 protected Map attributeFilter = null; 851 852 } 853 854 | Popular Tags |