Lugar para compartir información interesante con mis amigos.

Saturday, July 08, 2023

Cómo Validar un XML con múltiples XSD precargados como byte []

 El problema

Tengo varios XSD que dependen unos de otros y debo validar un XML con ellos. Para ejecutar esa operación rápidamente y evitar la carga de disco duro cada vez que voy a ejecutar esa transacción, voy a tener los XSD en memoria como arreglos de bytes.

SchemaFactory schemaFactory = SchemaFactory.
        newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source [] sources=schemas.toArray(new Source[schemas.size()]);
Schema schema = schemaFactory.newSchema(sources);



En teoría este código funciona para cargar todos los esquemas, pero estoy obteniendo esta excepción, a pesar de tener todas las definiciones en los esquemas:

org.xml.sax.SAXParseException; lineNumber: 27; columnNumber: 85; src-resolve: Cannot resolve the name 'cac:CountryType' to a(n) 'type definition' component.

Para verificar que todo esté bien con los esquemas, simplemente se cargaron como archivos y todo funcionó bien. Entonces, ¿qué hacer?

La Solución


Se implementó un ResourceResolver personalizado ByteArrayResourceResolver, que se establece al ShemaFactory así: 

schemaFactory.setResourceResolver(
    new ByteArrayResourceResolver(scheme.getXsdBytes())
);

En el constructor se envía un Map con el nombre de cada archivo y su contenido como arreglo de bytes. La implementación es la siguiente:

public class ByteArrayResourceResolver implements LSResourceResolver {
private final Map<String, byte[]> resources;

public ByteArrayResourceResolver(Map resources) {
this.resources = resources;
}

@Override
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
LSInput input =new Input();
ByteArrayInputStream bis=new ByteArrayInputStream(resources.get(systemId));
input.setByteStream(bis);
input.setBaseURI(baseURI);
input.setPublicId(publicId);
input.setSystemId(systemId);
return input;
}
}

Finalmente Input es una implementación con getters y setters de LSImput.

El error se genera porque baseURI llega en null para algunos de los schemas. (la investigación de la causa quedará pendiente )




Wednesday, July 05, 2023

Cómo es un pipeline y un release Devops para desplegar una Azure Function en Azure

Para desplegar en Azure, normalmente se tienen dos artefactos en Azure DevOps: un Pipeline para construir el artefacto y un Release para desplegarlo en un recurso:

El proyecto, debe disponer de un archivo pom.xml de maven y allí, contar con un goal: package. Para este ejemplo, el nombre de la aplicacion será "facel-validator".

Pipeline

El pipeline cuenta con tres pasos: 
  1. La ejecución del maven.
  2. La construcción del zip
  3. La publicación del zip
El pipeline se vería como sigue:

# Maven
# Build your Java project and run tests with Apache Maven.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/java

trigger:
master

pool:
  vmImageubuntu-latest

steps:
taskMaven@3
  inputs:    
    mavenPomFile'pom.xml'
    mavenOptions'-Xmx3072m'
    jdkDirectory'$JAVA_HOME_17_X64'
    javaHomeOption'JDKVersion'
    jdkVersionOption'1.17'
    jdkArchitectureOption'x64'
    publishJUnitResultstrue
    testResultsFiles'**/surefire-reports/TEST-*.xml'
    goals'package'
taskArchiveFiles@2
  inputs:
    rootFolderOrFile'$(system.defaultworkingdirectory)/target/azure-functions/facel-validator'
    includeRootFolderfalse    
    archiveType'zip'
    archiveFile'$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchivetrue
taskPublishBuildArtifacts@1
  inputs:
    PathtoPublish'$(Build.ArtifactStagingDirectory)'
    ArtifactName'drop'
    publishLocation'Container'


Release

El Release se hace con la plantilla normal para desplegar functions, indicando que se va a usar el stack de java y versión:



Popular Posts

Pedro Rozo. Powered by Blogger.