Základní implementace podepisování PDF dokumentů. Podpis implementován pouze pro sestavu schválení služební cesty (natvrdo v kódu). Spouští se univerzální podepisovací aplikace, která čte certifikát ze souboru.

closes #224
Verze_3.0
Josef Rokos 10 years ago
parent 312b62af7b
commit d6cff454fd

@ -0,0 +1,79 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 16464111046498525641 (0xe47c45c4252121c9)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=CZ, ST=Vysocina, O=bukova.info, CN=Josef Rokos/emailAddress=rokos@bukova.info
Validity
Not Before: Jun 24 09:59:50 2015 GMT
Not After : Jun 21 09:59:50 2025 GMT
Subject: C=CZ, ST=Vysocina, O=bukova.info, CN=Josef Rokos/emailAddress=rokos@bukova.info
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bc:fb:64:50:5b:58:03:8c:20:1c:77:d3:50:31:
94:55:78:d6:05:bb:bc:88:9d:cb:20:b1:8c:ff:ac:
fc:97:1a:b1:9c:29:c4:ac:af:ed:3b:de:93:d5:cf:
75:3e:d0:05:41:32:bf:12:25:53:60:28:af:ff:3e:
3c:3a:4c:52:78:3f:b2:78:b9:c6:2f:fc:0e:44:eb:
65:c3:7f:38:2b:ab:88:37:8c:68:55:69:e3:3d:5e:
9b:99:25:11:55:06:ab:e8:c1:fa:54:da:5b:e7:9b:
3e:3f:39:4f:cf:b3:cb:48:cf:96:02:89:0b:7e:24:
c7:00:e9:ce:8d:ea:07:cf:21:f2:89:51:c8:cc:7a:
04:e4:68:6f:1c:a8:e0:76:18:40:62:ee:2f:bd:13:
64:b7:1e:2e:18:bb:b1:d4:17:d5:fb:1f:07:59:65:
46:f0:c4:51:dc:ac:62:ff:31:a8:72:26:a6:1a:88:
37:23:82:49:9a:02:d2:39:74:98:71:7f:a4:77:52:
3a:ed:22:2e:99:9c:81:2c:48:16:3c:82:7b:af:2c:
0d:4b:28:4d:e0:46:7d:b5:b8:ea:3f:e7:5a:5b:4f:
d8:06:b2:a3:86:2f:8b:5b:9c:bc:04:2e:64:b6:e1:
09:c9:14:6d:54:7e:86:40:7b:66:33:27:33:4a:3d:
7c:97
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
EF:9B:88:5C:07:27:79:EA:60:90:5C:7A:28:45:FB:7F:35:E6:CB:3F
X509v3 Authority Key Identifier:
keyid:EF:9B:88:5C:07:27:79:EA:60:90:5C:7A:28:45:FB:7F:35:E6:CB:3F
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
08:e9:a4:32:cc:35:7c:66:5a:ea:f2:bd:e6:75:78:81:52:11:
22:27:32:c9:ec:91:6e:51:8a:f1:1e:0f:25:8a:e1:64:ba:e4:
85:1c:e4:fd:75:f0:26:3d:65:62:16:29:20:4f:5f:d2:66:36:
de:2b:bd:7b:96:71:f6:2c:d1:c5:54:69:89:dd:52:20:49:49:
b1:ac:09:b4:1e:33:59:0d:89:fd:a4:28:7a:70:96:e5:cb:58:
7e:b9:1d:02:7a:33:ee:ad:6a:ad:2c:3c:5e:7d:cc:f5:72:69:
51:fd:77:b4:0f:10:fd:9e:c2:1a:04:c5:a9:56:6e:fd:66:9f:
b6:1c:f9:d3:68:f4:4f:8c:6c:67:af:f5:e0:a5:30:67:a6:a7:
9b:6e:16:89:8a:e5:b4:20:f4:f7:74:f4:9c:ca:5d:c7:2f:e6:
30:9d:6b:2e:95:29:c1:e7:aa:d7:d6:59:dc:a9:f0:10:40:02:
66:3f:58:a2:38:8c:89:1a:0b:94:1a:e5:80:49:14:44:f4:06:
b1:11:1a:cd:ef:76:6a:bf:f8:6f:58:9d:af:a3:6b:9a:8e:bb:
6c:10:d6:d8:4e:73:58:20:0b:99:38:41:d4:22:d4:80:0b:09:
0d:25:40:3e:66:15:a0:44:4e:d6:59:5a:58:07:e5:4b:62:f1:
e9:ae:b6:7c
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIJAOR8RcQlISHJMA0GCSqGSIb3DQEBBQUAMG4xCzAJBgNV
BAYTAkNaMREwDwYDVQQIDAhWeXNvY2luYTEUMBIGA1UECgwLYnVrb3ZhLmluZm8x
FDASBgNVBAMMC0pvc2VmIFJva29zMSAwHgYJKoZIhvcNAQkBFhFyb2tvc0BidWtv
dmEuaW5mbzAeFw0xNTA2MjQwOTU5NTBaFw0yNTA2MjEwOTU5NTBaMG4xCzAJBgNV
BAYTAkNaMREwDwYDVQQIDAhWeXNvY2luYTEUMBIGA1UECgwLYnVrb3ZhLmluZm8x
FDASBgNVBAMMC0pvc2VmIFJva29zMSAwHgYJKoZIhvcNAQkBFhFyb2tvc0BidWtv
dmEuaW5mbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALz7ZFBbWAOM
IBx301AxlFV41gW7vIidyyCxjP+s/JcasZwpxKyv7Tvek9XPdT7QBUEyvxIlU2Ao
r/8+PDpMUng/sni5xi/8DkTrZcN/OCuriDeMaFVp4z1em5klEVUGq+jB+lTaW+eb
Pj85T8+zy0jPlgKJC34kxwDpzo3qB88h8olRyMx6BORobxyo4HYYQGLuL70TZLce
Lhi7sdQX1fsfB1llRvDEUdysYv8xqHImphqINyOCSZoC0jl0mHF/pHdSOu0iLpmc
gSxIFjyCe68sDUsoTeBGfbW46j/nWltP2Aayo4Yvi1ucvAQuZLbhCckUbVR+hkB7
ZjMnM0o9fJcCAwEAAaNQME4wHQYDVR0OBBYEFO+biFwHJ3nqYJBceihF+3815ss/
MB8GA1UdIwQYMBaAFO+biFwHJ3nqYJBceihF+3815ss/MAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQEFBQADggEBAAjppDLMNXxmWuryveZ1eIFSESInMsnskW5RivEe
DyWK4WS65IUc5P118CY9ZWIWKSBPX9JmNt4rvXuWcfYs0cVUaYndUiBJSbGsCbQe
M1kNif2kKHpwluXLWH65HQJ6M+6taq0sPF59zPVyaVH9d7QPEP2ewhoExalWbv1m
n7Yc+dNo9E+MbGev9eClMGemp5tuFomK5bQg9Pd09JzKXccv5jCday6VKcHnqtfW
Wdyp8BBAAmY/WKI4jIkaC5Qa5YBJFET0BrERGs3vdmq/+G9Yna+ja5qOu2wQ1thO
c1ggC5k4QdQi1IALCQ0lQD5mFaBETtZZWlgH5Uti8emutnw=
-----END CERTIFICATE-----

