streaming iText pdf directly to lotus email using xpages - xpages

i'm trying to stream a newly generated pdf (using itext) directly to the body of lotus notes email as an attachment. but i'm getting following error while setting body of the email from bytes
"com.ibm.jscript.types.GeneratedWrapperObject$StaticField incompatible with com.ibm.jscript.types.FBSValue"
following is my completed code(placed in a button of an xpage). Any help would be greatly appreciated
session.setConvertMIME(false);
outputStream:java.io.ByteArrayOutputStream = new java.io.ByteArrayOutputStream();
writePdf(outputStream);
var bytes = outputStream.toByteArray();
var inputStream:java.io.ByteArrayInputStream = new java.io.ByteArrayInputStream(bytes);
var db:NotesDatabase= session.getDatabase("","mail.box")
if (!db.isOpen()) {
print ("No mailbox!")
}
else
{
var doc:NotesDocument=db.createDocument()
doc.replaceItemValue("Form","Memo")
doc.replaceItemValue("From",context.getUser().getCommonName())
doc.replaceItemValue("Principal",context.getUser().getCommonName())
doc.replaceItemValue("SendTo","a#b.com");
doc.replaceItemValue("Recipients","a#b.com");
doc.replaceItemValue("CopyTo","a#b.com");
doc.replaceItemValue("INetFrom","b#c.com");
var strFileName="temp.pdf"
var body:NotesMIMEEntity = doc.createMIMEEntity('Body');
var hdr:NotesMIMEHeader = body.createHeader("Subject");
hdr.setHeaderValAndParams("Subject")
hdr=body.createHeader("MIME-Version")
hdr.setHeaderValAndParams("1.0")
body.setPreamble("multipart message in MIME")
var child1:NotesMIMEEntity= body.createChildEntity()
hdr = child1.createHeader("Content-Disposition")
hdr.setHeaderValAndParams('attachment; filename="test.pdf"')
var stream:NotesStream = session.createStream();
stream.setContents(inputStream)
child1.setContentFromBytes(stream, "application/pdf", body.ENC_IDENTITY_BINARY)
child1.encodeContent(body.ENC_BASE64)
doc.closeMIMEEntities(true,"Body")
doc.save(true, true);
// Restore conversion
session.setConvertMIME(true);
}
function writePdf(outputStream) {
var document:com.itextpdf.text.Document = new com.itextpdf.text.Document();
var writer = com.itextpdf.text.pdf.PdfWriter.getInstance(document,outputStream);
document.open();
document.addTitle("Test PDF");
document.addSubject("Testing email PDF");
document.addKeywords("iText, email");
document.addAuthor("Author");
document.addCreator("Creator");
var passChunk:com.itextpdf.text.Chunk = new com.itextpdf.text.Chunk("Hello");
document.add(new com.itextpdf.text.Paragraph(passChunk));
document.close();
}

you probably would be better off writing a small Java wrapper class.
For starters you need:
var stream:NotesStream = session.createStream();
stream.setContents(inputStream);
stream.setPosition(0);
so the stream is at the beginning.
Update:
Also you have:
var bytes = outputStream.toByteArray();
var inputStream:java.io.ByteArrayInputStream = new java.io.ByteArrayInputStream(bytes);
stream.setContents(inputStream);
where I would write:
var bytes = outputStream.toByteArray();
stream.write(bytes);
Still, make a helper in Java.
Note: iText is GPL licenced. Unless the application you build is internal use only, you either need to buy a commercial license or GPL your code as well. Look at Apache PDFBox for an alternative

Related

Azure service bus - Read messages sent by .NET Core 2 with BrokeredMessage.GetBody

