Unlock GraphQL – ORDS on GraalVM with Docker

ORDS 23.3.0 introduced GraphQL functionality which makes it possible for a user to define complex queries on REST Enable tables and views in the database. Specific information on how to use GraphQL is in the ORDS Developer Guide. Although ORDS is known as a Java Web Application, the GraphQL implementation is primarily in JavaScript. To use the GraphQL feature, ORDS must be running on Oracle GraalVM with the JavaScript component installed.

That’s as simple as downloading the Oracle GraalVM ( for Java 11 or Java 17 ), installing the JavaScript component, and running ORDS as usual with that JVM. See GraalVM Configuration in the Installation and Configuration Guide.

Running with docker / podman / kubernetes is also straight forward but there are one or two steps that may not be intuitive. Building on concepts introduced in a previous article I’ll walk through the steps to create an image for running the latest release of ORDS on Oracle GraalVM Enterprise.

The goal is to build a docker image which is based on a GraalVM image. The build process for that image will install the required GraalVM JavaScript component and download the latest release of ORDS. The resulting image can be used to spin up a new container which is running ORDS standalone. Similar to the containers used from the above previous article, the containers will use a shared docker volume for configuration.

Getting GraalVM

GraalVM is a high-performance runtime that provides support for various programming languages and execution modes. It includes a Java Virtual Machine (JVM) that is enhanced with the GraalVM compiler, which can improve the performance of Java applications such as ORDS. GraalVM is a polyglot virtual machine that supports multiple programming languages, including JavaScript, Python and more. To use these programming languages, specific components must also be installed, and as is common, licences for their use must be agreed. The Oracle Free Use Terms and Conditions licence that ORDS is available under, and the GraalVM Free Use Terms and Conditions licence that GraalVM is available under, do not extend to these components. Although convenient Docker images are available, to run a Java application which also uses JavaScript requires that JavaScript runtime component to be installed in the image. To install that component requires an activated download token which confirms you have accepted the software licence. This article will cover getting that token, but first, which image should be used?

GraalVM Image

Oracle GraalVM Enterprise container images are published in the Oracle Container Registry and there are quite a few to choose from. The following images are available:

Image NameDescription
jdk-eeA compact image containing the GraalVM Enterprise JDK.
native-image-eeA compact image containing the GraalVM Enterprise native-image utility and JDK
enterpriseProvides the GraalVM Enterprise JDK along with the gu (Graal Updater) utility to enable installation of additional features.
nodejs-eeIncludes the Node.js runtime and the GraalVM Enterprise JDK.
Images available at container-registry.oracle.com

We will require a GraalVM Enterprise JDK to run ORDS which is a Java application but will also require the JavaScript component installed so we’ll need the Graal Updater utility too. That means the enterprise image is the one for us. In fact, we’ll use container-registry.oracle.com/graalvm/enterprise:ol8-java17 which gives us a Java 17 JDK. At the time of writing, the only supported Java versions for ORDS are Java 11 and Java 17.

GraalVM Download Token

To install the GraalVM JavaScript component requires an activated download token. This token indicates that you have accepted a licence agreement for using the component and in this article we pass it as a parameter when building the image. There are a number of ways to obtain a token, in fact just by using the Graal Updater utility ( gu ) to install a component will initiate it…

Downloading: Artifacts catalog from gds.oracle.com
Skipping ULN EE channels, no username provided.
Downloading: Component catalog from www.graalvm.org
Processing Component: Graal.js
Enter your download token and press ENTER, or press ENTER to generate a new download token.
Enter a valid download token:

However, at this stage up may not have the Graal Updater on your machine. The most convenient way on a unix based operating system with bash is the handy dandy GraalVM Download Token Generator.