@ -168,4 +168,7 @@ public class Constants {
public final static int LEN_TEXT = 255; public final static int LEN_TEXT = 255;
public final static int LEN_DESCRIPTION = 8192; public final static int LEN_DESCRIPTION = 8192;
public final static int LEN_RESULT_MESSAGE = 8192; public final static int LEN_RESULT_MESSAGE = 8192;
public final static String KEY_SIGN_DATA = "SIGN_DATA";
public final static String KEY_SIGN_GUID = "SIGN_GUID";
} }

@ -5,6 +5,7 @@ import info.bukova.isspst.data.User;
import info.bukova.isspst.data.Workgroup; import info.bukova.isspst.data.Workgroup;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -13,16 +14,18 @@ public class SessionData implements Serializable {
/** /**
* *
*/ */
private static final long serialVersionUID = -764426911263559758L; private static final long serialVersionUID = -764426911263559759L;
private List<Workgroup> userCentres; private List<Workgroup> userCentres;
private List<Workgroup> userWorkgroups; private List<Workgroup> userWorkgroups;
private User currentUser; private User currentUser;
private Map<Integer, List<Role>> workgroupRoles; private Map<Integer, List<Role>> workgroupRoles;
private boolean loginFailed; private boolean loginFailed;
private Map<String, Object> properties;
public SessionData() { public SessionData() {
loginFailed = false; loginFailed = false;
properties = new HashMap<String, Object>();
} }
public List<Workgroup> getUserCentres() { public List<Workgroup> getUserCentres() {
@ -65,4 +68,11 @@ public class SessionData implements Serializable {
this.loginFailed = loginFailed; this.loginFailed = loginFailed;
} }
public void setProperty(String key, Object value) {
properties.put(key, value);
}
public Object getProperty(String key) {
return properties.get(key);
}
} }

@ -0,0 +1,55 @@
package info.bukova.isspst.reporting;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfAnnotation;
import com.lowagie.text.pdf.PdfFormField;
import com.lowagie.text.pdf.PdfName;
import net.sf.jasperreports.engine.JRGenericPrintElement;
import net.sf.jasperreports.engine.JRPropertiesMap;
import net.sf.jasperreports.engine.export.GenericElementHandler;
import net.sf.jasperreports.engine.export.GenericElementHandlerBundle;
import net.sf.jasperreports.engine.export.GenericElementPdfHandler;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRPdfExporterContext;
import net.sf.jasperreports.extensions.ExtensionsRegistry;
import net.sf.jasperreports.extensions.ExtensionsRegistryFactory;
import net.sf.jasperreports.extensions.SingletonExtensionRegistry;
/**
* @author Pepa Rokos
*/
public class SignaturePdfHandler implements GenericElementPdfHandler, GenericElementHandlerBundle, ExtensionsRegistryFactory {
@Override
public ExtensionsRegistry createRegistry(String registryId, JRPropertiesMap properties) {
return new SingletonExtensionRegistry<GenericElementHandlerBundle>(GenericElementHandlerBundle.class, this);
}
@Override
public void exportElement(JRPdfExporterContext exporterContext, JRGenericPrintElement element) {
PdfFormField field = PdfFormField.createSignature(exporterContext.getPdfWriter());
field.setFieldName("signature");
field.setFieldFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED);
field.setWidget(new Rectangle(element.getX(), element.getY(), element.getX() + element.getWidth(), element.getY() + element.getHeight()), PdfName.HIGHLIGHT);
exporterContext.getPdfWriter().addAnnotation(field);
}
@Override
public boolean toExport(JRGenericPrintElement element) {
return true;
}
@Override
public String getNamespace() {
return "urn:sig:sig";
}
@Override
public GenericElementHandler getHandler(String elementName, String exporterKey) {
if (elementName.equals("signature") && exporterKey.equals(JRPdfExporter.PDF_EXPORTER_KEY)) {
return this;
}
return null;
}
}

