How to get application and/or theme base URL from within application

I need a way to answer questions like: “What is the base URL of the currently running Vaadin application
as the client sees it
?” and “What is the base URL for this Vaadin application’s theme resources
as the client sees them
?”.

Now that
issue #4131
and
issue #6771
will be fixed in 7beta4, is this information going to be made available to the application?

To motivate, here’s a use case: I’m sending the client an HTML document that is built from a static template file. The HTML has references to theme’d resources (images, etc.). In order to make the HTML portable (in terms of servlet mappings
and
inverse proxies, etc.), a template expression is used as the basis of the URL of these theme’d resources in the HTML. This template expression can be substituted at runtime, but how do I get the base URL to substitute?

One example of how this could work: add a new method
public URL getBaseURL()
to the
VaadinRequest
class. This would be very helpful.

A related question: doesn’t it seem like there should also be a
public URL getURL()
method in the
ThemeResource
(and perhaps other Resource subclasses as well) that returns the specific client-view URL for those resources…?

Thanks.

We have also added Page.getLocation() which returns the URI that the browser thinks is used (it’s based on window.location.href). Would this work for your use case?

Resource was originally added to the framework to cope with the fact that the server-side couldn’t always know the right URL to use for resources e.g. with embedded applications or if the servlet is deployed behind a proxy. To cope with this, the server sends a special URI (e.g. theme://myimage.png) that the client-side code (ApplicationConnection.translateVaadinUri) translates based on its own knowledge about where things are located.

Now that the actual URL used by the browser is sent back for Page.getLocation(), all the information required to form a proper URL is available on the server. The challenge is however the context; the final URL of a ThemeResource still depends on which theme is used for the UI and which Page it should be displayed on. I guess UI.getCurrent() and Page.getCurrent() could be used to give the right URL in most situations, but I’m not sure this would be a sensible approach.

There are also other cases where additional context information is required to get a URL for a Resource, e.g. instances of ConnectorResource where the URL might be based on the id of the Component using the resource.

I know there are many cases where it would be very convenient to get a server-side URL for a Resource but I’m afraid there is no reliable way of achieving this as the main purpose of Resource is to cope with situations where the URL varies with the context.

I think so… although wouldn’t that also include any extra path information, # anchors, etc.? There needs to be a way to get the “base” URL of the current page without the extra path info.

Let me try another use case to motivate what I’m talking about. Suppose you have a custom
UIProvider
that directs certain URLs to certain parts of your application. So
http://…/main
goes to your main UI,
http://…/reports
goes to your reports UI, etc.

For whatever reason, you need to construct an absolute URL that points to one of those locations. Currently I don’t understand how to correctly do that.

To do this requires knowing the “base” URL of the application -
as the client sees it
- and then appending the appropriate extra path information that will be interpreted by your
UIProvider
(i.e., the
/main
,
/reports
, or whatever).

It seems that this concept of the “base URL” for a Vaadin application as the client sees it should be a well-defined one. It just needs to be exposed somewhere.

Understood… but this is all OK because perfection is not really needed here.

All we need is a very simple method like
getThemeBaseURL()
somewhere that would return the base URL for all themes. Then it would be easy to construct the full URL for a theme resource if you know the theme using something like
getThemeBaseURL() + “/mytheme/imgs/foobar.png”
,

In other words, I have the same need with theme’d resource URLs as with the URLs that point to
/main
,
/reports
, etc. I don’t mind having to do a little manual URL construction. I just need access to the basic ingredients. Right now those ingredients appear unobtainable. Providing those ingredients would make this problem go from impossible to possible, which represents a major advance.

Thanks.

Yes, we are aware of this challenge but we haven’t yet gotten around to doing anything about it. The real challenge here is there are a multitude of different “base URLs” that typically are equivalent but might diverge in some deployment scenarios. There should therefore be APIs that clearly tell what URL should be used in what situation.

  1. Current URI in the browser, including extra path information, query strings and anchors. This is what Page.getLoation() returns.
  2. Service URL (i.e. the root of the servlet mapping) that is often needed by the framework e.g. for finding where to send UIDL requests and file uploads. This is usually closely related to 1. but that might not be the case e.g. if embedding the application from another server.
  3. Context root URL is in itself not used by Vaadin, but it’s often useful for applications e.g. for serving static files from the .war. This is always related to 2.
  4. VAADIN folder URL which is where Vaadin looks for themes and widgetsets. This is typically relative to 3. but some applications might also have the static files served by dedicated servers or even a CDN. This is currently accessible using VaadinService.getStaticFileLocation(VaadinRequest) even though the way it uses relative URLs means that it probably only works properly during the initialization requests.
  5. UI base URL will probably be useful when we add support for pushState() in Navigator (currently scheduled for Vaadin 7.1) to help the framework know what part of an URL qualifies the UI and what parts are just parameters to the Navigator.

Related question… how do I solve the following problem in Vaadin 7beta4?

  • I have a
    Table
    with
    Action
    s configured for each row and presented in a right-mouse click menu
  • I have some HTML document that I can generate dynamically for each row
  • When the user right-clicks on a row and chooses the “Export” action, I want the browser to open an entirely new window/tab containing the generated document

Note: I can’t use a
Link
for this because this is not a hyperlink, this is a right-mouse menu action.

In Vaadin 7alpha3, I could handle this by expressing the document as a
StreamResource
, and then invoking
Page.open(Resource, String, int, int, BorderStyle)
.

In Vaadin 7beta4 that
Page.open()
method is deprecated.

Also, I can’t use the version of
Page.open()
that accepts an
URL
because there’s is no way to get an URL for the resource.

What is the new way to do this?

For simplicity in this discussion, let’s assume that the client’s and browser’s view of all URLs is the same (i.e., no reverse proxies or anything).

Also, I have the same question where instead of a right-mouse click menu
Action
, I just have an
Button
labeled “Export”.

The short and simple answer is that you can’t do this without getting a mess with popup blockers, especially in IE8 but to some degree also in other browsers. You’d get the same problem with Vaadin 6.x although it seems it is often overlooked or “solved” by assuming the browser will be configured to accept popups from the application’s domain.

The intermediate answer is that the helper that will be implemented for
#9513
should help at least for Buttons.

The long answer is that StreamResource and other similar resources should be bound to the component that “uses” it to ensure it can be garbage collected when that component is no longer used. Page.open wouldn’t have any other way of doing this than binding it to the UI instance, which would cause memory leaks unless very carefully managed by the developer. This was also an overlooked issue in Vaadin 6.x.

One alternative approach could be to instead have a RequestHandler or a separate Servlet that dynamically serves the HTML based on request parameters. A URL pointing there could be crafted right now based on e.g. VaadinServletService.getCurrentServletRequest().getContextPath() and quite soon also based on the upcoming API for getting an URL to the VaadinService that should work even behind proxies.

That may be true in general. But for enterprise applications, you would instruct your users to tell their browser to allow pop-ups for the application (once) and the problem is solved. Or, you automatically push pre-configured browser software to their desktop machines.

So while I agree with you that pop-up blockers are a potential problem, their existence is not a reason to conclude that opening windows from within a Vaadin application is a hopeless exercise.

By your argument, we should never use self-signed SSL certifiicates, because they generate a browser warning. While that may be true in some vague general sense, their use is necessary and perfectly appropriate in certain controlled situations.

I have in fact seen enterprises where the browser - including pre-installed enterprise SSL certs - is pushed automatically to user desktops.

Thanks for the explanation. I’ve never quite understood why a Link can reference a resource but not a Button… is there some difference between how the browser handles the two? Adding this capability to Button would be very helpful.

The alternative approach sounds reasonable as well.

That’s why we are still considering what would be the best way of providing the functionality. The biggest challenge is how to construct a URL to the Resource in such a way that the memory is released when the Resource is no longer needed.

For the record: IE8 doesn’t just display a warning - the main problem is that when the user accepts the warning, the page is reloaded which with Vaadin typically puts the user in a situation where the the download isn’t automatically started again.

With Link, the Resource URL is sent to the client-side and included in the a element’s href attribute when the component is added whereas a client-side Button doesn’t know anything about what the server-side click listeners might do.

The thing that causes differences with popup blockers is that Link opens the window while the browser processes an input event from the user whereas it in the Button case happens when the browser processes a networking event (i.e. when the response with the result form the server-side click listener arrives). This difference is typically what browsers use to determine whether a popup blocker should be used.

Interesting problem.

Perhaps there should be a new class called
SessionResource
. This would be a resource that:

  • Is constructed by providing a normal
    Resource
    to a constructor
  • Must be explicitly registered by the application with the
    VaadinServiceSession
  • Has a
    getURL()
    method that returns an absolute, client-view URL that when accessed will return the resource

Then you could create a
SessionResource
, register it with the
VaadinServiceSession
, and use
Page.open(URL, …)
to open it in a new window.

There could then also be some different options for memory management:

  • Automatically unregister the resource from the
    VaadinServiceSession
    after the first access
  • Automatically unregister the resource when no longer referenced by the client application (using weak keys)
  • Automatically unregister the resource when the
    SessionResource
    is closed (default/always)

Typical Microsoft stupidity. Does it at least remember the user’s preference so the same thing won’t happen next time?

Would it be possible to create a new
Link
style that makes it look and act like a
Button
? I guess this would still require Javascript in the triggering option, which would alert the popup blocker… ?

That approach would actually crack the nut that has been preventing me from coming up with any sensible solution. I have been so focused on a scheme that would do the URL translation in the browser that I didn’t realize that it should now be fully possible to produce the URL on the server and then pass it to any existing method working with URLs, e.g. Page.setLocation() or Page.open().

I’m afraid are only bad alternatives available here.

  • Unregistering on the first request is semantically wrong as a GET request should not have such side effects. There might be legitimate cases where the browser requests the same resource multiple times, e.g. with
  • I have understood that weak references are problematic with serialization and clustering though I have never studied the issue in depth.
  • Explicit close requires the user to know that it’s required, know when it’s appropriate to close the resource and remember to always do so. The situation is however slightly better with this kind of API compared to the Vaadin 6.x ApplicationResource as the registering still requires and explicit step instead of happening behind the scenes.
  • Because the explicit close would most often be performed when a specific Component is detached, there might as well be an option for binding the SessionResource to a specific Component (or Extension) instance. This is basically how GlobalResourceHandler works. It was introduced to support PaintTarget.addAttribute(String name, Resource) that many legacy components use.

Yes, luckily it remembers (presumably for the same host, though I haven’t verified the scope).

This is where
http://dev.vaadin.com/ticket/9524
and
http://dev.vaadin.com/ticket/9513
come into play. Opening the popup from JavaScript doesn’t matter as long as it happens in the context of a UI event. This means that a quite simple extension can be used to send the Resource URL to the client and attach a click listener for opening it to a normal Button or almost any other component.

There are however still some cases that can not be supported by those extensions - the two most notable being Actions and situations when it takes a considerable amount of time to generate the Resource so that you want to do the work in a background thread on the server, show a progress indicator to the user and automatically open the Resource when it has been generated.

Sorry, I made a typo in that list of ideas… for the third item, I actually meant to say:

  • Automatically unregister the resource when the

    VaadinServiceSession

    is closed (default/always)

In other words, just let the
SessionResource
be associated with the
VaadinServiceSession
until it closes. This is still a “memory leak” but at least its not permanent. This would of course always be in force, no matter what else you did. It goes without saying I guess.

But your “explicit close” idea is also a good option to have, as is associating the close with a component detach, because I would guess that in most cases you are setting up a resource that is available from a specific component in your GUI, and so your users would not expect to be grabbing that resource from anywhere else.


Ticket #10115
now tracks this feature.