Почему мой сервлет ORDS не выполняется, хотя я следовал существующим рекомендациям?
В настоящее время я пишу плагин ORDS, который предназначен для фильтрации определенных запросов. Я не совсем собираюсь заставить фильтрацию работать, поэтому я решил следовать инструкциям Oracle для их API Плагинов.
Я настроил большую часть сборки с помощью задачи Gradle, которая автоматически:
- Скачивает WAR
- Добавляет плагин JAR (также ранее собранный с Gradle) в ORDS
- Гарантирует, что configdir установлен правильно
По сути, это автоматический эквивалент для меня:
# Assuming the JAR is cURL'd in from somewhere...
java -jar ords.war plugin build/myPlugin.jar
java -jar ords.war configdir /home/makoto/ords-configuration
... и я развернул это в своем локальном экземпляре IntelliJ.
Вот как выглядит мой сервлет. Это довольно просто.
import oracle.dbtools.plugin.api.di.annotations.Provides;
import oracle.dbtools.plugin.api.http.annotations.Dispatches;
import oracle.dbtools.plugin.api.http.annotations.PathTemplate;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Provides
@Dispatches(@PathTemplate(("/plugin/servlet/")))
public class TestServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("this worked?!");
}
}
Документация заставляет меня поверить, что я должен иметь к ней доступ по адресу http://localhost:8080/ords/my_schema/plugin/servlet/, но, похоже, это не так. Меня вместо этого встречают с 404:
DispatcherNotFoundException [statusCode=404, reasons=[]]
at oracle.dbtools.http.entrypoint.Dispatcher.choose(Dispatcher.java:87)
at oracle.dbtools.http.entrypoint.Dispatcher.dispatch(Dispatcher.java:98)
at oracle.dbtools.http.entrypoint.EntryPoint$FilteredServlet.service(EntryPoint.java:240)
at oracle.dbtools.http.filters.FilterChainImpl.doFilter(FilterChainImpl.java:73)
at oracle.dbtools.url.mapping.RequestMapperImpl.doFilter(RequestMapperImpl.java:125)
at oracle.dbtools.url.mapping.URLMappingBase.doFilter(URLMappingBase.java:103)
at oracle.dbtools.url.mapping.filter.URLMappingFilter.doFilter(URLMappingFilter.java:148)
at oracle.dbtools.http.filters.HttpFilter.doFilter(HttpFilter.java:47)
at oracle.dbtools.http.filters.FilterChainImpl.doFilter(FilterChainImpl.java:64)
at oracle.dbtools.http.cors.CORSResponseFilter.doFilter(CORSResponseFilter.java:83)
at oracle.dbtools.http.filters.HttpResponseFilter.doFilter(HttpResponseFilter.java:45)
at oracle.dbtools.http.filters.FilterChainImpl.doFilter(FilterChainImpl.java:64)
at oracle.dbtools.http.errors.ErrorPageFilter.doFilter(ErrorPageFilter.java:94)
at oracle.dbtools.http.filters.HttpFilter.doFilter(HttpFilter.java:47)
at oracle.dbtools.http.filters.FilterChainImpl.doFilter(FilterChainImpl.java:64)
at oracle.dbtools.http.auth.ForceAuthFilter.doFilter(ForceAuthFilter.java:44)
at oracle.dbtools.http.filters.HttpFilter.doFilter(HttpFilter.java:47)
at oracle.dbtools.http.filters.FilterChainImpl.doFilter(FilterChainImpl.java:64)
at oracle.dbtools.http.filters.Filters.filter(Filters.java:47)
at oracle.dbtools.http.entrypoint.EntryPoint.service(EntryPoint.java:82)
at oracle.dbtools.http.entrypoint.EntryPointServlet.service(EntryPointServlet.java:49)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at oracle.dbtools.rt.web.HttpEndpointBase.dispatchableServices(HttpEndpointBase.java:116)
at oracle.dbtools.rt.web.HttpEndpointBase.service(HttpEndpointBase.java:81)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
-- snip --
Что мне не хватает? Мне неясно, каким должен быть очень простой сервлет - который практически аналогичен "Hello World!" Пример, который они привели - просто не регистрируется соответствующим образом.
Замечания:
- Схема включена для ORDS.
- Эта ошибка происходит с обоими контейнерами, которые я использовал; Glassfish и Tomcat.
- Я не использую APEX, который, кажется, является обычным дополнением для этого продукта. Я намерен использовать ORDS в качестве RESTful-провайдера для моих данных.
- Конечный слеш в
@Dispatches
путь, кажется, не имеет никакого эффекта; если он удален или присутствует, проблема остается.
Я ищу авторитетные ответы или идеи о том, что здесь может происходить. Догадки и выстрелы в темноте не приносят мне пользы, так как я сам с этим возился, и есть очень хороший шанс, что наши повозки будут пересекаться.
Как бы мне ни хотелось добавлять картинки к любому вопросу, BalusC предложил мне проверить содержимое JAR, чтобы убедиться, что в нем содержится определенный файл провайдеров.
Из этого скриншота, кажется, два...
... и их содержание одинаковое...
com.foo.bar.baz.bing.servlet.TestServlet
oracle.dbtools.plugin.api.di.AnnotationsProvider
... но когда я иду, чтобы извлечь JAR и осмотреть файл, он содержит только AnnotationsProvider
линия.
oracle.dbtools.plugin.api.di.AnnotationsProvider
Но ждать! Это становится страннее!
Когда я монтирую JAR для извлечения отдельных файлов, я вижу много дубликатов:
... что приводит меня к мысли, что каким-то образом старый файл перезаписывает новый.
2 ответа
Я понял проблему. Предложение BalusC указало мне правильное направление.
ORDS ожидает, что провайдеры будут зарегистрированы через файл с именем META-INF/oracle.dbtools.plugin.api.di.providers
, В этом файле приведен список классов, описанных их полным именем, которые были помечены @Provides
, Любой класс, который там не указан, не будет подхвачен ORDS.
То, с чем я столкнулся, как подчеркнул мой вопрос, было дублирующими именами файлов, присутствующими в JAR. Если бы я наблюдал это через Neovim, я бы увидел мои классы FQN в одном файле, а не в другом. Если бы я наблюдал это через Nautilus/File Extractor, я бы увидел файл только с одним из моих классов FQN.
Проблема с дублирующимся файлом оказалась дымящимся пистолетом. Чтобы заставить это работать, мне пришлось удалить дубликаты из моего встроенного JAR-файла. В Gradle способ сделать это так:
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Теперь только правильный *providers
файл обнаруживается, и мои сервлеты могут попасть в ORDS.
Я укажу, что это было неожиданно; Я не ожидал, что какие-либо дубликаты файлов будут упакованы в JAR, и при этом документация ORDS не предупредила об этой проблеме. Я вижу это как хороший маяк для других разработчиков, чтобы помнить об этом.
В исходном коде демонстрационного плагина JAR я вижу, что он регистрируется с помощью SPI. Вот как ядро ORDS в WAR находит его. Предоставленная задача Ant в папке примеров ORDS обеспечивает создание необходимых файлов SPI при создании JAR. Вы упомянули, что использовали для этого задачу Gradle, поэтому я понял, что вы написали ее самостоятельно.
Чтобы убедиться, что ваше задание Gradle также сгенерировало правильный JAR, извлеките файл JAR подключаемого модуля Gradle и проверьте, есть ли /META-INF/oracle.dbtools.plugin.api.di.providers
файл с единственным содержанием FQN вашего TestServlet
, Если нет, то это определенно не будет обнаружено ядром ORDS в WAR.
Вы можете подтвердить правильность исходного кода сервлета вашего плагина, заменив PluginDemo
исходный код сервлета с вашим собственным содержимым сервлета, а затем сборка JAR с использованием предоставленной задачи Ant, как указано в руководстве. Если это работает, то это определенно задача Gradle, которую нужно исправить, а не ваш сервлет плагина. Однако подробный ответ на этот вопрос не может быть дан, так как эта информация отсутствует в вопросе. Но это должно по крайней мере подтолкнуть вас в правильном направлении, чтобы решить проблему.