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/.
Advertisements

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.

Listener 2.x Static Resources and i.war

Oracle Application Express (APEX) relies on a set of static resources to function properly. These static resources contain the JavaScript, CSS, and images that the APEX user interface needs to render and function correctly. The static resources are located in the /images folder in the APEX distribution. Typically the resources are made available at the /i/ path on an APEX web server.

In the Oracle Application Express Listener (Listener) 1.x.x series the process for deploying the /i/ bundle was to manually zip the contents of /images into an archive named i.war and then to deploy that archive on the same application server as Listener.

This meant that every time the static resources were modified (for example to add custom stylesheets or images), the archive needed to be recreated and then redeployed on the application server.

In the Listener 2.x.x series the process was improved. Rather than creating the archive manually the static sub-command of apex.war is used to generate i.war as documented here, and reproduced below:

Use the static command to create a web archive file named i.war:

java -jar apex.war static <apex directory>/images

Where:

<apex directory> is the directory location of Oracle Application Express.

The created images WAR does not contain the static resources, instead it references the location where the static resources are stored. Therefore the static resources must be available at the specified path on the server where the WAR is deployed.

Note the emphasis in the last paragraph above. In contrast to Listener 1.x.x, in 2.x.x the static resources are not included in the archive. Instead functionality in Oracle WebLogic and Oracle GlassFish is leveraged to create an i.war that references the path where the static resource are located. This means that the static resources can be updated without having to recreate and redeploy i.war.

Thus when i.war is deployed on WebLogic or GlassFish, and a request for a resource is made within the /i/ path then the application server looks for the corresponding resource within the <apex directory>/images folder specified above. It looks for the path in the file system of the server where i.war is deployed. Therefore it is imperative that the APEX static resources are copied to the application server at the exact path specified when using the static command.

For example if i.war is created using the following command:

java -jar apex.war static /usr/local/apex/4.2.2/apex/images

then the path /usr/local/apex/4.2.2/apex/images must exist on the server where i.war is deployed and it must contain all the static resources for the version of APEX installed in the database. It is not sufficient that the files exist on a local development box where the i.war was created, they must be copied to the application server machine’s file system as well.

Deploying static resources at custom path

Occasionally you may need to deploy the APEX static resources at a path other than the default of /i/. To do this use the --context-path argument of the static command, for example to deploy static resources at /apex-images you would do the following:

java -jar apex.war static --context-path /apex-images /usr/local/apex/4.2.2/apex/images

which will produce output similar to the following:

WAR Generation complete
 WAR location     : /home/cdivilly/apex-images.war
 Context path     : /apex-images
 Static resources : /usr/local/apex/4.2.2/apex/images

Note that this time the archive is named apex-images.war. Note however it is not the name of the archive that determines it’s context-path, rather it is a setting in the deployment descriptor in the archive that determines this. In this case the value of that setting is /apex-images. You could rename the archive to abc.war and it would still be delpoyed at /apex-images. A previous post provides more detail on these deployment descriptors.

See Also

  • To learn more detail on the WebLogic and GlassFish functionality that enables i.war to refer to resources located in the file system, see this post.
  • If you are having problems with APEX static resources not being found and APEX pages not displaying properly, see this post

Configuring Application Express Static Resources with Listener 2.0

A problem sometimes encountered when using Oracle Application Express Listener, is getting a blank page displayed when attempting to access an Oracle Application Express (APEX) page. For example getting a blank page when trying to display http://server:port/apex/. The cause of this problem is not having the APEX static resources configured properly. This leads to the JavaScript and CSS resources required by APEX not being found, and the APEX page failing to render correctly.

Possible Causes

Any of the following can cause this issue to occur:

  1. Forgetting to deploy i.war on WebLogic/GlassFish
  2. Specifying an incorrect path when using the java -jar apex.war static command to generate i.war
  3. Configuring APEX to use a non default context path for static resources (/i) and not specifying the same context path (via the --context-path option) when using java -jar apex.war static.
  4. Moving, renaming or deleting the folder pointed to by i.war after deploying i.war
  5. When running in Standalone Mode, entering an incorrect path (or skipping specifying a path) when prompted, on the first run of Standalone Mode
  6. When running in Standalone Mode, entering an incorrect path via the --static-images option
  7. And last, the one I most often forget myself, upgrading to a new version of APEX and forgetting to reconfigure and redeploy i.war to point to the static resources for the new APEX version, or in Standalone Mode forgetting to update the location by using the --apex-images option.

Confirming the problem

Assume your APEX deployment is located at http://example.com/apex/ and your static resources have been deployed at http://example.com/i/, then try accessing the following url:

http://example.com/i/apex_version.txt

If you get a 404 Not Found error then you need to double check points 1-6 in the list above, i.war is not deployed or is not pointing at a folder containing APEX static resources.

