How should a RESTful server save user submitted images to file? - java

Currently, I am using ImageIO.write() in order to write to file. However, this method opens up a Java App on my computer, which then forcefully aborts the Bootstrap process if closed, thereby killing the 'server'. I'm testing locally, using IntelliJ, and the termination of the Bootstrap process means that we are unable to test the functionality without rebooting the server.
My method is below. It runs on an API call from our front-end.
/**
* Saves image to database, assuming that the input is not null or empty.
* #param filename name of file.
* #param fileext extension of file.
* #param uri uri in string form.
*/
public static void saveImageToDisk(String filename, String fileext, String uri) {
try {
String[] components = uri.split(",");
String img64 = components[1];
byte[] decodedBytes = DatatypeConverter.parseBase64Binary(img64);
BufferedImage bfi = ImageIO.read(new ByteArrayInputStream(decodedBytes));
File outputfile = new File(IMAGESTORAGEFOLDER + filename + "." + fileext);
ImageIO.write(bfi, fileext, outputfile);
bfi.flush();
} catch(Exception e) {
e.printStackTrace();
}
}
My question is as follows: How can I save an image (from Raw Data) to file without the server aborting? If my code can be adapted with minimal rewrite, what other improvements can I make to robustify my existing code? I would like a solution with no external dependencies (relying entirely on standard Java libraries).
I am on MacOSX, running IntelliJ IDEA CE. Our server runs with Spark and uses Maven.
Thank you very much.

