Setting an image source on page load

Hi all,
I am looking for some help with an issue I ran into while trying to show a logo on a view. The logo shows on first view load, but on change of view, it turns into a broken image icon.

I’ve got a navigation bar component which is added to the top of my page. It contains the navigation menu, a couple images, the name of the logged in user, and the client they are logged in under. I want to add a dynamic client logo to that as well, which gets set on page load depending on the client the user is logged in under.

Here is my navigation menu component which is added to every view:

public class NavigationMenu extends CustomComponent {

    private static final long serialVersionUID = -7094784739176389043L;
    private VerticalLayout mainLayout;
    private MenuBar navigation;
    private final Label welcomeMessage;
    private final Label clientMessage;
    private final Image clientLogo;

    
    public NavigationMenu() {
        buildMainLayout();
        setCompositionRoot(mainLayout);

        // Layout for buttons
        HorizontalLayout layout = new HorizontalLayout();
        layout.setSpacing(false);
        layout.setWidth("100%");
        layout.setMargin(true);

        Resource productIconFile = new ClassResource("/images/logo1.png");
        Resource companyIconFile = new ClassResource("/images/logo2.png");
        Image productIcon = new Image(null, productIconFile);
        Image companyIcon = new Image(null, companyIconFile);

        VerticalLayout messageLayout = new VerticalLayout();
        messageLayout.setWidth("250px");

        Label space = new Label();
        space.setHeight("10px");

        welcomeMessage = new Label();
        welcomeMessage.setHeight("18px");
        welcomeMessage.setWidth("-1px");

        clientMessage = new Label();
        clientMessage.setHeight("18px");
        clientMessage.setWidth("-1px");

        clientLogo = new Image();


        layout.addComponent(productIcon);
        layout.addComponent(clientLogo);
        messageLayout.addComponent(companyIcon);
        messageLayout.addComponent(space);
        messageLayout.addComponent(clientMessage);
        messageLayout.addComponent(welcomeMessage);
        messageLayout.setComponentAlignment(companyIcon, Alignment.TOP_RIGHT);
        messageLayout.setComponentAlignment(clientMessage, Alignment.MIDDLE_RIGHT);
        messageLayout.setComponentAlignment(welcomeMessage, Alignment.MIDDLE_RIGHT);
        layout.addComponent(messageLayout);
        layout.setComponentAlignment(productIcon, Alignment.MIDDLE_LEFT);
        layout.setComponentAlignment(clientLogo, Alignment.MIDDLE_RIGHT);
        layout.setComponentAlignment(messageLayout, Alignment.MIDDLE_RIGHT);

        mainLayout.addComponent(layout, 0);
        mainLayout.setComponentAlignment(layout, Alignment.BOTTOM_LEFT);
        mainLayout.setComponentAlignment(navigation, Alignment.BOTTOM_LEFT);
        mainLayout.setStyleName("navigation");
        
        /*
            A bunch of navigation menu stuff, unnecessary for this example
        */
        
    }

    private VerticalLayout buildMainLayout() {
        // common part: create layout
        mainLayout = new VerticalLayout();
        mainLayout.setImmediate(false);
        mainLayout.setWidth("100%");
        mainLayout.setHeight("125px");
        mainLayout.setMargin(false);

        // top-level component properties
        setWidth("100.0%");
        setHeight("130px");

        // navigation
        navigation = new MenuBar();
        navigation.setImmediate(false);
        navigation.setWidth("-1px");
        navigation.setHeight("-1px");
        mainLayout.addComponent(navigation);

        return mainLayout;
    }

    public void ToggleMenuItems(boolean toggle) {
        for (MenuItem item : navigation.getItems()) {
            item.setEnabled(toggle);
        }
    }

    public void setWelcomeMessage(Account userAccount) {
        if (userAccount != null)
            welcomeMessage.setValue("Welcome " + userAccount.getFirstName() + " " + userAccount.getLastName());
        else
            welcomeMessage.setValue("");
    }

