Reorganizing to a parent project, a light and a heavy (validating) library, a commandline application and the server

This commit is contained in:
Jochen Stärk
2020-03-28 18:28:32 +01:00
parent 7b0a3f2ae0
commit dea42f950e
218 changed files with 1003962 additions and 269 deletions

View File

@@ -0,0 +1,51 @@
package api;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import io.dropwizard.Application;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import mustang.MustangResource;
public class ApiApplication extends Application<ApiConfiguration> {
public static void main(String[] args) throws Exception {
new ApiApplication().run(args);
}
@Override
public String getName() {
return "Mustang Server";
}
@Override
public void initialize(Bootstrap<ApiConfiguration> bootstrap) {
bootstrap.addBundle(new SwaggerBundle<ApiConfiguration>() {
@Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(ApiConfiguration configuration) {
return configuration.swaggerBundleConfiguration;
}
});
}
@Override
public void run(ApiConfiguration configuration, Environment environment) {
final MustangResource resource = new MustangResource();
environment.jersey()
.register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new BasicAuthenticator()).setAuthorizer(new BasicAuthorizer())
.setRealm("Rest API access").buildAuthFilter()));
environment.jersey().register(RolesAllowedDynamicFeature.class);
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
environment.jersey().register(MultiPartFeature.class);
environment.jersey().register(resource);
}
}

View File

@@ -0,0 +1,12 @@
package api;
import io.dropwizard.Configuration;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ApiConfiguration extends Configuration {
@JsonProperty("swagger")
public SwaggerBundleConfiguration swaggerBundleConfiguration;
}

View File

@@ -0,0 +1,18 @@
package api;
import java.util.Optional;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
public class BasicAuthenticator implements Authenticator<BasicCredentials, User> {
@Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
if ("secret".equals(credentials.getPassword())) {
return Optional.of(new User(credentials.getUsername()));
}
return Optional.empty();
}
}

View File

@@ -0,0 +1,11 @@
package api;
import io.dropwizard.auth.Authorizer;
public class BasicAuthorizer implements Authorizer<User> {
@Override
public boolean authorize(User user, String role) {
return user.getName().equals("good-guy") && role.equals("ADMIN");
}
}

View File

@@ -0,0 +1,15 @@
package api;
import io.dropwizard.auth.PrincipalImpl;
public class User extends PrincipalImpl {
String username;
public User(String name) {
super(name);
username=name;
}
}

View File

@@ -0,0 +1,146 @@
package mustang;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.License;
import io.swagger.annotations.Info;
import io.swagger.annotations.SwaggerDefinition;
@Path("/mustang")
@Produces(MediaType.APPLICATION_JSON)
@Api(value = "Mustang")
@SwaggerDefinition(info=@Info(
description = "Rest API to read/write hybrid (ZUGFeRD/Factur-X) e-invoices with a Mustang Server",
version = "V0.0.2",
title = "Mustangproject API",
license = @License(name = "Apache 2.0", url = "http://www.apache.org")
),
schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}
)
public class MustangResource {
Logger logger = LoggerFactory.getLogger(MustangResource.class.getName());
public MustangResource() {
}
@POST
@Path("/extract")
//@RolesAllowed("ADMIN")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_XML)
@ApiOperation(value="Extracts XML from a zf/fx PDF",notes="Input PDF must be ZUGFeRD or Factur-X")
public String extractFile(@ApiParam(required=true,value="Input ZUGFeRD/Factur-X file") @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition contentDispositionHeader) {
ZUGFeRDImporter zi;
logger.debug("Reading...");
zi = new ZUGFeRDImporter(fileInputStream);
return "<response>"+zi.getUTF8()+"</response>";
}
@POST
@Path("/combine")
@RolesAllowed("ADMIN")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@ApiOperation(value="Combine PDF file and custom XML to zf/fx PDF",notes="Input PDF must be PDF/A-1, output PDF will be a ZUGFeRD/Factur-X PDF/A-3 file called invoice.pdf. Demo authentication good-guy:secret")
public Response combineFile(@ApiParam(required=true,value="Input PDF/A-1 file") @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition contentDispositionHeader,
@ApiParam(required=true, value="The zf/fx XML to add to the file") @FormDataParam("xml") String XML,
@ApiParam(required=true, defaultValue="zf", value="zf|fx:zf for ZUGFeRD, fx for Factur-X") @FormDataParam("format") String format,
@ApiParam(required=true, defaultValue="2", value="version, i.e. fx 1 or zf 1 or 2") @FormDataParam("version") int version,
@ApiParam(required=true, defaultValue="EN16931", value="Profile: BASIC|COMFORT|EXTENDED for zf1, MINIMUM|BASICWL|BASIC|CIUS|EN16931|EXTENDED for zf2/fx1") @FormDataParam("profile") String profile
) {
ZUGFeRDExporter ze;
ByteArrayOutputStream output=new ByteArrayOutputStream();
try {
logger.debug("Converting to PDF/A-3u");
if ((version<1)||(version>2)) {
// this should be checked with annotations but I did not get it to work
throw new IllegalArgumentException("invalid version");
}
// this should be restricted to the enum with annotations but I did not get it to work
ZUGFeRDConformanceLevel prof=ZUGFeRDConformanceLevel.valueOf(profile);
/*
* Add .setZUGFeRDVersion and .setZUGFeRDConformanceLevel in the next lines to
* set the ZUGFeRD version respective profile of the XML you are inserting.
*/
ze = new ZUGFeRDExporterFromA1Factory().setProducer("Mustang API")
.setCreator(System.getProperty("user.name"))
.setZUGFeRDVersion(version)
.setZUGFeRDConformanceLevel(prof)
.load(fileInputStream);
logger.debug("Attaching ZUGFeRD-Data");
if (format.equalsIgnoreCase("fx")) {
ze.setFacturX();
}
ze.setZUGFeRDXMLData(XML.getBytes("UTF-8"));
logger.debug("Writing ZUGFeRD-PDF");
ze.export(output);
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = output.toByteArray();
InputStream inputStream = new ByteArrayInputStream(bytes);
return Response.ok(inputStream)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"invoice.pdf\"")
.build();
}
@POST
@Path("/test")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value="Returns a hello world",notes="Just a test")
public Response test() {
return Response.status(Response.Status.OK)
.entity("{\"payload\":\"test\"}")
.build();
}
}

View File

@@ -0,0 +1,50 @@
package mustangAPI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import api.ApiApplication;
public class IntegrationTest {
/*@ClassRule
public static final DropwizardAppRule<ApiConfiguration> RULE
= new DropwizardAppRule<>(ApiApplication.class,
"config.yml");
@Test
public void testGetGreeting() {
//test w/ssl
* //Create SSL Configurator
SslConfigurator sslConfigurator = SslConfigurator.newInstance();
//Register a keystore
sslConfigurator.trustStoreFile("dwstart.keystore")
.trustStorePassword("crimson");
//Create SSL Context
SSLContext sSLContext = sslConfigurator.createSSLContext();
//Obtain client
Client client = ClientBuilder
.newBuilder()
.sslContext(sSLContext)
.build();
String expected = "Hello world!";
//Obtain client
Client client = ClientBuilder.newClient();
//Build a feature in basic authentication mode
HttpAuthenticationFeature feature
= HttpAuthenticationFeature.basic("javaeeeee", "crimson");
//Register the feature
client.register(feature);
//Get actual resul string
String actual = client
.target("http://localhost:8080/secured_hello")
.request(MediaType.TEXT_PLAIN)
.get(String.class);
//Do an assertion
assertEquals(expected, actual);
}*/
}