ImageIO.write() [...] method opens up a Java App on my computer
The issue here is that when you use the ImageIO class, it will also initialize the AWT because of some dependencies in the Java2D class hierarchy. This causes the Java launcher on OS X to also open up an icon in the dock and some other things, and I believe this is what you experience. There's really no new Java application being launched.
You can easily avoid this by passing a system property to the Java launcher at startup, telling it to run in "headless" mode. This is usually appropriate for a server process. Pass the following on the command line (or in the IntelliJ launch dialog):
-Djava.awt.headless=true
Read more about headless mode from Oracle's pages. Headless mode is the cross-platform way of doing this. There's also an OS X/MacOS specific way to hide the icon from the dock (-Dapple.awt.UIElement=true, but I don't recommend that here.
However, for your use case it's better to avoid the usage of ImageIO altogether. It's easier, more compatible, faster, and uses less memory as a bonus. Simply write the Base64 decoded bytes directly to disk. There's no need to treat a file containing an image differently from any other file in this case.
You can rewrite your method as follows:
public static void saveImageToDisk(String filename, String fileext, String uri) {
try {
String[] components = uri.split(",");
String img64 = components[1];
byte[] decodedBytes = DatatypeConverter.parseBase64Binary(img64);
File outputfile = new File(IMAGESTORAGEFOLDER, filename + "." + fileext);
Paths.write(outputFile.toPath(), decodedBytes);
} catch(Exception e) {
// You really shouldn't swallow this exception, but I'll leave that to you...
e.printStackTrace();
}
}

After running multiple users at the same time, running the process multiple times, etc, it seems to just be an artifact of either Java's ImageIO or IntelliJ. As long as the new process is not closed, Bootstrap continues to run properly, even if multiple browsers try to upload images, etc.

Related

CodenameOne - filesystem access problems on iOS for Library folder

My CodenameOne app is being tested on the iOS simulator (iPad 8th iOS 14).
It writes some files in the private folder by means of this method:
public void writeFile() throws IOException {
try(OutputStream os = FileSystemStorage.getInstance().openOutputStream(Utils.getRootPath()+DATA_FILE);)
{
os.write(JSONText.getBytes("UTF-8"));
os.flush();
os.close();
} catch(IOException err) {
System.out.println("exception trying to write");
}
}
It works on the CN simulator (writes inside the .cn1/ folder)
but on iOS the exception is catched. The Library folder is of paramount importance on iOS.
Below is the method to get the root path
public static String getRootPath()
{
String documentsRoot=FileSystemStorage.getInstance().getRoots()[0];
String os=Display.getInstance().getPlatformName();
if (os.toLowerCase().contains("ios")) {
int pos=documentsRoot.lastIndexOf("Documents");
if (pos==-1) return documentsRoot+"/";
String libraryRoot=documentsRoot.substring(0,pos)+"Library";
String result=libraryRoot+"/";
return result;
}
The CN version of my app has to write those private files in the same location as the swift version, that is Library.
There is string manipulation, and no extra '/' are added, the file path seems legit.
So the string
file:///Users/mac/Library/Developer/CoreSimulator/Devices/alphanumeric-string/data/Containers/Data/Application/another-alphanumeric-string/Documents/
is transformed and
the getRootPath() method returns
file:///Users/mac/Library/Developer/CoreSimulator/Devices/alphanumeric-string/data/Containers/Data/Application/another-alphanumeric-string/Library/
But there is exception.
Furthermore, at some point after the writing attempt, I see in the console output something I think is relevant:
Failed to create directory /Users/mac/Library/Developer/CoreSimulator/Devices/alphanumeric-string/data/Containers/Data/Application/another-alphanumeric-string/Documents/cn1storage/
What is this? Is it related to my problem?
Is CN filesystem access broken or flawed?
I know io access permissions are automatically created by the CN compiler, but are they working?
So how to fix my issue about the Library folder?
The cn1storage printout just means the storage directory already exists.
The way to get the library path is this: Getting an iOS application's "~/Library" path reliably
You need to use that approach. I think your assumption that Document and Library reside under the exact same hierarchy is just incorrect.

IOException: StreamClosed Without Apparent Cause

I have created a program in Java that I want packaged into an executable jar file. I want this program to take images from the jar file and display them. I created an abstract class with a method to take a String filename and return an Image object. However, when I try to run this method, it fails and produces an "IOException: Stream closed" error.
I can't find anything on why the stream is closed. I don't have any other input streams in my program, as far as I know. Using the method in a new main with nothing but a JFrame set-up still produces the same error.
Whether I call the image file only by its name (i.e. "example.png") or use its relative path (i.e. "/src/icons/example.png"), OR use its absolute path (i.e. "C:/Users/My_Name/Desktop/EXAMPLE/src/icons/example.png") I receive the same stream closed error.
public static Image importImage(String fileName) throws IOException {
Image img = null;
byte[] data = new byte[10000];
BufferedInputStream bis = new BufferedInputStream( Thread.currentThread().getClass().getResourceAsStream(fileName));
int byteRead = bis.read(data, 0, 10000);
img = Toolkit.getDefaultToolkit().createImage(data);
return img;
}
I expect the program to accept the name of the image file in question, and return an Image object. The image file is on the project's classpath, and should be visible.
Okay. So as it turns out, a method like this has two requirements: One, you have to call 'thisClassName.class.getResourceAsStream(fileName).' Exactly like that. You also need to have your fileName start with '/' or it will completely not work. But, as long as the resources you are looking for are included in your program's classpath, it should work from there.

Load a file from assets folder in android studio

I was wondering if there is a way to access a file and it's path from my assets folder in android studio? The reason why I need to access the file and its path is because I am working with a method that REQUIRES the String path for a file, and it must access the file from its String path. However, in android studio I haven't found a way to access the file directly from the String value of its path. I decided to use a workaround and simply read the file from an InputStream and write the file to an OutputStream, but the file is about 170MB, and it is too memory intensive to write the File to an OutputStream. It takes my application about 10:00 Minutes to download the file when I implement that strategy. I have searched all over this website and numerous sources to find a solution (books and documentation) but am unable to find a viable solution. Here is an example of my code:
#Override
public Model doInBackground(String... params){
try {
String filePath = context.getFilesDir() + File.separator + "my_turtle.ttl";
File destinationFile = new File(filePath);
FileOutputStream outputStream = new FileOutputStream(destinationFile);
AssetManager assetManager = context.getAssets();
InputStream inputStream = assetManager.open("sample_3.ttl");
byte[] buffer = new byte[10000000];
int length = 0;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
outputStream.close();
inputStream.close();
model = ModelFactory.createDefaultModel();
TDBLoader.loadModel(model, filePath, false);//THIS METHOD REQUIRES THE FILE PATH.
MainActivity.presenter.setModel(model);
}catch(FileNotFoundException e){
e.printStackTrace(System.out);
}
catch(IOException e){
e.printStackTrace(System.out);
}
return model;
}
As you can see the TDBLoader.loadModel() method requires a String for the file URI as the second argument, so it would be convenient to have the ability to access the File directly from my assets folder without utilizing an InputStream. The method takes as an argument (Model model, String url, Boolean showProgress). As I mentioned, the current strategy I am using utilizes too much memory and either crashes the Application entirely, or takes 10 minutes to download the file I need. I am using an AsyncTask to perform this operation, but due to the length of time required to perform the task that kind of defeats the purpose of an AsyncTask in this scenario.
What further complicates things is that I have to use an old version of Apache Jena because I am working with Android Studio and the official version of Apache Jena is not compatible with android studio. So I have to use a port that is 8 years old which doesn't have the updated classes that Apache Jena offers. If I could use the RDFParser class I could pass an InputStream, but that class does not exist in the older version of Apache Jena that I must use.
So I am stuck at this point. The method must utilize the String url path of the file in my assets folder, but I don't know how to access this without writing to a custom file from an InputStream, but writing to the file from the InputStream utilizes too much memory and forces the App to crash. If anyone has a solution I will greatly appreciate it.
Here is an example of my code
new byte[10000000] may fail, as you may not have a single contiguous block of memory that big. Plus, you might not have that much heap space to begin with. Use a smaller number, such as 65536.
It takes my application about 10:00 Minutes to download the file when I implement that strategy
The time will vary by hardware. I would not expect it to be that slow on most devices, but it could be on some.
I was wondering if there is a way to access a file and it's path from my assets folder in android studio?
You are running your app on Android. Android Studio is not running on Android. Assets are not files on the Android device. They are entries in the APK file, which is basically a ZIP archive. In effect, your code is unZIPping 170MB of material and writing it out to a file.
If anyone has a solution I will greatly appreciate it.
Work with some people to port over an updated version of Jena that offers reading RDF from an InputStream.
Or switch to some other RDF library.
Or work with the RDF file format directly.
Or use a smaller RDF file, so the copy takes less time.
Or download the RDF file, if you think that will be preferable to copying over the asset.
Or do the asset-to-file copying in a foreground JobIntentService, updating the progress in its associated Notification, so that the user can do other things on their device while you complete the copy.

How to open a file without saving it to disk

My Question: How do I open a file (in the system default [external] program for the file) without saving the file to disk?
My Situation: I have files in my resources and I want to display those without saving them to disk first. For example, I have an xml file and I want to open it on the user's machine in the default program for reading xml file without saving it to the disk first.
What I have been doing: So far I have just saved the file to a temporary location, but I have no way of knowing when they no longer need the file so I don't know when/if to delete it. Here's my SSCCE code for that (well, it's mostly sscce, except for the resource... You'll have to create that on your own):
package main;
import java.io.*;
public class SOQuestion {
public static void main(String[] args) throws IOException {
new SOQuestion().showTemplate();
}
/** Opens the temporary file */
private void showTemplate() throws IOException {
String tempDir = System.getProperty("java.io.tmpdir") + "\\BONotifier\\";
File parentFile = new File(tempDir);
if (!parentFile.exists()) {
parentFile.mkdirs();
}
File outputFile = new File(parentFile, "template.xml");
InputStream inputStream = getClass().getResourceAsStream("/resources/template.xml");
int size = 4096;
try (OutputStream out = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[size];
int length;
while ((length = inputStream.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
inputStream.close();
}
java.awt.Desktop.getDesktop().open(outputFile);
}
}
Because of this line:
String tempDir = System.getProperty("java.io.tmpdir") + "\\BONotifier\\";
I deduce that you're working on Windows. You can easily make this code multiplatform, you know.
The answer to your question is: no. The Desktop class needs to know where the file is in order to invoke the correct program with a parameter. Note that there is no method in that class accepting an InputStream, which could be a solution.
Anyway, I don't see where the problem is: you create a temporary file, then open it in an editor or whatever. That's fine. In Linux, when the application is exited (normally) all its temporary files are deleted. In Windows, the user will need to trigger the temporary files deletion. However, provided you don't have security constraints, I can't understand where the problem is. After all, temporary files are the operating system's concern.
Depending on how portable your application needs to be, there might be no "one fits all" solution to your problem. However, you can help yourself a bit:
At least under Linux, you can use a pipe (|) to direct the output of one program to the input of another. A simple example for that (using the gedit text editor) might be:
echo "hello world" | gedit
This will (for gedit) open up a new editor window and show the contents "hello world" in a new, unsaved document.
The problem with the above is, that this might not be a platform-independent solution. It will work for Linux and probably OS X, but I don't have a Windows installation here to test it.
Also, you'd need to find out the default editor by yourself. This older question and it's linked article give some ideas on how this might work.
I don't understand your question very well. I can see only two possibilities to your question.
Open an existing file, and you wish to operate on its stream but do not want to save any modifications.
Create a file, so that you could use file i/o to operate on the file stream, but you don't wish to save the stream to file.
In either case, your main motivation is to exploit file i/o existingly available to your discretion and programming pleasure, am I correct?
I have feeling that the question is not that simple and this my answer is probably not the answer you seek. However, if my understanding of the question does coincide with your question ...
If you wish to use Stream io, instead of using FileOutputStream or FileInputStream which are consequent to your opening a File object, why not use non-File InputStream or OutputStream? Your file i/o utilities will finally boil down to manipulating i/o streams anyway.
http://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html
http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
No need to involve temp files.

How to find and load a file within a Java Applet using getCodeBase()?

First time posting here, will try to be succinct. This is a classic 'can't access file within an Applet' problem, but I'm having a particular difficulty with it.
I'm trying to rewrite this file:
A JavaSound test for libpd
into a template applet to load libpd (https://github.com/libpd/libpd) patches made in PureData (puredata.info)...this already works in a normal Main function in a non-applet Java program (see above), where the main function finds the patch using:
PdBase.openAudio(0, outChans, (int) sampleRate);
int patch = PdBase.openPatch("samples/com/noisepages/nettoyeur/libpd/sample/test.pd");
PdBase.computeAudio(true);
The reason it tries to load the path and file into a int variable is that the core function itself does this with:
public synchronized static int openPatch(File file) throws IOException {
if (!file.exists()) {
throw new FileNotFoundException(file.getPath());
}
String name = file.getName();
File dir = file.getParentFile();
long ptr = openFile(name, (dir != null) ? dir.getAbsolutePath() : ".");
if (ptr == 0) {
throw new IOException("unable to open patch " + file.getPath());
}
int handle = getDollarZero(ptr);
patches.put(handle, ptr);
return handle;
}
public synchronized static int openPatch(String path) throws IOException {
return openPatch(new File(path));
}
This is because PD tries to identify each patch by giving an int 'handle' (dollarZero, for legacy reasons), so that int handle gets passed around to open and close the patch file.
So now. I'm trying to load the same file in an Applet, so since I believe it runs 'in the client' and won't know what path I'm talking about, I read up on java.net.URL and tried to build variations of:
patchURL = new URL("test.pd");
PdBase.openPatch(patchURL.getPath().toString());
and
URL url = this.getClass().getResource("test.pd");
inspired by previous questionsin the init() and start() functions of the applet, turning the original main into a local static method sound().
All I get is null pointers. I would've thought all I needed was a simple getDocumentBase(), but can't seem to make it work. Anyone?
libpd is just a thin wrapper on top of Pure Data, and Pure Data doesn't know about URLs or input streams in Java. The openPatch method merely sends the patch name and directory to Pd, and then Pd will try to open the corresponding file. So, applets are out, unless you're willing to tinker with security policies.
About finding files, the simple sample program is part of the libpd Eclipse project. It's meant to be run in Eclipse, and the hard-coded path to the patch is relative to the project root in Eclipse. If you want your code to run in a different setting, you have to adjust your paths accordingly.

Categories

Resources