XSDSchemaCollection.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.xml;

  21. import java.io.ByteArrayInputStream;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.File;
  24. import java.io.FileOutputStream;
  25. import java.io.OutputStream;
  26. import java.nio.file.Files;
  27. import java.nio.file.attribute.FileAttribute;
  28. import java.nio.file.attribute.PosixFilePermission;
  29. import java.nio.file.attribute.PosixFilePermissions;
  30. import java.text.SimpleDateFormat;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.Set;
  34. import java.util.zip.ZipEntry;
  35. import java.util.zip.ZipOutputStream;

  36. import javax.xml.validation.Schema;

  37. import org.openspcoop2.utils.date.DateManager;
  38. import org.openspcoop2.utils.date.DateUtils;
  39. import org.openspcoop2.utils.resources.FileSystemUtilities;
  40. import org.slf4j.Logger;

  41. /**
  42. * XSDSchemaCollection
  43. *
  44. * @author Andrea Poli (apoli@link.it)
  45.  * @author $Author$
  46.  * @version $Rev$, $Date$
  47. */
  48. public class XSDSchemaCollection {

  49.     private static boolean serializeXSDSchemiBuildSchemaSuccessDefault = false;
  50.     private static boolean serializeXSDSchemiBuildSchemaErrorDefault = true;
  51.     private static File serializeXSDSchemiBuildSchemaDefaultDir = null;
  52.     public static boolean isSerializeXSDSchemiBuildSchemaSuccessDefault() {
  53.         return serializeXSDSchemiBuildSchemaSuccessDefault;
  54.     }
  55.     public static void setSerializeXSDSchemiBuildSchemaSuccessDefault(boolean serializeXSDSchemiBuildSchemaSuccessDefault) {
  56.         XSDSchemaCollection.serializeXSDSchemiBuildSchemaSuccessDefault = serializeXSDSchemiBuildSchemaSuccessDefault;
  57.     }
  58.     public static boolean isSerializeXSDSchemiBuildSchemaErrorDefault() {
  59.         return serializeXSDSchemiBuildSchemaErrorDefault;
  60.     }
  61.     public static void setSerializeXSDSchemiBuildSchemaErrorDefault(boolean serializeXSDSchemiBuildSchemaErrorDefault) {
  62.         XSDSchemaCollection.serializeXSDSchemiBuildSchemaErrorDefault = serializeXSDSchemiBuildSchemaErrorDefault;
  63.     }
  64.     public static File getSerializeXSDSchemiBuildSchemaDefaultDir() {
  65.         return serializeXSDSchemiBuildSchemaDefaultDir;
  66.     }
  67.     public static void setSerializeXSDSchemiBuildSchemaDefaultDir(File serializeXSDSchemiBuildSchemaDefaultDir) {
  68.         XSDSchemaCollection.serializeXSDSchemiBuildSchemaDefaultDir = serializeXSDSchemiBuildSchemaDefaultDir;
  69.     }
  70.    
  71.     private byte[] schemaRoot;
  72.     private Map<String, byte[]> resources;
  73.     private Map<String, List<String>> mappingNamespaceLocations;
  74.        
  75.     private boolean serializeXSDSchemiBuildSchemaSuccess = false;
  76.     private boolean serializeXSDSchemiBuildSchemaError = true;
  77.     private File serializeXSDSchemiBuildSchemaDir = null;
  78.    
  79.     public XSDSchemaCollection() {
  80.         this.serializeXSDSchemiBuildSchemaSuccess = isSerializeXSDSchemiBuildSchemaSuccessDefault();
  81.         this.serializeXSDSchemiBuildSchemaError = isSerializeXSDSchemiBuildSchemaErrorDefault();
  82.         this.serializeXSDSchemiBuildSchemaDir = getSerializeXSDSchemiBuildSchemaDefaultDir();
  83.     }
  84.    
  85.     public boolean isSerializeXSDSchemiBuildSchemaSuccess() {
  86.         return this.serializeXSDSchemiBuildSchemaSuccess;
  87.     }
  88.     public void setSerializeXSDSchemiBuildSchemaSuccess(boolean serializeXSDSchemiBuildSchemaSuccess) {
  89.         this.serializeXSDSchemiBuildSchemaSuccess = serializeXSDSchemiBuildSchemaSuccess;
  90.     }
  91.     public boolean isSerializeXSDSchemiBuildSchemaError() {
  92.         return this.serializeXSDSchemiBuildSchemaError;
  93.     }
  94.     public void setSerializeXSDSchemiBuildSchemaError(boolean serializeXSDSchemiBuildSchemaErrror) {
  95.         this.serializeXSDSchemiBuildSchemaError = serializeXSDSchemiBuildSchemaErrror;
  96.     }
  97.     public File getSerializeXSDSchemiBuildSchemaDir() {
  98.         return this.serializeXSDSchemiBuildSchemaDir;
  99.     }
  100.     public void setSerializeXSDSchemiBuildSchemaDir(File serializeXSDSchemiBuildSchemaDir) {
  101.         this.serializeXSDSchemiBuildSchemaDir = serializeXSDSchemiBuildSchemaDir;
  102.     }
  103.    
  104.     public byte[] getSchemaRoot() {
  105.         return this.schemaRoot;
  106.     }
  107.     public void setSchemaRoot(byte[] schemaRoot) {
  108.         this.schemaRoot = schemaRoot;
  109.     }
  110.     public Map<String, byte[]> getResources() {
  111.         return this.resources;
  112.     }
  113.     public void setResources(Map<String, byte[]> resources) {
  114.         this.resources = resources;
  115.     }
  116.     public Map<String, List<String>> getMappingNamespaceLocations() {
  117.         return this.mappingNamespaceLocations;
  118.     }
  119.     public void setMappingNamespaceLocations(Map<String, List<String>> mappingNamespaceLocations) {
  120.         this.mappingNamespaceLocations = mappingNamespaceLocations;
  121.     }
  122.    
  123.     public void serialize(Logger log,File file) throws XMLException{
  124.         try (FileOutputStream fout = new FileOutputStream(file);){
  125.             serialize(log,fout);
  126.             fout.flush();
  127.         }catch(Exception e){
  128.             throw new XMLException(e.getMessage(),e);
  129.         }
  130.     }
  131.    
  132.     public void serialize(Logger log,String fileName) throws XMLException{
  133.         try (FileOutputStream fout = new FileOutputStream(fileName);){
  134.             serialize(log,fout);
  135.             fout.flush();
  136.         }catch(Exception e){
  137.             throw new XMLException(e.getMessage(),e);
  138.         }
  139.     }
  140.    
  141.     public byte[] serialize(Logger log) throws XMLException{
  142.         try{
  143.             ByteArrayOutputStream bout = new ByteArrayOutputStream();
  144.             serialize(log,bout);
  145.             bout.flush();
  146.             bout.close();
  147.             return bout.toByteArray();
  148.         }catch(Exception e){
  149.             throw new XMLException(e.getMessage(),e);
  150.         }
  151.     }


  152.     public void serialize(Logger log,OutputStream out) throws XMLException{
  153.    
  154.         try (ZipOutputStream zipOut = new ZipOutputStream(out);){
  155.             this.zipSerialize(log,zipOut);
  156.            
  157.             zipOut.flush();

  158.         }catch(Exception e){
  159.             throw new XMLException(e.getMessage(),e);
  160.         }
  161.     }
  162.    
  163.     public void zipSerialize(Logger log,ZipOutputStream zipOut) throws XMLException{
  164.        
  165.         try{
  166.             String rootPackageDir = "";
  167.             // Il codice dopo fissa il problema di inserire una directory nel package.
  168.             // Commentare la riga sotto per ripristinare il vecchio comportamento.
  169.             rootPackageDir = "schemi"+File.separatorChar;
  170.            
  171.             String nomeFile = "RootSchema.xsd";
  172.             zipOut.putNextEntry(new ZipEntry(rootPackageDir+nomeFile));
  173.             zipOut.write(this.schemaRoot);
  174.            
  175.             if(this.resources!=null && this.resources.size()>0){
  176.                 for (String name : this.resources.keySet()) {
  177.                    
  178.                     nomeFile = name;
  179.                     zipOut.putNextEntry(new ZipEntry(rootPackageDir+nomeFile));
  180.                     zipOut.write(this.resources.get(name));
  181.                    
  182.                     String namespaceFound = null;
  183.                     String locationFound = null;
  184.                     for (String namespace : this.mappingNamespaceLocations.keySet()) {
  185.                         List<String> split = this.mappingNamespaceLocations.get(namespace);
  186.                         if(split!=null){
  187.                         for (int i = 0; i < split.size(); i++) {
  188.                             if(split.get(i) != null && split.get(i).equals(nomeFile)){
  189.                                 namespaceFound = namespace;
  190.                                 locationFound = split.get(i);
  191.                                 break;
  192.                             }
  193.                         }
  194.                         if(namespaceFound!=null){
  195.                             break;}
  196.                         }
  197.                     }
  198.                        
  199.                     if(namespaceFound!=null){
  200.                         nomeFile = name+".namespace.txt";
  201.                         zipOut.putNextEntry(new ZipEntry(rootPackageDir+nomeFile));
  202.                         String valore = namespaceFound;
  203.                         if(locationFound!=null){
  204.                             valore = locationFound + "\n" + valore;
  205.                         }
  206.                         zipOut.write(valore.getBytes());
  207.                     }
  208.                    
  209.                 }
  210.             }
  211.            
  212.             try{
  213.                 this.buildSchemaEngine(log,false,false,null);
  214.             }catch(Throwable e){
  215.                 log.error("Costruzione Struttura degli Schemi XSD fallita: "+e.getMessage(),e);
  216.                 nomeFile = "BuildSchemaFailed.txt";
  217.                 zipOut.putNextEntry(new ZipEntry(nomeFile));
  218.                 String msg = e.getMessage();
  219.                 if(msg==null || msg.equals("")){
  220.                     if(e instanceof NullPointerException){
  221.                         msg = "Internal Error (NP)";
  222.                     }
  223.                     else{
  224.                         msg = e.toString();
  225.                         if(msg==null || msg.equals("")){
  226.                             msg = "Internal Error";
  227.                         }
  228.                     }
  229.                 }
  230.                 zipOut.write(msg.getBytes());
  231.             }
  232.         }catch(Exception e){
  233.             throw new XMLException(e.getMessage(),e);
  234.         }
  235.     }
  236.    
  237.     /**
  238.      * Costruisce un unico schema unendo tutti gli schemi importati
  239.      *
  240.      * @param logger logger
  241.      * @return Schema
  242.      * @throws XMLException
  243.      */
  244.     public Schema buildSchema(Logger logger) throws XMLException {
  245.         return this.buildSchemaEngine(logger, this.serializeXSDSchemiBuildSchemaSuccess, this.serializeXSDSchemiBuildSchemaError, this.serializeXSDSchemiBuildSchemaDir);
  246.     }
  247.     private Schema buildSchemaEngine(Logger logger, boolean serializeXSDSchemiBuildSchemaSuccess, boolean serializeXSDSchemiBuildSchemaError, File serializeXSDSchemiBuildSchemaDir) throws XMLException {
  248.        
  249.         // Creo XSDResolver con le risorse localizzate e procedo con la validazione
  250.         XSDResourceResolver resourceResolver = new XSDResourceResolver(this.resources);
  251.         try{
  252.             // UndeclaredPrefix: Cannot resolve 'example:xxxxType' as a QName: the prefix 'example' is not declared.
  253.             // After some debugging, I've found out that this is a bug of the JAXP api's built in to the JDK.
  254.             // You can fix it by making sure that you use the Xerces version of the SchemaFactory, and not the JDK internal one.
  255.             // The algorithm for choosing a SchemaFactory is explained at http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/validation/SchemaFactory.html#newInstance(java.lang.String).
  256.             // It comes down to setting the System property "javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema" to the value "org.apache.xerces.jaxp.validation.XMLSchemaFactory".
  257.             // Note that just adding Xerces to your classpath won't fix this, for reasons explained at http://xerces.apache.org/xerces2-j/faq-general.html#faq-4
  258.             /**return new ValidatoreXSD(org.apache.xerces.jaxp.validation.XMLSchemaFactory.class.getName(),xsdResourceResolver,is);*/
  259.             ValidatoreXSD validatoreXSD = new ValidatoreXSD(logger,"org.apache.xerces.jaxp.validation.XMLSchemaFactory",resourceResolver,
  260.                     new ByteArrayInputStream(this.schemaRoot));
  261.             /**ValidatoreXSD validatoreXSD = new ValidatoreXSD(this.logger,resourceResolver,new ByteArrayInputStream(schemaPerValidazione));*/

  262.             if(serializeXSDSchemiBuildSchemaSuccess){
  263.                 debugPrintXSDSchemi(this.schemaRoot, resourceResolver, logger, true, serializeXSDSchemiBuildSchemaDir);
  264.             }

  265.             return validatoreXSD.getSchema();

  266.         }catch (Exception e) {

  267.             if(serializeXSDSchemiBuildSchemaError){
  268.                 debugPrintXSDSchemi(this.schemaRoot, resourceResolver, logger, false, serializeXSDSchemiBuildSchemaDir);
  269.             }

  270.             throw new XMLException("Riscontrato errore durante l'inizializzazione dello schema: "+e.getMessage(),e);
  271.         }
  272.        
  273.     }
  274.    
  275.     private void debugPrintXSDSchemi(byte[]schemaPerValidazione,XSDResourceResolver resourceResolver,Logger logger, boolean success, File serializeXSDSchemiBuildSchemaDir){
  276.         try{
  277.             FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------"));
  278.             File dir = null;
  279.             if(serializeXSDSchemiBuildSchemaDir!=null) {
  280.                 dir = Files.createTempDirectory(serializeXSDSchemiBuildSchemaDir.toPath(), "xsd_dir_", attr).toFile();
  281.             }
  282.             else {
  283.                 dir = Files.createTempDirectory("xsd_dir_", attr).toFile();
  284.             }
  285.             boolean dirCreate = dir.exists();
  286.             /**System.out.println("FILE?["+dir.getAbsolutePath()+"] ["+dirCreate+"] ["+dir.isDirectory()+"]");*/
  287.             dirCreate = dirCreate && dir.isDirectory();
  288.             /**System.out.println("DIR CREATE ["+dirCreate+"]");*/
  289.            
  290.             // Provo a registrare lo schema principale
  291.             String uniqueID = XSDSchemaCollection.getIdForDebug();
  292.             File f = null;
  293.             if(dirCreate)
  294.                 f = File.createTempFile("root_"+uniqueID+"_", ".xsd",dir);
  295.             else
  296.                 f = FileSystemUtilities.createTempFile("root_"+uniqueID+"_", ".xsd");
  297.             FileSystemUtilities.writeFile(f, schemaPerValidazione);
  298.            
  299.             // Provo a registrare gli schemi utilizzati
  300.             if(resourceResolver!=null){
  301.                 XSDResourceResolver xsdResolver = resourceResolver;
  302.                 for (String systemId : xsdResolver.getResources().keySet()) {
  303.                     byte[] contenuto = xsdResolver.getResources().get(systemId);
  304.                     File schemaTmpLog = null;
  305.                     if(dirCreate)
  306.                         schemaTmpLog = File.createTempFile("import_"+uniqueID+"_"+systemId+"_", ".xsd", dir);
  307.                     else
  308.                         schemaTmpLog = FileSystemUtilities.createTempFile("import_"+uniqueID+"_"+systemId+"_", ".xsd");
  309.                     FileSystemUtilities.writeFile(schemaTmpLog, contenuto);
  310.                 }
  311.             }
  312.            
  313.             String motivo = null;
  314.             if(success){
  315.                 motivo = "completata con successo";
  316.             }
  317.             else{
  318.                 motivo = "completata con errore";
  319.             }
  320.            
  321.             String msg = null;
  322.             if(dirCreate)
  323.                 msg = "Inizializzazione dello schema "+motivo+", gli schemi sono stati registrati nella directory "+dir.getAbsolutePath();
  324.             else
  325.                 msg = "Inizializzazione dello schema "+motivo+", gli schemi sono stati registrati nella area temporanea (root schema: "+f.getAbsolutePath()+")";
  326.            
  327.             if(success){
  328.                 logger.info(msg);
  329.             }
  330.             else{
  331.                 logger.error(msg);
  332.             }
  333.                            
  334.         }catch(Exception eDebug){
  335.             logger.error("Registrazione xsd per debug non riuscita: "+eDebug.getMessage(),eDebug);
  336.         }
  337.     }
  338.    
  339.     private static long counter = 0;
  340.     private static synchronized String getIdForDebug(){
  341.         SimpleDateFormat dateformat = DateUtils.getSimpleDateFormatMs();
  342.         XSDSchemaCollection.counter++;
  343.         return "ID_"+XSDSchemaCollection.counter+"_"+dateformat.format(DateManager.getDate());
  344.     }
  345. }