delete file after serving over HTTP in play framework - java - java

How do i delete a file after serving it over http,
Files.TemporaryFile file = null;
try {
file = new Files.TemporaryFile(f);
return ok().sendFile(file.file());
} catch (IllegalArgumentException e) {
return badRequest(Json.newObject().put("message", e.getMessage()));
} finally {
file.clean();
}
with this code, the file gets deleted before it is served. i receive an empty file on the client.

Play framework in version 2.8 should support onClose argument in sendFile method also in Java (so far it seems to be supported only in Scala version).
In older versions (I have tried only on 2.7.x) you may apply the same approach like in the fix for 2.8, so:
public Result doSomething() {
final File fileToReturn = ....;
final Source<ByteString, CompletionStage<IOResult>> source = FileIO.fromFile(fileToReturn);
return Results.ok().streamed(wrap(source, () -> fileToReturn.delete()), Optional.of(fileToReturn.length()), Optional.of("content type, e.g. application/zip"));
}
private Source<ByteString, CompletionStage<IOResult>> wrap(final Source<ByteString, CompletionStage<IOResult>> source, final Runnable handler) {
return source.mapMaterializedValue(
action -> action.whenCompleteAsync((ioResult, exception) -> handler.run())
);
}

From reading the JavaFileUpload documentation for 2.6.x, it sounds like you don't need that finally block to clean up the file afterwards. Since you are using a TemporaryFile, garbage collection should take care of deleting the resource:
...the idea behind TemporaryFile is that it’s only in scope at completion and should be moved out of the temporary file system as soon as possible. Any temporary files that are not moved are deleted [by the garbage collector].
The same section goes on to describe that there is the potential that the file will not get garbage collection causing Denial Of Service issues. If you find that the files are not getting removed, then you can use the TemporaryFilesReaper:
However, under certain conditions, garbage collection does not occur in a timely fashion. As such, there’s also a play.api.libs.Files.TemporaryFileReaper that can be enabled to delete temporary files on a scheduled basis using the Akka scheduler, distinct from the garbage collection method.

