What does UnsupportedClassVersionError mean?

Every time the structure of Java byte-code changes, the version number embedded in .class files must also change.

Java 1.2 uses major version 46
Java 1.3 uses major version 47
Java 1.4 uses major version 48
Java 5 uses major version 49
Java 6 uses major version 50
Java 7 uses major version 51
Java 8 uses major version 52

Each newer version of Java fully supports classes compiled with an older Java version. A class file complied with JDK 6 is supported on Java 7 and Java 8, but it is not supported by Java 5 or earlier.

If a .class file compiled with a later JDK version is attempted to be used on an older Java version, then the java.lang.UnsupportedClassVersionError is raised by the Java runtime.

For example given this error:


java.exe -jar ords.war

Exception in thread "main" java.lang.

UnsupportedClassVersionError: oracle/dbtool
s/jarcl/Entrypoint (Unsupported major.minor version 50.0)
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:539)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

We can deduce that the Java version being used is Java 5 or earlier, since Java 6 or later will fully support .class files with a major version number of 50.

The Java version being used can be checked using the following command:


java -version

On UNIX systems, you can also use the which command to determine which Java executable is being used. On Windows you can use the where command.

In the above example it turned out that a 1.4.2 JRE that shipped with another product, was being picked up because of the way the Windows PATH environment variable was configured.

What does UnsupportedClassVersionError mean?

Configuring custom error pages with Oracle REST Data Services

If you need to configure a custom error page instead of the error page generated by Oracle REST Data Services (ORDS), then do the following:

  • Edit the defaults.xml file in the ORDS configuration folder
  • Add the following setting to defaults.xml:

    <entry key="error.externalPath">/path/to/error/pages/folder/</entry>
      
  • /path/to/error/pages/folder is the fully qualified path to a folder which contains files named with the following pattern {status}.html, where {status} is the HTTP status code that you wish to define a custom error page for.
  • For example if you wish to define a custom error page for the HTTP 404 – Not Found status and store it in a folder named /usr/local/share/ords/error-pages/ then create a file named 404.html in /usr/local/share/ords/error-pages/ and configure error.externalPath to point at /usr/local/share/ords/errro-pages/.
Configuring custom error pages with Oracle REST Data Services

Remote Debug Oracle Database in a VirtualBox VM using SQL Developer

It’s possible to debug pl/sql code in an Oracle Database, in much the same way as you can in any interactive debugger environment. Jeff Smith shows how it’s done in this blog post.

It get’s a little trickier to setup if your Oracle Database instance happens to be running in a guest VM and you want to debug using a SQL Developer instance running on the host, firstly because in this scenario you can only do ‘Remote Debugging’ as SQL Developer and the Database are not located on the same host, and secondly because setting up VirtualBox networking to ensure SQL Developer and the database can talk to each other takes a little bit of work. Read on to find out how to get it all configured correctly.

The important thing to realise ahead of trying to get this working, is that the protocol flow for debugging is the opposite of what you might expect. In a normal database interaction between SQL Developer and the database, SQL Developer initiates the call, the Database is listening for incoming requests and accepts the connection and initiates the session.

When debugging however, SQL Developer plays the listening role, and it is the database that initiates the session and performs the initial connect to the SQL Developer debugger listener.

The fact that the database is initiating the connection means that two important factors need to be setup correctly:

  • The Database Access Control List (ACL) must be configured correctly to permit the the database make the outbound Java Debug Wire Protocol (JDWP) connection.
  • VirtualBox must be configured to enable the guest VM (where the database is running) talk to the host machine (where SQL Developer is running).

The ACL must identify the host or hosts that outbound connections may be made to. So before we can figure out what the ACL should be, we need to figure out how to enable the guest VM talk to the host machine.

Configure Host Only Networking

Typically if you are running a guest VM in Virtual Box you’ll default the virtual machine’s network interface to use Network Address Translation (NAT), it’s quick and easy to setup and gives the guest VM access to the Internet. You can use port forwarding to enable the host machine talk to the database running in the guest VM (Jeff has another post showing how to set this up).

But port forwarding only enables the host talk to the guest, it doesn’t enable the guest talk to the host. Fortunately VirtualBox has another networking mode called a ‘Host Only Network’ that does. A Host Only Network is a separate virtual network that consists of the host machine plus any guest VMs running on that host. It doesn’t provide access outside of the virtual network, it just enables the host and guests to talk to each other like as if they had their own private LAN.