bash <(curl -sL https://get.graalvm.org/ee-token)

That will run a script to generate a token and initiate the licence agreement process. In this scenario I just copy the token string rather than persisting it.

About to request a download token for GraalVM Enterprise Edition...
Please provide an email address and review Oracle's Privacy Policy at https://www.oracle.com/legal/privacy/privacy-policy.html.
Enter a valid email address: pobalopalous@ordsexample.org
Your new download token is: 'NzY4MDYwYTk4ZjIyMTZmNTgzYWE3NzMwNGFkOGJiMmIwZTVlYTU3MmI3YThjZmY3NzExYzFlOWQxNjgyNTUwZGNiNzUxNmNlODIxNTkwYjM0MjA4NzkwNDVhNzUx'
Please check your email inbox and accept the license to activate your download token.
Would you like to persist this token in '/Users/pobalopalous/.gu/config' on this machine? (y/N): N
Download token not persisted.

Now I have an 88 character token but it has not been activated. Next, I must check my email for a link to accept the licence.

Email for activating the download token
Click that “Accept license and verity download token” button

The link will take you through the Oracle SSO sign-on process if you’re not already logged in. Keep the download token value safe. It will be baked into your docker image so do not go publishing the image out on the internet, in other words … distributing the software, because the token can be linked back to your Oracle SSO account.

Get Building

Now that an activated download token is at hand we can get on with building the docker image. The Dockerfile is very similar to the one used in Get started with Oracle REST Data Services (ORDS) and Docker but has a couple of extra lines for installing the JavaScript component.

#
# Defines a docker image, based on the Oracle JDK image, to run Oracle REST Data Services. During the image building 
# process the most recent version of ORDS will be automatically downloaded and extracted.
#
# Volumes for configuration and lib/ext are defined.
#
# docker run -p 8080:8080 -v ords-config:/opt/ords-config/ -v ords-lib-ext:/opt/ords/latest/lib/ext ords-latest/graaljdk
#
# See https://peterobrien.blog/ for more information and examples.
#
FROM container-registry.oracle.com/graalvm/enterprise:ol8-java17
MAINTAINER Peter O'Brien

# Get an Oracle Graal EE Download token and provide that value when building the image.
# See https://github.com/graalvm/graalvm-jdk-downloader/blob/main/README.md#set-up-a-download-token-for-graalvm-enterprise-edition-installations
# docker build  --build-arg="GRAAL_TOKEN=Get your own token" --tag ords-latest/graaljdk .
# Note that token will be baked into the image.
ARG GRAAL_TOKEN
ENV GRAAL_EE_DOWNLOAD_TOKEN=$GRAAL_TOKEN
RUN gu install --auto-yes --non-interactive js

ENV LATEST=/opt/ords-latest/
ENV CONFIG=/opt/ords-config/
WORKDIR $LATEST
ADD https://download.oracle.com/otn_software/java/ords/ords-latest.zip $LATEST
RUN jar xf ords-latest.zip; rm ords-latest.zip; chmod +x bin/ords
VOLUME $LATEST/lib/ext/ $CONFIG
EXPOSE 8080
EXPOSE 8443
WORKDIR $CONFIG
ENTRYPOINT ["/opt/ords-latest/bin/ords"]
CMD ["serve"]

When running docker build with this Dockerfile the download token must be provided as an argument. Otherwise there will be a build failure similar to this:

Step 3/13 : RUN gu install --auto-yes --non-interactive js
 ---> Running in 86da6cdbc24f
Downloading: Artifacts catalog from gds.oracle.com
Skipping ULN EE channels, no username provided.
Downloading: Component catalog from www.graalvm.org
Processing Component: Graal.js
Enter your download token and press ENTER, or press ENTER to generate a new download token.
Enter a valid download token:The command '/bin/sh -c gu install --auto-yes --non-interactive js' returned a non-zero code: 5

Convenient Dockerfile

To make things even easier, I’ve created a Dockerfile that you can use and the only thing you have to change is the token value on the command line:

docker build  --build-arg="GRAAL_TOKEN=NzY4MDYwYTk4ZjIyMTZmNTgzYWE3NzMwNGFkOGJiMmIwZTVlYTU3MmI3YThjZmY3NzExYzFlOWQxNjgyNTUwZGNiNzUxNmNlODIxNTkwYjM0MjA4NzkwNDVhNzUx" --tag ords-latest/graaljdk https://gist.githubusercontent.com/pobalopalous/a8c78d45c69fdb40763c913e2bda82c6/raw/4b57a40639385085e51dae21dec4b3fec7b1708c/

Let’s break those docker build command arguments down..

--build-arg="GRAAL_TOKEN=NzY4MDYwYTk4ZjIyMTZmNTgzYWE3NzMwNGFkOGJiMmIwZTVlYTU3MmI3YThjZmY3NzExYzFlOWQxNjgyNTUwZGNiNzUxNmNlODIxNTkwYjM0MjA4NzkwNDVhNzUx"

This specifies the GRAAL_TOKEN build argument that the Dockerfile will use to set the GRAAL_EE_DOWNLOAD_TOKEN environment variable which is used by the gu install js command when building the image.

--tag ords-latest/graaljdk 

The image that we build is going to be called ords-latest/graaljdk. That will differentiate it from the ords-latest/oraclejdk image we created in Get started with Oracle REST Data Services (ORDS) and Docker.

https://gist.githubusercontent.com/pobalopalous/a8c78d45c69fdb40763c913e2bda82c6/raw/4b57a40639385085e51dae21dec4b3fec7b1708c/

That’s the URL for the Dockerfile build context I have created for you so you don’t have to copy the text locally. Isn’t that nice?

Run that with your download token and you’ll see something like this…

Downloading build context from remote url: https://gist.githubusercontent.com/pobalopalous/a8c78d45c69fdb40763c913e2bda82c6/raw/4b57a40Downloading build context from remote url: https://gist.githubusercontent.com/pobalopalous/a8c78d45c69fdb40763c913e2bda82c6/raw/4b57a40639385085e51dae21dec4b3fec7b1708c/ORDS_Latest_GraalVM_Dockerfile [==================================================>]  1.371kB/1.371kB
Sending build context to Docker daemon  3.072kB
Step 1/16 : FROM container-registry.oracle.com/graalvm/enterprise:ol8-java17
 ---> 64dca1a5fa2a
Step 2/16 : MAINTAINER Peter O'Brien
 ---> Running in 33db11ef151e
Removing intermediate container 33db11ef151e
 ---> d38b7a7f3b67
Step 3/16 : ARG GRAAL_TOKEN
 ---> Running in 7613b2d725f7
Removing intermediate container 7613b2d725f7
 ---> f67809364f83
Step 4/16 : ENV GRAAL_EE_DOWNLOAD_TOKEN=$GRAAL_TOKEN
 ---> Running in fa3dc864e3b5
Removing intermediate container fa3dc864e3b5
 ---> 5fb687d736d1
Step 5/16 : RUN gu install --auto-yes --non-interactive js
 ---> Running in 9fb627218998
Downloading: Artifacts catalog from gds.oracle.com
Skipping ULN EE channels, no username provided.
Downloading: Component catalog from www.graalvm.org
Processing Component: Graal.js
Downloading: Component js: Graal.js from gds.oracle.com
Installing new component: Graal.js (org.graalvm.js, version 22.3.3)
Refreshed alternative links in /usr/bin/
Removing intermediate container 9fb627218998
 ---> ecef6d97d8db
Step 6/16 : ENV LATEST=/opt/ords-latest/
 ---> Running in f661804977a7
Removing intermediate container f661804977a7
 ---> 1005a3e3690b
Step 7/16 : ENV CONFIG=/opt/ords-config/
 ---> Running in 50901e104315
Removing intermediate container 50901e104315
 ---> 8a376e3151ee
Step 8/16 : WORKDIR $LATEST
 ---> Running in bd9810fe29f9
Removing intermediate container bd9810fe29f9
 ---> c18a57d2a8db
Step 9/16 : ADD https://download.oracle.com/otn_software/java/ords/ords-latest.zip $LATEST
Downloading [==================================================>]  114.1MB/114.1MB
 ---> 3cec2554cd2b
Step 10/16 : RUN jar xf ords-latest.zip; rm ords-latest.zip; chmod +x bin/ords
 ---> Running in 50a97beac418
Removing intermediate container 50a97beac418
 ---> 3f9fff9bded5
Step 11/16 : VOLUME $LATEST/lib/ext/ $CONFIG
 ---> Running in 0276fc517e42
Removing intermediate container 0276fc517e42
 ---> 5a8b5e5947e6
Step 12/16 : EXPOSE 8080
 ---> Running in c4dbf726988b
Removing intermediate container c4dbf726988b
 ---> c2ad8e7b94d3
Step 13/16 : EXPOSE 8443
 ---> Running in da46a9b873a3
Removing intermediate container da46a9b873a3
 ---> 5619e6b04ece
Step 14/16 : WORKDIR $CONFIG
 ---> Running in d5959c70115b
Removing intermediate container d5959c70115b
 ---> 440d4e54a4ce
Step 15/16 : ENTRYPOINT ["/opt/ords-latest/bin/ords"]
 ---> Running in 4452ce4de261
Removing intermediate container 4452ce4de261
 ---> f23c5cf67824
Step 16/16 : CMD ["serve"]
 ---> Running in 9f9f69dce7ae
Removing intermediate container 9f9f69dce7ae
 ---> ab2e0a2981e0
Successfully built ab2e0a2981e0
Successfully tagged ords-latest/graaljdk:latest

If you have made it this far, you now have an ords-latest/graaljdk image ready to be put into action.

Now RUN !

This is the part we’ve been waiting for. Remember that just like in Get started with Oracle REST Data Services (ORDS) and Docker the database already has ORDS installed and the configuration directory is a docker volume called ords-adb-config which gets mapped to /opt/ords-config/ in the container.

docker run --detach --rm --name ords-latest-8080 \
             -p 8080:8080 \
             -v ords-adb-config:/opt/ords-config/ \
             ords-latest/graaljdk

That will run in the background so you can use the docker logs command to check the output: docker logs -f ords-latest-8080

ORDS: Release 23.3 Production on Fri Nov 17 13:32:11 2023

Copyright (c) 2010, 2023, Oracle.

Configuration:
  /opt/ords-config/

2023-11-17T13:32:11.890Z INFO        HTTP and HTTP/2 cleartext listening on host: 0.0.0.0 port: 8080
...
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
java.vendor.version=GraalVM EE 22.3.3
...
2023-11-17T13:32:27.906Z INFO        

Mapped local pools from /opt/ords-config/databases:
  /ords/                              => default                        => VALID     


2023-11-17T13:32:28.233Z INFO        Oracle REST Data Services initialized
Oracle REST Data Services version : 23.3.0.r2891830
Oracle REST Data Services server info: jetty/10.0.17
Oracle REST Data Services java info: Java HotSpot(TM) 64-Bit Server VM 17.0.8+9-LTS-jvmci-22.3-b21

The GraphQL implementation in ORDS is based on REST Enabled tables and views. Therefore, to get any sensible use of GraphQL with ORDS one must first have a REST Enabled schema with some REST Enabled tables or views. Thankfully I already have that in my database so I can dive right in…

GraphQL in action with ORDS on GraalVM

Over to you

To sum it up, this article explained how to create a Docker image using GraalVM, specifically focusing on adding the JavaScript component needed for ORDS GraphQL. The image build process involves installing the GraalVM JavaScript part and downloading the latest ORDS release, resulting in a Docker image. Before doing so, you had to get and activate a download token so that the JavaScript component could be installed in the image. This image, when used, makes it easy to start a standalone ORDS container. You now have a straightforward solution for using ORDS GraphQL in a GraalVM environment that is ready for production.

To explore all the powerful querying options available to you with ORDS GraphQL see the relevant chapter in the ORDS Developer Guide.

QuickSQL is not available

Oracle APEX 23.2 was made generally available earlier this month ( November 2023 ). The announcement mentions some new functionality highlights but the release notes are more thorough in going through what is new. What this blog post is particularly interest in is this one…

Quick SQL Updates

Create, maintain, and review application data models with minimal typing, lighting-fast SQL generation, and a built-in entity relationship diagram.

apex.oracle.com

Quick SQL is a markdown-like shorthand syntax that expands to standards-based Oracle SQL. It is useful to rapidly design and prototype data models. Previously, Quick SQL was only available within APEX but it is now available at https://github.com/oracle/quicksql and a distribution of Quick SQL is available through ORDS 23.3.0.

Within APEX the feature is a utility accessible from the SQL Workshop menu.

QuickSQL is a Utility in the SQL Workshop

However, if you are running APEX 23.2 to use Quick SQL you must be running it with at least ORDS 23.3.0 to avoid this error message…

What you see when you’re not running ORDS 23.3.0 or above
QuickSQL is not available. This is likely due to an insufficient version of ORDS. Minimum ORDS version required is 23.3.

Solution is simple. Upgrade to ORDS 23.3.0 which was released October 23rd 2023. See oracle.com/rest for download link, etc. In other words, it’s…

What about the Autonomous Database?

At the time of writing the hosted Autonomous Database service offerings on cloud.oracle.com has not been upgraded to ORDS 23.3.0 yet. The current workaround is to use Customer Managed ORDS with Autonomous Database. Although the version of ORDS Metadata in your Autonomous Database will be ORDS 23.2.3 it will work fine with ORDS 23.3.0.

December Update on Autonomous Database

Most Autonomous Database production regions are running ORDS 23.3.0 now so this Quick SQL is not available issue should no longer occur.

Quick SQL in Autonomous Database

Oracle APM agent generates NullPointerException

April 2024 Update !
ORDS 24.1.0 no longer has this Java Agent / Classloader issue.
Use ORDS 24.1.0 or a later version.

When using Oracle APM Java Agent with ORDS, it crashes with a NullPointerException at startup. Not just when running in standalone mode, if your JVM is configured to use the Oracle APM Java Agent, you could encounter this issue with any command.

~/Downloads/ords-23.2.3.242.1937/bin/ords config list  
Oracle APM Agent: Starting APM Agent [premain]
Oracle APM Agent: Wrapper: version, hybrid
Oracle APM Agent: [DirectoryLocation] initialized on classloader [null]
Oracle APM - temp log directory is /var/folders/hq/6cg5drc54c3f371r9v65c8qm0000gn/T//
Oracle APM Agent: Parsing instrumentation directives
Oracle APM Agent: Loading directives from [built-in.directives]
Oracle APM Agent: Loading directives from [/~/work/ora_apm/oracle-apm-agent/config/1.8.3326/DirectivesConfig.acml]
Oracle APM Agent: Parsed a total of [116] directives
Oracle APM Agent: Initializing AgentInstance
Oracle APM Agent: Initialized AgentInstance
Oracle APM Agent: Started [premain] Agent
null
java.lang.NullPointerException
	at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
	at java.base/java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1541)
	at java.base/java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:667)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:591)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:575)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	at oracle.dbtools.launcher.executable.jar.ExecutableJarEntrypoint.invoke(ExecutableJarEntrypoint.java:42)
	at oracle.dbtools.launcher.executable.jar.ExecutableJarEntrypoint.main(ExecutableJarEntrypoint.java:64)