@ -0,0 +1,10 @@
package info.bukova.isspst.signapi;
/**
* @author Pepa Rokos
*/
public interface JnlpGenerator {
public byte[] generate();
}

@ -0,0 +1,109 @@
package info.bukova.isspst.signapi;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
/**
* @author Pepa Rokos
*/
public class JnlpGeneratorImpl implements JnlpGenerator {
@Autowired
private HttpServletRequest request;
@Override
public byte[] generate() {
String sessionId;
if (request.getParameter("id") != null && !request.getParameter("id").isEmpty()) {
sessionId = request.getParameter("id");
} else {
sessionId = request.getSession().getId();
}
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document document = docBuilder.newDocument();
Element root = document.createElement("jnlp");
root.setAttribute("spec", "1.0+");
String signerUrl = request.getRequestURL().toString();
signerUrl = signerUrl.substring(0, signerUrl.indexOf(request.getServletPath())) + "/api/sign";
root.setAttribute("codebase", signerUrl);
root.setAttribute("href", "signer.jnlp" + "?id=" + sessionId);
document.appendChild(root);
Element info = document.createElement("information");
Element title = document.createElement("title");
title.appendChild(document.createTextNode("Signer component"));
info.appendChild(title);
Element vendor = document.createElement("vendor");
vendor.appendChild(document.createTextNode("bukova.info"));
info.appendChild(vendor);
root.appendChild(info);
Element security = document.createElement("security");
security.appendChild(document.createElement("all-permissions"));
root.appendChild(security);
Element resources = document.createElement("resources");
Element j2se = document.createElement("j2se");
j2se.setAttribute("version", "1.8+");
Element jar = document.createElement("jar");
jar.setAttribute("href", "pdfsigner.jar");
resources.appendChild(j2se);
resources.appendChild(jar);
root.appendChild(resources);
Element appDesc = document.createElement("application-desc");
appDesc.setAttribute("main-class", "info.bukova.pdfsigner.Main");
Element argUrl = document.createElement("argument");
argUrl.appendChild(document.createTextNode(signerUrl + "/data"));
appDesc.appendChild(argUrl);
Element argSession = document.createElement("argument");
argSession.appendChild(document.createTextNode(sessionId));
appDesc.appendChild(argSession);
root.appendChild(appDesc);
System.out.println(signerUrl);
System.out.println(request.getSession().getId());
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StreamResult result = new StreamResult(bos);
transformer.transform(source, result);
return bos.toByteArray();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
return null;
}
}