A Host Only Network is of limited use in this day and age when we often want guest VMs to be able to auto-update from the internet, or call out to other services on the internet, so what we really need is to reconfigure our guest VM to have two network interfaces, one for the NAT interface, and one for the Host Only interface.

Create Host Only Network

  • In the VirtualBox main window (not the guest VM window), go the Preferences menu option (On OSX its VirtualBox|Preferences...).
  • Click the Network tab, then the Host-only Networks tab.
  • Click the Add button. Now you should have a new network named: vboxnet0 as shown below:

    Host Only Network Preference Pane
    Host Only Network Preference Pane
  • Click the Edit button.
  • Note the IPv4 Address value, it should default to 192.168.56.1. This is the IP address of the host machine on this virtual network
  • Click the Cancel or OK buttons.

Now we’ve configured the Host Only Network, next we need to configure the guest VM to use it.

Configure Guest VM

The exact set of steps will vary depending on the operating system used in the guest VM, I’m using the Oracle Developer Day VM, which runs Oracle Linux, so that’s what I’ll show steps for.

  • First, you must shutdown the guest VM. Note shutdown! Not pause, hibernate or suspend the VM, the operating system needs to be totally shutdown. If the OS is not powered off then VirtualBox will gray out the network adapter panels in the VM Network settings preventing the network interfaces being edited.
  • To edit the Network interfaces, select the guest VM in the main Virtual Box window and then click the Settings button. Click the Network button, showing a panel like below:
    VM Network Settings
    VM Network Settings
  • Click on the Adapter 2 tab.
  • Click Enable Network Adapter.
  • Choose Host-only Adapter for the Attached to option box.
  • Choose vboxnet0 for the Name option box.
    Adapter 2 Host-Only Network
    Adapter 2 Host-Only Network
  • Click the OK button.
  • Power on the Guest VM.

Confirm Network Configuration

At this point it’s useful to ensure the above changes have taken effect and that the host can talk to the guest, and the guest can talk to the host.

  • In the guest VM check the network settings, for example on the DevDay VM, click the networking icon on the taskbar, the menu should show an additional Ehternet interface.
    Oracle Linux Network Settings
    Oracle Linux Network Settings
    .

    Click the Network Settings menu option to see the details of the new network connection, it should show that the interface has an IP address of 192.168.1.56.101.

    192.168.56.101
    192.168.56.101
  • In the guest open a terminal and type ping 192.168.56.1, you should see output like the following:
    Guest Pinging Host
    Guest Pinging Host

    If the above output is displayed then the guest VM is able to reach the host (over the Host-only network).

  • In the host open a terminal and type ping 192.168.56.101, you should see output like the following:
    Host Pinging Guest
    Host Pinging Guest

    If the above output is displayed then the host is able to reach the guest VM (also over the Host-only network).

The first time I tried this, my guest could not ping the host, nor could the host ping the guest. I invoked the first rule of debugging, and powered off the guest VM, shutdown VirtualBox, and rebooted my Mac. Once everything was powered back on it all worked fine (Well… What actually happened was I spent several hours going round in circles, trying to figure out what the hell was wrong, and eventually, e-ven-tu-ally, in sheer frustration and desperation, I did the above. Sigh.).

Configure the Database ACL

In Oracle Database 12c and later all outbound connections from the database are disabled by default, the database administrator must selectively enable (whitelist) the outbound connections the database may make. You need to identify the host that is being connected to, the type of connection being made, and the user or roles being granted the privilege of making the connection.

In our case we want to enable the schema that we want to debug (e.g. scott) to make a jdwp connection to our host machine (192.168.56.1) where a SQL Developer instance is waiting to receive the connection. To do this a database administrator user needs to create an ACL permitting this, using code like the following:

BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE
 (
 host => '192.168.56.1',
 ace => xs$ace_type(privilege_list => xs$name_list('jdwp'),
 principal_name => 'scott',
 principal_type => xs_acl.ptype_db)
 );
END;

Start a Debugging Session

Firstly launch SQL Developer on the host machine and get it listening for a debug connection:

  • In the Connections view, choose the schema to be debugged, right click and select Remote Debug... from the context menu.
  • Click OK in the dialog that appears