This was one of the reasons that a previous article on using Oracle APM with ORDS focused on using Apache Tomcat rather then ORDS standalone.

When running standalone, ORDS uses a built-in embedded jetty server for HTTP(s) service handling. The ords.war file contains a META-INF/MANIFEST.MF which has the following 2 lines used in standalone mode:

Main-Class: oracle.dbtools.launcher.executable.jar.ExecutableJarEntrypoint 
Executable-Jar-Main-Class: oracle.dbtools.cmdline.CommandLine

The first line is used by by the JVM to launch the main method in class ExecutableJarEntrypoint. Inside this main method ORDS is trying to read the second line. This is done via a mechanism like what is shown below:

ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL url = cl.getResource("META-INF/MANIFEST.MF");

This works fine when running standalone since there is only 1 single war/jar file and therefore only a single manifest. However, when running with the APM Agent there are now 2 war/jar files and also 2 manifests in the classpath. In this case, the getResource call returns the MANIFEST.MF from the agent jar file instead of the MANIFEST.MF within ords.war file. This manifest from the APM agent does not have any Executable-Jar-Main-Class which makes ORDS throw the NullPointerException!

Workaround

Until this is addressed in ORDS java code, a simple workaround to allow the Oracle APM java agent monitor the standalone ORDS env is to simply edit the MANIFEST.MF file inside the agent to add a line like this:

Executable-Jar-Main-Class: oracle.dbtools.cmdline.CommandLine

This is an approach provided to me by the Oracle APM team.

Since a runtime environment may not have the jar command to unpack the agent jar, they were kind enough to write a python script to edit the agent jar for this and repackage everything properly afterwards.

import zipfile
import io
import shutil
# Specify the path to the APM Agent jar file
jar_filename = '/opt/oracle/product/oracle-apm-agent/bootstrap/ApmAgent.jar'
file_to_edit = 'META-INF/MANIFEST.MF'
new_line = 'Executable-Jar-Main-Class: oracle.dbtools.cmdline.CommandLine\n'
# Create a temporary file to hold the modified JAR content
temp_jar_filename = 'temp_modified.jar'
# Open the original JAR file in read mode
with zipfile.ZipFile(jar_filename, 'r') as original_jar:
    # Create a new JAR file in write mode
    with zipfile.ZipFile(temp_jar_filename, 'w') as temp_jar:
        for item in original_jar.infolist():
            # Copy all files from the original JAR to the new JAR
            if item.filename != file_to_edit:
                temp_jar.writestr(item, original_jar.read(item))
        # Read the contents of the file to be edited
        with original_jar.open(file_to_edit) as file:
            content = file.read().decode('utf-8')
        # Append the new line to the content
        modified_content = content + new_line
        # Write the modified content to the new JAR
        temp_jar.writestr(file_to_edit, modified_content.encode('utf-8'))