@ -0,0 +1,92 @@
package info.bukova.isspst.signapi;
import java.io.Serializable;
import java.util.Date;
/**
* @author Pepa Rokos
*/
public class SignData implements Serializable {
private byte[] pdfData;
private byte[] signImg;
private int areaId;
private Date signDate;
private String description;
private String numser;
private boolean signed;
private String signGuid;
private boolean signSuccess;
public byte[] getPdfData() {
return pdfData;
}
public void setPdfData(byte[] pdfData) {
this.pdfData = pdfData;
}
public Date getSignDate() {
return signDate;
}
public void setSignDate(Date signDate) {
this.signDate = signDate;
}
public String getNumser() {
return numser;
}
public void setNumser(String numser) {
this.numser = numser;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isSigned() {
return signed;
}
public void setSigned(boolean signed) {
this.signed = signed;
}
public String getSignGuid() {
return signGuid;
}
public void setSignGuid(String signGuid) {
this.signGuid = signGuid;
}
public boolean isSignSuccess() {
return signSuccess;
}
public void setSignSuccess(boolean signSuccess) {
this.signSuccess = signSuccess;
}
public byte[] getSignImg() {
return signImg;
}
public void setSignImg(byte[] signImg) {
this.signImg = signImg;
}
public int getAreaId() {
return areaId;
}
public void setAreaId(int areaId) {
this.areaId = areaId;
}
}

@ -0,0 +1,28 @@
package info.bukova.isspst.signapi;
import java.io.Serializable;
/**
* @author Pepa Rokos
*/
public class SignUploadResponse implements Serializable {
private boolean ok;
private String errorMessage;
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

@ -0,0 +1,133 @@
package info.bukova.isspst.signapi;
import info.bukova.isspst.Constants;
import info.bukova.isspst.SessionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author Pepa Rokos
*/
@Controller
public class SigningController {
@Autowired
private SessionData sessionData;
@Autowired
private JnlpGenerator jnlpGenerator;
@Autowired
private ServletContext context;
@RequestMapping(value="/sign/data", method= RequestMethod.GET)
public void dataForSign(HttpServletResponse response, HttpServletRequest request) {
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(response.getOutputStream());
response.setContentType("application/x-java-serialized-object");
os.writeObject(data);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@RequestMapping(value="/sign/data", method= RequestMethod.POST)
public void signedData(HttpServletRequest request, HttpServletResponse response) {
ObjectInputStream ois = null;
ObjectOutputStream os = null;
String error = null;
try {
ois = new ObjectInputStream(request.getInputStream());
SignData data = (SignData) ois.readObject();
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
} catch (IOException e) {
e.printStackTrace();
error = "IO error";
} catch (ClassNotFoundException e) {
e.printStackTrace();
error = "Loading error";
}
try {
SignUploadResponse resp = new SignUploadResponse();
if (error == null) {
resp.setOk(true);
} else {
resp.setOk(false);
resp.setErrorMessage(error);
}
os = new ObjectOutputStream(response.getOutputStream());
response.setContentType("application/x-java-serialized-object");
os.writeObject(resp);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@RequestMapping(value="/sign/signer.jnlp", method= RequestMethod.GET)
public void jnlp(HttpServletResponse response) {
byte[] data = jnlpGenerator.generate();
sendByte(response, data, "application/x-java-jnlp-file");
}
@RequestMapping(value="/sign/pdfsigner.jar", method= RequestMethod.GET)
public void pdfsigner(HttpServletResponse response) {
File inputJar = new File(context.getRealPath("/WEB-INF/signer/PDFSigner.jar"));
try {
byte[] data = new byte[(int) inputJar.length()];
FileInputStream is = new FileInputStream(inputJar);
is.read(data);
sendByte(response, data, "application/java-archive");
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendByte(HttpServletResponse response, byte[] data, String contentType) {
ServletOutputStream os = null;
try {
os = response.getOutputStream();
response.setContentType(contentType);
response.setContentLength(data.length);
os.write(data);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

@ -1,19 +1,32 @@
package info.bukova.isspst.ui.main; package info.bukova.isspst.ui.main;
import info.bukova.isspst.Constants;
import info.bukova.isspst.SessionData;
import info.bukova.isspst.StringUtils; import info.bukova.isspst.StringUtils;
import info.bukova.isspst.data.RequirementBase; import info.bukova.isspst.data.RequirementBase;
import info.bukova.isspst.reporting.Generator;
import info.bukova.isspst.reporting.GeneratorFactory;
import info.bukova.isspst.reporting.ParamFiller;
import info.bukova.isspst.reporting.Report;
import info.bukova.isspst.reporting.ReportDefinition;
import info.bukova.isspst.services.Service;
import info.bukova.isspst.services.requirement.ApproveException; import info.bukova.isspst.services.requirement.ApproveException;
import info.bukova.isspst.services.requirement.RequirementBaseService; import info.bukova.isspst.services.requirement.RequirementBaseService;
import info.bukova.isspst.signapi.SignData;
import info.bukova.isspst.ui.ListViewModel; import info.bukova.isspst.ui.ListViewModel;
import org.zkoss.bind.BindUtils; import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.BindingParam; import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ExecutionArgParam; import org.zkoss.bind.annotation.ExecutionArgParam;
import org.zkoss.bind.annotation.Init; import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Messagebox; import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window; import org.zkoss.zul.Window;
import java.util.Date; import java.util.Date;
import java.util.UUID;
/** /**
* @author Pepa Rokos * @author Pepa Rokos
@ -24,6 +37,16 @@ public class ApproveDialogVM {
private RequirementBase requirement; private RequirementBase requirement;
private ListViewModel grid; private ListViewModel grid;
private Date approveDate; private Date approveDate;
@WireVariable
private SessionData sessionData;
@WireVariable
private ReportDefinition reportDefinition;
@WireVariable
private GeneratorFactory genFactory;
@WireVariable
private ParamFiller paramFiller;
private boolean signed;
private boolean timer;
public Date getApproveDate() { public Date getApproveDate() {
return approveDate; return approveDate;
@ -41,6 +64,9 @@ public class ApproveDialogVM {
this.requirement = requirement; this.requirement = requirement;
this.grid = grid; this.grid = grid;
this.approveDate = new Date(); this.approveDate = new Date();
this.signed = false;
this.timer = false;
} }
@Command @Command
@ -57,4 +83,51 @@ public class ApproveDialogVM {
} }
} }
@Command
@NotifyChange("timer")
public void signPdf() {
SignData data = new SignData();
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
data.setSignGuid(UUID.randomUUID().toString());
sessionData.setProperty(Constants.KEY_SIGN_GUID, data.getSignGuid());
// ToDo: Generovat report
reportDefinition.clear();
reportDefinition.setSingleObject(requirement);
reportDefinition.setReport(new Report(0, true, "", "tripRequirementApp", false, true, true));
reportDefinition.setService((Service) service);
paramFiller.fill();
Generator gen = genFactory.createGenerator(reportDefinition);
data.setPdfData(gen.generate());
data.setDescription(requirement.getDescription());
data.setNumser(requirement.getNumser());
timer = true;
Executions.getCurrent().sendRedirect("/api/sign/signer.jnlp", "signer");
}
@Command
@NotifyChange({"signed", "timer"})
public void onTimer() {
String guid = (String) sessionData.getProperty(Constants.KEY_SIGN_GUID);
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
if (guid.equals(data.getSignGuid()) && data.isSignSuccess()) {
signed = true;
timer = false;
} else {
signed = false;
}
}
public boolean isSigned() {
return signed;
}
public boolean isTimer() {
return timer;
}
} }

@ -0,0 +1 @@
net.sf.jasperreports.extension.registry.factory.sig=info.bukova.isspst.reporting.SignaturePdfHandler

@ -0,0 +1,356 @@
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="tripRequirement" pageWidth="612" pageHeight="792" columnWidth="572" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="0b7fa2d2-d452-4a1f-b1c0-2d8e16a22525">
<property name="ireport.zoom" value="1.5"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="272"/>
<style name="table">
<box>
<pen lineWidth="1.0" lineColor="#000000"/>
</box>
</style>
<style name="table_TH" mode="Opaque" backcolor="#F0F8FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="table_CH" mode="Opaque" backcolor="#BFE1FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="table_TD" mode="Opaque" backcolor="#FFFFFF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<subDataset name="Passengers" uuid="89ee82de-f017-493e-85d1-439a0ff3be72">
<queryString>
<![CDATA[]]>
</queryString>
<field name="fullName" class="java.lang.String">
<fieldDescription><![CDATA[fullName]]></fieldDescription>
</field>
</subDataset>
<subDataset name="dataset1" uuid="2030e480-17f9-4ac5-a8f1-7499b269f3b4"/>
<parameter name="P_USER_SIGNATURE" class="java.lang.String"/>
<parameter name="P_APPROVE_DATE" class="java.util.Date"/>
<parameter name="P_APPROVER_SIGNATURE" class="java.lang.String"/>
<parameter name="P_LOGO" class="java.lang.String"/>
<parameter name="P_MAIN_ADDRESS" class="java.lang.String"/>
<parameter name="P_PREV_APPROVE_DATE" class="java.util.Date"/>
<parameter name="P_PREV_APPROVER_SIGNATURE" class="java.lang.String"/>
<parameter name="SUBREPORT_DIR" class="java.lang.String"/>
<field name="ownedBy" class="info.bukova.isspst.data.User"/>
<field name="reqDate" class="java.util.Date"/>
<field name="from" class="java.lang.String"/>
<field name="tripDate" class="java.util.Date"/>
<field name="to" class="java.lang.String"/>
<field name="description" class="java.lang.String"/>
<field name="end" class="java.lang.String"/>
<field name="endDate" class="java.util.Date"/>
<field name="passengers" class="java.util.Collection"/>
<field name="foreignPersons" class="java.lang.String"/>
<field name="vehicle" class="info.bukova.isspst.data.Vehicle"/>
<field name="vehicle.code" class="java.lang.String"/>
<field name="requireDownPayment" class="java.lang.Boolean"/>
<field name="downPayment" class="java.math.BigDecimal"/>
<field name="ownedBy.address" class="info.bukova.isspst.data.UsersAddress"/>
<field name="ownedBy.address.street" class="java.lang.String"/>
<field name="ownedBy.address.houseNumber" class="java.lang.String"/>
<field name="ownedBy.address.zipCode" class="java.lang.String"/>
<field name="ownedBy.address.city" class="java.lang.String"/>
<background>
<band splitType="Stretch"/>
</background>
<title>
<band height="79" splitType="Stretch">
<image onErrorType="Blank">
<reportElement uuid="ef1dc796-f5c6-4036-99eb-26e7b6b7abbc" x="0" y="0" width="100" height="79" isRemoveLineWhenBlank="true">
<printWhenExpression><![CDATA[$P{P_LOGO} != null]]></printWhenExpression>
</reportElement>
<imageExpression><![CDATA[$P{P_LOGO}]]></imageExpression>
</image>
<textField>
<reportElement uuid="3e2074cd-220c-4c9a-b94c-a0a254cc24a6" x="100" y="0" width="471" height="34"/>
<textElement textAlignment="Center">
<font isBold="true" pdfEncoding="Cp1250"/>
</textElement>
<textFieldExpression><![CDATA[$P{P_MAIN_ADDRESS}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="a7a82c52-e8b8-41cf-b13a-ebc54d30d04f" x="101" y="34" width="470" height="45"/>
<textElement textAlignment="Center" verticalAlignment="Bottom">
<font size="14" isBold="true" pdfEncoding="Cp1250"/>
</textElement>
<text><![CDATA[CESTOVNÍ PŘÍKAZ
k tuzemské pracovní cestě]]></text>
</staticText>
</band>
</title>
<detail>
<band height="529" splitType="Stretch">
<staticText>
<reportElement uuid="f6445d7f-1e96-4d17-9f1d-27eaa8f15022" x="0" y="7" width="143" height="20"/>
<textElement/>
<text><![CDATA[Příjmení, jméno, titul:]]></text>
</staticText>
<staticText>
<reportElement uuid="6f073490-98cc-445b-8b51-81facf335657" x="0" y="27" width="100" height="20"/>
<textElement/>
<text><![CDATA[Bydliště:]]></text>
</staticText>
<staticText>
<reportElement uuid="a3e2a5d3-ea50-48bd-94ea-4530f6624b52" x="0" y="51" width="572" height="20"/>
<textElement textAlignment="Center">
<font size="12" pdfFontName="Helvetica-Bold"/>
</textElement>
<text><![CDATA[Souhlasím s vysláním na pracovní cestu]]></text>
</staticText>
<staticText>
<reportElement uuid="306f2b85-5dc6-40a6-8c44-76ed46831680" x="0" y="76" width="143" height="20"/>
<textElement/>
<text><![CDATA[Požaduji poskytnutí zálohy:]]></text>
</staticText>
<line>
<reportElement uuid="029f1b4c-5f59-4a5e-8d3d-b644af41b657" x="301" y="121" width="271" height="1"/>
</line>
<staticText>
<reportElement uuid="2f0f450a-b89d-4862-b82e-4eb1e9861927" x="301" y="128" width="271" height="20"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Datum a podpis]]></text>
</staticText>
<textField pattern="dd. MM. yyyy">
<reportElement uuid="dd5f12d3-9ce1-4565-83ed-fe9004e3a6c3" x="301" y="101" width="77" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{reqDate}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="a2912fef-ae4a-4c7e-b08c-3f5f6b92a534" x="0" y="157" width="572" height="20"/>
<textElement textAlignment="Center">
<font size="16" isBold="true" pdfFontName="Helvetica-Bold" isPdfEmbedded="true"/>
</textElement>
<text><![CDATA[PODMÍNKY PRACOVNÍ CESTY]]></text>
</staticText>
<line>
<reportElement uuid="b415fa20-91d9-4772-9b73-fd26b6cf32a3" x="0" y="177" width="572" height="1"/>
</line>
<line>
<reportElement uuid="74a5cf40-10b4-4f99-8945-5e14323a7b98" x="0" y="253" width="572" height="1"/>
</line>
<line>
<reportElement uuid="a3a337aa-8b1c-4f4f-abc0-4b5a6cba04d5" x="0" y="156" width="572" height="1"/>
</line>
<staticText>
<reportElement uuid="ed4e3928-9a68-4f61-9876-254547efa04e" x="0" y="180" width="143" height="27"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Počátek cesty (místo, datum, hodina)]]></text>
</staticText>
<textField>
<reportElement uuid="ed4a676e-2647-4a91-a1b5-1ff326f50359" x="0" y="208" width="143" height="20"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{from}]]></textFieldExpression>
</textField>
<textField pattern="dd. MM. yyyy">
<reportElement uuid="fd80824e-0a50-4e37-abd5-1c8bf92ded4a" x="0" y="228" width="90" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{tripDate}]]></textFieldExpression>
</textField>
<textField pattern="hh:mm">
<reportElement uuid="4d004341-3dc5-4b77-a0f2-d93c93aff176" x="90" y="228" width="53" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{tripDate}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="36c8b801-3fdf-4464-99d7-4f07539d76f8" x="143" y="180" width="143" height="27"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Místo jednání]]></text>
</staticText>
<textField>
<reportElement uuid="6e9e44fe-3022-4802-854e-607238cb21be" x="143" y="208" width="143" height="20"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{to}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="398372d7-7995-42fa-a53a-f50b0f8936db" x="286" y="179" width="143" height="27"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Účel cesty]]></text>
</staticText>
<staticText>
<reportElement uuid="3dbc8b8d-7ac4-40d8-b43c-89e81d26f15c" x="429" y="180" width="143" height="26"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Konec cesty (místo, datum)]]></text>
</staticText>
<textField isBlankWhenNull="true">
<reportElement uuid="3b52420d-1c84-4042-bc88-16f4f36a3af8" x="286" y="208" width="143" height="40"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{description}]]></textFieldExpression>
</textField>
<textField>
<reportElement uuid="3e9b796b-fc9e-42e4-93d6-a966ce78c771" x="429" y="208" width="143" height="20"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{end}]]></textFieldExpression>
</textField>
<textField pattern="dd. MM. yyyy">
<reportElement uuid="6ae75bed-b03b-4857-b624-71daeb35513d" x="429" y="228" width="143" height="20"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{endDate}]]></textFieldExpression>
</textField>
<textField>
<reportElement uuid="ad778808-c5cc-419c-b34f-fc84effc1958" x="186" y="7" width="181" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{ownedBy}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="deafc33f-99ed-483e-8682-57a18872941d" x="0" y="265" width="143" height="20"/>
<textElement/>
<text><![CDATA[Spolucestující:]]></text>
</staticText>
<staticText>
<reportElement uuid="ab2fbb7c-28d3-4e6b-beb9-93c6fc8745c8" x="0" y="307" width="348" height="20"/>
<textElement/>
<text><![CDATA[Určený dopravní prostředek (u vlastního vozidla druh a reg. značka):]]></text>
</staticText>
<textField>
<reportElement uuid="1a52f009-c560-443a-9b84-cd9502b6b0c5" x="348" y="307" width="60" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{vehicle.code}]]></textFieldExpression>
</textField>
<staticText>
<reportElement uuid="8355e20a-124b-4c63-ab9c-4d64be5b912e" x="0" y="327" width="572" height="40"/>
<textElement textAlignment="Center"/>
<text><![CDATA[A - autobus, V - vlak
AUV - auto vlastní, AUS - auto služební, AUC - auto cizí
L - letadlo, P - pěšky, T - taxi]]></text>
</staticText>
<staticText>
<reportElement uuid="94f07671-9d8f-4542-9afe-f1c0b8ae1a02" x="0" y="369" width="143" height="20"/>
<textElement/>
<text><![CDATA[Ubytování:]]></text>
</staticText>
<staticText>
<reportElement uuid="b1cd5f7d-48fc-4f1b-82e1-69f81026b5ac" x="0" y="398" width="143" height="20"/>
<textElement/>
<text><![CDATA[Poskytnutí zálohy ve výši:]]></text>
</staticText>
<line>
<reportElement uuid="57398205-845b-4633-89db-3b0c4b31f03c" x="301" y="418" width="271" height="1"/>
</line>
<staticText>
<reportElement uuid="e33b0435-12e0-4d9f-9d3f-44f54eed9505" x="301" y="423" width="271" height="20"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Datum a podpis oprávněné osoby]]></text>
</staticText>
<staticText>
<reportElement uuid="cad8d17d-5fdc-41a8-a74d-54ea34e4cdad" x="0" y="449" width="100" height="20"/>
<textElement/>
<text><![CDATA[Povolená záloha]]></text>
</staticText>
<staticText>
<reportElement uuid="2b462c95-65b1-4295-ac47-7d2ac3e16f40" x="0" y="469" width="143" height="20"/>
<textElement/>
<text><![CDATA[Pokladní doklad číslo]]></text>
</staticText>
<staticText>
<reportElement uuid="4cfe5623-901b-4508-9161-920d90cd0405" x="301" y="449" width="100" height="20"/>
<textElement/>
<text><![CDATA[Vyplacená dne:]]></text>
</staticText>
<line>
<reportElement uuid="39f180e0-0300-4087-89b2-dbd9441d1e94" x="149" y="500" width="280" height="1"/>
</line>
<staticText>
<reportElement uuid="a7218a5e-4d69-41fe-a26b-a51dd240cfb1" x="149" y="508" width="280" height="20"/>
<textElement textAlignment="Center"/>
<text><![CDATA[Podpis pokladníka]]></text>
</staticText>
<line direction="BottomUp">
<reportElement uuid="0276901c-8949-4307-a4a6-efa1a9b83341" x="571" y="-79" width="1" height="607"/>
</line>
<line direction="BottomUp">
<reportElement uuid="01ad15ce-276d-4fb8-af37-d896fa7eb77a" x="-1" y="-79" width="1" height="607"/>
</line>
<line>
<reportElement uuid="31fec8f3-7de4-4c34-934e-dbc2ad813c49" x="-1" y="-80" width="573" height="1"/>
</line>
<line>
<reportElement uuid="11f1abd0-78a2-4cee-9553-c960a59a00d3" x="-1" y="528" width="573" height="1"/>
</line>
<line>
<reportElement uuid="00689195-f270-4b32-9878-74c6d5d353cd" x="-1" y="0" width="573" height="1"/>
</line>
<line>
<reportElement uuid="0d8ef0ad-db1e-4be9-8153-b3a885fb8ace" x="0" y="148" width="572" height="1"/>
</line>
<line>
<reportElement uuid="c9713d6e-9b2e-4ce6-8837-3fbbe320fa8b" x="143" y="178" width="1" height="75"/>
</line>
<line>
<reportElement uuid="4e1fb287-81be-477a-95c2-96691d638916" x="285" y="178" width="1" height="75"/>
</line>
<line>
<reportElement uuid="bc2f55db-f6e3-46eb-81cd-1b4161ceeffd" x="428" y="178" width="1" height="75"/>
</line>
<line>
<reportElement uuid="0e93a41e-d13e-4f12-83cb-70d69bb3c0fb" x="0" y="442" width="572" height="1"/>
</line>
<staticText>
<reportElement uuid="548c1550-c12d-42b3-a297-c9be96dbb2e8" x="144" y="76" width="31" height="20">
<printWhenExpression><![CDATA[$F{requireDownPayment}]]></printWhenExpression>
</reportElement>
<textElement/>
<text><![CDATA[Ano]]></text>
</staticText>
<staticText>
<reportElement uuid="e06aba6d-b74d-4ab1-9737-1134a6ac6519" x="144" y="76" width="32" height="20">
<printWhenExpression><![CDATA[$F{requireDownPayment} == null || $F{requireDownPayment} == false]]></printWhenExpression>
</reportElement>
<textElement/>
<text><![CDATA[Ne]]></text>
</staticText>
<textField pattern="###0.00;-###0.00" isBlankWhenNull="true">
<reportElement uuid="ac95738d-56c8-4ee2-8721-cad00e1b06e4" x="144" y="398" width="57" height="20"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$F{downPayment}]]></textFieldExpression>
</textField>
<image onErrorType="Blank">
<reportElement uuid="954e517f-5d23-4166-b776-7c31b4409ddd" x="378" y="69" width="183" height="50">
<printWhenExpression><![CDATA[$P{P_USER_SIGNATURE} != null]]></printWhenExpression>
</reportElement>
<imageExpression><![CDATA[$P{P_USER_SIGNATURE}]]></imageExpression>
</image>
<textField pattern="dd. MM. yyyy" isBlankWhenNull="true">
<reportElement uuid="97daa8a7-dab0-4104-babb-c3889faac21a" x="301" y="399" width="77" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$P{P_PREV_APPROVE_DATE}]]></textFieldExpression>
<anchorNameExpression><![CDATA["SIGN_1"]]></anchorNameExpression>
</textField>
<image onErrorType="Blank">
<reportElement uuid="baf922bc-b6fb-4dbf-abc9-250f448baef3" x="378" y="368" width="183" height="50">
<printWhenExpression><![CDATA[$P{P_PREV_APPROVER_SIGNATURE} != null]]></printWhenExpression>
</reportElement>
<imageExpression><![CDATA[$P{P_PREV_APPROVER_SIGNATURE}]]></imageExpression>
</image>
<textField>
<reportElement uuid="16e5c4e2-a366-4eca-ad27-7db7fef6771c" x="186" y="27" width="375" height="20">
<printWhenExpression><![CDATA[$F{ownedBy.address} != null]]></printWhenExpression>
</reportElement>
<textElement/>
<textFieldExpression><![CDATA[$F{ownedBy.address}]]></textFieldExpression>
</textField>
<subreport>
<reportElement uuid="b8144a34-f2c4-4b5a-9f48-b74b5dc99e8c" x="143" y="265" width="428" height="20"/>
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{passengers})]]></dataSourceExpression>
<subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "tripRequirementPassengers.jasper"]]></subreportExpression>
</subreport>
<textField isBlankWhenNull="true">
<reportElement uuid="f8e2f8b5-373d-46fd-9c61-5a6c1da44351" x="143" y="285" width="428" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{foreignPersons}]]></textFieldExpression>
</textField>
<genericElement>
<reportElement uuid="c1d18650-66b9-425c-acbe-7b4e952bfd16" x="442" y="460" width="119" height="48"/>
<genericElementType namespace="urn:sig:sig" name="signature"/>
</genericElement>
</band>
</detail>
</jasperReport>

@ -457,6 +457,8 @@
<property name="dao" ref="tripBillApprovalDao"/> <property name="dao" ref="tripBillApprovalDao"/>
</bean> </bean>
<bean id="jnlpGenerator" class="info.bukova.isspst.signapi.JnlpGeneratorImpl"/>
<bean id="signedDocumentService" class="info.bukova.isspst.services.signeddocs.SignedDocumentServiceImpl"> <bean id="signedDocumentService" class="info.bukova.isspst.services.signeddocs.SignedDocumentServiceImpl">
<property name="dao" ref="signedDocumentDao"/> <property name="dao" ref="signedDocumentDao"/>
</bean> </bean>

@ -17,15 +17,20 @@
<label value="${labels.RequirementApproveDate}"/> <label value="${labels.RequirementApproveDate}"/>
<datebox <datebox
value="@bind(vm.approveDate)" value="@bind(vm.approveDate)"
format="${labels.DateFormat}" /> format="${labels.DateFormat}" disabled="@load(vm.signed)"/>
</hbox> </hbox>
<separator bar="true" hflex="1"/> <separator bar="true" hflex="1"/>
<hbox> <hbox>
<button image="/img/approve-016.png" label="${labels.Confirm}" onClick="@command('approve', window=approveWin)" sclass="nicebutton"/> <button label="Podepsat" onClick="@command('signPdf')" sclass="nicebutton" disabled="@load(vm.signed)"/>
<button image="/img/approve-016.png" label="${labels.Confirm}" onClick="@command('approve', window=approveWin)" sclass="nicebutton" disabled="@load(not vm.signed)"/>
<button image="~./zul/img/misc/drag-disallow.png" label="${labels.ButtonStorno}" onClick="approveWin.detach()" sclass="nicebutton"/> <button image="~./zul/img/misc/drag-disallow.png" label="${labels.ButtonStorno}" onClick="approveWin.detach()" sclass="nicebutton"/>
</hbox> </hbox>
</vbox> </vbox>
<timer onTimer="@command('onTimer')" running="@load(vm.timer)" repeats="true" delay="500"/>
<iframe name="signer" width="5px" height="5px"/>
</window> </window>
</zk> </zk>
Loading…
Cancel
Save