Now we need to initiate a debugging session that connects to this listener.

  • Open a SQLPlus session in the guest VM, connecting as user scott.
  • Execute the following command:
    execute DBMS_DEBUG_JDWP.CONNECT_TCP('192.168.56.1',4000);
  • You should see output like the following:
    Successful Debug Session
    Successful Debug Session

If you see the above, then you’ve successfully created a debug session, you can set breakpoints where you wish, and whenever that code is invoked from the SQLPLus session, the session will be suspended and you can step through the code in SQL Developer.

Remote Debug Oracle Database in a VirtualBox VM using SQL Developer

Oracle REST Data Services & Entity Tags

Oracle REST Data Services (ORDS) has always had strong support for generating Entity Tag (ETag) HTTP Headers. Entity Tags are an important aspect of the HTTP protocol, they help reduce needlessly re-transmitting unchanged resources (aka Conditional GET) and they can also be leveraged to provide optimistic locking and thus prevent lost updates.

I recommend reading this post by Joe Gregorio for a detailed explanation of the benefits of generating and using ETags properly.

How ORDS generates ETag Headers

Entity Tag Strategies
Choosing the Entity Tag Strategy in Oracle Application Express

ORDS supports three ways to generate ETag headers:

  • Secure Hash – The bytes of the resource’s headers and body are hashed using a secure digest algorithm, which guarantee’s that anytime a header or the content of the resource changes, it’s ETag header value also changes. This is the default strategy
  • Query – The RESTful Service developer enters an SQL query. Every time a resource changes then the results of this query must also change
  • None – No ETag header is generated for the resource

Trade-offs

Each of these options has different strengths.

  • Secure Hash is the most reliable means for generating an ETag, if the resource or it’s headers change, the ETag is guaranteed to also change.

    Generating the Hash requires examining every byte of the resource’s headers and every byte of it’s body, before the ETag header can be generated. Since HTTP requires that HTTP Headers are sent before the body, this means that the entire contents of the resource must be temporarily buffered while the ETag is computed. For large resources this buffering may noticeably increase latency and increase the amount of RAM required.

    Note that for typical resources, whose size is in the order of hundreds of KBs, this buffering overhead is not significant, and thus using a secure Hash is the sensible default.

  • Sometimes it is possible to design a database table to know exactly when a row in the table changes, for example the table may have a version column or the table may be configured to use row level dependencies.

    In these cases it may be beneficial to use a custom query to generate the ETag. Instead of hashing the entire representation of the resource, ORDS will just hash the results returned from this custom query. ORDS will not need to buffer the entire representation in memory.

    However ORDS will need to perform the additional query to generate the ETag, as well as the query to generate the resource representation.

    For typical resources, the overhead of the network round trip for the additional query is far greater than the overhead for the secure hash. Only for very large resources will the custom query out-perform the secure hash strategy.

    There is also the risk that the custom query does not capture all of the data that may affect the representation of a resource. For example if a resource is composed from multiple rows in a table or rows from multiple tables, then the query must be designed to check the version state of each of those tables and rows. As the design of a resource evolves over time and the query used to generate the resource changes, it is easy to forget to keep the custom ETag query in sync. If this is not done then the ETag value may no longer change everytime the resource changes, and clients will miss updates to the resource, so this strategy may not be as robust as the secure hash strategy.

  • If no ETag is generated, then no buffering is required, but all the benefits of Entity Tags will also be lost.

    The entire resource will be regenerated and retransmitted for each and every request and there will be no means to perform concurrency control on the resource.

Oracle REST Data Services & Entity Tags

Why trailing slashes on URIs are important

Origin of the trailing slash

In Unix, a trailing slash on a pathname identifies the path as pointing to a folder (aka directory). If a pathname does not have a trailing slash then it points to a file. A folder is a ‘collection’ of files.

The syntax of URIs is derived from the syntax of Unix filenames, and the concept of using trailing slashes to identify ‘collection’ resources was carried over. However on the Web, the strong delineation between folders and files does not exist, frequently a ‘collection’ resource appears similar in structure and content to a normal resource (sometimes referred to as a ‘subordinate’ resource).

As a consequence, much confusion has arisen about the purpose and importance of trailing slashes on collection resources. It is common for users to forget the trailing slash on a resource, and common for web-servers to assist users, when they make this mistake, to redirect them to the URI with the trailing slash automatically.

