You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by Kamil Soboń <is...@gmail.com> on 2011/06/13 21:23:17 UTC

JSF + OSGi integration.

Hi all,

I don't know if I am writing in appropriate place, but assume that I am ;)
So ... for some time, me and my friend are trying to create JSF 
application in OSGi environment.
This application should be composed form core element and it's plug-ins. 
Each plug-in (OSGi bundle) can be install installed or uninstalled in 
run-time. Application should be aware of its plug-ins and its lifecycle 
(installing/uninstalling) without being restarted.

To do so, we are combining few technologies: JSF (MyFaces) + PrimeFaces 
+ Hibernate + Spring + OSGi (Equinox) + SpringDM (will be exchange to 
blueprint).
To simplicy prototype we are going to use JSF + Spring + Spring-DM + 
OSGi only.

As we have realized, JSF has not been planned to work with dynamic 
components (plug-ins) that can provide new views (xhtml pages), 
resources or manageable-beans. But specification of JSF allows to swap 
some application's modules/components.
I have figure out some mechanism for providing views and resources 
(manageable beans is quite more complicated and it is not part of my 
question now :)) in run-time without violate JSF specification (in my 
opinion ofcourse :)).

So our application is working in OSGi environment. The core is typical 
JSF application deployed to Tomcat (thanks to Spring-DM) which  is also 
running in OSGi environment. Each plug-in is simply OSGi bundle that has 
dependency to Core. In Core there is PluginsResolverService that is 
responsible for detecting Core's available plug-in (assume that we are 
keeping Bundle descriptor).

To provide views and resources in run-time (it is actuali working !) I 
have done 2 things:

1) I have implemented my own ExternalContext and ExternalContextFactory. 
Now we want to be aware of OSGi context not only about Servlet context, 
I have implemented:
OsgiAwareExternalContextFactory which is quite simmilar to default 
implementation. There are 2 differences. This class in constructor 
requires ExternalContextFactory (decorator design pattern <- it is part 
of JSF specification). The second difference is that we thos factory 
provides OsgiAwareExternalContext that in constructor requires 
ExternalContext (which we can obtain from original ExternalContextFactory).
OsgiAwareExternalContext (so far) delegates all of its method to 
original ExternalContext except of getResource(String) method. This 
method is using PluginsResolverService to obtain all plug-ins and to 
look if they are not containing resource that we are looking for.
2) I have implemented my own Servlet for handling non-faces request of 
resources.

That is all. Now if i'am installing plug-in that provides view: 
someView.xhtml, I'am able to display it (I'am typing in web browser: 
{Context path of Core}/someView.xhtml). But there is one problem. JSF 
caches views. So if plug-in will be uninstalled, page someView.xhtml is 
still visible for users.
I have found that DefaultFaceletFactory is responsible for caching 
views. And here is my question.
If I want to provide my own FaceletFactory implementation I have to 
provide brand new implementarion of ViewDeclarationLanguageFactory !!!

Standard implementation of ViewDeclarationLanguageFactory which is 
ViewDeclarationLanguageFactoryImpl creates in initialize() method 
FaceletViewDeclarationLanguageStrategy that is creating in constructor 
FaceletViewDeclarationLanguage that is creating in initialize() method 
FaceletFactory (DefaultFaceletFactory).

FaceletViewDeclarationLanguage has protected method 
createFaceletFactory(FacesContext, Compiler) (wchich is called in 
initialize() method) that is responsible for creating FaceletFactory. 
But even it is protected method that I Can override I cannot provide my 
own implementation of ViewDeclarationLanguageBase (which will extends 
FaceletViewDeclarationLanguage) because there is no way of informing 
FaceletViewDeclarationLanguageStrategy thats should use my 
implementation. Shouldn't it be possible ?

Sorry for my English :)

-- 
Pozdrawiam,
Kamil Soboń

iso.poczta(at)gmail.com
sobon(at)student.agh.edu.pl


Re: JSF + OSGi integration.

Posted by Kamil Soboń <is...@gmail.com>.
W dniu 2011-06-14 11:46, Jakob Korherr pisze:
> Hi,
>
> Actually you should not directly use stuff from myfaces-impl (package
> org.apache.myfaces.*). Theses classes are implementation specific and
> not built for extensions!
>
> If you need some base code, you should copy (or shade) it!
>
> Regards,
> Jakob
>

