basic pdf template lib

This commit is contained in:
jomu
2016-05-01 21:55:04 +00:00
parent 5cf92b57aa
commit 8fe4588555
14 changed files with 675 additions and 0 deletions

View File

@ -0,0 +1,37 @@
package de.muehlencord.shared.pdf;
/**
*
* @author jomu
*/
public class ConfigurationException extends Exception {
/**
* Creates a new instance of <code>ConfigurationException</code> without
* detail message.
*/
public ConfigurationException() {
}
/**
* Constructs an instance of <code>ConfigurationException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
public ConfigurationException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>ConfigurationException</code> with the
* specified detail message and the given root cause.
*
* @param msg the detail message.
* @param th the root cause.
*/
public ConfigurationException(String msg, Throwable th) {
super(msg);
}
}

View File

@ -0,0 +1,79 @@
package de.muehlencord.shared.pdf;
import com.google.gson.annotations.Expose;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
/**
*
* @author jomu
*/
public abstract class Content {
@Expose
protected int x;
@Expose
protected int y;
@Expose
protected Font standardFont;
@Expose
protected Map<String, Font> fontMap;
public Content(int x, int y) {
this.standardFont = new Font("Helvetica", 11);
this.x = x;
this.y = y;
this.fontMap = null;
}
public void addFont(String name, Font font) {
if (fontMap == null) {
fontMap = new ConcurrentHashMap<>();
}
fontMap.put(name, font);
}
protected PDFont getFont(String fontName) throws ConfigurationException {
if (fontName.equals(PDType1Font.HELVETICA.getBaseFont())) {
return PDType1Font.HELVETICA;
} else {
throw new ConfigurationException("Font " + fontName + " not supported");
}
}
protected abstract void addContentToPdf(PDRectangle rect, PDPageContentStream cos) throws IOException, ConfigurationException;
/* *** getter / setter *** */
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Font getStandardFont() {
return standardFont;
}
public void setStandardFont(Font standardFont) {
this.standardFont = standardFont;
}
}

View File

@ -0,0 +1,51 @@
package de.muehlencord.shared.pdf;
/**
*
* @author jomu
*/
public class Font {
private String fontName;
private int fontSize;
private int padding;
public Font(String fontName, int fontSize) {
this.fontName = fontName;
this.fontSize = fontSize;
this.padding = 2;
}
public Font(String fontName, int fontSize, int padding) {
this.fontName = fontName;
this.fontSize = fontSize;
this.padding = padding;
}
/* *** getter / setter *** */
public String getFontName() {
return fontName;
}
public void setFontName(String fontName) {
this.fontName = fontName;
}
public int getFontSize() {
return fontSize;
}
public void setFontSize(int fontSize) {
this.fontSize = fontSize;
}
public int getPadding() {
return padding;
}
public void setPadding(int padding) {
this.padding = padding;
}
}

View File

@ -0,0 +1,19 @@
package de.muehlencord.shared.pdf;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
*
* @author jomu
*/
public class GsonUtil {
public final static Gson getGsonInstance() {
return new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Content.class, new InterfaceAdapter<>())
.create();
}
}

View File

