I want to attach files to CouchbaseLite document. How can I do so? I did not find any code sample on official CBLite website for this - CBLite code Sample. I am still stuck how to accomplish it.
One way to do this in code is:
Document document = mDatabaseLocal.createDocument();
document.getCurrentRevision().createRevision().setAttachment(name, contentType, contentStream);
But this is not clear. *What should be the name?* - It is the absolute path of the attachment on your local disk?
For contentType: I do not know if there exists any enum class or constants that I can pass as contentType.
How would I attach multiple files to a document? Do I need to create unsavedRevision for every attachment?
The name must be unique per attachment, and doesn't refer to the local file, it refers to the name that you want to fetch it from on the document.
In this case you would call createRevision() once and then setAttachment() multiple times on the revision, before saving it.
you have to put an inputstream as attachment to your document.
A example can be found here CouchBase Attachment Example.
You have to convert each file into an InputStream and then you can set it to the document.
For convert you can use something like this:
private InputStream getAsStream(YourData data)
{
baos = new ByteArrayOutputStream();
try
{
objOstream = new ObjectOutputStream(baos);
objOstream.writeObject(data);
} catch (IOException e)
{
e.printStackTrace();
}
bArray = baos.toByteArray();
bais = new ByteArrayInputStream(bArray);
return bais;
}
In this example YourData can be every object or some of your own objectTypes.
Hope this explanation will help you.
Related
This is a non-xpages application.
I have inherited some code that I need to tweak....this code is used in a drag&drop file attachment subform. Normally, this will create a document in a separate dedicated .nsf that stores only attachments, and uses the main document's universalid as a reference to link the two....I need to change what the reference is to the value in a field already on the main document (where the subform is).
Java is challenging to me, but all I need to do is GET the value of the field from the main document (which has not necessarily been saved yet) and write that string value onto the attachment doc in that storage database, so I think I am just needing help with one line of code.
I will paste the relevant function here and hopefully someone can tell me how I get that value, or what else they need to see what is going on here.
You can see my commented-out attempt to write the field 'parentRef' in this code
...
private void storeUploadedFile( UploadedFile uploadedFile, Database dbTarget) {
File correctedFile = null;
RichTextItem rtFiles = null;
Document doc = null;
String ITEM_NAME_FILES = "file";
try {
if (uploadedFile==null) {
return;
}
doc = dbTarget.createDocument();
doc.replaceItemValue("form", "frmFileUpload");
doc.replaceItemValue("uploadedBy", dbTarget.getParent().getEffectiveUserName() );
Utils.setDate(doc, "uploadedAt", new Date() );
doc.replaceItemValue("parentUnid", parentUnid);
//doc.replaceItemValue("parentRef", ((Document) dbTarget.getParent()).getItemValue("attachmentDocKey"));
//get uploaded file and attach it to the document
fileName = uploadedFile.getClientFileName();
File tempFile = uploadedFile.getServerFile(); //the uploaded file with a cryptic name
fileSize = tempFile.length();
targetUnid = doc.getUniversalID();
correctedFile = new java.io.File( tempFile.getParentFile().getAbsolutePath() + java.io.File.separator + fileName );
//rename the file on the OS so we can embed it with the correct (original) name
boolean success = tempFile.renameTo(correctedFile);
if (success) {
//embed original file in target document
rtFiles = doc.createRichTextItem(ITEM_NAME_FILES);
rtFiles.embedObject(lotus.domino.EmbeddedObject.EMBED_ATTACHMENT, "", correctedFile.getAbsolutePath(), null);
success = doc.save();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
com.gadjj.Utils.recycle(rtFiles, doc);
try {
if (correctedFile != null) {
//rename the temporary file back to its original name so it's automatically
//removed from the os' file system.
correctedFile.renameTo(uploadedFile.getServerFile());
}
} catch(Exception ee) { ee.printStackTrace(); }
}
}
}
...
dbTarget.getParent does not do what you think it does. It returns a Session object that is the parent session containing all your objects. Casting it to (Document) won't give you your main document.
I don't see the declaration for it, but you appear to have a variable available called parentUNID. You can use it to get a handle on the main document.
You need to use the parentUNID value in a call to getDocumentByUNID() in order to retrieve the Document object representing your main document. But in order to do that, you need the Database object for the nsf file containing the main document, and if I understand you correctly, that is a different database than targetDb.
I'm going to have to assume that you already have that Database object in a variable called parentDb, or that you know the path to the NSF and can open it. In either case, your code would look like this (without error handling):
Document parentDoc = parentDb.getDocumentByUNID(parentUNID);
doc.replaceItemvalue("parentRef", parentDoc.getItemValue("attachmentDocKey"));
I have a spring boot application and I am trying to merge two pdf files. The one I am getting as a byte array from another service and the one I have it locally in my resources file: /static/documents/my-file.pdf. This is the code of how I am getting byte array from my file from resources:
public static byte[] getMyPdfContentForLocale(final Locale locale) {
byte[] result = new byte[0];
try {
final File myFile = new ClassPathResource(TEMPLATES.get(locale)).getFile();
final Path filePath = Paths.get(myFile.getPath());
result = Files.readAllBytes(filePath);
} catch (IOException e) {
LOGGER.error(format("Failed to get document for local %s", locale), e);
}
return result;
}
I am getting the file and getting the byte array. Later I am trying to merge this two files with the following code:
PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
pdfMergerUtility.addSource(new ByteArrayInputStream(offerDocument));
pdfMergerUtility.addSource(new ByteArrayInputStream(merkblattDocument));
ByteArrayOutputStream os = new ByteArrayOutputStream();
pdfMergerUtility.setDestinationStream(os);
pdfMergerUtility.mergeDocuments(null);
os.toByteArray();
But unfortunately it throws an error:
throw new IOException("Page tree root must be a dictionary");
I have checked and it makes this validation before it throws it:
if (!(root.getDictionaryObject(COSName.PAGES) instanceof COSDictionary))
{
throw new IOException("Page tree root must be a dictionary");
}
And I really have no idea what does this mean and how to fix it.
The strangest thing is that I have created totally new project and tried the same code to merge two documents (the same documents) and it works!
Additionally what I have tried is:
Change the spring boot version if it is ok
Set the mergeDocuments method like this: pdfMergerUtility.mergeDocuments(setupMainMemoryOnly())
Set the mergeDocuments method like this: pdfMergerUtility.mergeDocuments(setupTempFileOnly())
Get the bytes with a different method not using the Files from java.nio:
And also executed this in a different thread
Merging files only locally stored (in resources)
Merging the file that I am getting from another service - this works btw and that is why I am sure he is ok
Can anyone help with this?
The issue as Tilman Hausherr said is in that resource filtering that you can find in your pom file. If you have a case where you are not allowed to modify this then this approach will help you:
final String path = new
ClassPathResource(TEMPLATES.get(locale)).getFile().getAbsolutePath();
final File file = new File(path);
final Path filePath = Paths.get(file.getPath());
result = Files.readAllBytes(filePath);
and then just pass the bytes to the pdfMergerUtility object (or even the whole file instead of the list of bytes).
This is really getting into my nerve...
I already have all the ecore models up and running but I've been unable to load an XML file into those models.This is the code I'm using to do so:
ResultType res = ScheduleTableFactory.eINSTANCE.createResultType();
ByteArrayInputStream is;
try {
/* Read XML file to a string and send it to a buffer */
is = new ByteArrayInputStream((this.xml2String(fileName)).getBytes("UTF-8"));
ResourceSet rs = new ResourceSetImpl();
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml",
new ScheduleTableResourceFactoryImpl());
Map options = new Properties();
// Just a dummy url to specify the type of the document
URI uri = URI.createURI("http://www.baderous.de/doomz/trankz.xml");
ScheduleTableResourceImpl resource = (ScheduleTableResourceImpl) rs.createResource(uri);
((org.eclipse.emf.ecore.resource.Resource) resource).load(is, options);
}
catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
After a long struggle, now it's reaching the last method inside the try block, but it's giving me this error:
org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Value '2013-04-23.07:55:00' is not legal. (http://www.baderous.de/doomz/trankz.xml, 4, 56)
I wanted to be more precise in this description, but I'm quite new with EMF, so I will just stick to the basics. I would be really grateful if you can help me on this issue.
Thanks in advance!
Try to enclose the value '2013-04-23.07:55:00' in the block CDATA.
The problem was that the date format couldn't be handled, so I had to edit the model in EMf, and now I'm treating dates as Strings.And now everything is working properly!
Hope that in the future someone can benefit from this answer, and save some time.
I want to create and return a zip file from my server using JaxRS. I don't think that I want to create an actual file on the server, if possible I would like to create the zip on the fly and pass that back to the client. If I create a huge zip file on the fly will I run out of memory if too many files are in the zip file?
Also I am not sure the most efficient way to do this. Here is what I was thinking but I am very rusty when it comes to input/output in java.
public Response getFiles() {
// These are the files to include in the ZIP file
String[] filenames = // ... bunch of filenames
byte[] buf = new byte[1024];
try {
// Create the ZIP file
ByteArrayOutputStream baos= new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(baos));
// Compress the files
for (String filename : filenames) {
FileInputStream in = new FileInputStream(filename);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(filename));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
ResponseBuilder response = Response.ok(out); // Not a 100% sure this will work
response.type(MediaType.APPLICATION_OCTET_STREAM);
response.header("Content-Disposition", "attachment; filename=\"files.zip\"");
return response.build();
} catch (IOException e) {
}
}
Any help would be greatly appreciated.
There are two options:
1- Create ZIP in a temporal directory and then dump to client.
2- Use OutputStream from the Response to send zip directly to the client, when you are creating them.
But never use memory to create huge ZIP file.
There's no need to create the ZIP file from the first to the last byte in the memory before serving it to the client. Also, there's no need to create such a file in temp directory in advance as well (especially because the IO might be really slow).
The key is to start streaming the "ZIP response" and generating the content on the flight.
Let's say we have a aMethodReturningStream(), which returns a Stream, and we want to turn each element into a file stored in the ZIP file. And that we don't want to keep bytes of each element stored all the time in any intermediate representation, like a collection or an array.
Then such a pseudocode might help:
#GET
#Produces("application/zip")
public Response generateZipOnTheFly() {
StreamingOutput output = strOut -> {
try (ZipOutputStream zout = new ZipOutputStream(strOut)) {
aMethodReturningStream().forEach(singleStreamElement -> {
try {
ZipEntry zipEntry = new ZipEntry(createFileName(singleStreamElement));
FileTime fileTime = FileTime.from(singleStreamElement.getCreationTime());
zipEntry.setCreationTime(fileTime);
zipEntry.setLastModifiedTime(fileTime);
zout.putNextEntry(zipEntry);
zout.write(singleStreamElement.getBytes());
zout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
};
return Response.ok(output)
.header("Content-Disposition", "attachment; filename=\"generated.zip\"")
.build();
}
This concept relies on passing a StreamingOutput to the Response builder. The StreamingOutput is not a full response/entity/body generated before sending the response, but a recipe used to generate the flow of bytes on-the-fly (here wrapped into ZipOutputStream). If you're not sure about this, then maybe set a breakpoint next on flush() and observe the a download progress using e.g. wget.
The key thing to remember here is that the stream here is not a "wrapper" of pre-computed or pre-fetched items. It must be dynamic, e.g. wrapping a DB cursor or something like that. Also, it can be replaced by anything that's streaming data. That's why it cannot be a foreach loop iterating over Element[] elems array (with each Element having all the bytes "inside"), like
for(Element elem: elems)
if you'd like to avoid reading all items into the heap at once before streaming the ZIP.
(Please note this is a pseudocode and you might want to add better handling and polish other stuff as well.)
I need to write something into a text file's beginning. I have a text file with content and i want write something before this content. Say i have;
Good afternoon sir,how are you today?
I'm fine,how are you?
Thanks for asking,I'm great
After modifying,I want it to be like this:
Page 1-Scene 59
25.05.2011
Good afternoon sir,how are you today?
I'm fine,how are you?
Thanks for asking,I'm great
Just made up the content :) How can i modify a text file like this way?
You can't really modify it that way - file systems don't generally let you insert data in arbitrary locations - but you can:
Create a new file
Write the prefix to it
Copy the data from the old file to the new file
Move the old file to a backup location
Move the new file to the old file's location
Optionally delete the old backup file
Just in case it will be useful for someone here is full source code of method to prepend lines to a file using Apache Commons IO library. The code does not read whole file into memory, so will work on files of any size.
public static void prependPrefix(File input, String prefix) throws IOException {
LineIterator li = FileUtils.lineIterator(input);
File tempFile = File.createTempFile("prependPrefix", ".tmp");
BufferedWriter w = new BufferedWriter(new FileWriter(tempFile));
try {
w.write(prefix);
while (li.hasNext()) {
w.write(li.next());
w.write("\n");
}
} finally {
IOUtils.closeQuietly(w);
LineIterator.closeQuietly(li);
}
FileUtils.deleteQuietly(input);
FileUtils.moveFile(tempFile, input);
}
I think what you want is random access. Check out the related java tutorial. However, I don't believe you can just insert data at an arbitrary point in the file; If I recall correctly, you'd only overwrite the data. If you wanted to insert, you'd have to have your code
copy a block,
overwrite with your new stuff,
copy the next block,
overwrite with the previously copied block,
return to 3 until no more blocks
As #atk suggested, java.nio.channels.SeekableByteChannel is a good interface. But it is available from 1.7 only.
Update : If you have no issue using FileUtils then use
String fileString = FileUtils.readFileToString(file);
This isn't a direct answer to the question, but often files are accessed via InputStreams. If this is your use case, then you can chain input streams via SequenceInputStream to achieve the same result. E.g.
InputStream inputStream = new SequenceInputStream(new ByteArrayInputStream("my line\n".getBytes()), new FileInputStream(new File("myfile.txt")));
I will leave it here just in case anyone need
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (FileInputStream fileInputStream1 = new FileInputStream(fileName1);
FileInputStream fileInputStream2 = new FileInputStream(fileName2)) {
while (fileInputStream2.available() > 0) {
byteArrayOutputStream.write(fileInputStream2.read());
}
while (fileInputStream1.available() > 0) {
byteArrayOutputStream.write(fileInputStream1.read());
}
}
try (FileOutputStream fileOutputStream = new FileOutputStream(fileName1)) {
byteArrayOutputStream.writeTo(fileOutputStream);
}