It is impossible (or only I cannot find a way) to provide my own 
FaceletCache in approach that you suggest.
If I want to provide my own implementation of FaceletCache (suppose: 
MyFaceletCache) I am also obligated to provide implementation of 
Facelet. I cannot use DefaultFacelet class due to the fact that it is 
final has package access and is placed in myfaces-impl. So I am creating 
MyDefaultFacelet (copy-paste from DefaultFacelet). Now I am bound to 
DefaultFaceletContext. Due to the fact that I cannot use 
DefaultFaceletContext (the same story: final, package class and placed 
in myfaces-impl). So I am creating MyDefaultFaceletContext (copy-paste 
from DefaultFaceletContext). Now everything should be ok (despite the 
fact that now I am resposible for maintaining code of MyFaceleteCache, 
MyDefaultFacelet and MyDefaultFaceletContext. And every [brilliant] 
change that will be made I have to recreate in my code).

But it is not working ! Why ? Lets look into constructor of 
DefaultFaceletFactory (DefaultFaceletFactory(Compiler, ResourceResolver, 
long)). Lines 131-134
Method setMemberFactoriesMethod = 
FaceletCache.class.getDeclaredMethod("setMemberFactories", new 
Class[]{FaceletCache.MemberFactory.class, 
FaceletCache.MemberFactory.class});
setMemberFactoriesMethod.setAccessible(true);
setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, 
viewMetadataFaceletFactory);

faceletFactory and viewMetadataFaceletFactory are created in those 
constructor and are bound to those class.

This lines makes that my FaceletCache (MyFaceletCache) is bound to 
DefaultFaceletFactory, so in fact I am bound to DefaultFacelet. So how I 
can provide my own FaceletCache that is not bound to DefaultFacelet ?

Of course normally if I could put MyFaceletCache in 
org.apache.myfaces.view.facelets.impl package. Now I can implement my 
own MyFaceletCache that is extending FaceletCache<DefaultFacelet>.
I am not extending anything but using appropriate implementation of 
Facelet. But in OSGi it is impossible to do so. Even if I put my class 
in appropriate package, class MyFaceletCache and DefaultFacelet will be 
loaded by different ClassLoaders and in fact will not be considered to 
be placed in the same package. As a result IllegalAccessError will be 
thrown.

The only solution for me, is to make class DefaultFaclet public 
(DefaultFacletContext also ?). Will it broke some security or 
architectonical assumptions ?

I hope that you can understand what I have written. If not, please 
describe whuch part is not clear to you. I will try to describe the 
problem in other way.

-- 
Pozdrawiam,
Kamil Soboń

iso.poczta(at)gmail.com
sobon(at)student.agh.edu.pl


Re: JSF + OSGi integration.

Posted by Kamil Soboń <is...@gmail.com>.
In JSF 2.1 FaceletCache has been created and provided for custom caching 
and mapping URL (of view) to Facelet.
Why simmilar assumption has not been done for mapping uri of view to its 
physical URL ?
I am talking about DefaultFaceletFactory#getViewMetadataFacelet(String) 
method where _relativeLocations class field is use to cache mappings 
between view's uri to its physical location.

I can only guess that, it hasn't been done due to the fact, that we are 
not handling the situation when physically view (xhtml page) can 
disappear. But if myfaces provides now libraries that can be used in 
OSGi environemnt, we can provide fragemnts for main JSF application. If 
so, those fragments can contains views. Fragments can be uninstalled in 
run-time, so pages can disappear. Shouldn't we handle it ? If I am 
thinking wrong ?

-- 
Pozdrawiam,
Kamil Soboń

iso.poczta(at)gmail.com
sobon(at)student.agh.edu.pl


Re: JSF + OSGi integration.

Posted by Jakob Korherr <ja...@gmail.com>.
Hi,

Actually you should not directly use stuff from myfaces-impl (package
org.apache.myfaces.*). Theses classes are implementation specific and
not built for extensions!

If you need some base code, you should copy (or shade) it!

Regards,
Jakob

