What is the best way to compare tar archives in junit testing - java

I am attempting to create jUnit tests for some code that generates tar files. During testing I will be creating a variety of tar files and comparing them to "Gold" tar images of the expected output. I have been struggling to create an assertTarEquals(String file1, String file2) function, and was hoping someone could provide guidance as to the best approach. It's not important to have the tar file entries in the same order, or with the same attributes. I just need to verify that they have all the same files and that those files contain the same content. I have created a assertZipEquals(String file1, String file2) based on the example provided here: http://www.java2s.com/Tutorial/Java/0180__File/Comparetwozipfiles.htm but the ZipFile.getInputSteam(EntryName) does not appear to have a parallel function in the Commons Tar classes, as they have not implemented markers in the TarInputStream.

I would typically agree that unit testing is no place for testing Archives, but the code that is being tested manages the creation of archives, so in my mind it is not only appropriate but necessary. The code below is pretty ugly, and I would never want to use something like this in production code, but for testing I guess it's ok.... here's the code I'm using for assertArchiveEquals, it supports both tar and zip files.... as always all feedback is welcome.
package com.foo.util.merge;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.io.IOUtils;
import static org.junit.Assert.*;
public final class CompareArchives {
public static final void assertArchiveEquals(String type, String archive1, String archive2) throws NoSuchAlgorithmException, IOException {
if (type.endsWith("zip")) {
assertZipEquals(archive1, archive2);
} else {
assertTarEquals(archive1, archive2);
}
}
/**
* #param archive1
* #param archive2
* #throws ZipException
* #throws IOException
*/
public static final void assertZipEquals(String archive1, String archive2) throws ZipException, IOException {
// Get Archives
ZipFile zipFile1 = new ZipFile(new File(archive1));
ZipFile zipFile2 = new ZipFile(new File(archive2));
// Get Member Hash
HashMap<String, ZipEntry> files1 = getMembers(zipFile1);
HashMap<String, ZipEntry> files2 = getMembers(zipFile2);
// Compare Files
assertMembersEqual(zipFile1, files1, zipFile2, files2);
}
/**
* #param archive
* #return
* #throws IOException
*/
private static final HashMap<String, ZipEntry> getMembers(ZipFile archive) throws IOException {
HashMap<String, ZipEntry> map = new HashMap<String, ZipEntry>();
#SuppressWarnings("unchecked")
Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) archive.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
map.put(entry.getName(), entry);
}
return map;
}
/**
* #param zip1
* #param files1
* #param zip2
* #param files2
* #throws IOException
*/
private static final void assertMembersEqual(ZipFile zip1, HashMap<String, ZipEntry> files1,
ZipFile zip2, HashMap<String, ZipEntry> files2) throws IOException {
if (files1.size() != files2.size()) {
fail("Different Sizes, expected " + Integer.toString(files1.size()) + " found " + Integer.toString(files2.size()));
}
for (String key : files1.keySet()) {
if (!files2.containsKey(key)) {
fail("Expected file not in target " + key);
}
String file1 = IOUtils.toString(zip1.getInputStream(files1.get(key)));
String file2 = IOUtils.toString(zip2.getInputStream(files2.get(key)));
assertEquals(file1, file2);
}
}
/**
* #param archive1
* #param archive2
* #throws IOException
* #throws NoSuchAlgorithmException
*/
public static final void assertTarEquals(String archive1, String archive2) throws IOException, NoSuchAlgorithmException {
// Get Member Hash
HashMap<String, TarArchiveEntry> files1 = getMembers(archive1);
HashMap<String, TarArchiveEntry> files2 = getMembers(archive2);
// Compare Files
assertMembersEqual(archive1, files1, archive2, files2);
}
/**
* #param archive
* #return
* #throws IOException
*/
private static final HashMap<String,TarArchiveEntry> getMembers(String archive) throws IOException {
TarArchiveInputStream input = new TarArchiveInputStream(
new BufferedInputStream(
new FileInputStream(archive)));
TarArchiveEntry entry;
HashMap<String, TarArchiveEntry> map = new HashMap<String, TarArchiveEntry>();
while ((entry = input.getNextTarEntry()) != null) {
map.put(entry.getName(), entry);
}
input.close();
return map;
}
/**
* #param tar1
* #param files1
* #param tar2
* #param files2
* #throws IOException
*/
private static final void assertMembersEqual(String tar1, HashMap<String, TarArchiveEntry> files1,
String tar2, HashMap<String, TarArchiveEntry> files2) throws IOException {
if (files1.size() != files2.size()) {
fail("Different Sizes, expected " + Integer.toString(files1.size()) + " found " + Integer.toString(files2.size()));
}
for (String key : files1.keySet()) {
if (!files2.containsKey(key)) {
fail("Expected file not in target " + key);
}
}
for (String key : files1.keySet()) {
if (!files2.containsKey(key)) {
fail("Expected file not in target " + key);
}
}
for (String key : files1.keySet()) {
String file1 = getTarFile(tar1, key);
String file2 = getTarFile(tar2, key);
assertEquals(file1, file2);
}
}
/**
* #param archive
* #param name
* #return
* #throws IOException
*/
private static final String getTarFile(String archive, String name) throws IOException {
TarArchiveInputStream input = new TarArchiveInputStream(
new BufferedInputStream(
new FileInputStream(archive)));
TarArchiveEntry entry;
while ((entry = input.getNextTarEntry()) != null) {
if (entry.getName().equals(name)) {
byte[] content = new byte[(int) entry.getSize()];
input.read(content, 0, content.length);
input.close();
return new String(content);
}
}
input.close();
return "";
}
}

