5

I'm presently writing an ORDS plugin which is intended to filter certain requests. I'm not quite about to get the filtering working, so I decided to follow Oracle's provided instructions for their Plugin API.

I've configured much of the build with a Gradle task which automatically:

  • Downloads the WAR
  • Adds the plugin JAR (also previously built with Gradle) to ORDS
  • Ensures that the configdir is set appropriately

Effectively, this is the automated equivalent to me running:

# 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

...and I deploy this to my local IntelliJ instance.

Here is what my servlet looks like. It's pretty basic.

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?!");
    }
}

I'm led to believe by the documentation that I should be able to access it at http://localhost:8080/ords/my_schema/plugin/servlet/, but that doesn't seem to be the case. I'm instead greeted with a 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 --

What am I missing? I'm unclear as to what should be a very basic servlet - which is virtually analogous to the "Hello World!" example they have provided - is simply not registering appropriately.

Note:

  • The schema is enabled for ORDS.
  • This error happens with both containers I've used; Glassfish and Tomcat.
  • I am not using APEX, which seems to be a common add-on for this product. I'm intending to use ORDS as a RESTful provider for my data.
  • The trailing slash in the @Dispatches path doesn't seem to have an effect; if it's removed or if it's present the issue remains.

I am looking for authoritative answers or insights as to what could be going on here. Guesses and shots in the dark do me no good, as I've been tinkering with this myself, and there's a very good chance that our tinkering paths would have overlapped.


As loath as I am to add pictures to any question, BalusC suggested that I inspect the contents of the JAR to ensure that there's a specific providers file contained within.

From this screenshot, there appears to be two...

enter image description here

...and their contents are the same...

com.foo.bar.baz.bing.servlet.TestServlet
oracle.dbtools.plugin.api.di.AnnotationsProvider

...but when I go to extract the JAR and inspect the file, it only contains the AnnotationsProvider line.

oracle.dbtools.plugin.api.di.AnnotationsProvider

But wait! It gets weirder!

When I mount the JAR to extract individual files, I see lots of duplicates:

enter image description here

...which leads me to believe that, somehow, the older file is overwriting the newer file.

4

2 回答 2

3

我已经弄清楚了这个问题。 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文件,并且我的 servlet 能够在 ORDS 中被访问。

我会指出这是一个惊喜。我没有预料到 JAR 中会打包任何类型的重复文件,ORDS 文档也没有潜在地警告这个问题。我认为这对其他开发者来说是一个公平的灯塔,让他们注意这种情况。

于 2017-06-26T15:12:53.380 回答
2

我在演示插件 JAR 的源代码中看到它使用SPI注册自己。这就是 WAR 中的 ORDS 核心如何找到它的方式。ORDS 示例文件夹中提供的 Ant 任务负责在创建 JAR 时生成必要的 SPI 文件。您提到您为此使用了 Gradle 任务,所以我推测您是自己编写的。

为了验证您的 Gradle 作业是否也生成了正确的 JAR,请提取 Gradle 生成的插件 JAR 文件并检查是否有一个/META-INF/oracle.dbtools.plugin.api.di.providers文件包含您的TestServlet. 如果没有,那么它肯定不会被 WAR 中的 ORDS 核心发现。

PluginDemo您可以通过将servlet 源代码替换为您自己的 servlet 内容,然后按照教程中的说明使用提供的 Ant 任务构建 JAR 来确认您的插件 servlet 的源代码是否正确。如果可行,那么肯定是 Gradle 任务需要修复,而不是您的插件 servlet。但是,由于问题中缺少此信息,因此无法给出详细答案。但它至少应该把你推向正确的方向,以解决问题。

于 2017-06-26T20:00:44.507 回答