In fact this practice is so pervasive, that for the vast majority of users, a resource URI with or without a trailing slash is treated as a synonym. They are considered two URIs that point to the same resource, using either one is fine. However this understanding is not quite correct.

It is more correct to understand that the resource without the trailing slash does not exist at all. But instead of being unhelpful and reporting a 404 Not Found status, web-servers almost always apply Postel’s Law and tell the user where the resource they are looking for is actually located, via a permanent redirect.

Read on to learn why it is important to have the correct understanding when designing RESTful APIs.

Relative URIs

The main reason trailing slashes are so important, is that they are critical to relative URIs in your API functioning correctly. There are many reasons why you should want to use relative URIs, but let’s look at just a couple:

  • If your API is available over both HTTP and HTTPS, then which protocol should you specify in your fully qualified URI? You’ll need to make sure all the links in a generated response match the protocol used to request the resource, other wise problems with mixed content may be encountered.
  • In a multi-tiered architecture, where the application server generating a resource may be at some remove from the public endpoint that the consumer of an API accesses, determining the correct public URI to generate in a resource can become cumbersome. For example if you have a Java Servlet running on Apache Tomcat, fronted by Apache HTTPD and reverse proxy (mod_proxy directives), it takes a good bit of configuration for the Servlet to be able to determine the public request URL, and even then the Servlet needs to be aware that it is being fronted by mod_proxy, which is not good for encapsulation.
  • If for any reason the location at which your API resides changes (web-site re-branding, moving API to a distinct hostname for scaling/security reasons, etc. etc.), then all of the resources exposed by the API must be updated to use the new fully qualified URIs.
  • If your API does not allow for relative URIs properly, then it will, in turn, prevent users of your API using relative URIs in any content they store in your service. More on this below.

Everywhere the fully qualified URI is repeated, it must be changed if the URI ever needs to change. With relative URIs this problem is mitigated, the location of a resource is expressed relative to the location of the current resource, and the client is able to turn that relative location into an absolute location using URI resolution.

To be blunt, using fully qualified URIs, when a relative URI would suffice, is a violation of the Don’t Repeat Yourself (DRY) principle. By needlessly repeating the fully qualified URI, you create more work for yourself, if the fully qualified URI has to change for any reason. You can also create more work for the customers of your API, by potentially preventing them using relative URIs.

Doing it wrong

Let’s look at an example that neglects to use trailing slashes and attempts to use relative URIs, and as a consequence gets things wrong.

Assume we’ve noticed that there just aren’t enough blog engines in the world, and so we’ve created the greatest blog engine ever (GBEE), and we want to expose an API to it, so that the people who make those ‘sharing’ widgets have yet another API that they need to integrate with.

Here’s a rough idea of the API:

GET https://{blog-name}.gbee.io/blog/posts       # Retrieve the list of posts
GET https://{blog-name}.gbee.io/blog/posts/{id}  # Retrieve an individual post
GET https://{blog-name}.gbee.io/blog/images/{id} # Retrieve an image linked to in a post's content.

Here’s a sample of retrieving the list of blog posts:

GET /blog/posts HTTP/1.1
Host: some-blog.gbee.io

produces a listing like the following:

HTTP/1.1 200 OK
Content-Type: application/json

{
 "posts": [
  {
   "links": [{"href":"holiday"}],
   "tags": ["vacation", "mexico"],
   "summary": "
Had a great trip to Mexico recently,
here's a picture of where we stayed:
<img src="../images/hotel.jpg">
"
  },
  ...
 ]
}

We can see that the relative URI of the first blog post is holiday, so what is the correct absolute URI of the blog post?

You might expect it to be http://some-blog.gbee.io/blog/posts/holiday, but that’s not what the document above says. It actually says the absolute location is http://some-blog.gbee.io/blog/holiday. To understand why, you need to understand the algorithm for transforming relative URIs into absolute URIs.

The first step is to establish the base URI of a resource, in this case the base URI is the URI of the requested resource, i.e.: http://some-blog.gbee.io/blog/posts

The next step is to merge the base URI with the relative URI, RFC 3986 describes this process, the relevant statement is:

return a string consisting of the reference’s path component appended to all but the last segment of the base URI’s path (i.e., excluding any characters after the right-most “/” in the base URI path, or excluding the entire base URI path if it does not contain any “/” characters).