Related

TestNG Unit Testing Tar and 7z

folder structure is here
console output is here
I'd like to write a test class for the 2 methods below
package jfe;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
public class JThreadFile {
/**
* uncompresses .tar file
* #param in
* #param out
* #throws IOException
*/
public static void decompressTar(String in, File out) throws IOException {
try (TarArchiveInputStream tin = new TarArchiveInputStream(new FileInputStream(in))){
TarArchiveEntry entry;
while ((entry = tin.getNextTarEntry()) != null) {
if (entry.isDirectory()) {
continue;
}
File curfile = new File(out, entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
IOUtils.copy(tin, new FileOutputStream(curfile));
}
}
}
/**
* uncompresses .7z file
* #param in
* #param destination
* #throws IOException
*/
public static void decompressSevenz(String in, File destination) throws IOException {
//#SuppressWarnings("resource")
SevenZFile sevenZFile = new SevenZFile(new File(in));
SevenZArchiveEntry entry;
while ((entry = sevenZFile.getNextEntry()) != null){
if (entry.isDirectory()){
continue;
}
File curfile = new File(destination, entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
FileOutputStream out = new FileOutputStream(curfile);
byte[] content = new byte[(int) entry.getSize()];
sevenZFile.read(content, 0, content.length);
out.write(content);
out.close();
}
sevenZFile.close();
}
}
I use testNG and try to read from a folder, filter the folder for certain extensions (.tar and .7z) feed those files to the uncompress methods and compare the result to the actualOutput folder with AssertEquals. I manage to read the file names from the folder (see console output) but can't feed them to decompressTar(String in, File out). Is this because "result" is a String array and I need a String? I have no clue how DataProvider of TestNG handles data. Any help would be appreciated :) Thank you :)
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class JThreadFileTest {
protected static final File ACT_INPUT = new File("c:\\Test\\TestInput\\"); //input directory
protected static final File EXP_OUTPUT = new File("c:\\Test\\ExpectedOutput\\"); //expected output directory
protected static final File TEST_OUTPUT = new File("c:\\Test\\TestOutput\\");
#DataProvider(name = "tarJobs")
public Object[] getTarJobs() {
//1
String[] tarFiles = ACT_INPUT.list(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
return name.endsWith(".tar");
}
});
//2
Object[] result = new Object[tarFiles.length];
int i = 0;
for (String filename : tarFiles) {
result[i] = filename;
i++;
}
return result;
}
#Test(dataProvider = "tarJobs")
public void testTar(String result) throws IOException {
System.out.println("Running test" + result);
--> JThreadFile.decompressTar(result, TEST_OUTPUT);
Assert.assertEquals(TEST_OUTPUT, EXP_OUTPUT);
}
}

freemarker include + base64

