Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure that static web resources are available in OSGi #4230

Open
denis-anisimov opened this issue Jun 5, 2018 · 9 comments
Open

Make sure that static web resources are available in OSGi #4230

denis-anisimov opened this issue Jun 5, 2018 · 9 comments

Comments

@denis-anisimov
Copy link
Contributor

denis-anisimov commented Jun 5, 2018

This is similar to #4229 but the static web resources here are not handle by the VaadinServlet.
They are handled by the web server directly.
Those resources are frontend resources like CSS files, HTML files (template files) , JS files.
Such files are plain web resources in the application and should be somehow exposed in OSGi.

There can be different ways to do this but it should be simple enough for the developer.
Similar things are done here mmerruko/framework@687a900 bt it might be this is not applicable at all here.

What needs to be done: create an application, deploy it to OSGi and make sure the static web resources are available there.
If the custom way to do this is too complicated or may be improved then provide a way which can be used to simplify this in OSGi environment (see mentioned commit in FW).

@denis-anisimov
Copy link
Contributor Author

This is kind of blocked by the #4227 but it doesn't have to wait when the task will be completely done (and merged).
The #4227 should give a way to check whether an application can be used in OSGi.
At least there should be a simple way to deploy an application and check the result.
Otherwise this needs to be done every time when any OSGi related task is done and this is waste of time to reinvent the testing path every time.

@pleku pleku added this to the 1.1 milestone Jun 11, 2018
@denis-anisimov
Copy link
Contributor Author

I have some issues with static resources right now.

For the automation tests task I modified root-context tests so that it's OSGi bundle (including UI classes only) : it's a jar file (ui qualifier).

There is webapp folder which (I suppose) won't be properly served inside jar bundle.

So I configured the builder-helper plugin to use resources inside this folder as a part of META-INF/resources. So far so good. The resources are available inside META-INF/resources but they are not served as static resources.
That's the very first issue. Should they be served automatically? Servlet specification defines META-INF/resources folder for the resources inside jar files. But the bundle jar file is not a part of WAR file. It's standalone OSGi bundle.

So as a result servlet context which is used to get the resource in the end doesn't know about static resources inside META-INF/resources.

OK, may be it's how it's supposed to work.
To be able to expose those resource I register then via HttpService (which is created inside the bundle because Jetty OSGi bundle doesn't give any HttpService by the way).
Now resources are available via HTTP.

But we are using servlet context to get resource content by path inside template parser (DefaultTemplateParser uses service.getResourceAsStream which delegates to VaadinServletService::getResourceInServletContextOrWebJarAsStream and its implementation uses the ServletContext::getResourceAsStream method to get the resource content).

And since the servlet context knows nothing about static resources it returns null and the parser is unable to parse the template content.

So it's not enough to expose static resources via HTTP but they also should be available via servlet context (or we need to change our code somehow).

To be able to solve this issue I added also resources from the webapp folder into the root folder.

In the resulting configuration Jetty allows to get resources from the bundle jar and now resources becomes available by their correct path (previously path frontend/something had to be resolved via META-INF/resources/frontend/something, now it's available directly as frontend/something which makes servlet context find it and also via META-INF/resources/frontend/something which makes it's exposed via HTTP).

But this may be a result of main servlet mapping which is not mapped to the / but to the view.
I'm not sure that it will be possible with servlet mapped to the root.
And anyway this config is too cumbersome and inconvenient.

I will keep it for now for tests but once this ticket is fixed we should adjust tests accordingly.

@Sandared
Copy link

I'm not sure, but I think in my old Vaadin8 integration I had a similar problem.
Back then, I implemented a BundleTracker (again ;) ) that tracked the bundles with resources and added them via HttpService and a corresponding HttpContext, that delegated loading of resources to the bundle that contained the resources.

The BundleTracker code that adds the resource: https://github.com/Sandared/vaadin8integration/blob/master/de.modularco.vaadin.integration.impl/src/de/modularco/vaadin/integration/impl/OSGiResourceExtender.xtend#L69-L72

The HttpContext that delegates resource loading: https://github.com/Sandared/vaadin8integration/blob/master/de.modularco.vaadin.integration.impl/src/de/modularco/vaadin/integration/impl/OSGiResourceExtender.xtend#L127-L146

The code is unfortunately in written in Xtend but not so different from Java, so I hope it's readable.

I hope this helps.

@pleku pleku modified the milestones: 1.1, During 2018 candidates Jul 19, 2018
@denis-anisimov
Copy link
Contributor Author

denis-anisimov commented Jul 19, 2018

Thank you for the examples.

But in fact this is already done almost in the same way in our tests.

The problem is different.

  • In your example you are registering resources and make them available via HTTP.
  • I do the same and it works.
  • BUT. The resources should be available via ServletContext. This class is a part of Servlet specification not OSGi HttpService specification. You are using HttpContext to register resources via HTTP. And again I do the same.

As I mentioned in the comment : we have DefaultTemplateParser on the server side and it parses the template file. It doesn't use HTTP to access resources. It uses ServletContext::getResourceAsStream which has no relation to HTTP and it access resources "locally" ( like ClassLoader ) : get InputStream by resource path. And this is an issue.
Normally web server is specifically configured to treat some path for static web resources.
If it's configured (e.g. in Jetty resourceBase can be used for that) then ServletContext is able to resolve resources by path inside the configured folders and it returns their content via API method.
This is exactly what doesn't happen here.

@Sandared
Copy link

Ok I got it. I mistook HttpContext for ServletContext.
Nevertheless, the OSGi Compendium Specification states that all servlets registered with the same HttpContext also have the same ServletContext as described here

If the Servlet whose ServletContext is asked by the template processor for the resource is registered with the same HttpContext as the resources are, then it should be able to find and return the registered resource as stream.

If I'm still getting you wrong, then just ignore this comment. I'm not that deep into Servlets and web stuff as you probably are ;)

@QNENet
Copy link

QNENet commented Jul 19, 2018

A good example in using Vaadin in an OSGi environment can be found at https://github.com/opensecuritycontroller/osc-core/tree/master/osc-ui/src/main/java/org/osc/core/ui
It uses the servlet context.

@denis-anisimov
Copy link
Contributor Author

Thank you for the reference. I will look into this.

@denis-anisimov
Copy link
Contributor Author

Regarding to my issue with our flow-testroot-context module.
At the moment the -ui classifier jar is the WAB actually (even though it's a jar file).
OSGi compendium says that files in META-INF are protected and are not exposed via web.

In reality the web context path is "/" for this WAB and static web resources are available from the root folder.
So our frontend folder in the root may be server via HTTP and is available via servlet context out of the box. So no need to have an activator which register resources via HTTP service.
I made a PR to remove the activator : #4631.

So there is no issue with the static resource in a WAB file.

But that works only for the resources inside the WAB itself.
We still need register resources if they are outside of a WAB (inside a separate bundle).
But it's not clear : which resources may be required to register ? (not that webjars don't work and should be repackaged) and even if ew register them via HttpService then what to do with servlet context: they won't be available via Servlet context. Do we have usecases for resources which we want to register to make them available via HTTP and not via servlet context ?

@pleku pleku modified the milestones: Candidates, V12 Candidates Oct 2, 2018
@pleku
Copy link
Contributor

pleku commented Oct 5, 2018

Do we have usecases for resources which we want to register to make them available via HTTP and not via servlet context ?

As discussed, the component related static resources should be made available this way.

But we still need some resources like templates, web component files related to theming; available on the servlet context.

We will first take #4671, fix #4376, create more tests for OSGi (no issue yet) and then we will validate that this works out-of-the-box as it should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

5 participants