I am not forcing all the project, but you can use a Scala for only this controller, then you can use onClose parameter of the sendFile method. The only attention - that parameter is not workable in all versions, it looks like in 2.5 there was an issue so it was not triggered (was not work: https://github.com/playframework/playframework/issues/6351).
Another way - you can use Akka streams, like here: https://www.playframework.com/documentation/2.6.x/JavaStream#Chunked-responses.

Related

How can I properly set up this endpoint?

I'm making an URL shortener with the Javalin framework and have this endpoint set up:
app.routes(()->{
path("",()->{
get("/:id", ctx->{
//do stuff
ctx.redirect("somewhere.com");
});
});
});
Problem is when I need to serve a javascript file to load into my html files. It tries to load from http://localhost:7000/qrcode.min.js but ends up going to the endpoint mentioned above. From what I read in the documentation this is normal behaviour, Javalin first runs the endpoint handler and then (if it doesn't find an endpoint) runs the file handler.
So how can I fix this? should I define a GET request at "/qrcode.min.js"?, I dont think the javalin context handler has a function that lets me return a .js file.
As Matt already suggested in a comment, it would be way cleaner if you'd prefix either path. That way, you could have /r/:id (or /u/:id with "u" for "URL") and the static files would not get in your way, or you could prefix your static files with e.g. /static/, or even just /s/ for brevity, and your shortened URLs would not get in your way.
If you, however, prefer to stick with your current scheme, you can simply filter out JavaScript files (or any other non-id request) in the handler and instead provide the file (however, if you previously had auto-generated ETags, you'd lose caching if you don't want to handle that yourself).
The latter solution would look like so:
app.routes (() -> {
path ("", () -> {
get ("/:id", ctx -> {
String id = ctx.pathParam ("id");
if (id.endsWith (".js")) {
String resourcePath = "your/classpath/resources/folder/" + id;
try {
InputStream resultStream = Thread.currentThread ()
.getContextClassLoader ()
.getResourceAsStream (resourcePath);
if (resultStream == null)
throw new NullPointerException ("Script not found");
ctx.contentType ("application/javascript");
ctx.result (resultStream);
} catch (NullPointerException e) { // script does not exist
e.printStackTrace (); // for development only!
ctx.status (404);
}
return;
}
// do stuff
ctx.redirect ("somewhere.com");
});
});
});
Depending on your preference, you can also handle the resultStream == null case where my code is currently throwing an NPE to be caught by the outer try/catch and omit the try/catch completely.
Setting the Content-Type is essential so that the browser knows that you're actually responding with JavaScript code. Also, I'm typically using Thread.currentThread ().getContextClassLoader () because we'd want the resource to be resolved based upon the current HTTP handler thread, which could, in theory, have a different class path/class loader than the class we're currently in.
Please note that, as stated above, this will not support client-side caching as the handler simply ignores all ETag headers sent with the request* and instead respond with the complete file which, with many requests in a short amount of time and large scripts, will certainly put way more stress on your disks and CPUs.
Thus, I'd actually recommend to prefix the static files route and let Javalin/Jetty handle all the caching and files magic.
* Actually, the header sent by the client is If-None-Match most of the time. The server would respond with an ETag to allow for caching in the browser.

Java Application with Single Instance per User

currently I am struggling with the problem of a single instance JavaFX application, packed into an .exe using install4j. The application should run on a Windows terminal server and every user should only be able to run one instance of it. Meaning, Alice and Bob may use separate instances of the application but Alice may only have one instance open.
Writing a lock file with the process id is not a viable option, since the application is targed at Java 8, which has no consistent possibility to retrieve the process id. Opening a socket is also not a desirable solution, as there can be many instances on the same host. Moreover I suppose admins would not be that happy if some application randomly opened sockets on their server...
As I am using install4j to pack the application, I toggled the 'single instance only' feature which seems to run well when connected via a full RDP session. However, the application may be deployed using the RemoteApp feature which in some way circumvents install4j's checking mechanism, allowing one instance to be launched in a RDP session and another by using the RemoteApp.
This leads me to two questions:
How does the install4j check work? (I was not able to find any details...)
What would be the best solution to ensure a single instance per user at all times? (And also be failsafe, e.g. recover from JVM crashes)
Regarding the possibility of FileLock: as different operating system may handle file locks differently, can it be assured that the file lock is exclusively acquired by one JVM instance on the whole system?
Sockets will be a bit problematic if you want the application to run concurrently under different users.
The option of using an NIO FileLock is possible. You create the file under the user's directory so that another user can have his own lock file. The key thing to do here is to still try to acquire the file lock if the file exists already, by attempting to delete it before recreating it. This way if the application crashes and the file is still there, you will still be able to acquire a lock on it. Remember that the OS should release all locks, open file handles and system resources when a process terminates.
Something like this:
public ExclusiveApplicationLock
throws Exception {
private final File file;
private final FileChannel channel;
private final FileLock lock;
private ExclusiveApplicationLock() {
String homeDir = System.getProperty("user.home");
file = new File(homeDir + "/.myapp", app.lock");
if (file.exists()) {
file.delete();
}
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.tryLock();
if (lock == null) {
channel.close();
throw new RuntimeException("Application already running.");
}
Runtime.getRuntime().addShutdownHook(new Thread(() -> releaseLock());
}
private void releaseLock() {
try {
if (lock != null) {
lock.release();
channel.close();
file.delete();
}
}
catch (Exception ex) {
throw new RuntimeException("Unable to release application process lock", ex);
}
}
}
Another alternative is to use a library that does this for you like Junique. I haven't tried it myself but you could have a go. It seems very old but I guess there isn't much that needs to change in something like this, nothing much changed in NIO since Java 1.4.
http://www.sauronsoftware.it/projects/junique/
It is on Maven Central though so you can import it easily.
https://mvnrepository.com/artifact/it.sauronsoftware/junique/1.0.4
If you look at the code you will see that it does the same thing with file locks:
https://github.com/poolborges/it.sauronsoftware.junique/blob/master/src/main/java/it/sauronsoftware/junique/JUnique.java
As for 1: On Windows, install4j launchers create a semaphore with the CreateSemaphore function in the Windows API. You can check the name of the semaphore by executing the launcher from the command line with the
/create-i4j-log
argument.
I faced the same issue, and solved it by using a FileLock like the other answer.
In my case, the arguments that are passed to the launched processes needed to be forwarded to the first process. For this, I used a named pipe, which includes the username in its name. The first process creates the named pipe at \.\pipe\app_$USER. If the same exe is is started by the the same user, it is detected by the FileLock, and the agruments are passed through the named pipe.

Do the .commit*() or .batch*() methods of a JooQ's Loader<?> matter within a TransactionalRunnable?

This is using JooQ 3.7.0. JooQ allows you to use its API to import data from, for instance, a CSV.
Let us take this code as an example of an implementation (in Java 8, as a method reference) of a TransactionalRunnable:
// csvPath is a Path to a CSV file
private void writeCsv(final Configuration configuration)
{
try (
final Reader reader = Files.newBufferedReader(csvPath);
) {
final Loader<PermethodMetricsRecord> loader = DSL.using(configuration)
.loadInto(PERMETHOD_METRICS)
.loadCSV(reader)
.fields(PERMETHOD_METRICS.fields())
.execute();
LOGGER.info("{} lines stored in database", loader.stored());
} catch (IOException e) {
throw new RuntimeException("Cannot open CSV for reading", e);
}
}
Now, the call to a DSLContext's .loadInto() is a LoaderOptionStep. And this class has several methods on it, in particular a default commit policy (.commitNone() is the default) and batch methods.
Here we are in a transaction created by JooQ; I don't specify any commit nor batch policy other than the defaults.
Does it matter at all whether I use any commit/batch policy depending on the RDBMS engine I use? Note that in my case, this is PostgreSQL 9.4.X.
As of jOOQ 3.7, the behaviour of using jOOQ's transaction API along with anything other than commitNone() (the default) on the Loader API is undefined.
The Loader API will commit batches directly on the underlying JDBC connection, but this can behave differently, depending on how you produce this connection (e.g. via a connection pool, etc.)
There is a pending feature request to specify and implement a predictable behaviour:
https://github.com/jOOQ/jOOQ/issues/4770

Using WatchServiceDirectoryScanner in Spring

I have a requirement of implementing a Watch Service on a folder. This is straight forward approach of using Java7's watch service. I have successfully done it, I am able to capture events whenever a file is created/updated/deleted on the folder where I have been watching. The problem here is it is not applicable for contents of sub folders and it is clearly written in the documentation. My requirement is to watch over contents of sub folder as well. This is not possible using the above approach unless I write a loop over all the sub folders manually and listen to each and every folder, this I think leads to some memory leak if not programmed well. Hence I am going with what spring suggested in the newer release explained here This is very clear approach which I have seen for WatchService. The problem here is this will listen to only ENTRY_CREATE events i.e., only the events where we have created the file and this can be at any level. This is not working when I change the file or delete the file. How should we go ahead in this case.
public static void watchFolderTree(String pathStr)
throws Exception
{
long waitTime = 10000;
WatchServiceDirectoryScanner scanner = new WatchServiceDirectoryScanner(pathStr);
scanner.start();
List<File> changedFiles = null;
while(true)
{
changedFiles = scanner.listFiles(new File(pathStr));
if(changedFiles.size() > 0)
{
System.out.println("There is a file ");
}
Thread.sleep(waitTime);
}
}
References :
Monitor subfolders with a Java watch service
JAVA 7 watch service

Is it possible to supply a new PropertiesConfiguration file at runtime?

Background:
I have a requirement that messages displayed to the user must vary both by language and by company division. Thus, I can't use out of the box resource bundles, so I'm essentially writing my own version of resource bundles using PropertiesConfiguration files.
In addition, I have a requirement that messages must be modifiable dynamically in production w/o doing restarts.
I'm loading up three different iterations of property files:
-basename_division.properties
-basename_2CharLanguageCode.properties
-basename.properties
These files exist in the classpath. This code is going into a tag library to be used by multiple portlets in a Portal.
I construct the possible .properties files, and then try to load each of them via the following:
PropertiesConfiguration configurationProperties;
try {
configurationProperties = new PropertiesConfiguration(propertyFileName);
configurationProperties.setReloadingStrategy(new FileChangedReloadingStrategy());
} catch (ConfigurationException e) {
/* This is ok -- it just means that the specific configuration file doesn't
exist right now, which will often be true. */
return(null);
}
If it did successfully locate a file, it saves the created PropertiesConfiguration into a hashmap for reuse, and then tries to find the key. (Unlike regular resource bundles, if it doesn't find the key, it then tries to find the more general file to see if the key exists in that file -- so that only override exceptions need to be put into language/division specific property files.)
The Problem:
If a file did not exist the first time it was checked, it throws the expected exception. However, if at a later time a file is then later dropped into the classpath and this code is then re-run, the exception is still thrown. Restarting the portal obviously clears the problem, but that's not useful to me -- I need to be able to allow them to drop new messages in place for language/companyDivision overrides w/o a restart. And I'm not that interested in creating blank files for all possible divisions, since there are quite a few divisions.
I'm assuming this is a classLoader issue, in that it determines that the file did not exist in the classpath the first time, and caches that result when trying to reload the same file. I'm not interested in doing anything too fancy w/ the classLoader. (I'd be the only one who would be able to understand/maintain that code.) The specific environment is WebSphere Portal.
Any ways around this or am I stuck?
My guess is that I am not sure if Apache's FileChangedReloadingStrategy also reports the events of ENTRY_CREATE on a file system directory.
If you're using Java 7, I propose to try the following. Simply, implement a new ReloadingStrategy using Java 7 WatchService. In this way, every time either a file is changed in your target directories or a new property file is placed there, you poll for the event and able to add the properties to your application.
If not on Java 7, maybe using a library such as JNotify would be a better solution to get the event of a new entry in a directory. But again, you need to implement the ReloadingStrategy.
UPDATE for Java 6:
PropertiesConfiguration configurationProperties;
try {
configurationProperties = new PropertiesConfiguration(propertyFileName);
configurationProperties.setReloadingStrategy(new FileChangedReloadingStrategy());
} catch (ConfigurationException e) {
JNotify.addWatch(propertyFileDirectory, JNotify.FILE_CREATED, false, new FileCreatedListener());
}
where
class FileCreatedListener implements JNotifyListener {
// other methods
public void fileCreated(int watchId, String rootPath, String fileName) {
configurationProperties = new PropertiesConfiguration(rootPath + "/" + fileName);
configurationProperties.setReloadingStrategy(new FileChangedReloadingStrategy());
// or any other business with configurationProperties
}
}

Categories

Resources