I am using .NET Core 2 for an application which needs to put a message on the Service bus and read by a legacy .NET 4.6 receiver. The receiver listens to messages from other legacy applications as well.
Legacy sender:
UserData obj = new UserData()
{
id = 1,
name = "Alisha"
};
BrokeredMessage message = new BrokeredMessage(consentInstated);
_client.Send(message);
Legacy Receiver:
var dataObj = objBrokeredMessage.GetBody<UserData>();
businessFunc(dataObj.id, dataObj.name);
.NET Core 2 sender: as described in https://stackoverflow.com/a/45069423/1773900
var ser = new System.Runtime.Serialization.DataContractSerializer(typeof(UserData));
var ms = new MemoryStream();
ser.WriteObject(ms, objUserData);
var message = new Message(ms.ToArray());
_client.Send(message);
However, the reciever fails to deserialize the message and throws the following error
System.Runtime.Serialization.SerializationException: There was an
error deserializing the object of type UserData. The input source is
not correctly formatted. ---> System.Xml.XmlException: The input
source is not correctly formatted.
What can I do to make both senders work with the same receiver?
BrokeredMessage is using XML Binary Reader to deserialize the messages. So your sending part should look like this:
var ser = new DataContractSerializer(typeof(UserData));
var ms = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ms);
ser.WriteObject(binaryDictionaryWriter, obj);
binaryDictionaryWriter.Flush();
var message = new Message(ms.ToArray());
We could send serialize json Object string directly from .net core side, and we could get the message with following code in the .net side. It works correctly on my side.
var dataObj = message.GetBody<UserData>(new DataContractJsonSerializer(typeof(UserData)));
.net core side send message code:
var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(objUserData));
_client.SendAsync(new Message{Body = body,ContentType = "text/plain"}).Wait();
.net side receive message code:
var dataObj = message.GetBody<UserData>(new DataContractJsonSerializer(typeof(UserData)));
I also encountered the same problem, but neither solution worked. For me below code works
// model is the object that you want to sent to Topic
Model model = new Model();
var serializator = new DataContractSerializer(typeof(string));
var json = JsonConvert.SerializeObject(model);
var memoryStream = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memoryStream);
serializator.WriteObject(binaryDictionaryWriter, json);
binaryDictionaryWriter.Flush();
// below message can be sent to Topic via .NET Core and will be properly deserialized in .NET Framework subscriber
var message = new Message(memoryStream.ToArray());
var client = new TopicClient(_endpoint, _channelName );
await client.SendAsync(message);

NodeJS: Updating Exif data and saving image using PIEXIF

I need to update orientation tag(EXIF data) for the uploaded image. I am using "PIEXIF" for this. I am not using express but swagger. The code I've written is:
//Get the uploaded buffer
var _originalBuffer = req.swagger.params.uploadedFile.value.buffer;
let Duplex = require('stream').Duplex;
//Create stream from buffer. This stream is required later to send to cloud.
let _uploadedFileStream = new Duplex();
_uploadedFileStream.push(_originalBuffer);
_uploadedFileStream.push(null);
//Create base 64 string so that "PIEXIF" can read exif data from it.
const jpegData = "data:image/jpeg;base64, " + createStringFromBuffer(_originalBuffer, 'base64');
//Read exif data.
var _exifData = piexif.load(jpegData);
//Create a copy of exif data. Will be used to create a new image with updated orientation tag.
var _exifDataCopied = {};
for (var key in _exifData) {
_exifDataCopied[key] = _exifData[key];
}
//Update orientation tag.
if (_exifDataCopied["0th"][piexif.ImageIFD.Orientation])
_exifDataCopied["0th"][piexif.ImageIFD.Orientation] = 1;
//Example taken from https://www.npmjs.com/package/piexifjs
//From here onwards, there seems to be an issue.
var exifbytes = piexif.dump(_exifDataCopied);
var newData = piexif.insert(exifbytes, createStringFromBuffer(_originalBuffer, 'binary'));
var newJpeg = new Buffer(newData);
//Create a new stream and save it as image back.
let _updatedFileStream = new Duplex();
_updatedFileStream.push(newJpeg);
_updatedFileStream.push(null);
var fs = require('fs');
var writeStream = fs.createWriteStream("./uploads/" + "Whatever.jpg")
The issue is there is no error thrown by the code. The image is also getting saved in the directory but it is corrupted. I can not preview it. Since, the code does not breaks anywhere, I am confused what could be the issue? The function to convert buffer to string with different encoding(since I need it a lot) is:
var createStringFromBuffer = function(_buffer, _encoding) {
return Buffer.from(_buffer).toString(_encoding);
}
Can someone point out where I am mistaking? I am using the example given Here

Docusign - Error opening PDF downloaded through the Rest API

