Disable caching of static assets in Dropwizard - java

I have a Dropwizard webserver with a rest api which also serves some static content like html, css, javascript and jpg images. Unfortunately, when I change the html or add another image, the server always needs to be restarted to turn changes into effect.
As I thought that it might be a problem of caching, I explored bazaarvoice's Configurable Assets Bundle.
That's what I added to the configuration class:
#Valid
#NotNull
#JsonProperty
private final AssetsConfiguration assets = new AssetsConfiguration();
And in the main class
#Override
public void initialize(Bootstrap<MyConfiguration> bootstrap) {
// ...
CacheBuilderSpec cacheBuilderSpec = CacheBuilderSpec.disableCaching();
bootstrap.addBundle(new ConfiguredAssetsBundle("/html", cacheBuilderSpec, "/", "index.html", "Static assets"));
}
#Override
public void run(MyConfiguration config, Environment env) {
env.jersey().setUrlPattern("/api/*");
// ...
}
No changes in the yaml configuration.
The static files are located in src/main/resources/html.
How can caching be disabled such that Dropwizard shows changes instantly?
And second question, how can I make Dropwizard follow symbolic links from the assets directory?
Update
I found this in the ConfiguredAssetsBundle source:
// Let the cache spec from the configuration override the one specified in the code
CacheBuilderSpec spec = (config.getCacheSpec() != null)
? CacheBuilderSpec.parse(config.getCacheSpec())
: cacheBuilderSpec;
This certainly overrides the cache builder spec which was set in the code with the configuration from the yaml file. After append
assets:
cacheSpec: maximumSize=0
to the configuration, the debugger shows that maximum size is now 0. However, behaviour did not change.

Static content doesn't change not because you need to restart, but because the running server actually serves files under the target directory. Changing the files in this directory only confuses things (so it's not really a solution), but change a few lines and wait a second to verify that the server now serves the modified file with no need to restart.
As a solution, I prefer opening the dropwizard project as a maven project in eclipse and run the project with mvn exec:java on a terminal, using the exec-maven-plugin. Eclipse updates the target directory as files change, but it takes a few seconds, depending on the size of the project.

Related

Spring boot serving static resource