Otherwise a plain text file will be displayed with contents like the following:

Application Express Version:  4.2.1

Pay close attention to the version number displayed, it must match the version of APEX deployed on the database. If they differ then check point 7 on the list above, the Listener is not configured to use the correct version of APEX static resources to match the APEX version in the database.

Curing the problem

Consult the Oracle Application Express Listener for detailed documentation on how to create and deploy i.war. See instructions for WebLogic here, and GlassFish here.

You can get detailed help on the static listener command by typing the following at a command prompt:

java -jar apex.war help static

Listener 2.0 picks up changes to APEX static resources immediately

For Listener 1.1.x the deployment process for i.war required zipping all the APEX static resources into i.war and then deploying the resultant i.war.

The problem with this approach is that if the contents of the APEX static resources are updated (for example to add some custom style sheets), then i.war needs to be recreated and redeployed.

In 2.0 we leverage capabilities in WebLogic and GlassFish (described in more detail in a previous post) to create an i.war which does not actually contain the static resources, but instead points to the folder containing the static resources.

The advantage of this approach is that the static resources can be updated and the updates are immediately picked up by the server without requiring any restarting or redeploying of i.war

Weblogic & Basic Auth

Weblogic will by default attempt to authenticate any HTTP Basic credentials, even if the URI being accessed does not fall within a statically declared web.xml security constraint. Doesn’t seem like a reasonable default to me, but anyways there is a means to change this behaviour, the enforce-valid-basic-auth-credentials setting:

To set the enforce-valid-basic-auth-credentials flag, perform the following steps:

  1. Add the <enforce-valid-basic-auth-credentials> element to config.xml within the <security-configuration> element.
    ...
    <enforce-valid-basic-auth-credentials>false</enforce-valid-basic-auth-credentials>
    </security-configuration>
    ...
  2. Start or restart all of the servers in the domain.

It’s a shame there isn’t an equivalent setting in the weblogic.xml deployment descriptor.

Ubuntu, Subclipse, and JavaHL

If you get an error message like the following when using Subclipse (The Eclipse SVN plugin) on Ubuntu:

Failed to load JavaHL Library.

This means that your Ubuntu installation is missing the Java bindings for svn, to remedy this, install the relevant package:

sudo apt-get install libsvn-java

Add the following to your eclipse.ini after the line starting with -vmargs

-Djava.library.path=/usr/lib/jni

Restart Eclipse. An alternative solution is to reconfigure Subclipse to use the pure Java bindings provided by SVNKit, select the Window|Preferences menu option, then choose Team>SVN from the tree view in the left pane, then choose SVNKit for the Client setting under the SVN Interface heading.

Music|Albums|All Songs|Shuffle

This has been bugging me for ages. My preferred way to listen to my music collection is on Shuffle mode on my iPod Touch. I do this by choosing Music|Albums|All Songs|Shuffle. Within my Music Collection are lots of songs that I have more than one version off, live versions, soundtrack versions, compilation versions etc, and its been driving me crazy that Shuffle was playing each version in sequence. Why would I want to listen to the same song twice? That ain’t random!

I guess I’m slow, but I finally understood why this is happening today. This Shuffle menu option is not choosing songs randomly, instead it progresses through my collection in alphabetical order, just starting at a random point in the collection.

To truly shuffle the play order you need to tap the album artwork and then tap the shuffle icon that appears on the right hand side. Maybe this icon got switched off at some point, but I don’t recall doing that, I had to go hunting in the manual today to find out it even existed.

IMHO its a bug that choosing Music|Albums|All Songs|Shuffle doesn’t force this shuffle icon on.

Maven, JRuby and Rails Migrations

Here’s how I managed to get Rails Migrations working with a Maven build process, enabling me to leverage Migrations to maintain the RDBMS schema of a Java application.

Add JRuby and Database dependencies

Add the following dependencies to your pom.xml (adjust for whatever is latest version of jruby and whatever your database is).

  <dependency>
   <groupId>org.jruby</groupId>
   <artifactId>jruby-complete</artifactId>
   <version>1.3.0RC1</version>
  </dependency>
  <dependency>
   <groupId>oracle</groupId>
   <artifactId>jdbc</artifactId>
   <version>11.1.0</version>
  </dependency>

Add a goal to install required Ruby gems

To get Rails migrations running we’ll need the following gems:

  • activerecord
  • activerecord-jdbc-adapter
  • your database specific jdbc adapter

We’ll set up a profile to install these gems if they are missing (based on a approach used by Binil Thomas):