With the REST api, I am trying to get the documents out of a completed envelope. My header is using X-DocuSign-Authentication.
EnvelopesApi ap = new EnvelopesApi();
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
EnvelopeDocumentsResult edr = ap.ListDocuments((AccountId, "xxx-xx-xxx");
List<EnvelopeDocument> docs = edr.EnvelopeDocuments;
foreach(EnvelopeDocument doc in docs)
{
Stream stream1 = ap.GetDocument(AccountId, "xxx-xx-xxx", doc.DocumentId);
StreamReader reader = new System.IO.StreamReader(stream1, encode);
var data = reader.ReadToEnd();
StreamWriter writer = new StreamWriter(#"C:\mysigneddoc.pdf");
writer.Write(data);
writer.Close();
}
When I try to open the completed pdf, I get the error stating that
the signers identity has not been verified.
Any ideas where I might be going wrong?
Please look at the API recipe here to download the documents from an envelope.
var ap = new EnvelopesApi();
var edr = ap.ListDocuments((AccountId, "xxx-xx-xxx");
List<EnvelopeDocument> docs = edr.EnvelopeDocuments;
foreach(EnvelopeDocument doc in docs)
{
// GetDocument() API call returns a MemoryStream
var docStream = (MemoryStream)envelopesApi.GetDocument(accountId, envelopeId, doc.DocumentId);
// let's save the document to local file system
filePath = #"C:\temp\" + Path.GetRandomFileName() + ".pdf";
fs = new FileStream(filePath, FileMode.Create);
docStream.Seek(0, SeekOrigin.Begin);
docStream.CopyTo(fs);
fs.Close();
}
You can also download the combined documents in an envelope using the GetEnvelopeDocuments api. You are not required to query for each individual document.
Combined PDF
Pass the string combined as the documentId.
Retrieve a PDF that contains the combined content of all documents and the certificate.
string envelopeId = "XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
string accountId = "XXXXXX";
var envApi = new EnvelopesApi();
// GetDocument() API call returns a MemoryStream
var docStream = (MemoryStream)envApi.GetDocument(accountId, envelopeId, "combined");
// let's save the document to local file system
string filePath = #"C:\temp\" + Path.GetRandomFileName() + ".pdf";
var fs = new FileStream(filePath, FileMode.Create);
docStream.Seek(0, SeekOrigin.Begin);
docStream.CopyTo(fs);
fs.Close();
ZIP file
Pass the string archive as documentId
Retrieve a ZIP archive that contains all of the PDF documents, the certificate, and any .WAV files used for voice authentication.
var envApi = new EnvelopesApi();
// GetDocument() API call returns a MemoryStream
var docStream = (FileStream)envApi.GetDocument(accountId, envelopeId, "archive");
// let's save the document to local file system
string filePath = #"C:\temp\" + Path.GetRandomFileName() + ".zip";
var fs = new FileStream(filePath, FileMode.Create);
docStream.Seek(0, SeekOrigin.Begin);
docStream.CopyTo(fs);
fs.Close();

copy attachment from other document on fly

After I save my current XPages, in the event postNewDocument of datasources..I would to copy on the fly in the backend Domino Document without saving of disk the attachment from another document andI have found this solution:
var attachments:java.util.Vector = session.evaluate("#AttachmentNames", docReply);
for (var i = 0; i < attachments.size(); i++) {
embeddedObj = docReply.getAttachment(attachments.get(i).toString());
if (embeddedObj != null) {
bufferInStream = new java.io.BufferedInputStream(embeddedObj.getInputStream());
}
}
How how can I add every attachment stream into a RichTextItem of my current Domino Document?
Tnx
update 29 january 14: Tnx to #Sven I have insert this code into my PostSavedocument event..
But now I have another problem...seem that damage the MIME my "Body" that is the rt mime.
If I open with my Notes Client the document with this RT mime I see only the new attachments and not the original HTML content of CKEDITOR (If I comment the follow code...work correct)....Now I have the problem to re-edit exist MIME filed
session.setConvertMime(false);
var doc:NotesDocument=document1.getDocument(true);
var mimeRoot:NotesMIMEEntity=doc.getMIMEEntity("Body");
var docAttach:NotesDocument=database.getDocumentByUNID('XXXXXXXUNID'); //doc where are the attachmetns files MIME or RICHTEXT
var XSPReply=wrapDocument(docAttach); //function in Xsnippets from Opentntf.org
var listattachs=XSPReply.getAttachmentList("Body");
for (var i=0; i<listattachs.length; i++) {
var is=null;
var att = listattachs[i];
var persistentName = att.getPersistentName()==null?att.getName():att.getPersistentName();
var cid = att.getCID();
var eo:NotesEmbeddedObject = docAttach.getAttachment(persistentName);
if (null != eo) {
var child:NotesMIMEEntity=mimeRoot.createChildEntity(); //create child of original mail
var emailHeader:NotesMIMEHeader = child.createHeader("Content-Disposition");
emailHeader.setHeaderVal("attachment; filename=\"" + persistentName+ "\"");
emailHeader = child.createHeader("Content-ID");
emailHeader.setHeaderVal("<" + cid + ">");
var is = new java.io.BufferedInputStream(eo.getInputStream());
var stream:NotesStream = session.createStream();
stream.setContents(is);
child.setContentFromBytes(stream, att.getType(),NotesMIMEEntity.ENC_IDENTITY_BINARY);
}
}
doc.closeMIMEEntities(true,"Body")
doc.save()
session.setConvertMime(true);
You can try to add the attachments as MIME Entities. Have a look here for an example: Link

Apache Thrift with nodejs example

I am trying to use Apache Thrift for passing messages between applications implemented in different languages. It is not necessarily used as RPC, but more for serializing/deserializing messages.
One application is in node.js. I am trying to figure out how Apache thrift works with node.js, but I can't find too much documentation and examples, except for one tiny one regarding Cassandra at:
https://github.com/apache/thrift/tree/trunk/lib/nodejs
Again, I don't need any procedures declared in the .thrift file, I only need to serialize a simple data structure like:
struct Notification {
1: string subject,
2: string message
}
Can anyone help me with an example?
I finally found the answer to this question, after wasting a lot of time just by looking at the library for nodejs.
//SERIALIZATION:
var buffer = new Buffer(notification);
var transport = new thrift.TFramedTransport(buffer);
var binaryProt = new thrift.TBinaryProtocol(transport);
notification.write(binaryProt);
At this point, the byte array can be found in the transport.outBuffers field:
var byteArray = transport.outBuffers;
For deserialization:
var tTransport = new thrift.TFramedTransport(byteArray);
var tProtocol = new thrift.TBinaryProtocol(tTransport);
var receivedNotif = new notification_type.Notification();
receivedNotif.read(tProtocol);
Also the following lines need to be added to the index.js file from the nodejs library for thrift:
exports.TFramedTransport = require('./transport').TFramedTransport;
exports.TBufferedTransport = require('./transport').TBufferedTransport;
exports.TBinaryProtocol = require('./protocol').TBinaryProtocol;
Plus there is also at least one bug in the nodejs library.
The above answer is wrong, because it tries to use outBuffers directly, which is an array of buffers. Here is a working example of using thrift with nodejs:
var util = require('util');
var thrift = require('thrift');
var Notification = require('./gen-nodejs/notification_types.js').Notification;
var TFramedTransport = require('thrift/lib/thrift/transport').TFramedTransport;
var TBufferedTransport = require('thrift/lib/thrift/transport').TBufferedTransport;
var TBinaryProtocol = require('thrift/lib/thrift/protocol').TBinaryProtocol;
var transport = new TFramedTransport(null, function(byteArray) {
// Flush puts a 4-byte header, which needs to be parsed/sliced.
byteArray = byteArray.slice(4);
// DESERIALIZATION:
var tTransport = new TFramedTransport(byteArray);
var tProtocol = new TBinaryProtocol(tTransport);
var receivedNotification = new Notification();
receivedUser.read(tProtocol);
console.log(util.inspect(receivedNotification, false, null));
});
var binaryProt = new TBinaryProtocol(transport);
// SERIALIZATION:
var notification = new Notification({"subject":"AAAA"});
console.log(util.inspect(notification, false, null));
notification.write(binaryProt);
transport.flush();
DigitalGhost is right, the previous example is wrong.
IMHO the outBuffers is a private property to the transport class and should not be accessed.

Resources