Resource sharing

Hi all!

I am not able to share the same resource (a png image) in a way it is loaded just once by the client.

Look at this code:

protected void init(VaadinRequest request) { HorizontalLayout content = new HorizontalLayout(); Resource resource = new FileResource(new File("C:/Temp/image.png")); Image image1 = new Image(null, resource); Image image2 = new Image(null, resource); Image image3 = new Image(null, resource); content.addComponent(image1); content.addComponent(image2); content.addComponent(image3); setContent(content); } When i inspect the html generated in the client browser, i see it loading 3 distinct images from the server:

http://localhost:8080/APP/connector/0/2/source/image.png
http://localhost:8080/APP/connector/0/3/source/image.png
http://localhost:8080/APP/connector/0/4/source/image.png

I have a form (screenshot attached in this post) which shows the same image thousands of times (about 3.000 times).
The image has 1KB, what means the client has to load
3MB
from the server each time it opens the form, when it could load just 1KB…

I realized i can load the same resource just once in the client if i use a ThemeResource or ExternalResource, but my image is loaded from the database (not available from the theme or from an external URL), so i have to use a ConnectorResource (StreamResource).

Is there some way to force Vaadin to send always the same URL to the client for a given Resource, at least for the current form?

Regards,

Fabiano

17205.png

Hi all,

After some time i found a solution to my problem, so i will share it here:

First, i implemented a RequestHandler which keeps a global static cache of resources, and return them to my application when requested:

(Note that i implemented a GLOBAL cache, with resources that are create once when the container is started and are shared by all sessions. My need is to share some simple resources like button and status images in a way they are create once and loaded just once by the client browser. I am not concerned about security here. If you mind to share the resources globally, there is a GlobalResourceHandler implementation from Vaadin which associates the resource with a ClientConnector).

[code]
public class GlobalResourceHandler implements RequestHandler {

private static final long serialVersionUID = 1L;
private static final String PATH = UUID.randomUUID().toString();
private static final Map<String, String> mapResourceIdMIMEType = new HashMap<>();
private static final Map<String, byte[]> mapResourceIdBytes = new HashMap<>();

@Override
public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response)
        throws IOException {
    if (request.getPathInfo().startsWith("/" + PATH + "/")) {
        String resourceId = request.getPathInfo().substring(PATH.length() + 2);
        byte[] bytes = mapResourceIdBytes.get(resourceId);
        if (bytes == null)
            return false;
        response.setContentType(mapResourceIdMIMEType.get(resourceId));
        response.getOutputStream().write(bytes);
        return true;
    }
    return false;
}

public static Resource createResource(byte[] bytes, String MIMEType) {
    String resourceId = UUID.randomUUID().toString();
    mapResourceIdMIMEType.put(resourceId, MIMEType);
    mapResourceIdBytes.put(resourceId, bytes);
    return new ExternalResource(PATH + "/" + resourceId);
}

}
[/code]Then i registered my RequestHandler within my session:

[code]
public class TempUI extends UI {

public final RequestHandler requestHandler = new GlobalResourceHandler();

@Override
protected void init(VaadinRequest request) {
    getSession().addRequestHandler(requestHandler);
}

@Override
public void detach() {
    super.detach();
    getSession().removeRequestHandler(requestHandler);
}

[/code]The shared resource is created calling “GlobalResourceHandler.createResource”, which receives a byte containing the bytes of the resource and its MIME type:

byte[] image = ... // load my image or any other resource here as a byte array Resource resource = GlobalResourceHandler.createResource(image, "image/png"); After that, i can share this resource between how many components i want:

Image image1 = new Image(null, resource); Image image2 = new Image(null, resource); Image image3 = new Image(null, resource); HorizontalLayout layout = new HorizontalLayout(); layout.addComponent(image1); layout.addComponent(image2); layout.addComponent(image3); This way, when i inspect the generated html i see all images pointing to the same URL:



Regards,

Fabiano

If you use ThemeResource resource = new ThemeResource("img/image.png"); it would do the same.

Regards