Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '1.8', '11' ]
java: [ '8', '11' ]

name: build java ${{ matrix.java }}
steps:
- uses: actions/checkout@v1
- name: Set up java
uses: actions/setup-java@v1
- uses: actions/checkout@v3
- uses: actions/setup-java@v3.6.0
with:
distribution: temurin
java-version: ${{ matrix.java }}
cache: "maven"
- name: Build with Maven
run: mvn -B package --no-transfer-progress --file pom.xml
run: mvn -B clean verify --no-transfer-progress --show-version

makeversion:
if: github.ref != 'refs/heads/main'
Expand All @@ -44,7 +45,7 @@ jobs:
name: Deploy snapshot
steps:
- uses: actions/checkout@v1
- uses: digipost/action-maven-publish@1.1.0
- uses: digipost/action-maven-publish@1.3.0
with:
sonatype_secrets: ${{ secrets.sonatype_secrets }}
release_version: ${{ needs.makeversion.outputs.version }}
Expand All @@ -59,7 +60,7 @@ jobs:
- name: Check out Git repository
uses: actions/checkout@v1
- name: Release to Central Repository
uses: digipost/action-maven-publish@1.1.0
uses: digipost/action-maven-publish@1.3.0
with:
sonatype_secrets: ${{ secrets.sonatype_secrets }}
release_version: ${{ needs.makeversion.outputs.version }}
Expand Down
45 changes: 11 additions & 34 deletions jaxb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.8.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>5.3.13</version>
<version>5.9.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand All @@ -45,7 +38,7 @@
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.5</version>
<version>2.3.6</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -60,16 +53,6 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down Expand Up @@ -101,37 +84,31 @@
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.8</version>
<version>3.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>6.5.3</version>
<version>6.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>no.digipost</groupId>
<artifactId>digg</artifactId>
<version>0.30</version>
<version>0.33</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.32</version>
<artifactId>slf4j-api</artifactId>
<version>2.0.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-xml</artifactId>
<version>3.1.1</version>
<version>2.0.5</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -146,7 +123,7 @@
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.1</version>
<version>3.4.1</version>
<configuration>
<excludePackageNames>no.digipost.signature.api.xml.*</excludePackageNames>
<detectOfflineLinks>false</detectOfflineLinks>
Expand All @@ -163,7 +140,7 @@
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.15.4</version>
<version>0.17.1</version>
<configuration>
<oldVersion>
<dependency>
Expand Down Expand Up @@ -228,7 +205,7 @@
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.5</version>
<version>2.3.6</version>
</dependency>
</dependencies>
<configuration>
Expand Down
209 changes: 209 additions & 0 deletions jaxb/src/main/java/no/digipost/signature/jaxb/JaxbMarshaller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright (C) Posten Norge AS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package no.digipost.signature.jaxb;

import no.digipost.signature.xsd.SignatureApiSchemas;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;