# Replace the original JAR with the modified JAR
shutil.move(temp_jar_filename, jar_filename)
print('New line appended and old file removed successfully.')

Change the jar_filename variable to the location of your ApmAgent.jar and save the above as ords_apm.py. Then run it..

>python3 ords_apm.py

New line appended and old file removed successfully.

Now you can use the Oracle APM Java Agent with your ORDS command line.

> ~/Downloads/ords-23.2.3.242.1937/bin/ords config list  
Oracle APM Agent: Starting APM Agent [premain]
Oracle APM Agent: Wrapper: version, hybrid
Oracle APM Agent: [DirectoryLocation] initialized on classloader [null]
Oracle APM - temp log directory is /var/folders/hq/6cg5drc54c3f371r9v65c8qm0000gn/T//
Oracle APM Agent: Parsing instrumentation directives
Oracle APM Agent: Loading directives from [built-in.directives]
Oracle APM Agent: Loading directives from [~/work/ora_apm/oracle-apm-agent/config/1.8.3326/DirectivesConfig.acml]
Oracle APM Agent: Parsed a total of [116] directives
Oracle APM Agent: Initializing AgentInstance
Oracle APM Agent: Initialized AgentInstance
Oracle APM Agent: Started [premain] Agent

ORDS: Release 23.2 Production on Thu Oct 05 19:47:01 2023

