Skribble - Dokumente digital signieren
Mit Intrexx haben Sie die Möglichkeit, Dokumente digital signieren zu lassen. Intrexx bietet hierfür eine Anbindung an Skribble an.
Skribble
Skribble ist eine webbasierte Software, die das digitale Signieren von Dokumenten auf einfache und benutzerfreundliche Weise ermöglicht. Hersteller und Betreiber von Skribble ist die Skribble AG und Skribble Deutschland GmbH. Die Skribble AG und Skribble Deutschland GmbH ist Technologiepartner der INTREXX GmbH. Sie finden Sie im Internet unter folgendem Link: www.skribble.com
Für das Verständnis der folgenden Abschnitte ist es hilfreich, sich mit der Onlinehilfe von Skribble vertraut zu machen. Dort finden Sie alle relevanten Informationen zur Einrichtung von Skribble, zu gesetzlichen Vorgaben, zu Prozessen und vieles mehr.
Die Skribble Onlinehilfe finden Sie unter folgendem Link: Skribble Onlinehilfe
Prozessablauf
Im Folgenden finden Sie eine vereinfachte Darstellung des Signierprozesses.
-
Dokumente werden in einer Intrexx Applikation hochgeladen.
-
Die Dokumente werden einer oder mehreren Personen, die die Dokumente signieren sollen, zugeordnet.
-
Für diese Personen wird in Intrexx eine E-Mail-Adresse hinterlegt.
-
Über ein Event, zum Beispiel das Klicken einer Versenden-Schaltfläche, wird das Dokument per API an Skribble übergeben.
-
Gleichzeitig erhält die Person, die das Dokument signieren soll, eine E-Mail, in der sie aufgefordert wird, das Dokument zu signieren. Dabei muss die signierende Person nicht über ein eigenes Skribble-Konto verfügen.
-
Die E-Mail enthält einen Link, mit der sie die Skribble Web App starten und das Dokument digital signieren kann.
-
Das signierte Dokument wird an Intrexx per API übermittelt.
Zielgruppe
Die folgenden Abschnitte richten sich an erfahrene Intrexx Applikationsentwickler, die über Kenntnisse in Groovy-Skript verfügen.
Zentrale Schritte
Schritte bei Skribble
Registrierung bei Skribble
Registrieren Sie sich bei Skribble.
Detaillierte Informationen hierzu finden Sie in der Skribble-Onlinehilfe hier: Skribble-Konto erstellen
API-Schlüssel erstellen
Erstellen Sie in Skribble im Admin-Bereich einen API-Schlüssel.
Detaillierte Informationen hierzu finden Sie in der Skribble-Onlinehilfe hier: Manage API keys
Schritte in Intrexx
Applikation erstellen
Erstellen Sie eine Applikation, die die erforderlichen Felder enthält, damit Skribble eine Anfrage aus Intrexx korrekt verarbeiten kann.
-
E-Mail-Adresse der signierenden Person
Wenn die signierende Person über ein Skribble-Konto verfügt, ist die E-Mail-Adresse ausreichend.
Wenn die signierende Person nicht über ein Skribble-Konto verfügt, sind neben der E-Mail-Adresse noch folgende Felder erforderlich:
-
Vorname
-
Nachname
-
Mobilnummer
-
-
Titel
-
Nachrichtentext
-
Signaturqualität
Bei einer qualifizierten Signatur muss eine Auswahlmöglichkeit zwischen der EU und der Schweiz implementiert sein.
-
Signierstatus
-
Feld für die zu signierende PDF-Datei (Typ "Datei")
-
Feld für von Skribble übermittelte Request-ID
-
(Optional)Reihenfolge
-
(Optional)Beobachter
API-Daten hinterlegen
Hinterlegen Sie die Skribble-API-Daten in Intrexx. Im Groovy-Skript (s.u.) wird hierfür eine Systemdatengruppe verwendet. Dieser Ansatz ermöglicht die Option, die API-Daten in der Applikation im Portal zu pflegen.
Sie können aber auch die API-Daten im Anmeldeinformationsspeicher hinterlegen.
Prozess mit Groovy-Skript erstellen
Erstellen Sie einen Prozess, mit dem Sie die Aktionen für das digitale Signieren mit Skribble anstoßen und ausführen. Hierfür stellen wir Ihnen ein Groovy-Skript zur Verfügung, dass alle zentralen Funktionalitäten für die Anbindung an Skribble enthält. Dieses können Sie nach Ihren eigenen Bedürfnissen anpassen.
Groovy-Skript
Im Folgenden finden Sie ein Groovy-Skript, das Sie für die Anbindung an Skribble verwenden können.
Weiter unten finden Sie detaillierte Erläuterungen zu den einzelnen Sequenzen des Skripts.
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpGet
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import org.apache.http.client.utils.URIBuilder
import de.uplanet.scripting.groovy.util.Safely
def sbDebug = new StringBuilder()
CloseableHttpClient httpclient = HttpClients.createDefault()
def conn = g_dbConnections.systemConnection
def stmt = null
def rs = null
def signatures = []
def STRID = g_record["123456789CC5688C6514D46F166742F123456789"].value
// Data for API connection from XDATAGROUP8AEAEE02 (Skribble Config - AppProps)
def API_USERNAME = g_sysDg['123456789IXA39D44A251254E6ECIX123456789']
def API_KEY = g_sysDg['123456789IXB3E183390BD8EB0FIX123456789']
def API_HOST = g_sysDg['123456789IX5A7F21B81C261CF0IX123456789']
//Data sent with the document
def strTitle = g_record["123456789CDF6724B4007565824D486123456789"].value
def txtMessage = g_record["123456789IX12489B84569D9A20ACIX123456789"].value
try
{
stmt = g_dbQuery.prepare(conn, """
SELECT STR_EMAIL, L_SEQUENCE, STR_FIRSTNAME, STR_NAME, STR_MOBILENUMBER
FROM DATAGROUP('123456789IX2CEE38FE85FBCB7168IX123456789')
WHERE FKSTRID=? AND (B_OBSERVER=? OR B_OBSERVER IS NULL)
ORDER BY L_SEQUENCE
""")
stmt.setString(1, STRID)
stmt.setBoolean(2, false)
rs = stmt.executeQuery()
//Get signer data from IX_CRM_OFFER_EMAILSIGNING
while (rs.next()) {
def strEmail = rs.getStringValue(1)
def iSequence = rs.getIntValue(2)
def strFirstname = rs.getStringValue(3)
def strName = rs.getStringValue(4)
def strMobileNumber = rs.getStringValue(5)
if (strEmail) {
signatures << [
"account_email": strEmail,
"sequence" : iSequence,
"signer_identity_data": [
"email_address": strEmail,
"first_name" : strFirstname,
"last_name" : strName,
"mobile_number": strMobileNumber
]
]
}
}
}
finally
{
rs = Safely.close(rs)
stmt = Safely.close(stmt)
}
//Get Observer from IX_CRM_OFFER_EMAILSIGNING
def observer = []
try
{
stmt = g_dbQuery.prepare(conn, """
SELECT STR_EMAIL
FROM DATAGROUP('123456789IX2CEE38FE85FBCB7168IX123456789')
WHERE FKSTRID=? AND B_OBSERVER=?
""")
stmt.setString(1, STRID)
stmt.setBoolean(2, true)
rs = stmt.executeQuery()
while (rs.next()) {
def strEmail = rs.getStringValue(1)
if (strEmail) {
observer << strEmail
}
}
}
finally
{
rs = Safely.close(rs)
stmt = Safely.close(stmt)
}
//Convert document for signing
def fileField = g_record["123456789IX79C290AAB61A668EFBIX123456789"]
if (!fileField || !fileField.value) {
throw new RuntimeException("Keine Datei vorhanden!")
}
def fileDescriptor = fileField.value[0]
def file = fileDescriptor.getFile()
def inputStream = file.newInputStream()
byte[] pdfBytes = inputStream.bytes
inputStream.close()
String base64Pdf = Base64.encoder.encodeToString(pdfBytes)
// ==============================
// AUTHENTICATION
// ==============================
def authUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/access/login")
.build()
HttpPost authPost = new HttpPost(authUri)
authPost.setHeader("Content-Type", "application/json")
def authPayload = [
username: API_USERNAME,
"api-key": API_KEY
]
authPost.setEntity(new StringEntity(JsonOutput.toJson(authPayload), "UTF-8"))
def authResponse = httpclient.execute(authPost)
def status = authResponse.getStatusLine().getStatusCode()
def body = EntityUtils.toString(authResponse.getEntity())
if (status != 200) {
throw new RuntimeException("Login fehlgeschlagen: ${status} - ${body}")
}
def accessToken = body?.trim()
if (!accessToken) {
throw new RuntimeException("Kein Access Token erhalten")
}
// ==============================
// SIGNATURE REQUEST
// ==============================
def strSignaturQuality = g_record["123456789989F8FA362B65F89F251CD123456789"].value
def strLegislation = g_record["1234567890F9IXB57F1FCFAC153B7IX123456789"].value
def signPayload = [
"title" : strTitle,
"message" : txtMessage,
"content" : base64Pdf,
"signatures" : signatures
]
if (strSignaturQuality && strSignaturQuality != "DEMO") {
signPayload["quality"] = strSignaturQuality
if (strLegislation) {
signPayload["legislation"] = strLegislation
}
}
if (observer && !observer.isEmpty()) {
signPayload["cc_email_addresses"] = observer
}
// ==============
// REQUEST
// ==============
def signUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/signature-requests")
.build()
HttpPost signPost = new HttpPost(signUri)
signPost.setHeader("Content-Type", "application/json")
signPost.setHeader("Authorization", "Bearer ${accessToken}")
signPost.setEntity(new StringEntity(JsonOutput.toJson(signPayload), "UTF-8"))
def signResponse = httpclient.execute(signPost)
def statusCode = signResponse.getStatusLine().getStatusCode()
def signBody = EntityUtils.toString(signResponse.getEntity())
if (statusCode != 200 && statusCode != 201) {
throw new Exception("Signature Request fehlgeschlagen! Status: ${statusCode}\n${signBody}")
}
def signJson = new JsonSlurper().parseText(signBody)
strRequestID = signJson.id
if (!strRequestID) {
throw new Exception("Keine Request-ID erhalten!")
}
g_sharedState.put("requestId", strRequestID)
// ==============================
// STATUS CHECK
// ==============================
def statusUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/signature-requests/${strRequestID}")
.build()
def statusGet = new HttpGet(statusUri)
statusGet.setHeader("Authorization", "Bearer ${accessToken}")
def statusResponse = httpclient.execute(statusGet)
def statusBody = EntityUtils.toString(statusResponse.getEntity())
def json = new JsonSlurper().parseText(statusBody)
def strOverallStatus = json.status_overall
stmt = g_dbQuery.prepare(conn, """
UPDATE DATAGROUP('123456789IX8CC4092E4740444B6E1X123456789')
SET STR_DOKUMENTENSTATUS=?
WHERE STRID=?
""")
stmt.setString(1, strOverallStatus)
stmt.setString(2, STRID)
stmt.executeUpdate()
stmt = Safely.close(stmt)
// ===========================================================
// Update the status of the signaturesin the child data group
// ===========================================================
json.signatures?.each { sig ->
def strEmail = sig?.signer_identity_data?.email_address
def strSigStatus = sig.status_code
stmt = g_dbQuery.prepare(conn, """
UPDATE DATAGROUP('1234567899IX2CEE38FE85FBCB716IX123456789')
SET STR_SIGNIERSTATUS=?
WHERE FKSTRID=? AND STR_EMAIL=?
""")
stmt.setString(1, strSigStatus)
stmt.setString(2, STRID)
stmt.setString(3, strEmail)
stmt.executeUpdate()
stmt = Safely.close(stmt)
}
1. Benötigte Imports für folgenden Aktionen und abfragen
In diesem Schritt werden die benötigten Importe für die folgenden Aktionen abgefragt.
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpGet
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import org.apache.http.client.utils.URIBuilder
import de.uplanet.scripting.groovy.util.Safely
import java.io.File
import java.io.FileOutputStream
2. API-Daten in Intrexx speichern (beispielsweise in der Systemdatengruppe)
Detaillierte Informationen zu den API-Daten finden Sie in der Skribble-Onlinehilfe: Manage API keys
Nachdem Sie den API-Schlüssel erzeugt haben, können Sie sich diesen einmal anzeigen lassen bzw. ihn kopieren.
API-HOST: api.skribble.de
API-USERNAME: "aus Skribble Account"
API-KEY: "aus Skribble Account"
3. PDF aus Intrexx laden & vorbereiten
In diesem Schritt wird die im Datenfeld gespeicherte PDF-Datei ausgelesen. Die Datei wird als Byte-Array geladen und anschließend in einen Base64-String umgewandelt.
Diese Kodierung ist notwendig, da die PDF-Datei später in dieser Form an die Skribble API übertragen wird.
//PDF aus Datenfeld der App
def fileField = g_record["dataFieldGuid"]
if (!fileField || !fileField.value) {
throw new RuntimeException("Keine Datei vorhanden!")
}
def fileDescriptor = fileField.value[0]
def file = fileDescriptor.getFile()
def inputStream = file.newInputStream()
byte[] pdfBytes = inputStream.bytes
inputStream.close()
String base64Pdf = Base64.encoder.encodeToString(pdfBytes)
4. Gespeicherte Titel, Nachricht, Signaturqualität und ggf. Gesetzgebung abfragen
In diesem Schritt werden alle relevanten Informationen, die für die Signaturanfrage benötigt werden, aus dem Datensatz geladen. Dazu gehören der Titel, die Nachricht an die Signierenden sowie die Signaturqualität und - falls erforderlich - die passende Gesetzgebung. Diese Werte werden später in den Request an die Skribble API übernommen.
Gespeicherten Titel
def strTitle = g_record["dataFieldGuid"].value
Gespeicherte Nachricht
def txtMessage = g_record["dataFieldGuid"].value
Gespeicherte Signatur Qualität und Gesetzgebung
def strSignaturQuality = g_record["dataFieldGuid"].value //QES, AES, AES_MINIMAL, SES oder DEMO
def strLegislation = g_record["dataFieldGuid"].value // ZERTE oder EIDAS
5. Signierende mit Reihenfolge & Betrachter ermitteln
In diesem Schritt werden aus einer Kinddatengruppe alle beteiligten Personen geladen.
Dabei werden Signierende (mit Reihenfolge für die Unterschrift) und Betrachter (nur zur Information) unterschieden.
-
Signierende werden inklusive ihrer Reihenfolge (sequence) in eine Liste (signatures) übernommen.
-
Über account_email wird die E-Mail-Adresse des Signierenden an die API übergeben. Existiert bereits ein Skribble-Konto für diese Adresse, wird dieses Konto für den Signaturprozess verwendet.
-
Falls kein Skribble-Konto vorhanden ist, greift die API auf die Angaben in signer_identity_data zurück, um externe Signierende ohne eigenes Skribble-Konto anzulegen. Für externe Signaturen müssen dabei mindestens Vorname, Nachname, E-Mail-Adresse sowie Mobilnummer übergeben werden.
-
Betrachter werden separat als E-Mail-Liste (observer) gespeichert.
-
Die Unterscheidung erfolgt über ein Boolean-Feld (B_OBSERVER).
Diese Daten werden später an die Skribble API übergeben.
try
{
stmt = g_dbQuery.prepare(conn, """
SELECT STR_EMAIL, L_SEQUENCE, STR_FIRSTNAME, STR_NAME, STR_MOBILENUMMER
FROM DATAGROUP('dataGroupGuid')
WHERE FKSTRID=? AND (B_OBSERVER=? OR B_OBSERVER IS NULL)
ORDER BY L_SEQUENCE
""")
stmt.setString(1, STRID)
stmt.setBoolean(2, false)
rs = stmt.executeQuery()
while (rs.next()) {
def strEmail = rs.getStringValue(1)
def iSequence = rs.getIntValue(2)
def strFirstname = rs.getStringValue(3)
def strName = rs.getStringValue(4)
def strMobileNumber = rs.getStringValue(5)
if (strEmail) {
signatures << [
"account_email": strEmail,
"sequence" : iSequence,
"signer_identity_data": [
"email_address": strEmail,
"first_name" : strFirstname,
"last_name" : strName,
"mobile_number": strMobileNumber
]
]
}
}
}
finally
{
rs = Safely.close(rs)
stmt = Safely.close(stmt)
}
def observer = []
try
{
stmt = g_dbQuery.prepare(conn, """
SELECT STR_EMAIL
FROM DATAGROUP('dataGroupGuid')
WHERE FKSTRID=? AND B_OBSERVER=?
""")
stmt.setString(1, STRID)
stmt.setBoolean(2, true)
rs = stmt.executeQuery()
while (rs.next()) {
def strEmail = rs.getStringValue(1)
if (strEmail) {
observer << strEmail
}
}
}
finally
{
rs = Safely.close(rs)
stmt = Safely.close(stmt)
}
6. Authentifizierung bei Skribble
In diesem Schritt wird eine Verbindung zur Skribble API aufgebaut. Dazu wird eine Login-Anfrage mit Username und API-Key gesendet.
Die API prüft die Zugangsdaten und gibt bei Erfolg ein Access Token zurück. Dieses Token wird anschließend gespeichert und für alle weiteren API-Aufrufe (z. B. Signaturanfrage, Statusabfrage, PDF-Download) im Header verwendet.
Falls die Anmeldung fehlschlägt oder kein Token zurückkommt, wird das Skript mit einem Fehler abgebrochen.
def authUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/access/login")
.build()
HttpPost authPost = new HttpPost(authUri)
authPost.setHeader("Content-Type", "application/json")
def authPayload = [
username: API_USERNAME,
"api-key": API_KEY
]
authPost.setEntity(new StringEntity(JsonOutput.toJson(authPayload), "UTF-8"))
def authResponse = httpclient.execute(authPost)
def status = authResponse.getStatusLine().getStatusCode()
def body = EntityUtils.toString(authResponse.getEntity())
if (status != 200) {
throw new RuntimeException("Login fehlgeschlagen: ${status} - ${body}")
}
def accessToken = body?.trim()
if (!accessToken) {
throw new RuntimeException("Kein Access Token erhalten")
}
7. Signatur-Paket zusammenstellen
In diesem Schritt wird das komplette Signatur-Paket zusammengestellt. Zuerst werden die Basisdaten wie Titel, Nachricht, das PDF (als Base64) und die Signierenden zusammengefasst. Anschließend werden, je nach Auswahl, zusätzliche Optionen ergänzt:
-
Wenn eine Signaturqualität gesetzt ist, wird diese mitgegeben. Bei einer qualifizierten Signatur (QES) wird zusätzlich die gesetzliche Grundlage mitgegeben.
-
Optional werden auch Betrachter (CC-Empfänger) hinzugefügt, die den Signaturprozess verfolgen können.
def signPayload = [
"title" : strTitle,
"message" : txtMessage,
"content" : base64Pdf,
"signatures" : signatures
]
if (strSignaturQuality && strSignaturQuality != "DEMO") {
signPayload["quality"] = strSignaturQuality
if (strSignaturQuality== “QES”) {
signPayload["legislation"] = strLegislation
}
}
if (observer && !observer.isEmpty()) {
signPayload["cc_email_addresses"] = observer
}
8. Signatur-Anfrage senden & Request-ID speichern
In diesem Schritt wird die Signatur-Anfrage an die Skribble API gesendet und bei erfolgreicher Erstellung liefert die API eine Request-ID zurück.
Diese ID ist entscheidend, da sie später benötigt wird, um:
-
den Status der Signatur abzufragen
-
die final unterschriebene PDF-Datei herunterzuladen
Die Request-ID wird zunächst im g_sharedState gespeichert. Sie sollte anschließend über ein Datenereignis dauerhaft in einem Datenfeld gesichert werden.
def signUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/signature-requests")
.build()
HttpPost signPost = new HttpPost(signUri)
signPost.setHeader("Content-Type", "application/json")
signPost.setHeader("Authorization", "Bearer ${accessToken}")
signPost.setEntity(new StringEntity(JsonOutput.toJson(signPayload), "UTF-8"))
def signResponse = httpclient.execute(signPost)
def statusCode = signResponse.getStatusLine().getStatusCode()
def signBody = EntityUtils.toString(signResponse.getEntity())
if (statusCode != 200 && statusCode != 201) {
throw new Exception("Signature Request fehlgeschlagen! Status: ${statusCode}\n${signBody}")
}
def signJson = new JsonSlurper().parseText(signBody)
def strRequestID = signJson.id
if (!strRequestID) {
throw new Exception("Keine Request-ID erhalten!")
}
//Request-ID im g_sharedState gespeichert & muss anschließend über ein Datenereignis dauerhaft in einem Datenfeld gesichert werden.
g_sharedState.put("requestId", strRequestID)
9. Status der Signatur abfragen & speichern
In diesem Schritt wird der aktuelle Status der Signatur-Anfrage über die gespeicherte Request-ID bei der Skribble API abgefragt.
-
Der Gesamtstatus (status_overall) wird im Hauptdatensatz gespeichert.
-
Zusätzlich wird der Status jeder einzelnen Signatur (pro Person) in der Kinddatengruppe aktualisiert.
So bleibt der Fortschritt der Unterschrift jederzeit im System nachvollziehbar.
def statusUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/signature-requests/${strRequestID}")
.build()
def statusGet = new HttpGet(statusUri)
statusGet.setHeader("Authorization", "Bearer ${accessToken}")
def statusresponse = httpclient.execute(statusGet)
def statusBody = EntityUtils.toString(statusresponse.getEntity())
def json = new JsonSlurper().parseText(statusBody)
def strOverallStatus = json.status_overall
stmt = g_dbQuery.prepare(conn, """
UPDATE DATAGROUP('dataGroupGuid')
SET STR_DOKUMENTENSTATUS=?
WHERE STRID=?
""")
stmt.setString(1, strOverallStatus)
stmt.setString(2, STRID)
stmt.executeUpdate()
stmt = Safely.close(stmt)
// Status der Signaturen der einzelnen Personen in Kinddatengruppe aktualisieren
json.signatures?.each { sig ->
def strEmail = sig.sig?.signer_identity_data?.email_address
def strSigStatus = sig.status_code
stmt = g_dbQuery.prepare(conn, """
UPDATE DATAGROUP('dataGroupGuid')
SET STR_SIGNIERSTATUS=?
WHERE FKSTRID=? AND STR_EMAIL=?
""")
stmt.setString(1, strSigStatus)
stmt.setString(2, STRID)
stmt.setString(3, strEmail)
stmt.executeUpdate()
stmt = Safely.close(stmt)
}
10. Unterschriebene PDF-Datei herunterladen & speichern
Sobald der Status "SIGNED" erreicht ist, wird die fertige, unterschriebene PDF-Datei über die Skribble API heruntergeladen.
Die Datei wird temporär gespeichert und anschließend direkt in ein Intrexx-Dateifeld des Datensatzes kopiert. Danach wird die temporäre Datei wieder gelöscht.
So steht die unterschriebene Version direkt im System zur Verfügung.
if (json.status_overall == "SIGNED") {
def documentId = json.document_id
def pdfUri = new URIBuilder()
.setScheme("https")
.setHost(API_HOST)
.setPath("/v2/documents/${documentId}/content")
.build()
def pdfGet = new HttpGet(pdfUri)
pdfGet.setHeader("Authorization", "Bearer ${accessToken}")
def pdfResponse = httpclient.execute(pdfGet)
if (pdfResponse.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("PDF Download fehlgeschlagen")
}
File dirTemp = createTemporaryDirectory()
try {
File tmpFile = new File(dirTemp, "Signed_${documentId}.pdf")
FileOutputStream out = new FileOutputStream(tmpFile)
BufferedOutputStream bos = new BufferedOutputStream(out)
pdfResponse.getEntity().writeTo(bos)
bos.close()
out.close()
g_dgFile.copy(
guid: "dataFieldGuid",
id: STRID,
file: tmpFile,
mode: "appendFirst"
)
}
finally {
dirTemp.deleteDir()
pdfResponse.close()
}
}