/**
* @see JaxbMarshaller.ForResponsesOfAllApis
* @see JaxbMarshaller.ForRequestsOfAllApis
*/
public class JaxbMarshaller {

/**
* Marshaller for creating requests for both the Direct and Portal API.
* This marshaller will validate if the XML generated from marshalled Java objects
* adheres to the API schemas.
*/
public static class ForRequestsOfAllApis extends JaxbMarshaller {

public static JaxbMarshaller singleton() {
return SingletonHolder.instance;
}

private static final class SingletonHolder {
private static final JaxbMarshaller instance = new JaxbMarshaller.ForRequestsOfAllApis();
}

public ForRequestsOfAllApis() {
super(SignatureMarshalling.allApiRequestClasses(), SignatureApiSchemas.DIRECT_AND_PORTAL_API);
}
}


/**
* Marshaller (unmarshaller) for reading responses from both the Direct and Portal API.
* This marshaller does <em>not</em> validate the XML before attempting to unmarshal it to Java objects.
*/
public static class ForResponsesOfAllApis extends JaxbMarshaller {

public static JaxbMarshaller singleton() {
return SingletonHolder.instance;
}

private static final class SingletonHolder {
private static final JaxbMarshaller instance = new JaxbMarshaller.ForResponsesOfAllApis();
}

public ForResponsesOfAllApis() {
super(SignatureMarshalling.allApiResponseClasses());
}
}



/**
* Marshaller for both the Direct and Portal API.
* <p><strong>
* This marshaller is intended only to be used internally by Posten signering, as both
* requests and responses are validated against schemas. A 3rd party client should <em>not</em>
* validate responses from the API.
* </strong>
*
* @see JaxbMarshaller.ForResponsesOfAllApis
* @see JaxbMarshaller.ForRequestsOfAllApis
*/
public static class ForAllApis extends JaxbMarshaller {

public static JaxbMarshaller singleton() {
return SingletonHolder.instance;
}

private static final class SingletonHolder {
private static final JaxbMarshaller instance = new JaxbMarshaller.ForAllApis();
}

public ForAllApis() {
super(SignatureMarshalling.allApiClasses(), SignatureApiSchemas.DIRECT_AND_PORTAL_API);
}
}

private static InputSource createInputSource(String resource) {
URL resourceUrl = requireNonNull(JaxbMarshaller.class.getResource(resource), resource);
try (InputStream inputStream = resourceUrl.openStream()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

final int bufLen = 1024;
byte[] buf = new byte[bufLen];
int readLen;
while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
outputStream.write(buf, 0, readLen);

InputSource source = new InputSource(new ByteArrayInputStream(outputStream.toByteArray()));
source.setSystemId(resourceUrl.toString());
return source;
} catch (IOException e) {
throw new UncheckedIOException(
"Unable to resolve " + resource + " from " + resourceUrl + ", " +
"because " + e.getClass().getSimpleName() + " '" + e.getMessage() + "'", e);
}
}

private static Schema createSchema(Collection<String> resources) {
try {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
parserFactory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);

SAXParser saxParser = parserFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
Source[] schemaSources = resources.stream()
.map(resource -> new SAXSource(xmlReader, createInputSource(resource)))
.toArray(Source[]::new);

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaSources);
return schema;
} catch (Exception e) {
throw new RuntimeException("Could not create schema from resources [" + String.join(", ", resources) + "]", e);
}
}

private static JAXBContext initContext(Collection<Class<?>> classes) {
Class<?>[] classesToBeBound = classes.toArray(new Class[classes.size()]);
try {
return JAXBContext.newInstance(classesToBeBound);
} catch (JAXBException e) {
throw new RuntimeException("Could not create JAXBContext for classes [" + Stream.of(classesToBeBound).map(Class::getSimpleName).collect(joining(",")) + "]" , e);
}
}

private final JAXBContext jaxbContext;
private final Optional<Schema> schema;

public JaxbMarshaller(Set<Class<?>> classes, Set<String> schemaResources) {
this.jaxbContext = initContext(classes);
this.schema = Optional.ofNullable(schemaResources).filter(s -> !s.isEmpty()).map(JaxbMarshaller::createSchema);
}

public JaxbMarshaller(Set<Class<?>> classes) {
this(classes, null);
}

public void marshal(Object object, OutputStream outputStream){
try {
Marshaller marshaller = jaxbContext.createMarshaller();
schema.ifPresent(marshaller::setSchema);
marshaller.marshal(object, outputStream);
} catch (Exception e) {
throw new SignatureMarshalException("Failed marshalling " + (object != null ? object.getClass().getName() : "null") + " to XML", e);
}
}

public <T> T unmarshal(InputStream inputStream, Class<T> type){
try {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
schema.ifPresent(unmarshaller::setSchema);
return type.cast(unmarshaller.unmarshal(inputStream));
} catch (Exception e) {
throw new SignatureMarshalException("Failed unmarshalling XML to " + type.getName(), e);
}
}

public <T> T unmarshal(byte[] bytes, Class<T> type) {
return unmarshal(new ByteArrayInputStream(bytes), type);
}

}
Loading