Copyright (c) 2010, 2023, Oracle.

Configuration:
  /path/to/config/

Database pool: default

Setting                  Value                                          Source     
----------------------   --------------------------------------------   -----------
database.api.enabled     true                                           Global     
db.hostname              localhost                                      Pool       
db.password              ******                                         Pool Wallet
db.port                  2193                                           Pool       
db.servicename           DB193P                                         Pool       
db.username              ORDS_PUBLIC_USER                               Pool       
feature.sdw              false                                          Pool       
jdbc.MaxLimit            100                                            Pool       
plsql.gateway.mode       disabled                                       Pool       
restEnabledSql.active    true                                           Pool       

Conclusion

It really is as simple as that. Note that a similar workaround might work with other java agents which encounter a NullPointerException.

8080 is already in use

When trying to start Oracle REST Data Services (ORDS), you may encounter the frustrating error message: “could not start standalone mode because the listen port: 8080 is already in use by another process. check if another instance of ords is already running“. This error indicates that another application or process is already using port 8080, preventing ORDS from starting successfully. In this article, we will guide you through the steps to identify the application using port 8080 on Windows, macOS, and Linux, allowing you to resolve this issue and get ORDS up and running.

Note that this can happen if you are trying to run multiple ORDS instances using HTTPS traffic. See Multiple ORDS Instances on the Same Machine for more information on that.