@ -0,0 +1,54 @@
package de.muehlencord.shared.pdf;
import com.google.gson.JsonDeserializationContext;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
*
* @author jomu
*/
public class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {
@Override
public final JsonElement serialize(final T object, final Type interfaceType, final JsonSerializationContext context) {
final JsonObject member = new JsonObject();
member.addProperty("type", object.getClass().getName());
member.add("data", context.serialize(object));
return member;
}
@Override
public final T deserialize(final JsonElement elem, final Type interfaceType, final JsonDeserializationContext context) throws JsonParseException {
final JsonObject member = (JsonObject) elem;
final JsonElement typeString = get(member, "type");
final JsonElement data = get(member, "data");
final Type actualType = typeForName(typeString);
return context.deserialize(data, actualType);
}
private Type typeForName(final JsonElement typeElem) {
try {
return Class.forName(typeElem.getAsString());
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
private JsonElement get(final JsonObject wrapper, final String memberName) {
final JsonElement elem = wrapper.get(memberName);
if (elem == null) {
throw new JsonParseException(
"no '" + memberName + "' member found in json file.");
}
return elem;
}
}

View File

@ -0,0 +1,43 @@
package de.muehlencord.shared.pdf;
import com.google.gson.annotations.Expose;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author jomu
*/
public class PDFDocument {
@Expose
private PaperSize paperSize;
@Expose
private final List<Content> contentList;
public PDFDocument() {
this.contentList = new ArrayList<>();
}
public PDFDocument addContent (Content content) {
contentList.add (content);
return this;
}
/* *** getter / setter *** */
public PaperSize getPaperSize() {
return paperSize;
}
public void setPaperSize(PaperSize paperSize) {
this.paperSize = paperSize;
}
public List<Content> getContentList() {
return contentList;
}
}

View File

@ -0,0 +1,75 @@
package de.muehlencord.shared.pdf;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author jomu
*/
public class PDFTemplate {
private static final Logger LOGGER = LoggerFactory.getLogger(PDFTemplate.class);
public final static String A4 = "A4";
private final Template template;
private final ConcurrentHashMap<String, Object> dataModel;
public PDFTemplate(Template template) {
this.template = template;
this.dataModel = new ConcurrentHashMap<>();
}
public void create(String filenName) throws ConfigurationException, IOException {
Writer out = new StringWriter();
try {
template.process(dataModel, out);
} catch (TemplateException ex) {
throw new IOException("Error while processing template", ex);
}
String json = out.toString();
LOGGER.info(json);
Gson gson = GsonUtil.getGsonInstance();
PDFDocument pdfDoc = gson.fromJson(json, PDFDocument.class);
PDDocument doc = new PDDocument();
PDPage page;
switch (pdfDoc.getPaperSize()) {
case A4:
page = new PDPage(PDRectangle.A4);
break;
default:
throw new ConfigurationException("Papersize " + pdfDoc.getPaperSize().getLabel() + " not supported");
}
doc.addPage(page);
PDRectangle rect = page.getMediaBox();
PDPageContentStream cos = new PDPageContentStream(doc, page, AppendMode.APPEND, false);
for (Content content : pdfDoc.getContentList()) {
content.addContentToPdf(rect, cos);
}
cos.close();
doc.save(filenName);
}
void applyTemplate(Template template) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -0,0 +1,44 @@
package de.muehlencord.shared.pdf;
import com.google.gson.annotations.Expose;
import java.io.IOException;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
/**
*
* @author jomu
*/
public class TableContent extends Content {
@Expose
Font headerFont;
@Expose
List<Object> header;
@Expose
List<List<Object>> data;
public TableContent(int x, int y) {
super(x, y);
}
@Override
protected void addContentToPdf(PDRectangle rect, PDPageContentStream cos) throws IOException, ConfigurationException {
cos.beginText();
cos.setFont(getFont(headerFont.getFontName()), headerFont.getFontSize());
cos.newLineAtOffset(x,y);
}
/* *** getter / setter *** */
public Font getHeaderFont() {
return headerFont;
}
public void setHeaderFont(Font headerFont) {
this.headerFont = headerFont;
}
}

View File

@ -0,0 +1,65 @@
package de.muehlencord.shared.pdf;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
/**
*
* @author jomu
*/
public class TextContent extends Content {
private final List<String> textLines;
public TextContent() {
this(-1, -1);
}
public TextContent(int x, int y) {
super(x, y);
this.textLines = new LinkedList<>();
}
public TextContent(int x, int y, String text) {
super(x, y);
this.textLines = new LinkedList<>();
this.textLines.add(text);
}
public TextContent addLine() {
this.textLines.add("");
return this;
}
public TextContent addLine(String text) {
this.textLines.add(text);
return this;
}
public TextContent addLine(String text, String fontShortcut) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/* *** getter / setter */
public List<String> getTextLines() {
return textLines;
}
@Override
protected void addContentToPdf(PDRectangle rect, PDPageContentStream cos) throws IOException, ConfigurationException {
PDFont font = getFont(standardFont.getFontName());
cos.beginText();
cos.setFont(font, standardFont.getFontSize());
cos.setLeading(standardFont.getFontSize() + standardFont.getPadding());
cos.newLineAtOffset(x, y);
for (String line : textLines) {
cos.showText(line);
cos.newLine();
}
cos.endText();
}
}

View File

@ -0,0 +1,24 @@
package de.muehlencord.shared.pdf;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author jomu
*/
public class ContentTest {
public ContentTest() {
}
@Test
public void testGetFont() throws ConfigurationException {
TextContent textContent = new TextContent(1,1,"Helvetica");
PDFont font = textContent.getFont("Helvetica");
assertEquals (PDType1Font.HELVETICA, font);
}
}

View File

@ -0,0 +1,53 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.pdf;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author jomu
*/
public class PDFDocumentTest {
private static Gson gson;
@BeforeClass
public static void setUpClass() {
gson = GsonUtil.getGsonInstance();
}
@Test
public void testToJson() {
System.out.println("testToJson");
PDFDocument doc = new PDFDocument();
doc.setPaperSize(PaperSize.A4);
TextContent addressContent = new TextContent(40, 692, "Max Mustermann")
.addLine("Musterstraße 123")
.addLine("12345 Musterhausen");
doc.addContent(addressContent);
TextContent invoiceInfoInformation = new TextContent(40, 442, "Sehr geehrter Anzeigenkunde, ")
.addLine()
.addLine()
.addLine("Wir danken für den Auftrag und bitten um Erledigung der folgenden Anzeigenabrechnung");
doc.addContent(invoiceInfoInformation);
TextContent informationContent = new TextContent(400, 662);
informationContent.addFont("bold", new Font("Helvetica-Bold", 12, 2));
informationContent.addLine ("Anzeigenabrechnung", "bold");
System.out.println(gson.toJson(doc));
}
}

View File

@ -0,0 +1,31 @@
package de.muehlencord.shared.pdf;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
/**
*
* @author jomu
*/
public class PDFTemplateTest {
@Test
// @Ignore // TODO get template from test resources
public void testCreate() throws IOException, ConfigurationException {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_24);
cfg.setDirectoryForTemplateLoading(new File("c:/temp"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
Template template = cfg.getTemplate("test.ftlh");
PDFTemplate doc = new PDFTemplate(template);
doc.create ("c:/temp/test.pdf");
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="true">
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} %-5p [%c] %m%n" />
</layout>
</appender>
<logger name="org.hibernate">
<level value="warn" />
</logger>
<category name="de.muehlencord">
<priority value="DEBUG"/>
</category>
<category name="com.sun">
<priority value="WARN"/>
</category>
<category name="javax.xml">
<priority value="WARN"/>
</category>
<root>
<level value="INFO" />
<appender-ref ref="consoleAppender" />
</root>
</log4j:configuration>