changed to:

private void addFilterConfig(final Context context, final FilterDef filterDef) {
        // hack to force filter to get a config otherwise it is
ignored in the http routing
        try {
            final Constructor<ApplicationFilterConfig> cons =
ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,
FilterDef.class);
            if (!cons.isAccessible()) {
                cons.setAccessible(true);
            }
            final ApplicationFilterConfig config =
cons.newInstance(context, filterDef);
            ((Map<String, ApplicationFilterConfig>)
Reflections.get(context,
"filterConfigs")).put(filterDef.getFilterName(), config);
        } catch (final Exception e) {
            throw new IllegalStateException(e);
        }
    }

works fine even if not sexy

Thanks Konstantin for the feedback


Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau


2014-09-16 15:50 GMT+02:00 Romain Manni-Bucau <rmannibu...@gmail.com>:
> 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