Find the Application Using Port 8080:

Windows:

  1. Open the Command Prompt: Press Win + R, type “cmd,” and hit Enter.
  2. In the Command Prompt, enter the following command: netstat -ano | findstr :8080.
  3. Identify the line with the local address 0.0.0.0:8080 or 127.0.0.1:8080 in the output.
  4. Take note of the PID (Process Identifier) associated with that line.
  5. Open the Task Manager: Press Ctrl + Shift + Esc.
  6. Go to the “Details” tab in the Task Manager.
  7. Locate the process with the corresponding PID from step 4 to identify the application using port 8080.

macOS:

  1. Open Terminal: Navigate to the Applications/Utilities folder or use Spotlight Search to find it.
  2. In the Terminal, enter the following command: lsof -i :8080.
  3. Look for the line with the local address *:8080 in the output.
  4. Note the PID associated with that line.
  5. Enter the command: ps -p [PID] -o comm= (replace [PID] with the PID noted in step 4).
  6. The output of the above command will display the name of the application using port 8080.
On my mac the output of the lsof command looks like this

Linux:

  1. Open a Terminal: Use a terminal application such as GNOME Terminal, Konsole, or xterm.
  2. In the terminal, enter the following command: sudo lsof -i :8080.
  3. Look for the line with the local address *:8080 in the output.
  4. Note the PID associated with that line.
  5. Enter the command: ps -p [PID] -o comm= (replace [PID] with the PID noted in step 4).
  6. The output of the above command will display the name of the application using port 8080.
On a linux machine this is the output of “lsof -i :9193” which shows docker containers using that port

Resolving the Issue:

Once you have identified the application or process using port 8080, you have a few options to resolve the issue:

  1. Terminate the Conflicting Application: If the application using port 8080 is not essential or can be temporarily shut down, you can terminate it from the Task Manager (Windows) or using the appropriate command for macOS or Linux.
  2. Change the ORDS Port: If terminating the conflicting application is not feasible, you can have ORDS use a different port that is not in use such as port 8081. This can be achieved in one of two ways:
    • On the command line when starting standalone: ords serve --port 8081
    • In the configuration: ords config set standalone.http.port 8081
  3. Configure the Conflicting Application: If the conflicting application is critical and cannot be terminated, you may need to adjust its configuration to use a different port, freeing up port 8080 for ORDS. Consult the documentation or support resources for the specific application to learn how to modify its port configuration.
Just one more thing…

Of course you can change port 8080 for any other port that you happen to want to use. Using the standard ports 80 and 443 can be problematic in that there might be a service already using that port and the above approaches to not always list these background services. For example, if you are using a container management system such as Rancher and have Traefik enabled, it will not be shown as listing on the port, but it will have your traffic redirected to it, and not your ORDS instance.

Conclusion

Hitting the “8080 is already in use by another process” error when starting Oracle REST Data Services (ORDS) can be frustrating, but by following the steps outlined in this article, you can identify the application using that port and take appropriate action to resolve the issue. Whether it involves terminating the conflicting application, changing the ORDS port, or configuring the conflicting application differently, you’ll soon have ORDS running smoothly.