I work on spring boot application. I'm trying to serve static content with spring.
want to serve a resource stored in the /c:/frontend/files/ directory whenever a request comes in for the URL matching the pattern: /file/**:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/file/**")
.addResourceLocations("file:///C:/frontend/files/" );
}
but when i try to access to this resource using this url: http://localhost:9999/file/app.min.js
I have this problem
There was an unexpected error (type=Not Acceptable, status=406).
Could not find acceptable representation
I resolved the problem. it's related to "spring-cloud-config-server". I just delete this config: org.springframework.cloud spring-cloud-config-server
It sounds like your project's folder structure is wrong.
Code should go under src/main/java and resources (like your javascript) should go under src/main/resources. You have a few different options where you can actually serve the files from. This post on the spring.io blog has the following to say:
Spring Boot will automatically add static web resources located within any of the following directories:
/META-INF/resources/
/resources/
/static/
/public/
Another option you also have is using webjars.
Personally, I've found it easiest to put those kind of files under src/main/resources/public. It always works without any issues for me. The interesting thing is you can put a folder named /public anywhere in your project and spring-boot will serve files out of it. You have to be really careful that it's under src/main/resources/public though if you're using a build tool like maven, as when you come to build your .jar the files won't be in the right place otherwise.

access via spring injected property which references a directory to access its files

I'm trying to access a property defined in a bean like this:
<bean id="reportdepositService" class="a.b.c.ServiceImpl">
<property name="reportDeposit" value="/WebContent/WEB-INF/dirName/" />
</bean>
ServiceImpl class looks like this:
public class ServiceImpl implements IService {
private Resource springResource;
public Resource getSpringResource() {
return springResource;
}
public void setSpringResource(Resource springResource) {
this.springResource = springResource;
}
private File getSpringResourceFile() throws IOException{
Resource r = getSpringResource();
URL url = FileLocator.resolve(r.getURL());
return FileUtils.toFile(url);
}
public void doSomething(){
.. some logic .
File f = getSpringResourceFile();
}
executing that code within eclipse on a ubuntu machine works fine, application build on a jenkins works fine as well on ubuntu. Running that application on a win7/64, the code throws the following exception:
OSGi resource[/WebContent/WEB-INF/springResource/|bnd.id=332|bnd.sym=a.b.server] cannot be resolved to URL because it does not exist
java.io.FileNotFoundException: OSGi resource[/WebContent/WEB-INF/springResource/|bnd.id=332|bnd.sym=a.b.server] cannot be resolved to URL because it does not exist
at org.springframework.osgi.io.OsgiBundleResource.getURL(OsgiBundleResource.java:228)
What is necessary to access the property on windows hosted system?
Any ideas?
Thanks in advance
I am not sure whether you are on the correct road with this:
The /WebContent/WEB-INF path suggests that you are writing a web application to be run in a web container. In that case you should never assume that your resource is a file. You should open the resource using Resource.getInputStream() in stead of using the URL/File. The reason is that the the application may well be run directly from the .war without a file system being available.
That may immediately answer the question: is the Windows 7 environment the same in relation to the run-enviroment? My impression is that it is not. If you bundled the project into a bundle jar while transporting it to the windows machine, I guess you should add a prefix to the path (but probably need to leave the WebContent off), like bundle:, classpath:, etc. See Spring OSGI reference. But you need to give a little more information to be sure.

play 2.4.x current application environment

Is there any function to return the current working environment of a Play framework application ?
I tried the following but it doesn't seem to be working correctly;
String environment = play.api.Play.Mode
NOTE: I don't want to use isDev() isProd() stuff, I want to be able to create custom environments
PlayFramework 2.x supports only 3 modes: Prod, Dev and Test. First is used for production. Second provides more development additions like hotloading just editet classes. The last one is like the second one but with test libraries.
Play 1.x had also ID, which was able for using as different environment. For instance staging or instance of distributed server.
Play 2.x sadly doesn't support ID's anymore. But You can achieve the same effects manually.
Suppose you want to run your application in 'staging' mode.
First you need put configuration file along with basic configuration file, but named as application.staging.conf.
Second step is add to Global.scala code responsible for managing configuration files, something like this:
import java.io.File
import play.api._
import com.typesafe.config.ConfigFactory
object Global extends GlobalSettings {
override def onLoadConfig(config: Configuration, path: File, classloader: ClassLoader, mode: Mode.Mode): Configuration = {
val env = System.getProperty("environment")
val envConfig = config ++ Configuration(ConfigFactory.load(s"application.${environment}.conf"))
super.onLoadConfig(environmentSpecificConfig, path, classloader, mode)
}
}
As you see it reads environment value and look at specific configuration file.
The last step is telling play framework which mode it should use. The best way is by starting command:
activator run -Denvironment=staging
Should works.
In Java it is play.Application.isDev() and isProd() or isTest()
https://playframework.com/documentation/2.2.x/api/java/index.html

Can't find property files on classpath

I'm trying to load/read property files on glassfish 3.1 server.
I can't get it to work. I've searched and tried many possible solutions.
None worked so far, always NULL as result.
I've tried methods from the following link:
How to use a property with Glassfish
My method:
final public class GTS_Properties{
...
public static Properties getPropertiesFromFile(String fileName){
URL url = GTS_Properties.class.getResource(fileName)
...
// url is always null
}
}
My configuration:
Folder properties on build path.
/root/WEB-INF/classes/****.properties
How the Glassfish server looks like (using eclipse startup plugin)
/glassfish-root/domain/eclipseApps/MyWebApp/WEB-INF/classes/****.properties
I have tried to put the property files directly in WEB-INF instead of classes. same result.
I solved it by first going 2 'parent folders up' from the startpoint of the relative path.
Inserting "../../" on the start of the path was all that was needed.
WEB-INF/classes/WebApp/utils/GTS_Properties.class (The class to get the resource from)
WEB-INF/classes/prop.properties (Location of the resource file)
GTS_Properties.class.getResource("../../prop.properties")

Avoid server calls for loose resources that do not exist

I'm developing an applet application which is compiled on Java 1.5 (compatible with 1.5+).
It contains some resource property files that are bundled together in the same jar, which lies parallel to the Java package.
Whenever I access that resource file through applet it makes a request to server from where the applet is been downloaded. After that it reads the files from the jar and works as it used to be but I don't want it to make server request for those files.
This is how my java code access the resource file.
ResourceBundle messages = ResourceBundle.getBundle("resources/properties/Messages", locale);
I tried access in both ways:
ResourceBundle messages = ResourceBundle.getBundle("resources.properties.Messages", locale);
Both it had the same behaviour.
Note: Those resources are not available as loose resources in my web app.
I got these details from server logs.. I was analyzing my server log for 404 and 500 responses ..
The 404 (not found) & 500 (server error) messages can be expected because the plug-in is trying to check if the cached resources are up to date. To do that, it needs to check the time last updated on the server version of the resource.
The complicating factor is that the resource can be expected to be in a Jar mentioned in the archive attribute of the applet or it can be a 'loose file' on the same path as the codebase specified. So if a resource is in the following path of a Jar:
/resources/properties/Messages_en_US.properties
The JVM will also check
${codebase}/resources/properties/Messages_en_US.properties
as well as each Jar.
To fix them, see the codebase_lookup parameter. This use-case needs:
<param name='codebase_lookup' value='false' >
That tells the JVM that there are no resources stored as loose files on the class-path, and only Jars are to be searched. It should stop the 404/500 messages being reported as often (for newer JREs that understand that parameter).
I don't know much about the inner details of the Java Plug-in's caching of applets, but if your applet is using a .jnlp descriptor, I would try adding download="eager" to the descriptor's <jar> element.
You can also try defining your ResourceBundles as classes rather than .properties files. For instance:
package resources.properties;
import java.util.ListResourceBundle;
public class Messages
extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
{"entry1", "Some message text"},
{"entry2", "A different message"},
// etc.
};
}
}
Just like properties files, you can define them for as many locales as you wish:
package resources.properties;
import java.util.ListResourceBundle;
public class Messages_es
extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
{"entry1", "Some message text in Spanish"},
{"entry2", "A different message in Spanish"},
// etc.
};
}
}
If you define ResourceBundle subclasses, it's a good idea to remove the corresponding .properties files.

Categories