/*
* ARX: Powerful Data Anonymization
* Copyright 2012 - 2016 Fabian Prasser, Florian Kohlmayer and contributors
*
* 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.deidentifier.arx.certificate;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.deidentifier.arx.ARXConfiguration;
import org.deidentifier.arx.ARXLattice.ARXNode;
import org.deidentifier.arx.ARXLattice.Anonymity;
import org.deidentifier.arx.ARXResult;
import org.deidentifier.arx.DataDefinition;
import org.deidentifier.arx.DataHandle;
import org.deidentifier.arx.certificate.CertificateStyle.ListStyle;
import org.deidentifier.arx.certificate.elements.Element;
import org.deidentifier.arx.certificate.elements.ElementData;
import org.deidentifier.arx.certificate.elements.ElementList;
import org.deidentifier.arx.certificate.elements.ElementNewLine;
import org.deidentifier.arx.certificate.elements.ElementSubtitle;
import org.deidentifier.arx.certificate.elements.ElementTitle;
import org.deidentifier.arx.certificate.resources.Watermark;
import org.deidentifier.arx.criteria.PrivacyCriterion;
import org.deidentifier.arx.io.CSVDataChecksum;
import org.deidentifier.arx.io.CSVSyntax;
import rst.pdfbox.layout.elements.Document;
/**
* A PDF document
*
* @author Annika Saken
* @author Fabian Prasser
*/
public class ARXCertificate {
/**
* Creates a new instance
* @param input
* @param definition
* @param config
* @param result
* @param transformation
* @param output
*/
public static ARXCertificate create(DataHandle input, DataDefinition definition,
ARXConfiguration config, ARXResult result, ARXNode transformation, DataHandle output) {
return ARXCertificate.create(input, definition, config, result, transformation, output, null);
}
/**
* Renders the document into the given output stream.
* Includes a SHA-256 checksum of the output data.
*
* @param input
* @param definition
* @param config
* @param result
* @param transformation
* @param output
* @param syntax
*/
public static ARXCertificate create(DataHandle input,
DataDefinition definition,
ARXConfiguration config,
ARXResult result,
ARXNode transformation,
DataHandle output,
CSVSyntax syntax) {
return ARXCertificate.create(input, definition, config, result, transformation, output, syntax, null);
}
/**
* Renders the document into the given output stream.
* Includes a SHA-256 checksum of the output data and user defined metadata
*
* @param input
* @param definition
* @param config
* @param result
* @param transformation
* @param output
* @param syntax
* @param metadata
*/
public static ARXCertificate create(DataHandle input,
DataDefinition definition,
ARXConfiguration config,
ARXResult result,
ARXNode transformation,
DataHandle output,
CSVSyntax syntax,
ElementData metadata) {
return new ARXCertificate(input, definition, config, result, transformation, output, syntax, metadata);
}
/** The document style */
private final CertificateStyle style;
/** Elements*/
private final List<Element> elements = new ArrayList<Element>();
/**
* Creates a new instance
* @param input
* @param definition
* @param config
* @param result
* @param transformation
* @param output
* @param csvConfig
* @param metadata
*/
ARXCertificate(DataHandle input, DataDefinition definition,
ARXConfiguration config, ARXResult result,
ARXNode transformation, DataHandle output,
CSVSyntax csvConfig, ElementData metadata) {
this.style = CertificateStyle.create();
// Check
if (input == null || definition == null || config == null || result == null || transformation == null) {
throw new NullPointerException();
}
int section = 1;
if (metadata != null) {
this.add(new ElementTitle("Project"));
this.add(new ElementSubtitle((section++)+". Properties"));
this.add(asList(metadata));
this.add(new ElementNewLine());
}
section = 1;
this.add(new ElementTitle("Input specification"));
this.add(new ElementSubtitle((section++)+". Input data"));
this.add(asList(input.render()));
this.add(new ElementNewLine());
this.add(new ElementSubtitle((section++)+". Attributes and transformations"));
this.add(asList(definition.render()));
this.add(new ElementNewLine());
this.add(new ElementSubtitle((section++)+". Configuration"));
this.add(asList(config.render()));
if (result.isResultAvailable()) {
section = 1;
this.add(new ElementNewLine());
this.add(new ElementTitle("Output properties"));
this.add(new ElementSubtitle((section++)+". Output data"));
this.add(asList(output.render()));
if (csvConfig != null) {
String checksum = null;
try {
checksum = new CSVDataChecksum(csvConfig).getSHA256Checksum(output.iterator());
} catch (NoSuchAlgorithmException e) {
checksum = "Could not calculate hash";
}
this.add(asList(new ElementData("Checksum").addProperty("SHA-256", checksum)));
}
this.add(new ElementNewLine());
this.add(new ElementSubtitle((section++)+". Solutions"));
this.add(asList(result.getLattice().render()));
this.add(new ElementNewLine());
this.add(new ElementSubtitle((section++)+". Transformation"));
this.add(asList(transformation.render()));
this.add(new ElementNewLine());
if (config.getQualityModel() != null) {
this.add(new ElementSubtitle((section++)+". Data quality model"));
this.add(asList(config.getQualityModel().render(config)));
this.add(new ElementNewLine());
}
this.add(new ElementSubtitle((section++)+". Privacy models"));
if (transformation.getAnonymity() == Anonymity.ANONYMOUS) {
for (PrivacyCriterion c : config.getPrivacyModels()) {
this.add(asList(c.render()));
}
}
}
}
/**
* Renders the document into the given output stream
*
* @param file
* @throws IOException
*/
public void save(File file) throws IOException {
FileOutputStream stream = new FileOutputStream(file);
this.save(stream);
stream.close();
}
/**
* Renders the document into the given output stream
*
* @param stream
* @throws IOException
*/
public void save(OutputStream stream) throws IOException {
// Render
Document document = new Document(style.gethMargin(), style.gethMargin(), style.getvMargin(), style.getvMargin());
for (Element element : this.elements) {
element.render(document, 0, this.style);
}
// Save to temp file
File tmp = File.createTempFile("arx", "certificate");
document.save(tmp);
// Load and watermark
PDDocument pdDocument = PDDocument.load(tmp);
Watermark watermark = new Watermark(pdDocument);
watermark.mark(pdDocument);
// Save
pdDocument.save(stream);
pdDocument.close();
tmp.delete();
}
/**
* Renders as a list
* @param data
* @return
*/
private Element asList(ElementData data) {
ElementList list = new ElementList(ListStyle.BULLETS);
list.addItem(data.asList());
return list;
}
/**
* Renders as a list
* @param data
* @return
*/
private Element asList(List<ElementData> data) {
ElementList list = new ElementList(ListStyle.BULLETS);
for (ElementData d : data) {
list.addItem(d.asList());
}
return list;
}
/**
* Adds a new element
* @param element
*/
void add(Element element) {
this.elements.add(element);
}
/**
* Adds a new data element
* @param data
*/
void add(ElementData data) {
this.elements.add(data);
}
/**
* Adds a new list of data elements
* @param data
*/
void add(List<ElementData> data) {
this.elements.addAll(data);
}
}