Therefore we must exclude any characters after the right-most “/” in http://some-blog.gbee.io/blogs/posts, which gives: http://some-blog.gbee.io/blogs/. Finally the relative URI (holiday) is appended to this URI, thus giving http://some-blog.gbee.io/blog/holiday.

If a client attempts to retrieve http://some-blog.gbee.io/blog/holiday they will get a 404 Not Found error, because the resource doesn’t actually exist at that location.

If it is not already clear, placing a trailing slash on a collection resource is not optional. It is critical to relative URIs being resolved correctly. RFC 3986 is one of the foundational specifications of the web and as the example above demonstrates, collection resources are expected to have a trailing slash. It’s not just a stylistic preference, or something that provides an SEO optimization. It’s intrinsic to the syntax of URIs and therefore, important to get right.

I’d speculate that a lack of understanding of how relative URIs are transformed into absolute URIs, is a major factor in the all the too common occurrence, of web APIs not naming collection resources correctly, and consequently using fully qualified URIs throughout the API unnecessarily. I think developers encounter problems trying to get relative URIs working properly (through their lack of understanding of the mechanics) and then err on the side of caution and switch to using fully qualified URIs throughout.

The above ‘broken’ API also provides a commonly seen problem where relative URIs seem to be working in one case, but not in another. If we were to retrieve content of the blog post it would look like this:

GET /blog/posts/holiday HTTP/1.1
Host: some-blog.gbee.io
HTTP/1.1 200 OK
Content-Type: text/html

<p>Had a great trip to Mexico recently,
here's a picture of where we stayed:
<img src="../images/hotel.jpg">
</p>

Nothing unusual about this content, just regular HTML, and the relative URI of the image link looks correct:

Base URI
http://some-blog.gbee.io/blog/posts/holiday
Relative URI
../images/hotel.jpg
Absolute URI
http://some-blog.gbee.io/blog/images/hotel.jpg

So the problem doesn’t lie here, again it lies with the /blog/posts resource. When the <img> tag is evaluated relative to /blog/posts, the wrong location is produced:

Base URI
http://some-blog.gbee.io/blog/posts
Relative URI
../images/hotel.jpg
Absolute URI
http://some-blog.gbee.io/images/hotel.jpg

You can easily imagine many developers scratching their heads trying to figure out why the image location is not being calculated correctly for the /blog/posts resource, when it is working fine for the /blog/posts/holiday resource. The fact that the base URI is that of the requesting document (the list of posts), not of the blog post itself is easily missed.

Preventing API users doing things right

It is also worth appreciating that the author of the blog post may have the reasonable expectation that they can use relative URIs, since they are an intrinsic part of the Web. Users will expect that the blog engine will fully support the use of relative URIs. By choosing not to put a trailing slash on the /blogs/posts resource, the blogging engine has failed to meet this expectation. The post author can reasonably view the blog engine as defective in this regard.

Doing it right

All of the problems outlined above can be addressed by placing a trailing slash at the end of the blog posts resource, so it’s URI becomes:


http://some-blog.gbee.io/blog/posts/

Now the relative path for the holiday relative URI resolves correctly:

Base URI
http://some-blog.gbee.io/blog/posts/
Relative URI
holiday
Absolute URI
http://some-blog.gbee.io/blog/posts/holiday

The relative path for the image in the blog post also resolves correctly when resolved relative to the /blog/posts/ resource:

Base URI
http://some-blog.gbee.io/blog/posts/
Relative URI
../images/hotel.jpg
Absolute URI
http://some-blog.gbee.io/blog/posts/holiday

Getting Query URIs right

Another mistake that I have sometimes seen, is to get naming of a collection resource correct, but to get the URI for queries on the collection wrong, e.g.:

http://some-blog.gbee.io/blog/posts/              # retrieve all posts
http://some-blog.gbee.io/blog/posts?tags=vacation # retrieve posts tagged with 'vacation'

The problem here, once again, is that relative URIs returned in the http://some-blog.gbee.io/blog/posts?tags=vacation resource will be resolved relative to http://some-blog.gbee.io/blog rather than http://some-blog.gbee.io/blog/posts/, because the trailing slash is missing.

The correct form of the URI would be:


http://some-blog.gbee.io/blog/posts/?tags=vacation

The HTML <base> element

Some resource formats specify ways to override the base URI of a resource. For example HTML has the <base> element. XML has the xml:base extension.

