CXF OSGi bundle - зарегистрировать фильтр для CXFServlet?
У меня есть пакет CXF OSGi, развернутый в контейнере karaf с несколькими конечными точками, каждая в своем собственном пакете. Конечные точки представляют собой смесь вкусов JAX-RS и JAX-WS. Я хотел бы включить некоторую защиту на конечных точках с помощью JOSSO, и для этого нужно зарегистрировать фильтр сервлетов. Очевидно, что без web.xml для объявления фильтра мне нужно зарегистрировать их в реестре службы OSGi.
Я пытался использовать доску pax-web http для регистрации фильтра, но метод doFilter никогда не вызывался. Я заметил, что в реализации Distributed OSGI cxf есть условие для установки для свойства org.apache.cxf.httpservice.filter значения true в фильтре и указания фиктивной строки для servletNames, чтобы не перепутать интерактивную доску pax-web. Есть ли что-то похожее для стандартного CXF (нераспределенного) пакета OSGi, которое я могу сделать, чтобы зарегистрировать фильтр сервлета?
2 ответа
После многих копаний я смог установить фильтр для сервлета CXF с помощью Felix + PAX Web. Хитрость заключается в том, чтобы зарегистрировать фильтр в пакете CXF (для каждого пакета существует отдельный http-контекст).
В моем коде я извлек контекст пакета, называемый getBundles(), нашел пакет cxf и получил контекст пакета CXF. Затем я зарегистрировал фильтр в контексте пакета CXF. Сейчас я чувствую себя очень грязно, но это работает.
Напомню, что я видел рекомендацию о создании пакета fragement для конфигурации сервера Jetty PAX, это, вероятно, также будет работать для регистрации фильтра - однако я не хотел создавать еще один артефакт в нашем проекте в настоящее время.
Я оказался в ситуации, когда нужно было написать глобальный фильтр для Apache CXF, но не мог понять, как это сделать.
Некоторые исследования показали, что Apache CXF использует OSGi и напрямую регистрирует сервлет. Подробнее см. https://github.com/apache/cxf/blob/90df32db98d8fc76f091723561f42c6d16021db4/rt/transports/http/src/main/java/org/apache/cxf/transport/http/osgi/ServletExporter.java#L126 .
Вы можете видеть, что используется контекст http по умолчанию, который привязан к пакету. См. https://github.com/ops4j/org.ops4j.pax.web/blob/d2172a91ad2579714d40b509d6c420e5c28fa2d0/pax-web-runtime/src/main/java/org/ops4j/pax/web/service/internal/HttpServiceStarted.java#L337
Следовательно, вы не можете просто открыть фильтр и заставить его работать с сервлетом CXF.
Однако, как говорил froh42, можно получить пакет, экспортировав сервлет CXF, и использовать его контекст пакета для регистрации фильтра. Если вы сомневаетесь, какой пакет вам нужен, используйте следующую команду в оболочке Karaf:
service:list javax.servlet.ServletContext
и он покажет символическое имя пакета, раскрывающего контексты:
[javax.servlet.ServletContext]
------------------------------
osgi.web.contextname = default
osgi.web.contextpath = /
osgi.web.symbolicname = org.apache.cxf.cxf-rt-transports-http
osgi.web.version = 3.5.0
service.bundleid = 97
service.id = 218
service.scope = singleton
Provided by :
Apache CXF Runtime HTTP Transport (97)
Used by:
OPS4J Pax Web - Runtime (182)
Короче говоря, вот как вы могли бы написать такую логику регистрации. Имейте в виду, что вам нужно использовать
WebContainer
от
pax-web-api
модуль, так как это позволяет зарегистрировать фильтр.
HttpService
не имеет такой возможности.
package org.example.cxf.filter;
import org.ops4j.pax.web.service.WebContainer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.http.HttpContext;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Component
public class CxfFilterRegistrator {
@Activate
public void onActivate(BundleContext bundleContext) throws InvalidSyntaxException {
final WebContainer cxfWebContainer = findCxfWebContainerOrFail(bundleContext);
final HttpContext otherContext = cxfWebContainer.createDefaultHttpContext();
final Dictionary<String, String> initProperties = new Hashtable<>();
initProperties.put("key", "value");
cxfWebContainer.registerFilter(MyFilter.class, new String[]{"/*"}, null, initProperties, otherContext);
}
@Deactivate
public void onDeactivate(BundleContext bundleContext) throws InvalidSyntaxException {
final WebContainer cxfWebContainer = findCxfWebContainerOrFail(bundleContext);
cxfWebContainer.unregisterFilter(MyFilter.class);
}
private WebContainer findCxfWebContainerOrFail(final BundleContext bundleContext) throws InvalidSyntaxException {
final List<Bundle> cxf = Stream.of(bundleContext.getBundles())
.filter(bundle -> bundle.getSymbolicName().equals("org.apache.cxf.cxf-rt-transports-http"))
.collect(Collectors.toList());
if (cxf.isEmpty()) {
throw new IllegalStateException("CXF not found, Bailing");
}
final BundleContext cxfBundleContext = cxf.get(0).getBundleContext();
final Collection<ServiceReference<WebContainer>> serviceReferences = cxfBundleContext.getServiceReferences(WebContainer.class, null);
final WebContainer otherWebContainer = cxfBundleContext.getService(serviceReferences.iterator().next());
return otherWebContainer;
}
}