<profiles>
  <profile>
   <id>first.time</id>
   <activation>
    <file>
     <missing>${user.home}/.gem/jruby/1.8/gems/activerecord-2.3.2</missing>
    </file>
   </activation>
   <build>
    <plugins>
     <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <executions>
       <execution>
        <id>install-active-record-gem</id>
        <phase>initialize</phase>
        <goals>
         <goal>java</goal>
        </goals>
        <configuration>
         <mainClass>org.jruby.Main</mainClass>
         <arguments>
          <argument>-S</argument>
          <argument>gem</argument>
          <argument>install</argument>
          <argument>activerecord</argument>
          <argument>activerecord-jdbc-adapter</argument>
          <argument>activerecord-oracle_enhanced-adapter</argument>
          <argument>--no-ri</argument>
          <argument>--no-rdoc</argument>
          <argument>--no-test</argument>
         </arguments>
        </configuration>
       </execution>
      </executions>
     </plugin>
    </plugins>
   </build>
  </profile>
 </profiles>

Replace activerecord-oracle_enhanced-adapter with the name of your chosen database’s jdbc adapter.

Add a goal to run the migration

 <build>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
     <execution>
      <id>run-migrate</id>
      <phase>install</phase>
      <goals>
       <goal>java</goal>
      </goals>
      <configuration>
       <mainClass>org.jruby.Main</mainClass>
       <arguments>
        <argument>-S</argument>
        <argument>rake</argument>
        <argument>-f</argument>
        <argument>${basedir}/Rakefile</argument>
       </arguments>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>

Create a Rakefile

You’ll need a Rakefile to carry out the migration, in my case I wanted to avoid depending on all of Rails so I just used the following:

require 'active_record'
require 'yaml'

RAILS_ROOT = "#{File.dirname(__FILE__)}" unless defined?(RAILS_ROOT)

task :default => :migrate

task :migrate => :environment do
  ActiveRecord::Migrator.migrate('db/migrate', ENV["VERSION"] ? ENV["VERSION"].to_i : nil )
end

task :environment do
  ActiveRecord::Base.establish_connection(YAML::load(File.open("#{RAILS_ROOT}/config/database.yml")))
  ActiveRecord::Base.logger = Logger.new(File.open('database.log', 'a'))
end

Write your migrations

Create your migrations in db/migrate.

Apply database changes

Finally type:

mvn install

to deploy your database changes.

The full POM

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.example</groupId>
 <artifactId>schema</artifactId>
 <name>Example POM for doing Rails Migrations</name>
 <packaging>pom</packaging>
 <dependencies>
  <dependency>
   <groupId>org.jruby</groupId>
   <artifactId>jruby-complete</artifactId>
   <version>1.3.0RC1</version>
  </dependency>
  <dependency>
   <groupId>oracle</groupId>
   <artifactId>jdbc</artifactId>
   <version>11.2.0</version>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
     <execution>
      <id>run-migrate</id>
      <phase>install</phase>
      <goals>
       <goal>java</goal>
      </goals>
      <configuration>
       <mainClass>org.jruby.Main</mainClass>
       <arguments>
        <argument>-S</argument>
        <argument>rake</argument>
        <argument>-f</argument>
        <argument>${basedir}/Rakefile</argument>
       </arguments>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
 <profiles>
  <profile>
   <id>first.time</id>
   <activation>
    <file>
     <missing>${user.home}/.gem/jruby/1.8/gems/activerecord-2.3.2</missing>
    </file>
   </activation>
   <build>
    <plugins>
     <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <executions>
       <execution>
        <id>install-active-record-gem</id>
        <phase>initialize</phase>
        <goals>
         <goal>java</goal>
        </goals>
        <configuration>
         <mainClass>org.jruby.Main</mainClass>
         <arguments>
          <argument>-S</argument>
          <argument>gem</argument>
          <argument>install</argument>
          <argument>activerecord</argument>
          <argument>activerecord-jdbc-adapter</argument>
          <argument>activerecord-oracle_enhanced-adapter</argument>
          <argument>--no-ri</argument>
          <argument>--no-rdoc</argument>
          <argument>--no-test</argument>
         </arguments>
        </configuration>
       </execution>
      </executions>
     </plugin>
    </plugins>
   </build>
  </profile>
 </profiles>
</project>

Add Oracle JDBC Jar to Maven Repository

If a jar is not available from a public repository (for example, Oracle JDBC jars), then you can get Maven to manually install a copy of the jar in the local repository. To manually deploy the Oracle JDBC driver to your local repository type the following:

mvn install:install-file -Dfile={ORACLE_HOME}/jdbc/lib/ojdbc6.jar -Dpackaging=jar\
 -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.1.0

where {ORACLE_HOME} is the path to the Oracle Database installation.

You can then reference the the jar via a dependency declaration like the following:

<dependency>
 <groupId>com.oracle</groupId>
 <artifactId>ojdbc6</artifactId>
 <version>11.1.0</version>
</dependency>