These mechanisms exist to provide a way for a HTML or XML document to render correctly when using embedded hyper-links that use relative URIs, regardless of whether the hosting document is correctly named with a trailing slash or not (or if the URI of the hosting document cannot be determined).

I only mention these for completeness, I would not recommend their use unless required to workaround an existing API that does not name collection resources correctly.

Rules of Thumb

URIs are hierarchial in nature. The path component of a URI is particularly hierarchal. Levels in the hierarchy are delimited by the slash (“/“) character. Paths to the right of a slash are subordinate to paths to the left of a slash:

/a/b # b is subordinate to a
/c/d/e # e is subordinate to d, d is subordinate to c

Any path which occurs to the left of a slash is a collection resource, any path which occurs to the right is a subordinate. Note that a resource can be both a collection resource and a subordinate resource (as shown by the /c/d/e example, d is both a collection resource and a subordinate resource).

If a resource is a collection resource (even if it is subordinate to another resource), then it’s URI must have a trailing slash. If you visualize the path hierarchy of your API as a tree, then only the leaf nodes in the tree should lack a trailing slash.

  • Only leaf resources (resources with no subordinates) should lack a trailing slash in their URI.
  • If a request is received without a trailing slash, then do a permanent redirect to the URI with the trailing slash.
  • Use relative paths wherever possible (DRY principle).
  • Remember to include the trailing slash in query URIs.
  • Don’t do anything that would prevent consumers of your API using relative URIs.
Why trailing slashes on URIs are important

Understanding the Oracle REST Data Services Configuration Folder

Oracle REST Data Services (ORDS) needs a location to store it’s configuration files. The location is configured using the config.dir setting. You can view and set this setting using the configdir command.

Set config.dir setting

$ java -jar ords.war configdir /tmp/wls/conf
Feb 27, 2014 2:58:47 PM oracle.dbtools.cmdline.ModifyConfigDir execute
INFO: Set config.dir to /tmp/wls/conf in: /Users/cdivilly/ords.war

View config.dir setting

$ java -jar ords.war configdir
Feb 27, 2014 3:00:16 PM oracle.dbtools.cmdline.ModifyConfigDir execute
INFO: The config.dir value is /tmp/wls/conf

The important thing to be aware of is that the configuration data is not stored directly in the location pointed to by config.dir. Instead the data is located in a sub-folder named after the context-path (aka context-root) that ords.war is deployed at.

A second point to be aware of is that when configuring ORDS, the context-path that the application will be deloyed at is not known, so it is inferred from the filename of ords.war.

Deploying to /apex

If you need to deploy ORDS to a context-path of: /apex, then make sure to do the following:

  1. Rename ords.war to apex.war
  2. Configure ORDS by doing:
    java -jar apex.war
  3. Deploy apex.war to your application server

If you follow these steps in the order laid out above, you will not encounter any issues.

Help! I forgot to rename ords.war before configuring and deploying it

If you did not rename ords.war before doing configuration and deployment, then you are likely to see an error page like the following:

ORDS Not Configured
ORDS Not Configured

Note the highlighted text in the bottom left. This reveals the problem, ORDS is expecting to find the configuration files in /tmp/wls/conf/apex (because the context-path is /apex), but does not find anything in this folder, because the data is actually in /tmp/wls/conf/ords.

In this case, to address the problem rename or copy /tmp/wls/conf/ords to /tmp/wls/conf/apex, and restart ORDS.

Understanding the Oracle REST Data Services Configuration Folder

Introducing Oracle REST Data Services

Oracle REST Data Services

Oracle Application Express Listener is now known as Oracle REST Data Services. We just pushed out a new point release (2.0.6) that uses the new product branding. We’ve changed the product name to emphasise the product’s future direction, focussing on ways to easily expose Oracle Database and it’s suite of offerings, to the RESTful Web, while still continuing to provide the PL/SQL Web Gateway that applications such as Oracle Application Express rely on.

The major change as a consequence of the product rebranding, is that the web application name changes from apex.war to ords.war, which also means the default context path changes from /apex to /ords. You can read more about this in the release notes.

If you want to learn more about how to use Oracle REST Data Services to create RESTful Web Services, take a look at the Developer Guide. I’d also recommend subscribing to this blog and also Kris Rice’s blog, and following both of us on Twitter: @cdivilly, @krisrice.

Introducing Oracle REST Data Services