2011/6/14 Kamil Soboń <is...@gmail.com>:
> W dniu 2011-06-14 01:30, Jakob Korherr pisze:
>>
>> Hi,
>>
>> Nice stuff ;)
>>
>> I think JSF 2.1 might have the answer to your problem. Two new classes
>> were introduced: FaceletCache and FaceletCacheFactory (see [1] and
>> [2]). With a custom impl of those two you should be able to control
>> the caching behavior!
>>
>> Regards,
>> Jakob
>>
>> [1]
>> http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCache.html
>> [2]
>> http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCacheFactory.html
>>
>> 2011/6/13 Kamil Soboń<is...@gmail.com>:
>>
>
> I have encountered some problems.
> I have investigated default implementation of FaceleteCache
> (FaceletCacheImpl) that is caching DefaultFacelet.
> Natural solution for me to provide my smart Facelet caching system that is
> aware of OSGi is to extend FaceletCacheImpl and provide new implementation
> of needsToBeRefreshed(DefaultFacelet) method. But it is not possible due to
> the fact that both classes has default (package) access modifier. In order
> to have access in using this classes i should put my own new implementation
> in org.apache.myfaces.view.facelets.impl package. But OSGi is throwing
> IllegalAccessError.
> I also cannot provide new implementation of FaceletCache (that bases on
> FaceletCacheImpl - simply copy&paste) due to the fact I want to use
> DefaultFacelete, which has also default (package) access modifier.
>
> Here is my question: why those classes has default (not public) access level
> ?
>
> --
> Pozdrawiam,
> Kamil Soboń
>
> iso.poczta(at)gmail.com
> sobon(at)student.agh.edu.pl
>
>



-- 
Jakob Korherr

blog: http://www.jakobk.com
twitter: http://twitter.com/jakobkorherr
work: http://www.irian.at

Re: JSF + OSGi integration.

Posted by Kamil Soboń <is...@gmail.com>.
W dniu 2011-06-14 01:30, Jakob Korherr pisze:
> Hi,
>
> Nice stuff ;)
>
> I think JSF 2.1 might have the answer to your problem. Two new classes
> were introduced: FaceletCache and FaceletCacheFactory (see [1] and
> [2]). With a custom impl of those two you should be able to control
> the caching behavior!
>
> Regards,
> Jakob
>
> [1] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCache.html
> [2] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCacheFactory.html
>
> 2011/6/13 Kamil Soboń<is...@gmail.com>:
>

I have encountered some problems.
I have investigated default implementation of FaceleteCache 
(FaceletCacheImpl) that is caching DefaultFacelet.
Natural solution for me to provide my smart Facelet caching system that 
is aware of OSGi is to extend FaceletCacheImpl and provide new 
implementation of needsToBeRefreshed(DefaultFacelet) method. But it is 
not possible due to the fact that both classes has default (package) 
access modifier. In order to have access in using this classes i should 
put my own new implementation in org.apache.myfaces.view.facelets.impl 
package. But OSGi is throwing IllegalAccessError.
I also cannot provide new implementation of FaceletCache (that bases on 
FaceletCacheImpl - simply copy&paste) due to the fact I want to use 
DefaultFacelete, which has also default (package) access modifier.

Here is my question: why those classes has default (not public) access 
level ?

-- 
Pozdrawiam,
Kamil Soboń

iso.poczta(at)gmail.com
sobon(at)student.agh.edu.pl


Re: JSF + OSGi integration.

Posted by Kamil Soboń <is...@gmail.com>.
W dniu 2011-06-14 01:30, Jakob Korherr pisze:
> Hi,
>
> Nice stuff ;)
>
> I think JSF 2.1 might have the answer to your problem. Two new classes
> were introduced: FaceletCache and FaceletCacheFactory (see [1] and
> [2]). With a custom impl of those two you should be able to control
> the caching behavior!
>
> Regards,
> Jakob
>
> [1] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCache.html
> [2] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCacheFactory.html

Thanks for the answer ! Few hours after my question, by fortune I have 
found this FaceletCache in JSF 2.1 implementation ;) I haven't chance to 
test it yet, due to the fact that it was quite late, but it seems to be 
promissing :)
I will report if it will going to work ;)
If someone is interested in our work, I can put here some information 
and our consideration about application that we are creating (and info 
about JSF and OSGi integration).

-- 
Pozdrawiam,
Kamil Soboń

iso.poczta(at)gmail.com
sobon(at)student.agh.edu.pl


Re: JSF + OSGi integration.

Posted by Jakob Korherr <ja...@gmail.com>.
Hi,

Nice stuff ;)

I think JSF 2.1 might have the answer to your problem. Two new classes
were introduced: FaceletCache and FaceletCacheFactory (see [1] and
[2]). With a custom impl of those two you should be able to control
the caching behavior!

