2014-09-16 15:16 GMT+02:00 Konstantin Kolinko <knst.koli...@gmail.com>:
> 2014-09-15 23:01 GMT+04:00 Romain Manni-Bucau <rmannibu...@gmail.com>:
>> Hi guys,
>>
>> in TomEE I'd like to add a filter but after context filter are started
>> (means filterStart() from StandardContext is called).
>>
>
> Why? What is the use case?
>

we add a filter with a tomee service (passing after tomee started)

> You code adds filter definitions. A filter definitions just associates
> filter with a name. A filter is unreachable if it has no mappings for
> it.
> Where are filter mappings for your filter? How do you add filter mappings?
>

full code is:

        final FilterDef filterDef = new FilterDef();
        filterDef.setAsyncSupported("true");
        filterDef.setDescription(description);
        filterDef.setFilterName(description);
        filterDef.setDisplayName(description);
        filterDef.setFilter(new CXFJAXRSFilter(cxfRsHttpListener,
context.findWelcomeFiles()));
        filterDef.setFilterClass(CXFJAXRSFilter.class.getName());
        context.addFilterDef(filterDef);

        String mapping = completePath;
        if (!completePath.endsWith("/*")) {
            if (completePath.endsWith("*")) {
                mapping = completePath.substring(0, completePath.length() - 1);
            }
            mapping = mapping + "/*";
        }

        final String urlPattern = removeWebContext(webContext, mapping);
        cxfRsHttpListener.setUrlPattern(urlPattern.substring(0,
urlPattern.length() - 1));

        final FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern(urlPattern);
        filterMap.setFilterName(filterDef.getFilterName());
        context.addFilterMap(filterMap);

        addFilterConfig(context, filterDef); // the hack I sent previously


> When do you add your new filter? Is context already started and
> serving requests, or it has not started yet?  Why cannot you add
> filter definition before a filterStart() call?
>
> Do you use "StandardContext" class directly, or you can subclass it?
>

directly, tomee doesn't change StandardContext (one big goal)

> The proper solutions should be to add new API, but I would like the
> answers on the above questions first, as
> a) There shall be some API for filter mappings as well.
> b) If context has already been started, implementation would be more
> complicated.
>
>> What I do today is:
>>
>
> Where do I start with this?
>
> Just several notes on the code.
>
> 1. Missing synchronization. filterStart() uses "synchronized
> (filterConfigs)" Your code does not use synchronization.
>

Actually we don't care that much here since that's still in the start
context (app is not yet fully usable) so multithreading shouldnt
occur, does it in tomcat?

> 2. If you using "setAccessible(true)",
>
> A simpler way would be to mark ApplicationFilterConfig constructor as
> accessible and call it directly instead of playing with filterStart().
>
> Playing with filterStart() without accompanying filterStop() call is broken
>
> filterStart() does "filterConfigs.clear();" as one of the first steps.
> A lot of code in your method are a workaround against that clear()
> call. (You copy the filterConfigs into a temporary map to preserve the
> map entries from being cleared). Essentially this clear() call throws
> away filter instances (wrapped in ApplicationFilterConfig classes)
> without properly destroying them.
>
> You code might break if "filterConfigs" field were marked as"final"
> (as it should be).
>

we already got this before in webapp classloader and until tomcat
supports our feature we forced by reflection the field to not be
final. That said I agree (and why I ask for a simpler API) that it is
mainly workarounds but I don't see why StandardContext is not exposing
it (what would be blocking).

>
>
>>     try {
>>             final Field def =
>> StandardContext.class.getDeclaredField("filterDefs");
>>             if (!def.isAccessible()) {
>>                 def.setAccessible(true);
>>             }
>>             final Field config =
>> StandardContext.class.getDeclaredField("filterConfigs");
>>             if (!config.isAccessible()) {
>>                 config.setAccessible(true);
>>             }
>>             final Object oldDefs = def.get(context);
>>             final Map<String, ApplicationFilterConfig> oldConfig = new
>> HashMap<>((Map<String, ApplicationFilterConfig>) config.get(context));
>>             try {
>>                 final Map<String, FilterDef> tempDef = new HashMap<>();
>>                 tempDef.put(filterDef.getFilterName(), filterDef);
>>                 def.set(context, tempDef);
>>
>>                 StandardContext.class.cast(context).filterStart();
>
> Why such code style? The following is shorter.
>                   ((StandardContext)context).filterStart();
>
>
>>                 // update configs
>>                 oldConfig.putAll((Map<String,
>> ApplicationFilterConfig>) config.get(context));
>>             } finally {
>>                 def.set(context, oldDefs);
>>                 def.set(context, oldConfig);
>>             }
>>         } catch (final Exception e) {
>>             throw new IllegalStateException(e);
>>         }
>>
>> but it is really hacky just to get a ApplicationFilterConfig. Is there
>> an easier way I miss or is it possible to make it a bit more easy?
>>
>>
>> Romain Manni-Bucau
>> Twitter: @rmannibucau
>> Blog: http://rmannibucau.wordpress.com/
>> LinkedIn: http://fr.linkedin.com/in/rmannibucau
>> Github: https://github.com/rmannibucau
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
> For additional commands, e-mail: dev-h...@tomcat.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to