Java tutorial
/** * Copyright 2014 Instituto Superior Tcnico * * This file is part of FenixEdu Identification Cards. * * FenixEdu Identification Cards is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * FenixEdu Identification Cards is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FenixEdu Identification Cards. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.idcards.domain; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.lang.StringUtils; import org.fenixedu.academic.domain.ExecutionYear; import org.fenixedu.academic.domain.Person; import org.fenixedu.academic.domain.exceptions.DomainException; import org.fenixedu.bennu.core.domain.Bennu; import org.fenixedu.idcards.IdCardsConfiguration; import org.joda.time.DateTime; public class SantanderBatch extends SantanderBatch_Base { private static String recordEnd = "*"; private static String lineEnd = "\r\n"; static final public Comparator<SantanderBatch> COMPARATOR_BY_MOST_RECENTLY_CREATED = new Comparator<SantanderBatch>() { @Override public int compare(SantanderBatch o1, SantanderBatch o2) { return o1.getCreated().isAfter(o2.getCreated()) ? 1 : 0; } }; private SantanderBatch() { super(); setRootDomainObject(Bennu.getInstance()); } public SantanderBatch(Person requester, ExecutionYear executionYear) { this(); setSantanderBatchRequester(new SantanderBatchRequester(requester)); setExecutionYear(executionYear); setCreated(new DateTime()); } public void delete() { if (getSent() != null) { throw new DomainException("santander.cards.cant.delete.batch.was.already.sent"); } getSantanderBatchRequester().delete(); if (getSantanderBatchSender() != null) { getSantanderBatchSender().delete(); } setSantanderSequenceNumberGenerator(null); for (SantanderEntry entry : getSantanderEntriesSet()) { entry.delete(); } for (SantanderProblem problem : getSantanderProblemsSet()) { problem.delete(); } setExecutionYear(null); setRootDomainObject(null); deleteDomainObject(); } public List<SantanderEntry> getSortedSantanderEntries() { List<SantanderEntry> sortedList = new ArrayList<SantanderEntry>(getSantanderEntriesSet()); Collections.sort(sortedList, SantanderEntry.COMPARATOR_BY_MOST_RECENTLY_CREATED); return sortedList; } public String generateTUI() throws Exception { if (getGenerated() == null) { throw new DomainException("santander.batch.cant.generate.TUI."); } StringBuilder fileBuilder = new StringBuilder(1500000); buildHeader(fileBuilder); for (SantanderEntry entryLine : getSortedSantanderEntries()) { String line = entryLine.getLine(); String visibleLine = line.substring(0, 307); //Update line with the persons Santander PIN if (entryLine.getPerson().getSantanderPIN() == null) { SantanderSequenceNumberGenerator.generateSantanderPIN(entryLine.getPerson()); } visibleLine += SantanderSequenceNumberGenerator .decodeSantanderPIN(entryLine.getPerson().getSantanderPIN()); // Update line with the institutions own PIN visibleLine += IdCardsConfiguration.getConfiguration().appInstitutionPIN(); visibleLine += line.substring(315); fileBuilder.append(visibleLine); } buildTrailer(fileBuilder); return fileBuilder.toString(); } private StringBuilder buildHeader(StringBuilder strBuilder) throws Exception { String recordType = "1"; String institutionId = makeZeroPaddedNumber(42, 5); String institutionName = makeStringBlock("TECNICO LISBOA", 14, ' '); String fileName = makeStringBlock("SANTUNIV", 15, ' '); DateTime dateObj = new DateTime(); String date = dateObj.toString("yyyyMMdd"); String sequenceNumber = makeZeroPaddedNumber((getSequenceNumber() != null ? getSequenceNumber() : 0), 5); String filler = makeStringBlock("", 1451, ' '); strBuilder.append(recordType); strBuilder.append(institutionId); strBuilder.append(institutionName); strBuilder.append(fileName); strBuilder.append(date); strBuilder.append(sequenceNumber); strBuilder.append(filler); strBuilder.append(recordEnd); strBuilder.append(lineEnd); return strBuilder; } private StringBuilder buildTrailer(StringBuilder stringBuilder) throws Exception { String recordType = "9"; String numberOfEntries = makeZeroPaddedNumber(getSantanderEntriesSet().size(), 5); String filler = makeStringBlock("", 1493, ' '); stringBuilder.append(recordType); stringBuilder.append(numberOfEntries); stringBuilder.append(filler); stringBuilder.append(recordEnd); stringBuilder.append(lineEnd); return stringBuilder; } private String makeStringBlock(String content, int size, char filler) throws Exception { int fillerLength = size - content.length(); if (fillerLength < 0) { throw new Exception("Content is bigger than string block."); } StringBuilder blockBuilder = new StringBuilder(size); blockBuilder.append(content); for (int i = 0; i < fillerLength; i++) { blockBuilder.append(filler); } return blockBuilder.toString(); } private String makeZeroPaddedNumber(int number, int size) throws Exception { if (String.valueOf(number).length() > size) { throw new Exception("Number has more digits than allocated room."); } String format = "%0" + size + "d"; return String.format(format, number); } private String makeRightShiftedPaddedNumber(int number, int size) { if (String.valueOf(number).length() > size) { number = number % (int) Math.pow(10, size); } String format = "%0" + size + "d"; return String.format(format, number); } private String getCardName(String name) { String purgedName = purgeString(name); String cleanedName = StringUtils.trimToEmpty(purgedName); String[] names = cleanedName.split(" "); return names[0] + " " + names[names.length - 1]; } private String purgeString(final String name) { if (!StringUtils.isAlphaSpace(name)) { final char[] ca = new char[name.length()]; int j = 0; for (int i = 0; i < name.length(); i++) { final char c = name.charAt(i); if (Character.isLetter(c) || c == ' ') { ca[j++] = c; } } return new String(ca); } return name; } public byte[] getPhotosAndDDXR() throws Exception { final ByteArrayOutputStream file = new ByteArrayOutputStream(); final ZipOutputStream zipFile = new ZipOutputStream(file); List<SantanderEntry> batch2k = new ArrayList<SantanderEntry>(); int entryCnt = 0; int batchCnt = 0; DateTime today = new DateTime(); for (SantanderEntry santanderEntry : getSortedSantanderEntries()) { if (santanderEntry.getSantanderPhotoEntry() != null) { batch2k.add(santanderEntry); if (++entryCnt % 2000 == 0) { batchCnt++; zipFile.putNextEntry(new ZipEntry( today.toString("yyyy-MM-dd") + "_E" + makeZeroPaddedNumber(batchCnt, 4) + ".xml")); zipFile.write(generateDDXR(batch2k, batchCnt, today)); zipFile.closeEntry(); zipFile.putNextEntry(new ZipEntry( today.toString("yyyy-MM-dd") + "_E" + makeZeroPaddedNumber(batchCnt, 4) + ".zip")); zipFile.write(generatePhotoZip(batch2k, batchCnt, today)); zipFile.closeEntry(); batch2k.clear(); } } } if (batch2k.size() > 0) { batchCnt++; zipFile.putNextEntry( new ZipEntry(today.toString("yyyy-MM-dd") + "_E" + makeZeroPaddedNumber(batchCnt, 4) + ".xml")); zipFile.write(generateDDXR(batch2k, batchCnt, today)); zipFile.closeEntry(); zipFile.putNextEntry( new ZipEntry(today.toString("yyyy-MM-dd") + "_E" + makeZeroPaddedNumber(batchCnt, 4) + ".zip")); zipFile.write(generatePhotoZip(batch2k, batchCnt, today)); zipFile.closeEntry(); batch2k.clear(); } zipFile.close(); return file.toByteArray(); } private byte[] generateDDXR(List<SantanderEntry> entries, int seqNumber, DateTime timestamp) throws Exception { StringBuilder ddxrBuilder = new StringBuilder(); ddxrBuilder.append( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<ns0:Root xmlns:ns0=\"http://SIBS.Balc.Schemas.DDXR\">\n"); ddxrBuilder.append("<HDR>\n"); ddxrBuilder.append("\t<FICH>" + "DDXR" + "</FICH>\n"); ddxrBuilder.append("\t<BANCO>" + "0018" + "</BANCO>\n"); ddxrBuilder.append("\t<NSEQFICH>" + "E" + makeZeroPaddedNumber(seqNumber, 4) + "</NSEQFICH>\n"); ddxrBuilder.append("\t<DTFICH>" + timestamp.toString("yyyy-MM-dd") + "T" + timestamp.toString("HH:mm:ss") + "</DTFICH>\n"); ddxrBuilder.append("\t<DATAPROC>" + timestamp.toString("yyyy-MM-dd") + "</DATAPROC>\n"); ddxrBuilder.append("\t<TIPOPRODUTO>" + "002" + "</TIPOPRODUTO>\n"); ddxrBuilder.append("\t<OPERATIVA>" + "01" + "</OPERATIVA>\n"); ddxrBuilder.append("\t<TOTLT>" + "1" + "</TOTLT>\n"); ddxrBuilder.append("\t<TOTDOC>" + entries.size() + "</TOTDOC>\n"); ddxrBuilder.append("\t<TOTDOCDET>" + entries.size() + "</TOTDOCDET>\n"); ddxrBuilder.append("</HDR>\n"); ddxrBuilder.append("<LT>\n"); ddxrBuilder.append("\t<LTHDR>\n"); ddxrBuilder.append("\t\t<NLOTE>" + "1" + "</NLOTE>\n"); ddxrBuilder.append("\t\t<BANCO>" + "0018" + "</BANCO>\n"); ddxrBuilder.append("\t\t<BALCAO>" + "0000" + "</BALCAO>\n"); ddxrBuilder.append("\t\t<DATAREM>" + timestamp.toString("yyyy-MM-dd") + "</DATAREM>\n"); ddxrBuilder.append("\t\t<SERIE>" + "0001" + "</SERIE>\n"); ddxrBuilder.append("\t\t<SUBSERIE>" + "0001" + "</SUBSERIE>\n"); ddxrBuilder.append("\t\t<TIPOREM>" + "001" + "</TIPOREM>\n"); ddxrBuilder.append("\t\t<TIPOANOMA>" + "000" + "</TIPOANOMA>\n"); ddxrBuilder.append("\t</LTHDR>\n"); ddxrBuilder.append("\t<LTBODY>\n"); for (SantanderEntry entry : entries) { ddxrBuilder.append("\t\t<DOC>\n"); ddxrBuilder.append("\t\t\t<DOCHDR>\n"); ddxrBuilder.append("\t\t\t\t<NUMDOC>" + timestamp.toString("yy") + "E0042" + makeRightShiftedPaddedNumber(entry.getSantanderPhotoEntry().getSequenceNumber(), 7) + "</NUMDOC>\n"); ddxrBuilder.append("\t\t\t\t<TIPOANOMA>" + "000" + "</TIPOANOMA>\n"); ddxrBuilder.append("\t\t\t\t<TIPODOC>" + "000" + "</TIPODOC>\n"); ddxrBuilder.append("\t\t\t\t<DTHCAPT>" + timestamp.toString("yyyy-MM-dd") + "T" + timestamp.toString("HH:mm:ss") + "</DTHCAPT>\n"); ddxrBuilder.append("\t\t\t\t<USRCAPT>" + "tecnico/fenix" + "</USRCAPT>\n"); ddxrBuilder.append("\t\t\t</DOCHDR>\n"); ddxrBuilder.append("\t\t\t<DOCDET>\n"); ddxrBuilder.append("\t\t\t\t<NUMDOC>" + timestamp.toString("yy") + "E0042" + makeRightShiftedPaddedNumber(entry.getSantanderPhotoEntry().getSequenceNumber(), 7) + "</NUMDOC>\n"); ddxrBuilder.append("\t\t\t\t<NUMDOCFOTO>" + "018042" + makeStringBlock(entry.getPerson().getUsername(), 10, 'x') + "</NUMDOCFOTO>\n"); ddxrBuilder.append("\t\t\t\t<TIPODOC>" + "000" + "</TIPODOC>\n"); ddxrBuilder.append("\t\t\t\t<NUMPAG>" + "2" + "</NUMPAG>\n"); ddxrBuilder.append("\t\t\t\t<DADOSADIC>" + "00042E" + makeRightShiftedPaddedNumber(entry.getSantanderPhotoEntry().getSequenceNumber(), 6) + "3" + makeStringBlock(entry.getPerson().getUsername(), 10, 'x') + "x" + makeStringBlock(getCardName(entry.getPerson().getName()).length() > 21 ? getCardName(entry.getPerson().getName()).substring(0, 21) : getCardName(entry.getPerson().getName()), 21, ' ').toUpperCase() + "0" + makeZeroPaddedNumber(0, 21) + makeZeroPaddedNumber(0, 10) + "1" + "</DADOSADIC>\n"); ddxrBuilder.append("\t\t\t</DOCDET>\n"); ddxrBuilder.append("\t\t</DOC>\n"); } ddxrBuilder.append("\t</LTBODY>\n"); ddxrBuilder.append("</LT>\n"); ddxrBuilder.append("</ns0:Root>\n"); return ddxrBuilder.toString().getBytes("UTF-8"); } private byte[] generatePhotoZip(List<SantanderEntry> entries, int seqNumber, DateTime timestamp) throws IOException { final ByteArrayOutputStream file = new ByteArrayOutputStream(); final ZipOutputStream zipFile = new ZipOutputStream(file); for (SantanderEntry entry : entries) { zipFile.putNextEntry(new ZipEntry(timestamp.toString("yy") + "E0042" + makeRightShiftedPaddedNumber(entry.getSantanderPhotoEntry().getSequenceNumber(), 7) + ".jpg")); zipFile.write(entry.getSantanderPhotoEntry().getPhotoAsByteArray()); zipFile.closeEntry(); } zipFile.close(); return file.toByteArray(); } }