Regards,
Jakob

[1] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCache.html
[2] http://javaserverfaces.java.net/nonav/docs/2.1/javadocs/javax/faces/view/facelets/FaceletCacheFactory.html

2011/6/13 Kamil Soboń <is...@gmail.com>:
> Hi all,
>
> I don't know if I am writing in appropriate place, but assume that I am ;)
> So ... for some time, me and my friend are trying to create JSF application
> in OSGi environment.
> This application should be composed form core element and it's plug-ins.
> Each plug-in (OSGi bundle) can be install installed or uninstalled in
> run-time. Application should be aware of its plug-ins and its lifecycle
> (installing/uninstalling) without being restarted.
>
> To do so, we are combining few technologies: JSF (MyFaces) + PrimeFaces +
> Hibernate + Spring + OSGi (Equinox) + SpringDM (will be exchange to
> blueprint).
> To simplicy prototype we are going to use JSF + Spring + Spring-DM + OSGi
> only.
>
> As we have realized, JSF has not been planned to work with dynamic
> components (plug-ins) that can provide new views (xhtml pages), resources or
> manageable-beans. But specification of JSF allows to swap some application's
> modules/components.
> I have figure out some mechanism for providing views and resources
> (manageable beans is quite more complicated and it is not part of my
> question now :)) in run-time without violate JSF specification (in my
> opinion ofcourse :)).
>
> So our application is working in OSGi environment. The core is typical JSF
> application deployed to Tomcat (thanks to Spring-DM) which  is also running
> in OSGi environment. Each plug-in is simply OSGi bundle that has dependency
> to Core. In Core there is PluginsResolverService that is responsible for
> detecting Core's available plug-in (assume that we are keeping Bundle
> descriptor).
>
> To provide views and resources in run-time (it is actuali working !) I have
> done 2 things:
>
> 1) I have implemented my own ExternalContext and ExternalContextFactory. Now
> we want to be aware of OSGi context not only about Servlet context, I have
> implemented:
> OsgiAwareExternalContextFactory which is quite simmilar to default
> implementation. There are 2 differences. This class in constructor requires
> ExternalContextFactory (decorator design pattern <- it is part of JSF
> specification). The second difference is that we thos factory provides
> OsgiAwareExternalContext that in constructor requires ExternalContext (which
> we can obtain from original ExternalContextFactory).
> OsgiAwareExternalContext (so far) delegates all of its method to original
> ExternalContext except of getResource(String) method. This method is using
> PluginsResolverService to obtain all plug-ins and to look if they are not
> containing resource that we are looking for.
> 2) I have implemented my own Servlet for handling non-faces request of
> resources.
>
> That is all. Now if i'am installing plug-in that provides view:
> someView.xhtml, I'am able to display it (I'am typing in web browser:
> {Context path of Core}/someView.xhtml). But there is one problem. JSF caches
> views. So if plug-in will be uninstalled, page someView.xhtml is still
> visible for users.
> I have found that DefaultFaceletFactory is responsible for caching views.
> And here is my question.
> If I want to provide my own FaceletFactory implementation I have to provide
> brand new implementarion of ViewDeclarationLanguageFactory !!!
>
> Standard implementation of ViewDeclarationLanguageFactory which is
> ViewDeclarationLanguageFactoryImpl creates in initialize() method
> FaceletViewDeclarationLanguageStrategy that is creating in constructor
> FaceletViewDeclarationLanguage that is creating in initialize() method
> FaceletFactory (DefaultFaceletFactory).
>
> FaceletViewDeclarationLanguage has protected method
> createFaceletFactory(FacesContext, Compiler) (wchich is called in
> initialize() method) that is responsible for creating FaceletFactory. But
> even it is protected method that I Can override I cannot provide my own
> implementation of ViewDeclarationLanguageBase (which will extends
> FaceletViewDeclarationLanguage) because there is no way of informing
> FaceletViewDeclarationLanguageStrategy thats should use my implementation.
> Shouldn't it be possible ?
>
> Sorry for my English :)
>
> --
> Pozdrawiam,
> Kamil Soboń
>
> iso.poczta(at)gmail.com
> sobon(at)student.agh.edu.pl
>
>



-- 
Jakob Korherr

blog: http://www.jakobk.com
twitter: http://twitter.com/jakobkorherr
work: http://www.irian.at