This document describes how to develop and deploy plugins that integrate with the Oracle REST Data Services (ORDS) runtime.
For a more a more detailed reference, consult the developer guide.
Below are some examples that give a flavour of the programming model.
The Hello World example below demonstrates the basics of creating a request handler plugin:
@Dispatches(@PathTemplate("/hello"))
@Provides
public class HelloWorld extends HttpServlet {
public doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.getWriter().println("Hello World");
}
}
A plugin can express it's dependencies on external APIs using the @Inject annotation on its constructor.
@Dispatches(@PathTemplate("/uses-logging"))
@Provides
public class UsesLogging extends HttpServlet {
@Inject
public UsesLogging(Logger log) {
this.log = log;
}
public doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
log.fine("received request:\n" + request.toString());
response.setContentType("text/plain");
response.getWriter().println("Hello World");
log.fine("processed request");
}
private final Logger log;
}
UsesLogging
type, the DI framework looks for a constructor annotated with @Inject. It then examines the arguments of the constructor and attempts to resolve an implementation of the specified type. Once all dependencies have been resolved, the DI framework invokes the Constructor with the required arguments.All of the files referenced in this tutorial are included in the product distribution under the examples/plugins
folder:
${ORDS_HOME}
|-- examples
|-- plugins
|-- lib
|-- plugin-demo
| |-- src
|-- plugin-echo-cmd
|-- src
where ${ORDS_HOME}
is the location where the product distribution was unzipped.
Consult the instructions in the Oracle REST Services Documentation to install and configure ORDS.
To make a database schema accessible to ORDS, it must be explicitly enabled. To demonstrate this we will create a new schema and enable it:
$ sqlplus /nolog
SQL> CONNECT SYS as SYSDBA
Enter password: SYS_password
SQL> create user TEST_SCHEMA identified by TEST_SCHEMA_password;
SQL> grant connect, resource to TEST_SCHEMA;
SQL> DISCONNECT
SQL> CONNECT TEST_SCHEMA
Enter password: TEST_SCHEMA_password
SQL> execute ords.enable_schema;
SQL> commit;
Note: Replace TEST_SCHEMA_password
with your own choice of password.
To verify if a schema is enabled for ORDS access, check the USER_ORDS_SCHEMAS
view:
SQL> select * from USER_ORDS_SCHEMAS;
ID PARSING_SCHEMA TYPE PATTERN
-- -------------- --------- -----------
2 TEST_SCHEMA BASE_PATH test_schema
In this guide we will walk through building and deploying the plugin-demo
plugin that queries the database to determine the current database user and echo that information in the response. This example uses Apache ANT to manage the build process.
The plugin-demo
source files are located within the ${ORDS_HOME}
folder at:
${ORDS_HOME}/examples/plugins/plugin-demo
The folder contains the following:
src
folder which contains:
PluginDemo.java
- the Java source code of the plugin.build.xml
- ANT build script, which compiles and packages the source codebuilt
- folder generated by build.xml
which will contain the packaged plugin: plugin-demo.jar
.Located in the parent folder is a lib/
folder which holds the .jar
files required to compile plugins.
To compile a plugin the following libraries must be in the classpath:
Each of the required jars is included in the product distribution in the ${ORDS_HOME}/examples/plugins/lib
folder.
This library provides the glue code - such as @Dispatches - to weave the plugin into the runtime.
This library provides the JSR-330 API types such as @Inject.
This library provides the Java Servlet 2.5 API types, such as HttpServlet.
This library is optional and is only required if the plugin needs to access the Oracle JDBC Extension APIs such as OracleConnection.
The source code of the plugin is reproduced below, following that is a point by point explanation of the source code.
import java.io.IOException;
import java.sql.*;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import oracle.dbtools.plugin.api.di.annotations.Provides;
import oracle.dbtools.plugin.api.http.annotations.*;
import oracle.dbtools.plugin.api.routes.*;
/**
* This example plugin {@link HttpServlet} demonstrates:
* <ul>
* <li>Using the injected {@link Connection} to query the database.</li>
* <li>Using the injected {@link PathTemplates} service to decode the parameters
* of the servlet's {@link PathTemplateMatch}.</li>
* </ul>
*
* <h4>Testing the Servlet</h4> Invoke the servlet with the following URL:
*
* <pre>
* http://<i>server</i>/ords/<i>schema</i>/demos/plugin?who=<i>somebody</i>
* </pre>
*
* where:
* <ul>
* <li><i>server</i> is the hostname and port of the server.</li>
* <li><i>schema</i> is the name of the REST enabled database schema.</li>
* <li><i>somebody</i> is any value you wish, e.g. a person's name.</li>
* <ul>
* For example:
*
* <pre>
* http://localhost:8080/ords/test_schema/demos/plugin?who=Scott
* </pre>
*
* @author cdivilly
*
*/
@Provides
@Dispatches(@PathTemplate("/demos/plugin"))
class PluginDemo extends HttpServlet {
@Inject
PluginDemo(Connection conn, PathTemplates pathTemplates) {
this.conn = conn;
this.pathTemplates = pathTemplates;
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PathTemplateMatch match = pathTemplates
.matchedTemplate(request);
try {
/* retrieve 'who' query parameter */
String who = match.parameters().get("who");
who = null == who ? "anonymous" : who;
/* execute database query */
PreparedStatement ps = conn
.prepareStatement("select sys_context('USERENV','CURRENT_USER') from dual");
ResultSet rs = ps.executeQuery();
rs.next();
/* determine the database user */
String user = rs.getString(1);
/* Print the greeting */
response.getWriter().println(user + " says hello to: " + who);
rs.close();
ps.close();
} catch (SQLException e) {
throw new ServletException(e);
}
}
private final Connection conn;
private final PathTemplates pathTemplates;
}
PluginDemo
type is annotated with @Provides
to indicate that it offers a service, in this case it offers the HttpServlet
service.@Dispatches
and @PathTemplate
annotations which indicate the request URL pattern that the servlet listens for.PluginDemo
constructor is annotated with @Inject
to indicate that this constructor should be used by the dependency injection framework to instantiate instances of the type.PluginDemo
depends on:
Connection
is required, ORDS connects this connection instance to a database schema, which schema is determined by the request URL to database schema mapping rules.PathTemplates
service which provides a method for determining the PathTemplate
bound to a request.PluginDemo
overrides the doGet()
method to indicate that it supports the GET
HTTP method.PathTemplates
service to determine the PathTemplateMatch
bound to the request.PathTemplate
parameters, and extracts the value of the who
parameter.Connection
instance is queried to determine the identity of the current database user.who
parameter is printed in the response.In the plugin-demo
folder type the following command:
$ ant
The source code will be compiled and packaged into an archive named built/plugin-demo.jar
Update the ords.war
archive to add plugin-demo.jar
as follows:
Invoke the plugin
command to package plugin-demo.jar
into ords.war
:
$ java -jar ../../../ords.war plugin built/plugin-demo.jar
Start the updated ords.war
in standalone mode.
$ cd ${ORDS_HOME}
$ java -jar ords.war
The plugin we have built needs a database connection to function. Therefore ORDS must be able to figure out what database and schema to connect to. ORDS does this by examine the Request URL and mapping the URL to the appropriate database pool and database schema.
If ORDS cannot determine a mapping, then it will report a 404 Not Found
status for the request URL.
To map a database schema to a URL, you must enable the schema to be accessed by ORDS, as we did in the section titled 'Enable Database Schema'.
With ORDS running in standalone mode on localhost
, try the following URL:
http://localhost:8080/ords/test_schema/demos/plugin?who=Scott
The browser should display the following text:
TEST_SCHEMA says hello to: Scott
/test_schema
portion of the request URL maps the request to the TEST_SCHEMA
database schema.Connection
instance connected to the TEST_SCHEMA
schema is injected into the PluginDemo
instance.PluginDemo
queries the Connection
to determine the current user and decodes the {who}
parameter bound to the request URL, and uses this information to construct the message displayed above.