I am looking for a freemarker feature like:
<#include "big_file.json" parse="true" encode="base64">
to include a file
parse the content of this file
encode the result as base64
I know this is not possible out of the box.
Is there a way to extend freemarker?
The solution is to use the: freemarker directives
To solve this example:
"grafana_dashboards": {
<#list_dir folder="./grafana_dashboards/" suffix="json"; dashboard_file, dashboard_name, dashboard_file_has_next>
${dashboard_name}": "<#encode enc="base64"><#include dashboard_file></#encode>"<#if (dashboard_file_has_next)>,</#if>
</#list_dir>
}
I add this both vars:
cfg = new Configuration(Configuration.VERSION_2_3_29);
...
final Map<String, Object> vars = new HashMap<>();
vars.put("list_dir", new xxx.freemarker.directives.ListDirDirective());
vars.put("encode", new xxx.freemarker.directives.EncodeDirective());
final Template temp = cfg.getTemplate(file.getName());
try ( //
final ByteArrayOutputStream bao = new ByteArrayOutputStream(); //
final Writer out = new OutputStreamWriter(bao); //
) {
temp.process(vars, out);
return bao.toString();
}
Here are the Directives:
EncodeDirective
package xxx.freemarker.directives;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
/**
* FreeMarker user-defined directive that progressively transforms the output of
* its nested content to given encoding.
*
*
* <p>
* <b>Directive info</b>
* </p>
*
* Parameters:
* <ul>
* <li><code>enc</code>: The name of the encoding to use. Possible options:
* "base64". Required.
* </ul>
* <p>
* Loop variables: None
* <p>
* Directive nested content: Yes
*/
public class EncodeDirective implements TemplateDirectiveModel {
private static final String PARAM_NAME_ENC = "enc";
private static final Map<String, Function<String, String>> encoder = new HashMap<>();
static {
encoder.put("base64", EncodeDirective::encodeBase64);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public void execute(final Environment env, final Map rawParams, final TemplateModel[] loopVars, final TemplateDirectiveBody body)
throws TemplateException, IOException {
final Params params = parseAndValidateParams(rawParams, loopVars);
// If there is non-empty nested content:
if (body != null) {
// Executes the nested body. Same as <#nested> in FTL, except
// that we use our own writer instead of the current output writer.
final EncodeFilterWriter writer = new EncodeFilterWriter(env.getOut(), params.getEncoderFunction());
body.render(writer);
writer.flush();
} else {
throw new RuntimeException("missing body");
}
}
/**
* A {#link Writer} that transforms the character stream to upper case and
* forwards it to another {#link Writer}.
*/
private static class EncodeFilterWriter extends Writer {
private StringBuffer buffer = new StringBuffer();
private final Writer out;
private final Function<String, String> encoder;
EncodeFilterWriter(final Writer out, final Function<String, String> encoder) {
this.out = out;
this.encoder = encoder;
}
public void write(final char[] cbuf, final int off, final int len) throws IOException {
buffer.append(cbuf, off, len);
}
public void flush() throws IOException {
out.write(encoder.apply(buffer.toString()));
out.flush();
}
public void close() throws IOException {
out.close();
}
}
private Params parseAndValidateParams(final Map<String, TemplateModel> params, final TemplateModel[] loopVars)
throws TemplateModelException {
boolean encParamSet = false;
final Params p = new Params();
final Iterator<Entry<String, TemplateModel>> paramIter = params.entrySet().iterator();
while (paramIter.hasNext()) {
final Entry<String, TemplateModel> ent = paramIter.next();
final String paramName = ent.getKey();
final TemplateModel paramValue = ent.getValue();
if (paramName.equals(PARAM_NAME_ENC)) {
if (!(paramValue instanceof TemplateScalarModel)) {
throw new TemplateModelException("The \"" + PARAM_NAME_ENC + "\" parameter must be a string.");
}
p.setEnc(((TemplateScalarModel) paramValue).getAsString());
encParamSet = true;
} else {
throw new TemplateModelException("Unsupported parameter: " + paramName);
}
}
if (!encParamSet) {
throw new TemplateModelException("The required \"" + PARAM_NAME_ENC + "\" paramter is missing.");
}
if (loopVars.length != 0) {
throw new TemplateModelException("This directive doesn't allow loop variables.");
}
return p;
}
#Data
private class Params {
private String enc;
public void setEnv(final String enc) {
this.enc = enc;
}
public String getEnv() {
return this.enc;
}
public Function<String, String> getEncoderFunction() throws TemplateModelException {
final Function<String, String> encoderFunc = encoder.get(enc.toLowerCase());
if (encoderFunc == null) {
throw new TemplateModelException("The required \"" + PARAM_NAME_ENC + "\" paramter, must be one of: " + encoder.keySet());
}
return encoderFunc;
}
}
private static String encodeBase64(final String in) {
try {
return Base64.getEncoder().encodeToString( //
in.getBytes("UTF-8"));
} catch (final UnsupportedEncodingException e) {
throw new IllegalArgumentException("The required \"" + PARAM_NAME_ENC + "\" paramter, encode error:: " + e.getMessage(), e);
}
}
}
ListDirDirective
package xxx.freemarker.directives;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import freemarker.cache.TemplateLoader;
import freemarker.core.Environment;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
/**
* FreeMarker user-defined directive for repeating a section of a template, that
* scan a folder on file system and loop through matching files.
*
*
* <p>
* <b>Directive info</b>
* </p>
*
* <p>
* Parameters:
* <ul>
* <li><code>folder</code>: The relative path of the folder on file system.
* Required.
* <li><code>suffix</code>: File ending too scan for. Required.
* </ul>
*
* Loop variables:
* <ul>
* <li><code>file_path</code>: String: The relative file path, used by
* "<#include" or "<#import". Required.</li>
* <li><code>file_name</code>: String: The file name without suffix.
* Optional.</li>
* <li><code>has_next</code>: Boolean: Indicator if it is last file or not.
* Optional.</li>
* </ul>
* <p>
* Nested content: Yes
*/
public class ListDirDirective implements TemplateDirectiveModel {
private static final String PARAM_NAME_FOLDER = "folder";
private static final String PARAM_NAME_SUFFIX = "suffix";
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public void execute(final Environment env, final Map rawParams, final TemplateModel[] loopVars,
final TemplateDirectiveBody body) throws TemplateException, IOException {
final Path basePath = getCurrentTemplate(env).getParentFile().toPath();
final Params params = parseAndValidateParams(rawParams, loopVars);
final List<String> files = findFiles("**/*." + params.getSuffix(), basePath, params.getFolder());
if (files.isEmpty()) {
throw new IllegalArgumentException(
"No files found with suffix: " + params.getSuffix() + " using base path: " + params.getFolder());
}
if (body != null) {
final Iterator<String> filesIt = files.iterator();
while (filesIt.hasNext()) {
final String filePath = filesIt.next();
loopVars[0] = new SimpleScalar(filePath);
// Set file name without extension/suffix
if (loopVars.length > 1) {
loopVars[1] = new SimpleScalar(getFilennameWithoutSuffix(filePath, params.getSuffix()));
}
// Set has_next variable if set
if (loopVars.length > 2) {
loopVars[2] = filesIt.hasNext() ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
// Executes the nested body (same as <#nested> in FTL). In this
// case we don't provide a special writer as the parameter:
body.render(env.getOut());
}
}
}
private File getCurrentTemplate(final Environment env) throws IOException {
final TemplateLoader templateLoader = env.getConfiguration().getTemplateLoader();
final Object tmp = templateLoader.findTemplateSource(env.getCurrentTemplate().getSourceName());
if (!(tmp instanceof File)) {
throw new IllegalArgumentException("The ListDirDirective is only compatible with FileTemplateLoader");
}
return (File) tmp;
}
private static String getFilennameWithoutSuffix(final String filePath, final String suffix) {
final File file = new File(filePath);
return file.getName() //
.replace("\\.?" + Pattern.quote(suffix) + "$", "");
}
private static List<String> findFiles(final String pattern, final Path basePath, final String pathName)
throws IOException {
final Path path = basePath.resolve(pathName).toAbsolutePath();
final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
try (final Stream<Path> paths = Files.find(path, 10,
(currentPath, fileAttributes) -> pathMatcher.matches(currentPath))) {
return paths //
.map(basePath::relativize) //
.map(Path::toString) //
.collect(Collectors.toList());
}
}
private Params parseAndValidateParams(final Map<String, TemplateModel> params, final TemplateModel[] loopVars)
throws TemplateModelException {
boolean folderParamSet = false;
boolean suffixParamSet = false;
final Params p = new Params();
final Iterator<Entry<String, TemplateModel>> paramIter = params.entrySet().iterator();
while (paramIter.hasNext()) {
final Entry<String, TemplateModel> ent = paramIter.next();
final String paramName = ent.getKey();
final TemplateModel paramValue = ent.getValue();
if (paramName.equals(PARAM_NAME_FOLDER)) {
if (!(paramValue instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"The \"" + PARAM_NAME_FOLDER + "\" parameter must be a string.");
}
p.setFolder(((TemplateScalarModel) paramValue).getAsString());
folderParamSet = true;
} else if (paramName.equals(PARAM_NAME_SUFFIX)) {
if (!(paramValue instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"The \"" + PARAM_NAME_SUFFIX + "\" parameter must be a string.");
}
final String suffix = ((TemplateScalarModel) paramValue).getAsString();
if (!suffix.matches("[a-zA-Z0-9]{1,10}")) {
throw new TemplateModelException("The \"" + PARAM_NAME_SUFFIX + "\" parameter "
+ "must only contain letter and number and needs to be between 1-10 chars.");
}
p.setSuffix(suffix);
suffixParamSet = true;
} else {
throw new TemplateModelException("Unsupported parameter: " + paramName);
}
}
if (!folderParamSet) {
throw new TemplateModelException("The required \"" + PARAM_NAME_FOLDER + "\" paramter is missing.");
}
if (!suffixParamSet) {
throw new TemplateModelException("The required \"" + PARAM_NAME_SUFFIX + "\" paramter is missing.");
}
if (loopVars.length < 1) {
throw new TemplateModelException("At least 1 loop vars is required: file_name, [name], [has_next]");
}
if (loopVars.length > 3) {
throw new TemplateModelException("Max 3 loop vars are allowed: file_name, [name], [has_next]");
}
return p;
}
#Data
private class Params {
private String folder;
private String suffix;
public void setFolder(final String folder) {
this.folder = folder;
}
public String getFolder() {
return this.folder;
}
public void setSuffix(final String suffix) {
this.suffix = suffix;
}
public String getSuffix() {
return this.suffix;
}
}
}

unzipping files in /data/data/ folder - Android Java Programming

How would I programmatically unzip backed up data directly into a /data/data/com.appname folder from the SD Card?
I am able to directly unzip folders in the /data/data/com.appname folder using ES File Explorer, however I need to automate this via the app I'm developing.
I've tried the following code, Unfortunately I am only able to unzip to the SD Card and data folder of my app.
I'm guessing this is due to some form of app/folder security?
MainActivity.java
package fb.ziptester;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void buttonOnClick(View v) {
TextView zipSource = (TextView)findViewById(R.id.zip_source);
TextView zipDest = (TextView)findViewById(R.id.zip_dest);
String sZipSource = "/storage/sdcard1/ACC/BU.zip";
String sZipDest = "/data/data/com.appname/";
zipSource.setText(sZipSource);
zipDest.setText(sZipDest);
UnzipUtility zipUtil = new UnzipUtility();
try {
zipUtil.unzip(sZipSource, sZipDest);
} catch(Exception ex) {
//TODO
}
}
}
package fb.ziptester;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
UnzipUtility.java
public class UnzipUtility {
/**
* Size of the buffer to read/write data
*/
private static final int BUFFER_SIZE = 4096;
/**
* Extracts a zip file specified by the zipFilePath to a directory specified by
* destDirectory (will be created if does not exists)
* #param zipFilePath
* #param destDirectory
* #throws IOException
*/
public void unzip(String zipFilePath, String destDirectory) throws IOException {
File destDir = new File(destDirectory);
if (!destDir.exists()) {
destDir.mkdir();
}
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry entry = zipIn.getNextEntry();
// iterates over entries in the zip file
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
if (!entry.isDirectory()) {
// if the entry is a file, extracts it
extractFile(zipIn, filePath);
} else {
// if the entry is a directory, make the directory
File dir = new File(filePath);
dir.mkdir();
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
zipIn.close();
}
/**
* Extracts a zip entry (file entry)
* #param zipIn
* #param filePath
* #throws IOException
*/
private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
byte[] bytesIn = new byte[BUFFER_SIZE];
int read = 0;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
bos.close();
}
}
Any help would be much appreciated.
Thank you.

How to retrieve field values by passing field name using JPOS ISO8583 message format

I want to retrieve field values by passing filed name .in order to achieve that i have implemented a method which loop through the ISOMsg object and then if it found a match to the passed filed name then it returns .my requirement is to read the .xml file once and have a static map using that then on the next time retrieve corresponding value by passing field name in order to achieve this is there a way to retrieve all field in config xml.
protected static void getISO8583ValueByFieldName(ISOMsg isoMsg, String fieldName) {
for (int i = 1; i <= isoMsg.getMaxField(); i++) {
if (isoMsg.hasField(i)) {
if (isoMsg.getPackager().getFieldDescription(isoMsg, i).equalsIgnoreCase(fieldName)) {
System.out.println(
" FOUND FIELD -" + i + " : " + isoMsg.getString(i) + " " + isoMsg.getPackager()
.getFieldDescription(isoMsg, i));
break;
}
}
}
}
You can also define an enum with the field names, mapped to field numbers.
Please note the field names may vary from packager to packager, so your solution is kind of brittle, it's better to use an enum, or just constants.
Solution is to implement a own custom mapper.here is an memory implementation singleton class which reads all the configurations one time and then provide key id by name.
/**
* This is an memory implementation of singleton mapper class which contains ISO8583
* field mappings as Key Value pairs [Field Name,Field Value]
* in order
*
* Created on 12/16/2014.
*/
public class ISO8583MapperFactory {
private static Logger logger= Logger.getLogger(ISO8583MapperFactory.class);
private static ISO8583MapperFactory instance = null;
private static HashMap<String,Integer> fieldMapper=null;
/**
*
* #throws IOException
* #throws SAXException
* #throws ParserConfigurationException
*/
private ISO8583MapperFactory() throws IOException, SAXException, ParserConfigurationException {
fieldMapper =new HashMap<String, Integer>();
mapFields();
}
/**
*
* #throws ParserConfigurationException
* #throws IOException
* #throws SAXException
*/
private void mapFields() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
dBuilder.setEntityResolver(new GenericPackager.GenericEntityResolver());
//InputStream in = new FileInputStream(ISO8583Constant.ISO8583_CONFIG_FILE_NAME);
InputStream in = getClass().getClassLoader().getResourceAsStream(ISO8583Constant.ISO8583_CONFIG_FILE_NAME);
Document doc = dBuilder.parse(in);
logger.info("Root element :" + doc.getDocumentElement().getNodeName());
if (doc.hasChildNodes()) {
loadNodes(doc.getChildNodes(), fieldMapper);
}
}
/**
*
* #return
* #throws ParserConfigurationException
* #throws SAXException
* #throws IOException
*/
public static ISO8583MapperFactory getInstance()
throws ParserConfigurationException, SAXException, IOException {
if(instance==null){
instance=new ISO8583MapperFactory();
}
return instance;
}
/**
*
* #param fieldName
* #return
*/
public Integer getFieldidByName(String fieldName){
return fieldMapper.get(fieldName);
}
/**
* Recursive method to read all the id and field name mappings
* #param nodeList
* #param fieldMapper
*/
protected void loadNodes(NodeList nodeList,HashMap<String,Integer> fieldMapper) {
logger.info(" Invoked loadNodes(NodeList nodeList,HashMap<String,Integer> fieldMapper)");
for (int count = 0; count < nodeList.getLength(); count++) {
Node tempNode = nodeList.item(count);
// make sure it's element node.
if (tempNode.getNodeType() == Node.ELEMENT_NODE) {
// get node name and value
logger.info("\nNode Name =" + tempNode.getNodeName() + " [OPEN]");
logger.info("Node Value =" + tempNode.getTextContent());
if (tempNode.hasAttributes()) {
// get attributes names and values
NamedNodeMap nodeMap = tempNode.getAttributes();
fieldMapper.put(nodeMap.getNamedItem(ISO8583Constant.FIELD_NAME).getNodeValue(),Integer.valueOf( nodeMap.getNamedItem(ISO8583Constant.FIELD_ID).getNodeValue()));
}
if (tempNode.hasChildNodes()) {
// loop again if has child nodes
loadNodes(tempNode.getChildNodes(), fieldMapper);
}
logger.info("Node Name =" + tempNode.getNodeName() + " [CLOSE]");
}
}
}
/**
*
* #return
*/
public static HashMap<String, Integer> getFieldMapper() {
return fieldMapper;
}
/**
*
* #param fieldMapper
*/
public static void setFieldMapper(HashMap<String, Integer> fieldMapper) {
ISO8583MapperFactory.fieldMapper = fieldMapper;
}
}
Example
public static void main(String[] args) throws IOException, ISOException, InterruptedException {
try {
ISO8583MapperFactory.getInstance().getFieldidByName("NAME");
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
An enhancement to Seth's very helpful answer from above, to getFieldNameById instead of getFieldidByName:
// package ...
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jpos.iso.packager.GenericPackager;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.imohsenb.ISO8583.exceptions.ISOException;
import lombok.extern.slf4j.Slf4j;
#Slf4j
public class ISO8583MapperFactory {
private static ISO8583MapperFactory instance = null;
private static HashMap<Integer, String> fieldMapper = null;
/**
*
* #throws IOException
* #throws SAXException
* #throws ParserConfigurationException
*/
private ISO8583MapperFactory() throws IOException, SAXException, ParserConfigurationException {
fieldMapper = new HashMap<Integer, String>();
mapFields();
}
/**
*
* #throws ParserConfigurationException
* #throws IOException
* #throws SAXException
*/
private void mapFields() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
dBuilder.setEntityResolver(new GenericPackager.GenericEntityResolver());
// InputStream in = new
// FileInputStream(ISO8583Constant.ISO8583_CONFIG_FILE_NAME);
InputStream in = getClass().getClassLoader().getResourceAsStream(ISO8583Constant.ISO8583_CONFIG_FILE_NAME);
Document doc = dBuilder.parse(in);
// log.info("Root element :" + doc.getDocumentElement().getNodeName());
if (doc.hasChildNodes()) {
loadNodes(doc.getChildNodes(), fieldMapper);
}
}
/**
*
* #return
* #throws ParserConfigurationException
* #throws SAXException
* #throws IOException
*/
public static ISO8583MapperFactory getInstance()
throws ParserConfigurationException, SAXException, IOException {
if (instance == null) {
instance = new ISO8583MapperFactory();
}
return instance;
}
/**
*
* #param fieldName
* #return
*/
public String getFieldNameById(int fieldId) {
return fieldMapper.get(Integer.valueOf(fieldId));
}
/**
* Recursive method to read all the id and field name mappings
*
* #param nodeList
* #param fieldMapper
*/
protected void loadNodes(NodeList nodeList, HashMap<Integer, String> fieldMapper) {
// log.info(" Invoked loadNodes(NodeList nodeList,HashMap<String,Integer>
// fieldMapper)");
for (int count = 0; count < nodeList.getLength(); count++) {
Node tempNode = nodeList.item(count);
// make sure it's element node.
if (tempNode.getNodeType() == Node.ELEMENT_NODE) {
// get node name and value
// log.info("\nNode Name =" + tempNode.getNodeName() + " [OPEN]");
// log.info("Node Value =" + tempNode.getTextContent());
if (tempNode.hasAttributes()) {
// get attributes names and values
NamedNodeMap nodeMap = tempNode.getAttributes();
// fieldMapper.put(nodeMap.getNamedItem(ISO8583Constant.FIELD_NAME).getNodeValue(),
// Integer.valueOf(nodeMap.getNamedItem(ISO8583Constant.FIELD_ID).getNodeValue()));
fieldMapper.put(Integer.valueOf(nodeMap.getNamedItem(ISO8583Constant.FIELD_ID).getNodeValue()),
nodeMap.getNamedItem(ISO8583Constant.FIELD_NAME).getNodeValue());
}
if (tempNode.hasChildNodes()) {
// loop again if has child nodes
loadNodes(tempNode.getChildNodes(), fieldMapper);
}
// log.info("Node Name =" + tempNode.getNodeName() + " [CLOSE]");
}
}
}
/**
*
* #return
*/
public static HashMap<Integer, String> getFieldMapper() {
return fieldMapper;
}
/**
*
* #param fieldMapper
*/
public static void setFieldMapper(HashMap<Integer, String> fieldMapper) {
ISO8583MapperFactory.fieldMapper = fieldMapper;
}
public static void main(String[] args) throws IOException, ISOException, InterruptedException {
try {
String a = ISO8583MapperFactory.getInstance().getFieldNameById(2);
System.out.println(a);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
}
enum ISO8583Constant {
;
static String ISO8583_CONFIG_FILE_NAME = "iso8583map.xml";
static String FIELD_NAME = "name";
static String FIELD_ID = "id";
}

Adding attachment to pdf file with a link to it

How can i attach a file to existing pdf including a link to the attachment on the main page?
I am using Itext and so far managed to attach on the document level only.
Use the below code to create an attachments,
please go throw the code as I have spent only few minutes, understand
it and remove the unnecessary codes.
There is a RESOURCE variable which points all the
pdf's or files you want to attach.
here in this case, it is public static final String RESOURCE = "chapter16/%s.pdf";
Where the chapter16 folder has the pdf's you want to attached
and %s will be replaced with the name of the file that you provide and
the file format is .pdf(if you are attaching a pdf file)
It works and tested in my system. I refered this code from here
// I create the list which has the list of files names i want to attach
ArrayList<String> strList = new ArrayList<String>();
strList.add("Strings"); // its the same file I'm attaching four times
strList.add("Strings"); // where "Strings" is the name of the file
strList.add("Strings");
strList.add("Strings");
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfAnnotation;
import com.itextpdf.text.pdf.PdfArray;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
/**
* Creates a PDF listing of attachments
* The attachments can be extracted.
*/
public class AttachFiles {
/** Path to the resources. */
public static final String RESOURCE = "chapter16/%s.pdf";
/** The filename of the resulting PDF. */
public static final String FILENAME = "ResultingFile.pdf";
/** The path to the resulting PDFs */
public static final String PATH = "chapter16/%s";
/** The filename of the PDF */
public static final String RESULT = String.format(PATH, FILENAME);
/**
* Creates a PDF listing
* #throws IOException
* #throws DocumentException
* #throws SQLException
*/
public static void main(String[] args) throws IOException, DocumentException, SQLException {
AttachFiles attachFiles = new AttachFiles();
FileOutputStream os = new FileOutputStream(RESULT);
os.write(attachFiles.createPdf());
os.flush();
os.close();
attachFiles.extractAttachments(RESULT);
}
/**
* Extracts attachments from an existing PDF.
* #param src the path to the existing PDF
* #param dest where to put the extracted attachments
* #throws IOException
*/
public void extractAttachments(String src) throws IOException {
PdfReader reader = new PdfReader(src);
PdfArray array;
PdfDictionary annot;
PdfDictionary fs;
PdfDictionary refs;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
array = reader.getPageN(i).getAsArray(PdfName.ANNOTS);
if (array == null) continue;
for (int j = 0; j < array.size(); j++) {
annot = array.getAsDict(j);
if (PdfName.FILEATTACHMENT.equals(annot.getAsName(PdfName.SUBTYPE))) {
fs = annot.getAsDict(PdfName.FS);
refs = fs.getAsDict(PdfName.EF);
for (PdfName name : refs.getKeys()) {
FileOutputStream fos
= new FileOutputStream(String.format(PATH, fs.getAsString(name).toString()));
fos.write(PdfReader.getStreamBytes((PRStream)refs.getAsStream(name)));
fos.flush();
fos.close();
}
}
}
}
}
/**
* Creates the PDF.
* #return the bytes of a PDF file.
* #throws DocumentExcetpion
* #throws IOException
* #throws SQLException
*/
public byte[] createPdf() throws DocumentException, IOException, SQLException {
// step 1
Document document = new Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, baos);
// step 3
document.open();
// step 4
document.add(new Paragraph("This is a list pdf attachments."));
PdfAnnotation annot;
ListItem item;
Chunk chunk;
List list = new List();
// I create the list which has the list of files names i want to attach
ArrayList<String> strList = new ArrayList<String>();
strList.add("Strings"); // its the same file I'm attaching four times
strList.add("Strings");
strList.add("Strings");
strList.add("Strings");
for (String strWord : strList) {
annot = PdfAnnotation.createFileAttachment(
writer, null, "Name", null,
String.format(RESOURCE, strWord), String.format("%s.pdf", strWord));
item = new ListItem("Name");
item.add("\u00a0\u00a0");
chunk = new Chunk("\u00a0\u00a0\u00a0\u00a0");
chunk.setAnnotation(annot);
item.add(chunk);
list.add(item);
}
document.add(list);
// step 5
document.close();
return baos.toByteArray();
}
}

Categories

Resources