Reorganizing to a parent project, a light and a heavy (validating) library, a commandline application and the server
This commit is contained in:
252
Mustang-CLI/pom.xml
Normal file
252
Mustang-CLI/pom.xml
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.zugferd</groupId>
|
||||||
|
<artifactId>Mustang-CLI</artifactId>
|
||||||
|
<name>Mustang commandline tool</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>mavencentral</id>
|
||||||
|
<url>http://repo.maven.apache.org/maven2</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<!-- for jargs -->
|
||||||
|
<id>sonatype-oss-public</id>
|
||||||
|
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<!-- for java9 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- for xml pretty print -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dom4j</groupId>
|
||||||
|
<artifactId>dom4j</artifactId>
|
||||||
|
<version>2.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- for ph-schematron -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.googlecode.slf4j-maven-plugin-log/slf4j-maven-plugin-log -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.slf4j-maven-plugin-log</groupId>
|
||||||
|
<artifactId>slf4j-maven-plugin-log</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Verapdf plugin <dependency> <groupId>org.verapdf</groupId> <artifactId>core</artifactId>
|
||||||
|
<version>1.6.2</version> </dependency> -->
|
||||||
|
<!-- embedded verapdf -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.verapdf</groupId>
|
||||||
|
<artifactId>validation-model</artifactId>
|
||||||
|
<version>1.12.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.helger/ph-schematron -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>ph-schematron</artifactId>
|
||||||
|
<version>5.0.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>libraryExtended</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
|
||||||
|
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
|
||||||
|
-->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-core</artifactId>
|
||||||
|
<version>2.6.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-assertj</artifactId>
|
||||||
|
<version>2.6.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<!-- for commandline options -->
|
||||||
|
<groupId>com.sanityinc</groupId>
|
||||||
|
<artifactId>jargs</artifactId>
|
||||||
|
<version>2.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.riversun</groupId>
|
||||||
|
<artifactId>bigdoc</artifactId>
|
||||||
|
<version>0.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<!-- mvn help:effective-pom will otherwise tell it just defaults
|
||||||
|
to 2.3.2 - which does not release in the maven repo, and neither shows any
|
||||||
|
error message :-( -->
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<!-- allow getImplementationVersion for the pom.xml -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||||
|
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<mainClass>org.mustangproject.commandline.main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
||||||
|
mvn clean compile assembly:single -->
|
||||||
|
<!-- or whatever version you use -->
|
||||||
|
<source>1.7</source>
|
||||||
|
<target>1.7</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- /ZUV -->
|
||||||
|
<!-- generate XSLT files from schematron upon build (goal convert is part
|
||||||
|
of the preparation of the "package" step)
|
||||||
|
<plugin> <groupId>com.helger.maven</groupId> <artifactId>ph-sch2xslt-maven-plugin</artifactId>
|
||||||
|
<version>5.0.8</version> <configuration> <schematronDirectory>${basedir}/src/main/resources/</schematronDirectory>
|
||||||
|
<xsltDirectory>${basedir}/src/main/resources/xslt</xsltDirectory> </configuration>
|
||||||
|
<executions> <execution> <goals> <goal>convert</goal> </goals> </execution>
|
||||||
|
</executions> </plugin> -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.4.3</version>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.mustangproject.commandline.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
<minimizeJar>false</minimizeJar>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>log4j:log4j</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.sun.xml.bind:jaxb-core</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactSet>
|
||||||
|
<excludes />
|
||||||
|
</artifactSet>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache License, Version 2.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
<comments>A business-friendly OSS license</comments>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Jochen Stärk</name>
|
||||||
|
<email>jstaerk@usegroup.de</email>
|
||||||
|
<roles>
|
||||||
|
<role>architect</role>
|
||||||
|
<role>developer</role>
|
||||||
|
</roles>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
</project>
|
||||||
95
Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java
Executable file
95
Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java
Executable file
@@ -0,0 +1,95 @@
|
|||||||
|
/** **********************************************************************
|
||||||
|
*
|
||||||
|
* Copyright 2018 Jochen Staerk
|
||||||
|
*
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* 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 org.mustangproject.commandline;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
|
||||||
|
|
||||||
|
public class FileChecker {
|
||||||
|
String filename;
|
||||||
|
StatRun thisRun;
|
||||||
|
boolean isPDF = false;
|
||||||
|
|
||||||
|
public FileChecker(String filename, StatRun statistics) {
|
||||||
|
this.filename = filename;
|
||||||
|
thisRun = statistics;
|
||||||
|
thisRun.incFileCount();
|
||||||
|
String extension = "";
|
||||||
|
if (!thisRun.shallIgnoreFileExt()) {
|
||||||
|
int extIndex = filename.lastIndexOf(".");
|
||||||
|
if (extIndex >= 0) {
|
||||||
|
extension = filename.substring(extIndex).toLowerCase();
|
||||||
|
isPDF = extension.equals(".pdf");// alternative check for PDF: File starts with %PDF-
|
||||||
|
if (isPDF) {
|
||||||
|
thisRun.incPDFCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
thisRun.incPDFCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkForZUGFeRD() {
|
||||||
|
if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ZUGFeRDImporter zi = new ZUGFeRDImporter(filename);
|
||||||
|
try {
|
||||||
|
if (zi.canParse()) {
|
||||||
|
thisRun.incZUGFeRDCount(zi.getVersion());
|
||||||
|
thisRun.incTotal(new BigDecimal(zi.getAmount()));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// something really rare happened -- corrupted ZF?
|
||||||
|
/***
|
||||||
|
* e.g. Exception in thread "main" java.lang.NullPointerException
|
||||||
|
at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extractLowLevel(ZUGFeRDImporter.java:90)
|
||||||
|
at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extract(ZUGFeRDImporter.java:64)
|
||||||
|
at toecount.FileChecker.checkForZUGFeRD(FileChecker.java:33)
|
||||||
|
at toecount.Toecount.main(Toecount.java:111)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// Ignore nevertheless, most likely we're batch processing
|
||||||
|
return false;
|
||||||
|
} catch (Exception e2) {
|
||||||
|
/**
|
||||||
|
* probably thrown up from
|
||||||
|
AM org.apache.pdfbox.pdfparser.PDFParser parse, most likely
|
||||||
|
INFORMATION: Document is encrypted
|
||||||
|
but also other internal PDF errors possible like
|
||||||
|
..Okt 23, 2015 11:17:53 AM org.apache.pdfbox.pdfparser.XrefTrailerResolver setStartxref
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPDF() {
|
||||||
|
return isPDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutputLine() {
|
||||||
|
return thisRun.getOutputLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
75
Mustang-CLI/src/main/java/org/mustangproject/commandline/FileTraverser.java
Executable file
75
Mustang-CLI/src/main/java/org/mustangproject/commandline/FileTraverser.java
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
/** **********************************************************************
|
||||||
|
*
|
||||||
|
* Copyright 2018 Jochen Staerk
|
||||||
|
*
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* 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 org.mustangproject.commandline;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
|
||||||
|
import static java.nio.file.FileVisitResult.CONTINUE;
|
||||||
|
|
||||||
|
public class FileTraverser extends SimpleFileVisitor<Path> {
|
||||||
|
|
||||||
|
|
||||||
|
private StatRun thisRun;
|
||||||
|
|
||||||
|
public FileTraverser(StatRun statistics) {
|
||||||
|
this.thisRun = statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check each file
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
|
||||||
|
if (attr.isSymbolicLink()) {
|
||||||
|
// Not yet handled
|
||||||
|
} else if (attr.isRegularFile()) {
|
||||||
|
String filename = file.toString();
|
||||||
|
FileChecker fc = new FileChecker(filename, thisRun);
|
||||||
|
fc.checkForZUGFeRD();
|
||||||
|
System.out.print(fc.getOutputLine());
|
||||||
|
|
||||||
|
}
|
||||||
|
return CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for each directory
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
|
||||||
|
// System.out.format("Directory: %s%n", dir);
|
||||||
|
thisRun.incDirCount();
|
||||||
|
return CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show errors like file permission stacktraces
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFileFailed(Path file, IOException exc) {
|
||||||
|
System.err.println(exc);
|
||||||
|
return CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
637
Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
Executable file
637
Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
Executable file
@@ -0,0 +1,637 @@
|
|||||||
|
/** **********************************************************************
|
||||||
|
*
|
||||||
|
* Copyright 2018 Jochen Staerk
|
||||||
|
*
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* 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 org.mustangproject.commandline;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator;
|
||||||
|
import ZUV.ZUGFeRDValidator;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* This is the command line interface to mustangproject
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sanityinc.jargs.CmdLineParser;
|
||||||
|
import com.sanityinc.jargs.CmdLineParser.Option;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
// build with: /opt/local/bin/mvn clean compile assembly:single
|
||||||
|
private static void printUsage() {
|
||||||
|
System.err.println(getUsage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getUsage() {
|
||||||
|
return "Usage: [-d,--directory] [-l,--listfromstdin] [-i,--ignorefileextension] | [-c,--combine] | [-e,--extract] | [-u,--upgrade] | [-a,--a3only] | [-h,--help] \r\n"
|
||||||
|
+ "* Count operations\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
|
||||||
|
+ " If it is a directory, it will recurse.\n"
|
||||||
|
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
|
||||||
|
+ " It will start once a blank line has been entered.\n" + "\n"
|
||||||
|
+ " Additional parameter for both count operations\n"
|
||||||
|
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf)\n"
|
||||||
|
+ "\n" + "* Merge operations\n" + " -e, --extract extract ZUGFeRD PDF to XML file\n"
|
||||||
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
|
+ " [--out <filename>]: set output XML file\n"
|
||||||
|
+ " -u, --upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
|
||||||
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
|
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
|
||||||
|
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
|
||||||
|
+ " -a, --a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
|
||||||
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
|
+ " [--out <filename>]: set output PDF file\n"
|
||||||
|
+ " -c, --combine combine XML and PDF file to ZUGFeRD PDF file\n"
|
||||||
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
|
+ " [--source-xml <filename>]: set input XML file\n"
|
||||||
|
+ " [--out <filename>]: set output PDF file\n"
|
||||||
|
+ " [--format <fx|zf>]: set ZUGFeRD or FacturX\n"
|
||||||
|
+ " [--version <1|2>]: set ZUGFeRD version\n"
|
||||||
|
+ " [--profile <...>]: set ZUGFeRD profile\n"
|
||||||
|
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\n"
|
||||||
|
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED ";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHelp() {
|
||||||
|
System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n"
|
||||||
|
+ "A Apache Public License library and command line tool for statistics on PDF invoices with\r\n"
|
||||||
|
+ "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n"
|
||||||
|
+ "* Count operations\r\n" + "\t-d, --directory\tcount ZUGFeRD files in directory to be scanned\r\n"
|
||||||
|
+ "\t\tIf it is a directory, it will recurse.\r\n"
|
||||||
|
+ "\t-l, --listfromstdin\tcount ZUGFeRD files from a list of linefeed separated files on runtime.\r\n"
|
||||||
|
+ "\t\tIt will start once a blank line has been entered.\r\n" + "\r\n"
|
||||||
|
+ "\tAdditional parameter for both count operations\r\n"
|
||||||
|
+ "\t[-i, --ignorefileextension]\tCheck for all files (*.*) instead of PDF files only (*.pdf)\r\n"
|
||||||
|
+ "\r\n" + "* Merge operations\r\n" + "\t-e, --extract\textract ZUGFeRD PDF to XML file\r\n"
|
||||||
|
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||||
|
+ "\t\t[--source <filename>]: set input PDF file\r\n"
|
||||||
|
+ "\t\t[--out <filename>]: set output XML file\r\n"
|
||||||
|
+ "\t-u, --upgrade\tupgrade ZUGFeRD XML to ZUGFeRD 2 XML\r\n"
|
||||||
|
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||||
|
+ "\t\t[--source <filename>]: set input XML ZUGFeRD 1 file\r\n"
|
||||||
|
+ "\t\t[--out <filename>]: set output XML ZUGFeRD 2 file\r\n"
|
||||||
|
+ "\t-a, --a3only\tupgrade from PDF/A1 to A3 only (no ZUGFeRD data attached) \r\n"
|
||||||
|
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||||
|
+ "\t\t[--source <filename>]: set input PDF file\r\n"
|
||||||
|
+ "\t\t[--out <filename>]: set output PDF file\r\n"
|
||||||
|
+ "\t-c, --combine\tcombine XML and PDF file to ZUGFeRD PDF file\r\n"
|
||||||
|
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||||
|
+ "\t\t[--source <filename>]: set input PDF file\r\n"
|
||||||
|
+ "\t\t[--source-xml <filename>]: set input XML file\r\n"
|
||||||
|
+ "\t\t[--out <filename>]: set output PDF file\r\n"
|
||||||
|
+ "\t\t[--format <fx|zf>]: enable factur-x or ZUGFeRD\r\n"
|
||||||
|
+ "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n"
|
||||||
|
+ "\t\t\tFor ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\r\n"
|
||||||
|
+ "\t\t\tFor ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user (repeatedly, if neccessary) on the command line for a String
|
||||||
|
* (offering a defaultValue) conforming to a Regex pattern
|
||||||
|
*
|
||||||
|
* @param prompt
|
||||||
|
* the question to be asked to the user
|
||||||
|
* @param defaultValue
|
||||||
|
* the default return value if user hits enter
|
||||||
|
* @param pattern
|
||||||
|
* a regex of acceptable values
|
||||||
|
* @return the user answer conforming to pattern
|
||||||
|
* @throws Exception
|
||||||
|
* if pattern not compielable or IOexception on input
|
||||||
|
*/
|
||||||
|
protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception {
|
||||||
|
String input = "";
|
||||||
|
if (!defaultValue.matches(pattern)) {
|
||||||
|
throw new Exception("Default value must match pattern");
|
||||||
|
}
|
||||||
|
boolean firstInput = true;
|
||||||
|
do {
|
||||||
|
// for a more sophisticated dialogue maybe https://github.com/mabe02/lanterna/
|
||||||
|
// could be taken into account
|
||||||
|
System.out.print(prompt + " (default: " + defaultValue + ")");
|
||||||
|
if (!firstInput) {
|
||||||
|
System.out.print("\n(allowed pattern: " + pattern + ")");
|
||||||
|
|
||||||
|
}
|
||||||
|
System.out.print(":");
|
||||||
|
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
try {
|
||||||
|
input = buffer.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.isEmpty()) {
|
||||||
|
// pressed return without entering anything
|
||||||
|
input = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstInput = false;
|
||||||
|
} while (!input.matches(pattern));
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user for a input or output filename
|
||||||
|
*
|
||||||
|
* @param prompt the text the user is asked
|
||||||
|
* @param defaultFilename a default Filename
|
||||||
|
* @param expectedExtension will warn if filename does not match expected file extension
|
||||||
|
* @param ensureFileExists will warn if file does NOT exist (for input files)
|
||||||
|
* @param ensureFileNotExists will warn if file DOES exist (for output files)
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension,
|
||||||
|
boolean ensureFileExists, boolean ensureFileNotExists) {
|
||||||
|
boolean fileExistenceOK = false;
|
||||||
|
String selectedName = "";
|
||||||
|
do {
|
||||||
|
// for a more sophisticated dialogue maybe https://github.com/mabe02/lanterna/
|
||||||
|
// could be taken into account
|
||||||
|
System.out.print(prompt + " (default: " + defaultFilename + "):");
|
||||||
|
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
try {
|
||||||
|
selectedName = buffer.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedName.isEmpty()) {
|
||||||
|
// pressed return without entering anything
|
||||||
|
selectedName = defaultFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error cases
|
||||||
|
if (!selectedName.toLowerCase().endsWith(expectedExtension.toLowerCase())) {
|
||||||
|
System.err.println("Expected " + expectedExtension
|
||||||
|
+ " extension, this may corrupt your file. Do you still want to continue?(Y|N)");
|
||||||
|
String selectedAnswer = "";
|
||||||
|
try {
|
||||||
|
selectedAnswer = buffer.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
|
||||||
|
System.err.println("Aborted by user");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ensureFileExists) {
|
||||||
|
if (fileExists(selectedName)) {
|
||||||
|
fileExistenceOK = true;
|
||||||
|
} else {
|
||||||
|
System.out.println("File does not exist, try again or CTRL+C to cancel");
|
||||||
|
// discard the input, a scanner.reset is not sufficient
|
||||||
|
fileExistenceOK = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileExistenceOK = true;
|
||||||
|
|
||||||
|
if (ensureFileNotExists) {
|
||||||
|
if (fileExists(selectedName)) {
|
||||||
|
fileExistenceOK = false;
|
||||||
|
System.out.println("Output file already exists, try again or CTRL+C to cancel");
|
||||||
|
// discard the input, a scanner.reset is not sufficient
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileExistenceOK = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!fileExistenceOK);
|
||||||
|
|
||||||
|
return selectedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /opt/local/bin/mvn clean compile assembly:single
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
CmdLineParser parser = new CmdLineParser();
|
||||||
|
|
||||||
|
// Option: Help
|
||||||
|
Option<Boolean> helpOption = parser.addBooleanOption('h', "help");
|
||||||
|
// Option: Action
|
||||||
|
Option<String> actionOption = parser.addStringOption('a', "action");
|
||||||
|
|
||||||
|
// Generic options available for multiple command
|
||||||
|
// --source: input file
|
||||||
|
Option<String> sourceOption = parser.addStringOption("source");
|
||||||
|
// --out: output file
|
||||||
|
Option<String> outOption = parser.addStringOption("out");
|
||||||
|
|
||||||
|
// Command: Extract XML
|
||||||
|
// --extract
|
||||||
|
// (--source: input PDF file)
|
||||||
|
// (--out: output XML file)
|
||||||
|
Option<Boolean> extractOption = parser.addBooleanOption('e', "extract");
|
||||||
|
|
||||||
|
// Command: Migrating ZUGFeRD 1 to 2
|
||||||
|
// --upgrade
|
||||||
|
// (--source: input XML ZUGFeRD 1 file)
|
||||||
|
// (--out: output XML ZUGFeRD 2 file)
|
||||||
|
Option<Boolean> upgradeOption = parser.addBooleanOption('u', "upgrade");
|
||||||
|
|
||||||
|
// Command: Convert PDF/A-1 to PDF/A-3
|
||||||
|
// --a3only
|
||||||
|
// (--source: input PDF file)
|
||||||
|
// (--out: output PDF file)
|
||||||
|
Option<Boolean> a3onlyOption = parser.addBooleanOption('a', "a3only");
|
||||||
|
|
||||||
|
// Command: Combining PDF and XML
|
||||||
|
// --combine
|
||||||
|
// (--source: input PDF file)
|
||||||
|
// (--source-xml: input XML file)
|
||||||
|
// (--out: output PDF file)
|
||||||
|
// (--version: ZUGFeRD version)
|
||||||
|
// (--profile: ZUGFeRD profile)
|
||||||
|
Option<Boolean> combineOption = parser.addBooleanOption('c', "combine");
|
||||||
|
Option<String> sourceXmlOption = parser.addStringOption("source-xml");
|
||||||
|
Option<String> formatOption = parser.addStringOption('f', "format");
|
||||||
|
Option<String> zugferdVersionOption = parser.addStringOption("version");
|
||||||
|
Option<String> zugferdProfileOption = parser.addStringOption("profile");
|
||||||
|
|
||||||
|
// Command: Show metrics in dir
|
||||||
|
// --directory
|
||||||
|
// (--ignorefileextension)
|
||||||
|
Option<String> dirnameOption = parser.addStringOption('d', "directory");
|
||||||
|
Option<Boolean> ignoreFileExtOption = parser.addBooleanOption('i', "ignorefileextension");
|
||||||
|
|
||||||
|
// Command: Show metrics from list from stdin
|
||||||
|
// --listfromstdin
|
||||||
|
Option<Boolean> filesFromStdInOption = parser.addBooleanOption('l', "listfromstdin");
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parse(args);
|
||||||
|
} catch (CmdLineParser.OptionException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
printUsage();
|
||||||
|
System.exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all options
|
||||||
|
String action = parser.getOptionValue(actionOption);
|
||||||
|
String directoryName = parser.getOptionValue(dirnameOption);
|
||||||
|
Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption, Boolean.FALSE);
|
||||||
|
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE) || ((action!=null)&&(action.equals("combine")));
|
||||||
|
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE) || ((action!=null)&&(action.equals("extract")));
|
||||||
|
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE) || ((action!=null)&&(action.equals("help")));
|
||||||
|
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE) || ((action!=null)&&(action.equals("upgrade")));
|
||||||
|
Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption, Boolean.FALSE);
|
||||||
|
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE) || ((action!=null)&&(action.equals("a3")));
|
||||||
|
String sourceName = parser.getOptionValue(sourceOption);
|
||||||
|
String sourceXMLName = parser.getOptionValue(sourceXmlOption);
|
||||||
|
String outName = parser.getOptionValue(outOption);
|
||||||
|
String format = parser.getOptionValue(formatOption);
|
||||||
|
String zugferdVersion = parser.getOptionValue(zugferdVersionOption);
|
||||||
|
String zugferdProfile = parser.getOptionValue(zugferdProfileOption);
|
||||||
|
boolean optionsRecognized=false;
|
||||||
|
if (helpRequested) {
|
||||||
|
printHelp();
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) {
|
||||||
|
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if (combineRequested) {
|
||||||
|
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile);
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if (extractRequested) {
|
||||||
|
performExtract(sourceName, outName);
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if (a3only) {
|
||||||
|
performConvert(sourceName, outName);
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if (upgradeRequested) {
|
||||||
|
performUpgrade(sourceName, outName);
|
||||||
|
optionsRecognized=true;
|
||||||
|
} else if ((action!=null)&&(action.equals("validate"))) {
|
||||||
|
ZUGFeRDValidator zfv=new ZUGFeRDValidator();
|
||||||
|
System.out.println(zfv.validate(sourceName));
|
||||||
|
|
||||||
|
optionsRecognized = !zfv.hasOptionsError();
|
||||||
|
if (!zfv.wasCompletelyValid()) {
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// no argument or argument unknown
|
||||||
|
printUsage();
|
||||||
|
System.exit(2);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException {
|
||||||
|
|
||||||
|
// Get params from user if not already defined
|
||||||
|
if (xmlName == null) {
|
||||||
|
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||||
|
} else {
|
||||||
|
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
|
||||||
|
}
|
||||||
|
if (outName == null) {
|
||||||
|
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "zugferd-invoice.xml", "xml", false, true);
|
||||||
|
} else {
|
||||||
|
System.out.println("ZUGFeRD 1.0 XML source set to " + outName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify params
|
||||||
|
ensureFileExists(xmlName);
|
||||||
|
ensureFileNotExists(outName);
|
||||||
|
|
||||||
|
// All params are good! continue...
|
||||||
|
ZUGFeRDMigrator zmi = new ZUGFeRDMigrator();
|
||||||
|
String xml = null;
|
||||||
|
xml = zmi.migrateFromV1ToV2(xmlName);
|
||||||
|
Files.write(Paths.get(outName), xml.getBytes());
|
||||||
|
System.out.println("Written to " + outName);
|
||||||
|
/*
|
||||||
|
* } catch (FileNotFoundException ex) {
|
||||||
|
* Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performConvert(String pdfName, String outName) throws IOException {
|
||||||
|
/*
|
||||||
|
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
||||||
|
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
||||||
|
* .loadFromPDFA1("invoice.pdf");
|
||||||
|
*/
|
||||||
|
// Get params from user if not already defined
|
||||||
|
if (pdfName == null) {
|
||||||
|
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||||
|
} else {
|
||||||
|
System.out.println("Source PDF set to " + pdfName);
|
||||||
|
}
|
||||||
|
if (outName == null) {
|
||||||
|
outName = getFilenameFromUser("Target PDF", "invoice.a3.pdf", "pdf", false, true);
|
||||||
|
} else {
|
||||||
|
System.out.println("Target PDF set to " + outName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify params
|
||||||
|
ensureFileExists(pdfName);
|
||||||
|
ensureFileNotExists(outName);
|
||||||
|
|
||||||
|
// All params are good! continue...
|
||||||
|
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(pdfName);
|
||||||
|
|
||||||
|
ze.export(outName);
|
||||||
|
System.out.println("Written to " + outName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performExtract(String pdfName, String xmlName) throws IOException {
|
||||||
|
// Get params from user if not already defined
|
||||||
|
if (pdfName == null) {
|
||||||
|
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||||
|
} else {
|
||||||
|
System.out.println("Source PDF set to " + pdfName);
|
||||||
|
}
|
||||||
|
if (xmlName == null) {
|
||||||
|
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", false, true);
|
||||||
|
} else {
|
||||||
|
System.out.println("ZUGFeRD XML set to " + pdfName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify params
|
||||||
|
ensureFileExists(pdfName);
|
||||||
|
ensureFileNotExists(xmlName);
|
||||||
|
|
||||||
|
// All params are good! continue...
|
||||||
|
ZUGFeRDImporter zi = new ZUGFeRDImporter(pdfName);
|
||||||
|
byte[] XMLContent = zi.getRawXML();
|
||||||
|
if (XMLContent == null) {
|
||||||
|
System.err.println("No ZUGFeRD XML found in PDF file");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Files.write(Paths.get(xmlName), XMLContent);
|
||||||
|
System.out.println("Written to " + xmlName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
|
||||||
|
String zfProfile) throws Exception {
|
||||||
|
/*
|
||||||
|
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
||||||
|
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
||||||
|
* .loadFromPDFA1("invoice.pdf");
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
int zfIntVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion;
|
||||||
|
ZUGFeRDConformanceLevel zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||||
|
|
||||||
|
if (pdfName == null) {
|
||||||
|
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||||
|
} else {
|
||||||
|
System.out.println("Source PDF set to " + pdfName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlName == null) {
|
||||||
|
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||||
|
} else {
|
||||||
|
System.out.println("ZUGFeRD XML set to " + xmlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outName == null) {
|
||||||
|
outName = getFilenameFromUser("Ouput PDF", "invoice.ZUGFeRD.pdf", "pdf", false, true);
|
||||||
|
} else {
|
||||||
|
System.out.println("Ouput PDF set to " + outName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == null) {
|
||||||
|
try {
|
||||||
|
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Format set to " + format);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zfVersion == null) {
|
||||||
|
try {
|
||||||
|
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Version set to " + zfVersion);
|
||||||
|
}
|
||||||
|
zfIntVersion = Integer.valueOf(zfVersion);
|
||||||
|
|
||||||
|
if (zfProfile == null) {
|
||||||
|
try {
|
||||||
|
if (format.equals("zf") && (zfIntVersion == 1)) {
|
||||||
|
zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e");
|
||||||
|
} else {
|
||||||
|
zfProfile = getStringFromUser(
|
||||||
|
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E",
|
||||||
|
"M|m|W|w|B|b|C|c|E|e|X|x|");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Profile set to " + zfProfile);
|
||||||
|
}
|
||||||
|
zfProfile = zfProfile.toLowerCase();
|
||||||
|
|
||||||
|
// Verify params
|
||||||
|
ensureFileExists(pdfName);
|
||||||
|
ensureFileExists(xmlName);
|
||||||
|
ensureFileNotExists(outName);
|
||||||
|
|
||||||
|
if ((format.equals("fx")) && (zfIntVersion > 1)) {
|
||||||
|
throw new Exception("Factur-X is only available in version 1 (roughly corresponding to ZF2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((format.equals("zf")) && (zfIntVersion == 1)) {
|
||||||
|
if (zfProfile.equals("b")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC;
|
||||||
|
} else if (zfProfile.equals("c")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.COMFORT;
|
||||||
|
} else if (zfProfile.equals("e")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||||
|
} else {
|
||||||
|
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
|
||||||
|
}
|
||||||
|
} else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) {
|
||||||
|
if (zfProfile.equals("m")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM;
|
||||||
|
} else if (zfProfile.equals("w")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASICWL;
|
||||||
|
} else if (zfProfile.equals("b")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC;
|
||||||
|
} else if (zfProfile.equals("c")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.CIUS;
|
||||||
|
} else if (zfProfile.equals("e")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EN16931;
|
||||||
|
} else if (zfProfile.equals("x")) {
|
||||||
|
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||||
|
} else {
|
||||||
|
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception(String.format("Unknown version '%i'", zfIntVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
// All params are good! continue...
|
||||||
|
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Mustang-cli")
|
||||||
|
.setZUGFeRDVersion(zfIntVersion)
|
||||||
|
.setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(zfConformanceLevelProfile)
|
||||||
|
.load(pdfName);
|
||||||
|
|
||||||
|
if (format.equals("fx")) {
|
||||||
|
ze.setFacturX();
|
||||||
|
}
|
||||||
|
|
||||||
|
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName)));
|
||||||
|
|
||||||
|
ze.export(outName);
|
||||||
|
|
||||||
|
System.out.println("Written to " + outName);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performMetrics(String directoryName, Boolean filesFromStdIn, Boolean ignoreFileExt)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
StatRun sr = new StatRun();
|
||||||
|
if (ignoreFileExt) {
|
||||||
|
sr.ignoreFileExtension();
|
||||||
|
}
|
||||||
|
if (directoryName != null) {
|
||||||
|
Path startingDir = Paths.get(directoryName);
|
||||||
|
|
||||||
|
if (Files.isRegularFile(startingDir)) {
|
||||||
|
String filename = startingDir.toString();
|
||||||
|
FileChecker fc = new FileChecker(filename, sr);
|
||||||
|
|
||||||
|
fc.checkForZUGFeRD();
|
||||||
|
System.out.print(fc.getOutputLine());
|
||||||
|
|
||||||
|
} else if (Files.isDirectory(startingDir)) {
|
||||||
|
FileTraverser pf = new FileTraverser(sr);
|
||||||
|
Files.walkFileTree(startingDir, pf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filesFromStdIn) {
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
String s;
|
||||||
|
while ((s = in.readLine()) != null && s.length() != 0) {
|
||||||
|
FileChecker fc = new FileChecker(s, sr);
|
||||||
|
|
||||||
|
fc.checkForZUGFeRD();
|
||||||
|
System.out.print(fc.getOutputLine());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
System.out.println(sr.getSummaryLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureFileExists(String fileName) throws IOException {
|
||||||
|
if (!fileExists(fileName)) {
|
||||||
|
throw new IOException(String.format("File %s does not exists", fileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureFileNotExists(String fileName) throws IOException {
|
||||||
|
if (fileExists(fileName)) {
|
||||||
|
throw new IOException(String.format("File %s does not exists", fileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Boolean fileExists(String fileName) {
|
||||||
|
if (fileName == null)
|
||||||
|
return false;
|
||||||
|
File f = new File(fileName);
|
||||||
|
return f.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
99
Mustang-CLI/src/main/java/org/mustangproject/commandline/StatRun.java
Executable file
99
Mustang-CLI/src/main/java/org/mustangproject/commandline/StatRun.java
Executable file
@@ -0,0 +1,99 @@
|
|||||||
|
/** **********************************************************************
|
||||||
|
*
|
||||||
|
* Copyright 2018 Jochen Staerk
|
||||||
|
*
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* 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 org.mustangproject.commandline;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class StatRun {
|
||||||
|
private int pdfCount = 0;
|
||||||
|
private int horseCount = 0;
|
||||||
|
private int fileCount = 0;
|
||||||
|
private int dirCount = 0;
|
||||||
|
private BigDecimal total = BigDecimal.ZERO;
|
||||||
|
private boolean checkFileExt = true;
|
||||||
|
|
||||||
|
public void ignoreFileExtension() {
|
||||||
|
checkFileExt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shallIgnoreFileExt() {
|
||||||
|
return !checkFileExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incFileCount() {
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incPDFCount() {
|
||||||
|
pdfCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incZUGFeRDCount(int version) {
|
||||||
|
horseCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incDirCount() {
|
||||||
|
dirCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFileCount() {
|
||||||
|
return fileCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPDFCount() {
|
||||||
|
return pdfCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZUGFeRDCount() {
|
||||||
|
return horseCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDirCount() {
|
||||||
|
return dirCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns final statistics
|
||||||
|
*
|
||||||
|
* @return english string with linefeeds detailling number of files, directories, number of pdfs and of zugferd files
|
||||||
|
*/
|
||||||
|
public String getSummaryLine() {
|
||||||
|
|
||||||
|
return "\r\n===================================================================\r\n" + String.format(
|
||||||
|
"Files:\t%d\tDirs:\t%d\tPDF:\t%d\tZUGFeRD:\t%d\tTotal:\t%s\r\n",
|
||||||
|
getFileCount(), getDirCount(), getPDFCount(), getZUGFeRDCount(), total.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show that something is happening
|
||||||
|
*
|
||||||
|
* @return String, usually a dot
|
||||||
|
*/
|
||||||
|
public String getOutputLine() {
|
||||||
|
return ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incTotal(BigDecimal delta) {
|
||||||
|
total=total.add(delta);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
14
Mustang-Server/History.md
Normal file
14
Mustang-Server/History.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
0.0.2
|
||||||
|
=====
|
||||||
|
2019-09-15
|
||||||
|
|
||||||
|
- Https support,
|
||||||
|
- User authentication (for combine method, username good-guy password secret)
|
||||||
|
- completed mandatory swagger attributes.
|
||||||
|
|
||||||
|
|
||||||
|
0.0.1
|
||||||
|
=====
|
||||||
|
2019-08-18
|
||||||
|
|
||||||
|
Possibility to extract/combine files, swagger support
|
||||||
201
Mustang-Server/LICENSE
Normal file
201
Mustang-Server/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
45
Mustang-Server/README.md
Normal file
45
Mustang-Server/README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# mustangAPI
|
||||||
|
A rest API for [Mustangproject](https://www.mustangproject.org), i.e. for ZUGFeRD/Factur-X
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Using a
|
||||||
|
* [Dropwizard](https://dropwizard.io) and a
|
||||||
|
* Swagger integration
|
||||||
|
|
||||||
|
Recommended: German 45min Dropwizard/Swagger introduction [video](https://media.ccc.de/v/froscon2017-1985-einfache_rest-apis_mit_dropwizard_und_swagger) and [slides](https://programm.froscon.de/2017/system/event_attachments/attachments/000/000/469/original/20170818_LeanIX_Presentation_Froscon.pdf) from Froscon 2017
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
|
||||||
|
* Integrates its own (jersey) webserver
|
||||||
|
* get the API documentation online (Human readable and as OpenAPI)
|
||||||
|
* try the API in a swagger generated demo web client
|
||||||
|
* Extract the XML from a ZUGFeRD/Factur-X invoice
|
||||||
|
* Combine custom XML and a PDF/A-1 file to a ZUGFeRD/Factur-X invoice
|
||||||
|
|
||||||
|
Feel free to send pull requests for more functionality.
|
||||||
|
|
||||||
|
## Compile
|
||||||
|
|
||||||
|
`mvn clean package`
|
||||||
|
|
||||||
|
## Start
|
||||||
|
|
||||||
|
`java -jar target/server-0.0.2-SNAPSHOT.jar server config.yml`
|
||||||
|
|
||||||
|
## Use
|
||||||
|
|
||||||
|
use http://127.0.0.1:8080/swagger to try the methods (https://localhost:8443/swagger would work but is self-signed).
|
||||||
|
Access http://localhost:8080/swagger.yaml to build your clients.
|
||||||
|
For demo purposes, extract does not require authentication but combine requires http authentication with user name "good-guy" and password "secret".
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Community support is available via the [ZUGFeRD Google Group](https://groups.google.com/forum/?hl=de#!forum/zugferd)
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
For commercial and/or legal inquiries contact Jochen Stärk jochen@zugferd.org
|
||||||
BIN
Mustang-Server/README_screenshot.png
Normal file
BIN
Mustang-Server/README_screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
13
Mustang-Server/config.yml
Normal file
13
Mustang-Server/config.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
swagger:
|
||||||
|
resourcePackage: mustang
|
||||||
|
server:
|
||||||
|
applicationConnectors:
|
||||||
|
- type: http
|
||||||
|
port: 8080
|
||||||
|
- type: https
|
||||||
|
port: 8443
|
||||||
|
# keytool -genkeypair -keyalg RSA -dname "CN=localhost" -keystore dwstart.keystore -keypass crimson -storepass crimson
|
||||||
|
keyStorePath: ./dwstart.keystore
|
||||||
|
keyStorePassword: "crimson"
|
||||||
|
validateCerts: false
|
||||||
|
validatePeers: false
|
||||||
BIN
Mustang-Server/dwstart.keystore
Normal file
BIN
Mustang-Server/dwstart.keystore
Normal file
Binary file not shown.
147
Mustang-Server/pom.xml
Normal file
147
Mustang-Server/pom.xml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>Mustang-Server</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<name>Mustang Server</name>
|
||||||
|
<description>A rest API for ZUGFeRD, Factur-X and XRechnung</description>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
<dropwizard.version>1.3.12</dropwizard.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>libraryExtended</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
|
||||||
|
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
|
||||||
|
-->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.dropwizard</groupId>
|
||||||
|
<artifactId>dropwizard-core</artifactId>
|
||||||
|
<version>${dropwizard.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.smoketurner</groupId>
|
||||||
|
<artifactId>dropwizard-swagger</artifactId>
|
||||||
|
<version>1.3.12-1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.dropwizard</groupId>
|
||||||
|
<artifactId>dropwizard-forms</artifactId>
|
||||||
|
<version>${dropwizard.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.dropwizard</groupId>
|
||||||
|
<artifactId>dropwizard-auth</artifactId>
|
||||||
|
<version>${dropwizard.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
junit
|
||||||
|
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit5-api</artifactId>
|
||||||
|
<version>5.0.0-ALPHA</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit5-engine</artifactId>
|
||||||
|
<version>5.0.0-ALPHA</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- the rest -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox-tools</artifactId>
|
||||||
|
<version>2.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.cssbox</groupId>
|
||||||
|
<artifactId>pdf2dom</artifactId>
|
||||||
|
<version>1.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.itextpdf</groupId>
|
||||||
|
<artifactId>itextpdf</artifactId>
|
||||||
|
<version>5.5.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.itextpdf.tool</groupId>
|
||||||
|
<artifactId>xmlworker</artifactId>
|
||||||
|
<version>5.5.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>3.15</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-scratchpad</artifactId>
|
||||||
|
<version>3.15</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.3</version>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
<!-- includes <include>assets/**</include> </includes ! -->
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
||||||
|
|
||||||
|
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>api.ApiApplication</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
51
Mustang-Server/src/main/java/api/ApiApplication.java
Normal file
51
Mustang-Server/src/main/java/api/ApiApplication.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
Mustang-Server/src/main/java/api/ApiConfiguration.java
Normal file
12
Mustang-Server/src/main/java/api/ApiConfiguration.java
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
18
Mustang-Server/src/main/java/api/BasicAuthenticator.java
Normal file
18
Mustang-Server/src/main/java/api/BasicAuthenticator.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Mustang-Server/src/main/java/api/BasicAuthorizer.java
Normal file
11
Mustang-Server/src/main/java/api/BasicAuthorizer.java
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Mustang-Server/src/main/java/api/User.java
Normal file
15
Mustang-Server/src/main/java/api/User.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
146
Mustang-Server/src/main/java/mustang/MustangResource.java
Normal file
146
Mustang-Server/src/main/java/mustang/MustangResource.java
Normal 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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
50
Mustang-Server/src/test/java/mustangAPI/IntegrationTest.java
Normal file
50
Mustang-Server/src/test/java/mustangAPI/IntegrationTest.java
Normal 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);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
347
libraryBasic/pom.xml
Normal file
347
libraryBasic/pom.xml
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>libraryBasic</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>libraryBasic</name>
|
||||||
|
<description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs
|
||||||
|
</description>
|
||||||
|
<url>http://www.mustangproject.org/</url>
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
|
||||||
|
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
|
||||||
|
<url>https://github.com/ZUGFeRD/mustangproject</url>
|
||||||
|
<tag>mustang-1.7.3</tag>
|
||||||
|
</scm>
|
||||||
|
<repositories>
|
||||||
|
<repository><!-- for jargs -->
|
||||||
|
<id>sonatype-oss-public</id>
|
||||||
|
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>internal.repo</id>
|
||||||
|
<name>Temporary Staging Repository</name>
|
||||||
|
<url>file://${project.build.directory}/mvn-repo</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<github.global.server>github</github.global.server>
|
||||||
|
<additionalparam>-Xdoclint:none</additionalparam>
|
||||||
|
<!-- Skip error check for javadoc -->
|
||||||
|
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.saxon</groupId>
|
||||||
|
<artifactId>Saxon-HE</artifactId>
|
||||||
|
<version>9.8.0-11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
<version>2.2.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
<version>2.2.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
|
<version>2.2.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
<version>2.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.activation</groupId>
|
||||||
|
<artifactId>activation</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>preflight</artifactId>
|
||||||
|
<version>[2.0.15,2.0.17]</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
<version>[2.0.15,2.0.17]</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dom4j</groupId>
|
||||||
|
<artifactId>dom4j</artifactId>
|
||||||
|
<version>2.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>ph-schematron</artifactId>
|
||||||
|
<version>5.0.4</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-core</artifactId>
|
||||||
|
<version>2.6.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- For Toecount -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sanityinc</groupId>
|
||||||
|
<artifactId>jargs</artifactId>
|
||||||
|
<version>2.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin><!-- mvn help:effective-pom will otherwise tell it just defaults
|
||||||
|
to 2.3.2 - which does not release in the maven repo, and neither shows any
|
||||||
|
error message :-( -->
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
<!-- toecount -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<mainClass>org.mustangproject.toecount.Toecount</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
||||||
|
mvn clean compile assembly:single -->
|
||||||
|
<!-- or whatever version you use -->
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- /toecount -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<excludePackageNames>org.mustangproject.ZUGFeRD.model.*</excludePackageNames>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.8.2</version>
|
||||||
|
<configuration>
|
||||||
|
<altDeploymentRepository>internal.repo::default::file://${project.build.directory}/mvn-repo
|
||||||
|
</altDeploymentRepository>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.github</groupId>
|
||||||
|
<artifactId>site-maven-plugin</artifactId>
|
||||||
|
<version>0.12</version>
|
||||||
|
<configuration>
|
||||||
|
<message>Maven artifacts for ${project.version}</message>
|
||||||
|
<!-- git commit message -->
|
||||||
|
<noJekyll>true</noJekyll>
|
||||||
|
<!-- disable webpage processing -->
|
||||||
|
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory>
|
||||||
|
<!-- matches distribution management repository url above -->
|
||||||
|
<branch>refs/heads/mvn-repo</branch>
|
||||||
|
<!-- remote branch name -->
|
||||||
|
<includes>
|
||||||
|
<include>**/*</include>
|
||||||
|
</includes>
|
||||||
|
<merge>true</merge>
|
||||||
|
<repositoryName>mustangproject</repositoryName>
|
||||||
|
<!-- github repo name -->
|
||||||
|
<repositoryOwner>ZUGFeRD</repositoryOwner>
|
||||||
|
<!-- github username -->
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<!-- run site-maven-plugin's 'site' target as part of the build's normal
|
||||||
|
'deploy' phase -->
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>site</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>deploy</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.mustangproject.toecount.Toecount</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
<minimizeJar>false</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
|
||||||
|
<filters>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>log4j:log4j</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.sun.xml.bind:jaxb-core</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactSet>
|
||||||
|
<excludes>
|
||||||
|
<!--exclude>classworlds:classworlds</exclude> <exclude>junit:junit</exclude>
|
||||||
|
<exclude>jmock:*</exclude> <exclude>*:xml-apis</exclude> <exclude>org.apache.maven:lib:tests</exclude>
|
||||||
|
<exclude>log4j:log4j:jar:</exclude -->
|
||||||
|
</excludes>
|
||||||
|
</artifactSet>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>templating-maven-plugin</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>filtering-java-templates</id>
|
||||||
|
<goals>
|
||||||
|
<goal>filter-sources</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>xjc</id>
|
||||||
|
<goals>
|
||||||
|
<goal>xjc</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<target>2.1</target>
|
||||||
|
<packageName>org.mustangproject.ZUGFeRD.model</packageName>
|
||||||
|
<sources>
|
||||||
|
<source>src/main/resources/schema/ZUGFeRD1p0.xsd</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<mailingLists>
|
||||||
|
<mailingList>
|
||||||
|
<name>User List</name>
|
||||||
|
<archive>https://groups.google.com/forum/?hl=de#!forum/mustangproject</archive>
|
||||||
|
</mailingList>
|
||||||
|
</mailingLists>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache License, Version 2.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
<comments>A business-friendly OSS license</comments>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Jochen Stärk</name>
|
||||||
|
<email>jstaerk@usegroup.de</email>
|
||||||
|
<roles>
|
||||||
|
<role>architect</role>
|
||||||
|
<role>developer</role>
|
||||||
|
</roles>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<name>Alexander Schmidt</name>
|
||||||
|
<email>schmidt.alexander@mail.de</email>
|
||||||
|
<roles>
|
||||||
|
<role>developer</role>
|
||||||
|
</roles>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
</project>
|
||||||
@@ -156,7 +156,6 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
|
|||||||
@Override
|
@Override
|
||||||
public IZUGFeRDExportableContact getOwnContact() {
|
public IZUGFeRDExportableContact getOwnContact() {
|
||||||
return new SenderContact();
|
return new SenderContact();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user