    public void setClientMessage(Client client) {
        if (client != null)
            clientMessage.setValue("Client: " + client.getClientName());
        else
            clientMessage.setValue("");
    }
    public void setClientLogo(Client client) {
        if (client != null && client.getClientSettings().getLogoStream() != null) {
            StreamResource.StreamSource source = new StreamResource.StreamSource() {
                @Override
                public InputStream getStream() {
                    return client.getClientSettings().getLogoStream();
                }
            };
            StreamResource resource = new StreamResource(source, String.valueOf(System.currentTimeMillis()));
            resource.setCacheTime(0);
            resource.setMIMEType("PNG");
            clientLogo.setSource(resource);
            clientLogo.setVisible(true);
        }
        else {
            clientLogo.setVisible(false);
        }
    }
}

My views all have this as part of their enter method.

public void enter(ViewChangeEvent event) { // Check this on all protected pages, to ensure the user has actually logged in and is able to access this page. Account account = getSession().getAttribute(Account.class); if (account == null && !getUI().getNavigator().getState().equals(Navigation.LOGIN.getNavAddress()) && !getUI().getNavigator().getState().equals(Navigation.LOGOUT.getNavAddress())) { getUI().getNavigator().navigateTo(Navigation.LOGIN.getNavAddress()); toggleMenuItems(false); return; } else if (account != null) { Client client = (Client) ClientContainer.INSTANCE.get(account.getClientID()); navigation.setWelcomeMessage(account); navigation.setClientMessage(client); navigation.setClientLogo(client); toggleMenuItems(true); } else { navigation.setWelcomeMessage(null); navigation.setClientMessage(null); navigation.setClientLogo(null); toggleMenuItems(false); } } You can see if the user is logged in, it will call the navigation.setClientLogo(client) method. This works the first time, and then breaks after that.

Looking for any help on this, i’ve been messing with it for a while with no luck so far.

Thanks,
-Adam

Just by looking at your code, I couldn’t find any issues. Check the network tab in chrome inspector; what is the URL of the first (working) image it loads, and what does it change to? Also, are there any javascript exceptions when this happens?

I’ve attached some screenshots of the issue. Does that help?
15334.png
15335.png
15336.png
15337.png

Also, here is a video of what is happening: https://dl.dropboxusercontent.com/u/12156055/Test.mp4

A couple of things; as the logging say, you have an incorrect mimetype in your code. it needs to be “image/png”. Secondly, Chrome says it loads both images from the cache; clear the cache and force reload to check if that clears the issues. The third thing you could do is add a file extension to your file name, to additionally help the browser determine the file type.

I have actually tried all of those suggestions already. I moved the code from a method that is called on entering the view to the constructor, and hard coded it to pull from a single client.

I had cleared the cache prior to taking the screenshots and video, but I had loaded the page a couple times between that and taking screencaps and video. I also did change the filename to have an extension.

        clientLogo = new Image();
        StreamResource.StreamSource source = new StreamResource.StreamSource() {
            @Override
            public InputStream getStream() {
                return ((Client)ClientContainer.INSTANCE.get(1)).getClientSettings().getLogoStream();
            }
        };
        StreamResource resource = new StreamResource(source, "logo.png");
        resource.setCacheTime(1000000);
        resource.setMIMEType("image/png");
        clientLogo.setSource(resource);

In that case I’m out of ideas… Are you sure your LogoStream works correctly? is the getStream method called at all?

Yes, the get getStream() method is called every first load of the view. It is returning the correct inputstream every time it’s called.

Yeah, I’m drawing a blank here… anyone else?

Sorry… bump anyone?

It’s been almost another week of messing with this, and I still haven’t come up with a solution. Pretty frusturating. Can anyone chime in?

For now, I just switched to creating files instead of storing the images in my database as I wanted to. It gets it working, even though I don’t like the solution.