Проблемы с GWT в OSGi+Pax-Web с использованием декларативных сервисов
Я перевожу существующее приложение GWT, работающее на OSGi (Equinox) и Pax-web, чтобы использовать декларативные сервисы вместо программного отслеживания сервисов.
Я использую Pax-Web в Equinox. Приложение GWT на основе WAR загружается без проблем с помощью расширителя PAX-WEB War, но вы не можете использовать декларативные службы в этом способе работы.
Я успешно реорганизовал все сервлеты вне войны и превратил их в декларативные сервисы OSGi (<provide interface="javax.servlet.Servlet"/>
). Таким образом я избавился от всего грязного кода Service Tracker и определенных зависимостей OSGi в сервлетах. Далее я скопировал все остальные функции web.xml, чтобы зарегистрировать фильтр, обслуживать статическое содержимое и страницу приветствия, используя информацию из [1].
На данный момент, это обычно должно работать, но у меня проблемы с PAX-WEB и способом, которым GWT пытается загрузить свои ресурсы:
При загрузке дескрипторов сериализации GWT загружает файл политики сериализации из локального контекста. В моем случае он пытается разрешить ресурсы следующим образом: /ctx/ctx/62394587E47773FB1594FF.gwt.rpc Этот ресурс создается компилятором GWT и помещается в: /war/ctx/ctx/resource...
Перед использованием стандартного wab mapping (Webapp-Context: /ctx, Webapp-Root: /war
) gwt найдет свои ресурсы правильно. Теперь, когда я использую программное сопоставление ресурсов:
DefaultResourceMapping resourceMapping = new DefaultResourceMapping();
resourceMapping.setAlias( "/ctx" );
resourceMapping.setPath( "/war" );
GWT не может загрузить ресурс и выдает следующую ошибку:
2012-06-20 12:46:36.283:INFO:/:AbcProxy: ERROR: The serialization policy file '/ctx/ctx/600000000000000773FB1594FF.gwt.rpc' was not found; did you forget to include it in this deployment?
2012-06-20 12:46:36.283:INFO:/:AbcProxy: WARNING: Failed to get the SerializationPolicy '600000000000000773FB1594FF' for module 'https://localhost:8443/ctx/ctx/'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.
[NB Последнее предложение должно гласить: "В результате вы столкнетесь с адскими проблемами сериализации"]
Я отследил проблему с HttpServiceContext, загружающим ресурс и интерпретирующим путь как файл, а не как URL относительно программного веб-контекста:
getting resource: [/mx/mx/6ECAD5B3A6F908CE17E47773FB1594FF.gwt.rpc]
HttpServiceContext | not a URL or invalid URL: [/ctx/ctx/600000000000000773FB1594FF.gwt.rpc], treating as a file path
DefaultHttpContext | Searching bundle [bundle] for resource [/ctx/ctx/600000000000000773FB1594FF.gwt.rpc]
Это явно не сработает, так как этот ресурс находится в / war / ctx / ctx / в файловой системе пакета. Похоже, это относится к ошибке PAXWEB-314 [2], реализация которой заключается в превращении относительного пути в путь к файлу:
// IMPROVEMENT start PAXWEB-314
257 try {
258 resource = new URL(path);
259 LOG.debug( "resource: [" + path + "] is already a URL, returning" );
260 return resource;
261 }
262 catch (MalformedURLException e) {
263 // do nothing, simply log
264 LOG.debug( "not a URL or invalid URL: [" + path + "], treating as a file path" );
265 }
266 // IMPROVEMENT end PAXWEB-314
Есть ли способ обойти эту проблему? Кто-то использует GWT и PAX-WEB, используя OSGi DS вместо WAB? Один из возможных способов - скопировать / war / ctx, созданный компилятором GWT, обратно в / ctx, но я бы хотел найти достойное решение, прежде чем идти в направлении взлома.
Есть идеи?
1 - https://github.com/ops4j/org.ops4j.pax.web/blob/master/samples/whiteboard/src/main/java/org/ops4j/pax/web/extender/samples/whiteboard/internal/Activator.java[2] - http://team.ops4j.org/browse/PAXWEB-314
1 ответ
Я продолжил копать.
В GWT это соответствующий фрагмент кода, отвечающий за загрузку этих файлов политики: [1]
protected SerializationPolicy doGetSerializationPolicy(
HttpServletRequest request, String moduleBaseURL, String strongName) {
// The request can tell you the path of the web app relative to the
// container root.
String contextPath = request.getContextPath();
String modulePath = null;
if (moduleBaseURL != null) {
try {
modulePath = new URL(moduleBaseURL).getPath();
} catch (MalformedURLException ex) {
// log the information, we will default
log("Malformed moduleBaseURL: " + moduleBaseURL, ex);
}
}
...
Я подозревал, что contextPath может быть потенциальным кандидатом в этом случае. Чтобы проверить эту теорию, я развернул простой сервлет, который выводит его контекст. Я развернул его с помощью WAB (MANIFEST: Webapp-Context + web.xml). В этом развертывании сервлет сообщает: [getContextPath]->[/ctx]
Затем изменил развертывание на OSGi-ds с программным активатором, содержащим сопоставление ресурсов. DefaultResourceMapping resourceMapping = new DefaultResourceMapping(); resourceMapping.setAlias ( "/ctx"); resourceMapping.setPath( "/war");
В этом случае сервлет сообщает: [getContextPath]->[]
В переводе на проблему gwt -> когда gwt развернут с помощью WAB, он находит свою конфигурацию в / ctx / app, а когда я использую программное сопоставление ресурсов, он просматривает / app и, следовательно, не находит свои ресурсы.
Итог: в PAX-WEB Webapp-Context не эквивалентен псевдониму. Псевдоним не заполняет ContextPath так же, как Webapp-Context.
Единственный способ обойти эту ситуацию - позволить сборке копировать сгенерированные GWT файлы на один уровень ниже (исключая путь к контексту приложения).
PS: вслед за Ахимом Нирбеком из Pax-web, спецификация OSGi развивается для решения проблемы app-ctx: http://wiki.osgi.org/wiki/WebExperience