Hi guys,

let me weigh in on the filter question: please, no filter!

@prefix suffix mappings: you can get the registered mappings

in previous servlet versions: parsing the web.xml
in servlet 3.0: via the API
http://download.oracle.com/javaee/6/api/javax/servlet/ServletRegistration.html

the resource url should then always be generated with the prefix
mapping - how can this lead to inconsistencies?

best regards,

Martin

On Thu, Jun 23, 2011 at 11:54 PM, Leonardo Uribe <lu4...@gmail.com> wrote:
> Hi
>
> In the last days this enhancements were commited:
>
> ------------------------------------------------------------------------------
>
> Added GZIP compression to ExtendedResourceHandler and these params:
>
>    /**
>     * Enable or disable gzip compressions for resources served by
> this extended resource handler. By default is disabled (false).
>     */
>    @JSFWebConfigParam(defaultValue="false")
>    public static final String INIT_PARAM_GZIP_RESOURCES_ENABLED =
> "org.apache.myfaces.commons.GZIP_RESOURCES_ENABLED";
>
>    /**
>     * Indicate the suffix used to recognize resources that should be
> compressed. By default is ".css .js".
>     */
>    @JSFWebConfigParam(defaultValue=".css, .js")
>    public static final String INIT_PARAM_GZIP_RESOURCES_SUFFIX =
> "org.apache.myfaces.commons.GZIP_RESOURCES_SUFFIX";
>    public static final String
> INIT_PARAM_GZIP_RESOURCES_EXTENSIONS_DEFAULT = ".css .js";
>
>    /**
>     * Indicate if gzipped files are stored on a temporal directory to
> serve them later. By default is true. If this is
>     * disable, the files are compressed when they are served.
>     */
>    @JSFWebConfigParam(defaultValue="true")
>    public static final String INIT_PARAM_CACHE_DISK_GZIP_RESOURCES =
> "org.apache.myfaces.commons.CACHE_DISK_GZIP_RESOURCES";
>
> by default compression is set to false. It could be good to enable
> compression only on files bigger than some specified lenght, to allow
> finer tuning.
>
> ------------------------------------------------------------------------------
>
>
> and these enhancements:
>
>
> ------------------------------------------------------------------------------
>
> Added new scanning and parsing of myfaces-resources-config.xml files.
> It was added this param:
>
>    /**
>     * This param allow to override the default strategy to locate
> myfaces-resources-config.xml files, that will be parsed later. In this
> way
>     * it is possible to include new source locations or handle cases
> like OSGi specific setup.
>     */
>    @JSFWebConfigParam
>    public static final String
> INIT_PARAM_EXTENDED_RESOURCE_HANDLER_CONFIG_URL_PROVIDER =
> "org.apache.myfaces.commons.EXTENDED_RESOURCE_HANDLER_CONFIG_URL_PROVIDER";
>
> I think just a param that instantiate a class implementing
> MyFacesResourceHandlerUrlProvider is enough. The default algorithm
> loook on classpath for META-INF/myfaces-resources-config.xml and on
> servlet context for WEB-INF/myfaces-resources-config.xml files.
>
> myfaces-resources-config.xml files can be used with these options:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <myfaces-resources-config>
>    <!-- Mark this library to be handled by Extended Resource Handler -->
>    <library>
>        <library-name>libraryA</library-name>
>    </library>
>
>    <!-- Indicate this library has another name, so if libraryC is used,
>    resources should be redirected to libraryC1 -->
>    <library>
>        <library-name>libraryC</library-name>
>        <redirect-name>libraryC1</redirect-name>
>    </library>
>
>    <!-- Allow to customize the request path generated, to do things like
>    take library resources from a Content Delivery Network (CDN) or just
>    take it directly from an specified location. Note it is responsibility
>    of the developer to configure it properly, and the resources should
>    exists locally under the library name selected. -->
>    <library>
>        <library-name>libraryB</library-name>
>        
> <request-path>http://someaddress.com/alternatePath/#{resourceName}</request-path>
>         <!-- This example shows the variables that can be called
> inside the expression to construct the request map
>        <request-path>#{extensionMapping ? '' :
> mapping}/javax.faces.resource/$/#{localePrefix}/#{libraryName}/#{resourceName}#{extensionMapping
> ? mapping : ''}</request-path>
>         -->
>    </library>
>
> </myfaces-resources-config>
>
> All libraries referenced here will be handled by the extended
> ResourceHandler. Additionally, there is an option to redirect a
> library name into another, to deal with possible conflicts between
> resources loaded, specially javascript libraries. And finally there is
> an option to override the request-path with an EL expression, so if
> you have a library with some static resources it is easy to construct
> an url to load them from a Content Delivery Network (CDN) or just from
> some specified path. The only thing you should note is the library
> should exists locally under the library name, to detect when a
> resource can be resolved or not.
>
> ------------------------------------------------------------------------------
>
> I have not tested it fully, but in my opinion it looks good. I has the
> best of the previous AdvancedResourceHandler with some new valuable
> features proposed.
>
> If no objections I'll remove the previous code, since it was
> integrated on the alternate solution.
>
> Suggestions and tomatoes are welcome
>
> Leonardo Uribe
>
> 2011/6/14 Leonardo Uribe <lu4...@gmail.com>:
>> Hi Jakob
>>
>> 2011/6/14 Jakob Korherr <jakob.korh...@gmail.com>:
>>> Hi Leonardo,
>>>
>>>>Because set prefix and suffix mapping for the same webapp could lead
>>>>to inconsistencies.
>>>
>>> Which inconsistencies exactly? Please give an example, I can't really
>>> think of any!
>>>
>>
>> Let's take a look to AdvanceResource.getRequestPath:
>>
>>    public String getRequestPath()
>>    {
>>        FacesContext facesContext = FacesContext.getCurrentInstance();
>>        StringBuilder path = new StringBuilder();
>>        path.append(ResourceUtils.getFacesServletPrefix(facesContext));
>>        .....
>>
>> Now look on getFacesServletPrefix:
>>
>>    public static String getFacesServletPrefix(FacesContext facesContext)
>>    {
>>        ExternalContext externalContext = facesContext.getExternalContext();
>>        Map<String, Object> applicationMap =
>> externalContext.getApplicationMap();
>>
>>        // check if already cached
>>        String prefix = (String) applicationMap.get(FACES_SERVLET_PREFIX_KEY);
>>        if (prefix == null)
>>        {
>>            // try to extract it from current request
>>            prefix = getFacesServletPrefixMapping(facesContext);
>>            ....
>>
>>    public static String getFacesServletPrefixMapping(FacesContext 
>> facesContext)
>>    {
>>        ExternalContext externalContext = facesContext.getExternalContext();
>>
>>        String pathInfo = externalContext.getRequestPathInfo();
>>        String servletPath = externalContext.getRequestServletPath();
>>
>>        if (pathInfo != null)
>>        {
>>             return servletPath;
>>        }
>>        else
>>        {
>>            // In the case of extension mapping, no "extra path" is available.
>>            // Still it's possible that prefix-based mapping has been used.
>>            // Actually, if there was an exact match no "extra path"
>>            // is available (e.g. if the url-pattern is "/faces/*"
>>            // and the request-uri is "/context/faces").
>>            int slashPos = servletPath.lastIndexOf('/');
>>            int extensionPos = servletPath.lastIndexOf('.');
>>            if (extensionPos > -1 && extensionPos > slashPos)
>>            {
>>                // we are only interested in the prefix mapping
>>                return null;
>>            }
>>            else
>>            {
>>                // There is no extension in the given servletPath and 
>> therefore
>>                // we assume that it's an exact match using
>> prefix-based mapping.
>>                return servletPath;
>>            }
>>        }
>>    }
>>
>> The code takes pathInfo/servletPath information and prepend it to the
>> beggining. The first bug is the code prepend the extension when suffix
>> mapping is used!. But look the mapping is saved on the application
>> map. So on further request, the mapping is retrieved from application
>> map, so if the first request is suffix mapping, all later resource
>> request paths will be generated wrong, even if prefix mapping is used.
>>
>> The problem is to know if prefix mapping is used you should parse
>> web.xml file, but that's wrong, because in servlet 3.0 spec you don't
>> necessary have that file (web fragment?). In conclusion there is no
>> way to "detect" and generate the mapping correctly.
>>
>> The nice part about the filter is you can put some code to detect
>> automatically if the filter is registered or not and act according.
>> This is the param:
>>
>>    /**
>>     * Indicate if this filter is being used to process request. It
>> works in three modes:
>>     *
>>     * <ul>
>>     * <li>true: assume the filter is correctly setup.</li>
>>     * <li>check: check if the filter has been setup and if that so,
>> use it. Otherwise, it uses FacesServlet (use prefix mapping to make
>> all features work).</li>
>>     * <li>false: filter is not used at all.</li>
>>     * </ul>
>>     */
>>    @JSFWebConfigParam(defaultValue="check", expectedValues="true,
>> false, check")
>>    public static final String INIT_PARAM_USE_EXTENDED_RESOURCE_FILTER
>> = "org.apache.myfaces.commons.USE_EXTENDED_RESOURCE_FILTER";
>>    public static final String
>> INIT_PARAM_USE_EXTENDED_RESOURCE_FILTER_DEFAULT = "check";
>>
>> In this way, there will not be inconsistencies, because we have the
>> three options:
>>
>> - If prefix mapping is used -> prepend the prefix
>> - If suffix mapping is used and no filter setup -> use suffix mapping
>> like always
>> - If suffix mapping is used and filter setup -> use filter prefix mapping
>>
>>>>[...] If a page is rendered using suffix mapping,
>>>>resource paths will use that and not prefix mapping, because faces
>>>>mapping is derived from the request path.
>>>
>>> Nope. That's the whole point of the AdvancedResourceHandler. It always
>>> uses prefix mapping, regardless of what the current page is using!!
>>> Just check the code (before your commit) ;)
>>>
>>
>> As you can see, I have found many bugs in the previous code. I usually
>> take my time to check this stuff. In fact, I implemented all
>> ResourceHandler implementation in MyFaces, and other alternate
>> implementations on tomahawk and sandbox for different use cases, so I
>> know step by step what says the spec and how the code works.
>>
>>> I have to say I am not a real fan of this filter. It's like in the old
>>> days.. with tomahawk...
>>>
>>
>> Note every JSF library uses a filter! Trinidad, RichFaces, PrimeFaces,
>> IceFaces. It could be good to find a solution without use a filter but
>> based on the previous discussion I don't see any. I don't get the
>> point. If you have a better idea please send your comments.
>>
>> I think the strategy proposed is an advance, because you only use it
>> when it is necessary. The other alternative is tell users don't use
>> suffix mapping.
>>
>>>> I think the opposite in this case, because the previous syntax is
>>>> ambiguous, so you can't decide how to get the libraryName and
>>>> resourceName from the resourceBasePath, and the spec requires describe
>>>> that in a explicit way. Think about a resource on:
>>>>
>>>> /de/mydir/myresource.js  (resourceName="de/mydir/myresource.js")
>>>>
>>>> will produce this request path:
>>>>
>>>> http://{server}[:port]/{appPath}/javax.faces.resource/de_AT/mydir/myresource.js
>>>>
>>>> The algorithm will detect de as a locale prefix, mydir as a library
>>>> and myresource.js as a resource name, but that's wrong because the
>>>> resource name is de/mydir/myresource.js.
>>>
>>> I am sorry, but this is wrong, Leo.
>>>
>>> At first a resourceName of "de/mydir/myresource.js" should not be
>>> used. It should rather be resourceName="myresource.js" and
>>> libraryName="de/mydir". I know the spec does not explicitly tell us
>>> that the resourceName must not be a path, but it is the only way it
>>> really makes sence, if you think about it. Otherwise separation of
>>> libraryName and resourceName would not be necessary!
>>>
>>
>> The problem is "should not be used" is not an option. I'm saying here
>> that the same url could be handled by both the default and the
>> proposed method. Assume that a developer will do everything you
>> imagine is not very realistic.
>>
>>> Furthermore, a resourceName of "de/mydir/myresource.js" would produce
>>> the following path (you did skip "de" and "faces"):
>>>
>>> http://{server}[:port]/{appPath}/faces/javax.faces.resource/de_AT/de/mydir/myresource.js
>>>
>>> ..thus producing a resource with libraryName="de/mydir" and
>>> resourceName="myresource.js". And this is exactly what is expected of
>>> it!!
>>
>> No, because "de" is a valid locale!.
>>
>> I think that the relationship between Resource instances and request
>> paths generated should be 1:1 and should be symmetric. That means, if
>> I call this code from a renderer:
>>
>> ResourceHandler.createResource("","","de/mydir/myresource.js");
>>
>> Later the ResourceHandler implementation, when
>> handleResourceRequest(FacesContext) is called should call the same
>> method, but instead it will call:
>>
>> ResourceHandler.createResource("de","mydir","myresource.js");
>>
>> Who should attend the request? the extended resource handler or the
>> default one. The first call expect the default one, but the second?.
>>
>> In conclusion, if the example does not fulfit the two conditions (be
>> 1:1 and symmetric), for any imaginable Resource instance, it will not
>> be correctly specified.
>>
>>>
>>>> Anyway we need something to "diferentiate" between the old and the
>>>> alternate syntax, so use '$/' is as good as any other we can imagine.
>>>
>>> I don't think we need to do this differentiation in the first place. I
>>> see no reason for it. My code in MyFaces commons (before you committed
>>> your stuff) did not use it either and it worked well! Of course, I did
>>> not have this filter, but I don't like that anyway (see above).
>>>
>>
>> Why don't you like it? do you have something better in mind?. If you
>> want I change of opinion, please provide me with arguments to think
>> the opposite. I'm always open to any suggestions or critics.
>>
>>>> My interest is put this as a module for JSF 2.0, because there is
>>>> nothing that prevent us doing it, and this is the "base stone" to make
>>>> components with libraries like dojo, that requires load modules from
>>>> derived base paths. After that, we can push this on the spec for JSF
>>>> 2.2 and the EG will decide.
>>>
>>> That's the general idea. And note that I am the guy working on the
>>> resource handler stuff in the JSF 2.2 EG ;)
>>>
>>>
>>> One more note at the end: actually I am not very happy that you
>>> committed your code directly into the svn without providing it as
>>> patch before. You did not do any work on the AdvancedResourceHandler
>>> before (it was all my code) and it was a pretty big commit (even took
>>> 2 commit-mails). Thus you gave me no choice to take a look at it and
>>> discuss the changes with you. If I did something like this, the first
>>> thing you would do is reverting my commit and providing it as patch so
>>> that we can discuss it. I won't do that, but actually it's kinda
>>> annoying...
>>>
>>
>> I commited the code instead create a patch, because the code commited
>> does not override the previous code. So you can put the two solutions
>> side by side and compare them in a easier way. If something doesn't
>> like us, we can remove the added files and that's it, there is no harm
>> or you don't have to do something difficult to revert the code,
>> right?. Note the code has not released yet, so we don't have to
>> preserve the package or the class name or any structure.
>>
>> Things are different when you have already code and you need to
>> "override" something, to include something new. A patch is better in
>> that case. But in this case, I'm working on a completely different
>> solution from scratch.
>>
>> regards,
>>
>> Leonardo Uribe
>>
>>> Regards,
>>> Jakob
>>>
>>> 2011/6/14 Leonardo Uribe <lu4...@gmail.com>:
>>>> Hi Jakob
>>>>
>>>> 2011/6/13 Jakob Korherr <jakob.korh...@gmail.com>:
>>>>> Hi Leo,
>>>>>
>>>>> Overall this seems nice, thanks!
>>>>>
>>>>> However, I have some comments on your solution:
>>>>>
>>>>> 1) If I have to configure a Filter in web.xml I can just as good
>>>>> define a prefix mapping for the FacesServlet. I don't see why an
>>>>> additional Filter is better than an additional servlet-mapping. So why
>>>>> exactly?
>>>>>
>>>>
>>>> Because set prefix and suffix mapping for the same webapp could lead
>>>> to inconsistencies. If a page is rendered using suffix mapping,
>>>> resource paths will use that and not prefix mapping, because faces
>>>> mapping is derived from the request path.
>>>>
>>>> We can't change FacesServlet to only handle resource request for a
>>>> specific mapping, but with the filter this is done by default. Note
>>>> the filter will be used only when suffix mapping is used. I tried it
>>>> using FacesServlet but it is useless, because you should do changes on
>>>> jsf impl, so at the end it will only work on myfaces, and the
>>>> intention is provide it as a module for any jsf implementation.
>>>>
>>>>> 2) The locale in the resource path really is essential, please do NOT
>>>>> remove it. I did a lot of tests with different browsers about this and
>>>>> you just cannot verify that every user will get the right (localized)
>>>>> resource, if the user's locale is not on the request path. The two
>>>>> main problems here are: a) the user changes the locale, but the
>>>>> browser uses the cached resource (with the old locale), because it
>>>>> cannot know that it has changed (some browsers will not even start a
>>>>> request for it) - however, if the locale is in the path, it will
>>>>> change and thus the browser will trigger a new request for the
>>>>> resource. b) you cannot really know if there are multiple versions of
>>>>> a resource for different locales, because you should not scan all jar
>>>>> files for them (--> remember the performance-issue we had with this
>>>>> stuff) and furthermore the classpath might change!
>>>>>
>>>>
>>>> Ok, good to know that. The current code works "forcing" output the
>>>> locale, so we can just let things as is.
>>>>
>>>>> 3)
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/{locale}/{libraryName}/[resourceName]
>>>>>>
>>>>>> Unfortunately, this syntax is ambiguous, because it is not possible to
>>>>>> identify if the request should be handled by the default algorithm or
>>>>>> by the "extended" ResourceHandler. So I tried this one on
>>>>>> ExtendedResourceHandler:
>>>>>>
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/$/{locale}/{libraryName}/[resourceName]
>>>>>
>>>>> This is a nice idea, but I guess this will not be an option for the
>>>>> JSF 2.2 resource handler (which will most likely be a modified version
>>>>> of the AdvancedResourceHandler).
>>>>>
>>>>
>>>> I think the opposite in this case, because the previous syntax is
>>>> ambiguous, so you can't decide how to get the libraryName and
>>>> resourceName from the resourceBasePath, and the spec requires describe
>>>> that in a explicit way. Think about a resource on:
>>>>
>>>> /de/mydir/myresource.js  (resourceName="de/mydir/myresource.js")
>>>>
>>>> will produce this request path:
>>>>
>>>> http://{server}[:port]/{appPath}/javax.faces.resource/de_AT/mydir/myresource.js
>>>>
>>>> The algorithm will detect de as a locale prefix, mydir as a library
>>>> and myresource.js as a resource name, but that's wrong because the
>>>> resource name is de/mydir/myresource.js.
>>>>
>>>> Anyway we need something to "diferentiate" between the old and the
>>>> alternate syntax, so use '$/' is as good as any other we can imagine.
>>>> My interest is put this as a module for JSF 2.0, because there is
>>>> nothing that prevent us doing it, and this is the "base stone" to make
>>>> components with libraries like dojo, that requires load modules from
>>>> derived base paths. After that, we can push this on the spec for JSF
>>>> 2.2 and the EG will decide.
>>>>
>>>> regards,
>>>>
>>>> Leonardo Uribe
>>>>
>>>>>
>>>>> Please take this stuff into account - thanks!
>>>>>
>>>>> Regards,
>>>>> Jakob
>>>>>
>>>>> 2011/6/14 Leonardo Uribe <lu4...@gmail.com>:
>>>>>> Hi
>>>>>>
>>>>>>  I committed on myfaces-commons-resourcehandler module on trunk an
>>>>>> alternative solution for this issue. It is still not complete, so the
>>>>>> idea is discuss it. See:
>>>>>>
>>>>>> https://issues.apache.org/jira/browse/MFCOMMONS-33
>>>>>>
>>>>>> From previous discussion, on AdvancedResource handler we have:
>>>>>>
>>>>>> a. relative paths between resources (css files referencing images
>>>>>> without using #resource['..'])
>>>>>> b. caching resources in the client (disabled if ProjectStage == 
>>>>>> Development)
>>>>>> c. GZIP compression and local cache in tmp dir (disabled if
>>>>>> ProjectStage == Development)
>>>>>> d. i18n (supporting country code and language).
>>>>>>
>>>>>> We had the following proposals:
>>>>>>
>>>>>> 1. reutilize resource information to prevent unnecessary calls to
>>>>>> getResource() (shared ResourceCache).
>>>>>> 2. Alternate xml file
>>>>>> 3. Make it work with suffix mapping.
>>>>>> 4. Add a SPI interface to delegate .xml resource scanning.
>>>>>> 5. Use content delivery network (CDN) to load known javascript or other
>>>>>> resource files like jQuery or prototype.
>>>>>>
>>>>>> The objective is provide a solution for all those wanted features.
>>>>>>
>>>>>> The most important one is number 3. (make it work with suffix
>>>>>> mapping), because it limits the scope where a. (relative paths between
>>>>>> resources) could be applied. Use a parse on some files it is not a
>>>>>> very good solution, so I tried to found an alternative. The most
>>>>>> simple one is use a filter that just do the "resource handling" part,
>>>>>> just like FacesServlet does. So with suffix mapping you only need to
>>>>>> add this on web.xml file:
>>>>>>
>>>>>>    <filter>
>>>>>>        <filter-name>Faces Filter</filter-name>
>>>>>>        
>>>>>> <filter-class>org.apache.myfaces.commons.resourcehandler.filter.ResourceHandlerFilter</filter-class>
>>>>>>    </filter>
>>>>>>
>>>>>>    <filter-mapping>
>>>>>>        <filter-name>Faces Filter</filter-name>
>>>>>>        <url-pattern>/javax.faces.resource/*</url-pattern>
>>>>>>    </filter-mapping>
>>>>>>
>>>>>> and that's it. In this way, there is no need to any parser, just put
>>>>>> the files on a library, register it on the xml file. If you are using
>>>>>> prefix mapping for Faces Servlet, you will not need that entry,
>>>>>> because everything will be handled from Faces Servlet.
>>>>>>
>>>>>> With this solution, javascript libraries like dojo that loads files or
>>>>>> have css resources with url(...) entries will work without any
>>>>>> changes.
>>>>>>
>>>>>> I have seen this issue:
>>>>>>
>>>>>> https://issues.apache.org/jira/browse/MFCOMMONS-30
>>>>>> Change URL management of Advanced JSF 2 ResourceHandler
>>>>>>
>>>>>> The idea was use this
>>>>>>
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/{locale}/{libraryName}/[resourceName]
>>>>>>
>>>>>> Unfortunately, this syntax is ambiguous, because it is not possible to
>>>>>> identify if the request should be handled by the default algorithm or
>>>>>> by the "extended" ResourceHandler. So I tried this one on
>>>>>> ExtendedResourceHandler:
>>>>>>
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/$/{locale}/{libraryName}/[resourceName]
>>>>>>
>>>>>> The first $ caracter says this extension should be handled by the
>>>>>> ExtendedResourceHandler. We can go further and allow this notation:
>>>>>>
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/$$/{libraryName}/[resourceName]
>>>>>>
>>>>>> In this way there is no ambiguity, and we don't need to force locale
>>>>>> to be output. This could be possible too:
>>>>>>
>>>>>> http://{server}[:port]/{appPath}/javax.faces.resource/$$$/[resourceName]
>>>>>>
>>>>>> But that it is not really necessary at all.
>>>>>>
>>>>>> The proposed code still does not contains the options for GZIP
>>>>>> compression, because the previous algorithm does not take into account
>>>>>> what happen on concurrent requests (two threads modifying the same
>>>>>> file at the same time). I did an algorithm for sandbox for JSF 2.0
>>>>>> s:roundedPanel. It uses an application scope map and some synchronized
>>>>>> blocks to ensure only one thread writes the file. Exactly the same
>>>>>> pattern works in this case, so the only thing we need to do is
>>>>>> refactor that code and put it here.
>>>>>>
>>>>>> Does that sounds good? if no objections commit the proposals here soon.
>>>>>>
>>>>>> regards,
>>>>>>
>>>>>> Leonardo Uribe
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Jakob Korherr
>>>>>
>>>>> blog: http://www.jakobk.com
>>>>> twitter: http://twitter.com/jakobkorherr
>>>>> work: http://www.irian.at
>>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Jakob Korherr
>>>
>>> blog: http://www.jakobk.com
>>> twitter: http://twitter.com/jakobkorherr
>>> work: http://www.irian.at
>>>
>>
>



-- 

http://www.irian.at

Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German

Professional Support for Apache MyFaces

Reply via email to