Friday, 12 February 2016

Accepting payments with Stripe in APEX, Part 1

I've just been investigating a payment gateway for an APEX application. I already knew about the recent startup Stripe, and their fees seemed just as good (if not better) than the other well-known contenders - I figured there would be a good place to start.

Now, I haven't actually worked with the others, but so far, I'm very impressed with the system/API available. From my little bit of research, all the card information will be stored on Stripe's servers, so we need not deal with storing and encrypting customers card information. With that, we are left with this general workflow:

  1. Include a form for customers to enter there card information
  2. The form gets submitted to Stripe's servers
  3. Returned is a token. We use this to then complete the charge

For this first part, I'll be focusing on the form. In particular, Stripe provides a form for us that we can re-use. Check out the documentation on the form here - Keep in mind, you can just as easily develop your own form if you have your own design in mind.

The basic example (for a form) they give on the docs is:

<form action="" method="POST">
    src="" class="stripe-button"
    data-name="Demo Site"
    data-description="2 widgets"

Side note: In your account, you can retrieve your API tokens (and test tokens) from:

So, if you add that to a static region on your page, you will see a nice checkout button and form:

What would then happen after submitting the payment information, is the form would get submitted, with some additional parameters being sent in the POST request. Being on APEX, this won't do since the whole page is wrapped around a form - resulting in this being an embedded form (unsupported).

Looking at the documentation some more, they have a more advanced example giving us more control over what happens once the Pay button is selected.

We still need to leave a reference to checkout.js on our page, so for now this can live in our region where the pay button will live. The next part will be to add a regular APEX button to our region - with the action being Defined by a Dynamic Action.

Then, we need a dynamic action for when the button is clicked - with the true action being to execute a block of JavaScript code (the handler could be set up on page load, but just chucked it in one spot for simplicity)

var handler = StripeCheckout.configure({
    key: '[redacted]',
    locale: 'auto',
    token: function(token) {
    name: 'Demo Site',
    description: '2 widgets',
    currency: "aud",
    amount: 2000

So, now with our advanced implementation, we are left with much the same form:

(This is just test card information supplied with by Stripe - see:

So, when the user submits the payment information, the token function will be called. With that we are returned with the following information:

Further, if we look in our dashboard on Stripe for the account, we should see this activity logged:

So, with that information, you would then want to initiate a request to a PL/SQL process to make the actual charge to the customers card. A post for another day.

Saturday, 23 January 2016

APEX Dashboard Competition for English Locale

The other day Tobias announced a new competition where you can win Apple products, and what you need to do is build a dashboard in Oracle Application Express using some supplied data.

I'm about to go on a little trip so I thought I'd load up this data into my local VM so that if I had some down time, I could have a play around with it (not yet sure if I'll enter!). The only problem was, I started receiving errors during the data import, as per:

As from that screenshot, you will see the number is using a decimal point as a comma (as opposed to what I am used to, and what the session is expecting, a period). To be honest, I didn't even realise different locale's used different decimal marks - but after turning to Wikipedia, I see there are a large number of nations that do:

After a bit of research, I discovered that you can change the session parameter NLS_NUMERIC_CHARACTERS to support the different locale's. With that I came up with the script:

alter session set NLS_NUMERIC_CHARACTERS=',.';
alter session set NLS_NUMERIC_CHARACTERS='.,';

With those session modifications the data should (it did for me) load seamlessly.

The next task, was that all the data is in German. It's not a huge deal, as it's the numbers that matter. But, I feel it a lot easier to work with data I can at least interpret! So, I wanted to go ahead and come up with a way to tweak this so I can understand the information better. With a bit of google translate help, I made a series of CSV files to create a mapping. Check out this little project: In the raw folder is a series of tabular data with the word as it is in the data (original) and an English translation (not all perfect!). Once you have the project files, from the same directory, you can apply the updates as per the CSV files with:

sql dash_comp/dash_comp@// @to_en

Hope it's useful!

Thursday, 14 January 2016

Upgrading APEX on XE without the patch sets

To get APEX patch sets requires a paid support account to get access to the patch sets for minor updates - so upgrading APEX on our XE database installations can be challenging for those of us without a paid support account.

So effectively, what you need to do is remove APEX, and re-install from scratch. APEX also comes with a Java program to perform backups, where you can for example export invididual workspaces, export all workspaces, export invidual applications, export applications by workspace id, or export all applications. I grabbed the idea from this apexbackup project on GitHub: Basically, you need to set your CLASSPATH to point to:

  1. The Oracle Java database driver - typically $ORACLE_HOME/lib/ojdbc5.jar or $ORACLE_HOME/jdbc/lib/ojdbc5.jar
  2. The utilities folder in the APEX installation files

After that has been set,  you can run the program. e.g: 

export CLASSPATH=$ORACLE_HOME/jdbc/lib/ojdbc5.jar:$ORACLE_HOME/apex/utilities/
java oracle.apex.APEXExport

With the requires arguments depending on which operation you wish to perform. If you run it without any arguments, output to the screen will be a list of all the options:

Usage APEXExport -db  -user  -password  -applicationid  -workspaceid -instance -expWorkspace -expMinimal -expFiles -skipExportDate -expPubReports -expSavedReports -expIRNotif -expTranslations -expTeamdevdata -expFeedback -deploymentSystem -expFeedbackSince -expOriginalIds -debug  
    -db:               Database connect url in JDBC format 
    -user:             Database username
    -password:         Database password
    -applicationid:    ID for application to be exported
    -workspaceid:      Workspace ID for which all applications to be exported or the workspace to be exported
    -instance:         Export all applications
    -expWorkspace:     Export workspace identified by -workspaceid or all workspaces if -workspaceid not specified
    -expMinimal:       Only export workspace definition, users, and groups
    -expFiles:         Export all workspace files identified by -workspaceid
    -skipExportDate:   Exclude export date from application export files
    -expPubReports:    Export all user saved public interactive reports
    -expSavedReports:  Export all user saved interactive reports
    -expIRNotif:       Export all interactive report notifications
    -expTranslations:  Export the translation mappings and all text from the translation repository
    -expFeedback:      Export team development feedback for all workspaces or identified by -workspaceid to development or deployment
    -expTeamdevdata:   Export team development data for all workspaces or identified by -workspaceid
    -deploymentSystem: Deployment system for exported feedback
    -expFeedbackSince: Export team development feedback since date in the format YYYYMMDD
    -expOriginalIds:   If specified, the application export will emit ids as they were when the application was imported
    Application Example: 
       APEXExport -db localhost:1521:ORCL -user scott -password scotts_password -applicationid 31500 
    Workspace  Example: 
       APEXExport -db localhost:1521:ORCL -user scott -password scotts_password -workspaceid 9999 
    Instance Example:
       APEXExport -db localhost:1521:ORCL -user system -password systems_password -instance 
    Export All Workspaces Example:
       APEXExport -db localhost:1521:ORCL -user system -password systems_password -expWorkspace 
    Export Feedback to development environment:
       APEXExport -db localhost:1521:ORCL -user scott -password scotts_password -workspaceid 9999 -expFeedback 
    Export Feedback to deployment environment EA2 since 20100308:
       APEXExport -db localhost:1521:ORCL -user scott -password scotts_password -workspaceid 9999 -expFeedback -deploymentSystem EA2 -expFeedbackSince 20100308

So with that, to upgrade our APEX instances on minor releases (patches) we can script up a program to export all our workspaces, and restore them after a fresh installation - by getting the latest, full download from OTN.

I started working on a new project over the weekend to do exactly this - It's still in early stages, but to the point it's working for me. Basically, the arguments it accepts (current order being important) is:
  • Path to the apex installation files
  • Database host
  • Database port
  • Database sid
  • System password
  • Sys password
  • Path to where the images are stored
Once you grab the project on your server, you would simply run it like so:

sudo -E ./ /home/trent/apex localhost 1521 xe oracle oracle /ords/apex_images

Using the same order of arguments described above.

That goes without saying, this should be run as a user with permissions to write to the destination image directory, and they should have $ORACLE_HOME set. And you will likely want to take a separate backup of all your applications in case anything breaks in the script after the APEX removal - especially in these early stages of the project (I haven't had any other testers so far).

My script is also taking a backup of the instance configuration to restore it post upgrade (though, I haven't got everything working so far due to apex_instance_admin.set_parameter seemingly not being supported for all parameters). The main thing that will be missing post upgrade is all the users previously set up in the INTERNAL workspace. I have my machine installed in VirtualBox, so I took a snapshot beforehand should anything fall over, so I can easily restore it.

Some immediate enhancements requires are to support named arguments so order isn't important, along with default values if any are omitted; as well as adding some additional ones (namely, for the values passed to the APEX install script).

Even if you don't use my specific script/project, it can be a good example case to base off to develop something for your own business.

Have I left any other crucial bits off my script - that would need backup and restoration?

Here's a little video of my running the script:

Monday, 11 January 2016

APEX Instance Admin Preferences Cheat Sheet

APEX comes with an API - APEX_INSTANCE_ADMIN - where you can both get and set instance preferences. There is a list of available properties on the documentation, however I found that not all preferences were documented there. For example, in Feature Configuration, there are some preferences surrounding packaged applications:

Looking at the documentation,, you may find it difficult locating these.

Then, there other properties in there that I don't think are relevant any more (..but not an expert on the subject, so may be wrong). Lets take the example of PASSWORD_HISTORY_DAYS - this states "Defines the maximum number of days a developer or administrator account password may be used before the account expires. The default value is 45 days.". We can locate the property it's talking about under Security - Authentication Control - Development Environment Settings.

If we attempt to query this property name, you will find nothing is returned.

Connected to:

Oracle Database 11g Express Edition Release - 64bit Production

SQL> set serveroutput on

SQL> begin

  2    dbms_output.put_line('Value: ' || apex_instance_admin.get_parameter('PASSWORD_HISTORY_DAYS'));

  3  end;

  4  /


PL/SQL procedure successfully completed.


Digging into this, it looks to me this relates to the parameter ACCOUNT_LIFETIME_DAYS.

So anyway, with all this said, here is what I've come up with a table mapping each field to a parameter name - some on the docs, others not.

Text Version:

Feature Configuration

Application DevelopmentParameter Name
Allow PL/SQL Program Unit EditingPLSQL_EDITING
Create demonstration objects in new workspacesWORKSPACE_PROVISION_DEMO_OBJECTS
Create websheet objects in new workspacesWORKSPACE_WEBSHEET_OBJECTS
Enable SQL Access in WebsheetsWEBSHEET_SQL_ACCESS
Packaged Application install Options
Allow HTTP Header Variable authenticationPKG_APP_AUTH_ALLOW_HHEAD
Allow LDAP Directory authenticationPKG_APP_AUTH_ALLOW_LDAP
Allow Oracle Applicaion Server Single Sign-On authenticationPKG_APP_AUTH_ALLOW_SSO
SQL Workshop
SQL Commands Maximum Inactivity in minutesSQL_COMMAND_MAX_INACTIVITY
SQL Scripts Maximum Script Output Size in bytesSQL_SCRIPT_MAX_OUTPUT_SIZE
SQL Scripts Maximum Workspace Output Size in bytesWORKSPACE_MAX_OUTPUT_SIZE
SQL Script Maximum Script Size in bytesMAX_SCRIPT_SIZE
Enable transactional SQL CommandsENABLE_TRANSACTIONAL_SQL
Enable Database MonitoringALLOW_DB_MONITOR
Enable Application TracingTRACING_ENABLED
Workspace Administration
Team Development
Enable Team Developer's File RepositoryWORKSPACE_TEAM_DEV_FILES_YN


SecurityParameter Name
Disable Adminstrator LoginDISABLE_ADMIN_LOGIN
Disable Workspace loginDISABLE_WORKSPACE_LOGIN
Restrict Access by IP AddressRESTRICT_IP_RANGE
HTTP Protocol
RESTful Access
Allow RESTful AccessALLOW_REST
Session Timeout
Maximum Session Length in SecondsMAX_SESSION_LENGTH_SEC
Maximum Session Idle Time in SecondsMAX_SESSION_IDLE_SEC
Workspace Isolation
Resource Consumer GroupRM_CONSUMER_GROUP
Maximum Concurrent Workspace RequestsQOS_MAX_WORKSPACE_REQUESTS
Maximum Concurrent Session RequestsQOS_MAX_SESSION_REQUESTS
Concurrent Session Requests Kill TimeoutQOS_MAX_SESSION_KILL_TIMEOUT
Maximum Size of FIles in WorkspaceWORKSPACE_MAX_FILE_BYTES
Region and Web Service Excluded Domains
Domain Must Not ContainBAD_URLS
Authentication Control
General Settings
Delay after failed login attempts in SecondsLOGIN_THROTTLE_DELAY
Method for computing the DelayLOGIN_THROTTLE_METHODS
Inbound Proxy ServersINBOUND_PROXIES
Single Sign-On Logout URLSSO_LOGOUT_URL
Development Environment Settings
Username validation expressionUSERNAME_VALIDATION
Require User Account Expiration and LockingEXPIRE_FND_USER_ACCOUNTS
Maximum Login Failures AllowedMAX_LOGIN_FAILURES
Account Password Lifetime (days)ACCOUNT_LIFETIME_DAYS
Current Workspace Authentication SchemAPEX_BUILDER_AUTHENTICATION
Password Policy
Minimum Password LengthPASSWORD_MIN_LENGTH
Minimum Password DifferencesPASSWORD_NEW_DIFFERS_BY
Must Contain At Least One Alphabetic CharacterPASSWORD_ONE_ALPHA
Must Contain At Least One Numeric CharacterPASSWORD_ONE_NUMERIC
Must COntain At Least One Punctuation CharacterPASSWORD_ONE_PUNCTUATION
Must Contain At Least One Upper Case CHaracterPASSWORD_ONE_UPPER_CASE
Must Contain At Least One Lower Case CharacterPASSWORD_ONE_LOWER_CASE
Must Not Contain Workspace NamePASSWORD_NOT_LIKE_WS_NAME
Service Administrator Poassword PolicySTRONG_SITE_ADMIN_PASSWORD

Instance Settings

Self ServiceParameter Name
Notification Email AddressNOTIFICATION_EMAIL
Email Provisioning
Email ProvisioningDISABLE_WS_PROV
Require New SchemaREQ_NEW_SCHEMA
Delete Uploaded Files After (days)DELETE_UPLOADED_FILES_AFTER_DAYS
Application Express Instance URLEMAIL_INSTANCE_URL
Application Express Images URLEMAIL_IMAGES_URL
SMTP Authentication usernameSMTP_USERNAME
SMTP Authentication passwordSMTP_PASSWORD
Default Email From AddressSMTP_FROM
Maximum Emails per WorkspaceWORKSPACE_EMAIL_MAXIMUM
Wallet PasswordWALLET_PWD
Report Printing
Printer Server ProtocolPRINT_SVR_PROTOCOL
Print Server Host AddressPRINT_SVR_HOST
Print Server PortPRINT_SVR_PORT
Print Server ScriptPRINT_SVR_SCRIPT
Application ID Range

Workspace Purge Settings:

Workspace Purge SettingsParameter Name
Purge Adminsitration Email AddressPURGE_ADMIN_EMAIL
Days until purgePURGE_DAYS_TO_PURGE
Reminder days in advancePURGE_REMINDER_DAYS_IN_ADVANCE
Grace period (days)PURGE_GRACE_PERIOD_DAYS
Maximum execution time (hours)PURGE_MAX_RUN_HOURS
Maximum number of workspacesPURGE_MAX_WORKSPACES
Maximum number of emailsPURGE_MAX_EMAILS


Feature Configuration:


Instance Settings:

Workspace purge settings:

Friday, 25 September 2015

Compiling Oracle code from Atom text editor

Just yesterday I was watching a webinar titled: "Fill the Glass: Measuring Software Performance" which featured Jorge Rimblas. You can check out the video on Vimeo at the following URL: It's just giving an insight into a project Jorge is working on, giving various tips here and there - so if you have a minute (rather, an hour) to spare, go and check it out.

One of the sections that particularly caught my attention was the fact Jorge was able to compile packages from his editor of choice (which is Sublime text editor) (this happens at around the 18:20 mark). Because I like free (and open source) software, I actually use Atom text editor. Being centred around a plugin ecosystem, I was curious how he was able to do this - and if in fact I'd be able to accomplish the same, in Atom.

So, first of all I did some hunting to see how it was done in Sublime. This led me to this great post by Tim St. Hilaire - - which covers all the plugins he uses with Sublime. The section of interest is titled "Building Code" - where I discovered it used a build system embedded into the application itself; Tim also provides some sample scripts that he uses for the actual compilation, so I grabbed them (it's actually a zip file with a couple of examples) as a reference point.

The next thing was to find how to build code in Atom. I did a search for "atom editor build system". This immediately led me to the package - I installed that and begun hacking away to get this build process working! As per the documentation, depending on the files in your project directory, will determine which build process gets initiated. If your desired build process isn't built in (which it isn't for Oracle), you can add a file to your project .atom-build.json.

Now, because I'm on Ubuntu, my script is a `sh` script, and I'm going to place it in /usr/local/bin - which goes without saying, this file should be executable. Ideally, this will all be packaged into a plugin that extends from the build package, but that's for a future date.

It's worth mentioning here, that of course you will need an Oracle client set up on your system.

So, my .atom-build.json, in the root of my project folder, will look like this:

  "cmd": "/usr/local/bin/",
  "name": "Build Oracle code file",
  "args": [ "${host}", "${port}", "${sid}", "${user}", "${password}", "{FILE_ACTIVE}" ],
  "sh": true,
  "cwd": "{FILE_ACTIVE_PATH}",
  "env": {
    "user": "hr",
    "password" : "hr",
    "host" : "",
    "port" : "1521",
    "sid" : "XE"
  "errorMatch": [
  "keymap": "",
  "targets": {

So, for each project, you will just update the environment settings accordingly. To support for different environments (e.g dev and prod) I would guess the targets could be used here - I haven't got that far yet.

Then, the actual script would look like (again, script based from Tim St. Hilaire's examples):

echo "Running"
echo "host: $1"
echo "port: $2"
echo "sid: $3"
echo "user: $4"
# echo "password: $5"
echo "Compiling file: $6"

sqlplus -S -L $4/$5@$1:$2/$3 << EOF

    set linesize 200
    set tab off
    set serveroutput on

    --Show the details of the connection for confirmation
        user as MY_USER
      , ora_database_name as DB
      --, '$3' as SID
      , systimestamp as NOW
    from dual;



    show error


So, in SQL Developer I confirm I have no packages:

Then, I have the config file for database settings:

So, this is a good template that can be copied and updated to your other Oracle projects, so you can compile directly. You of course would likely want to ignore it from being committed to version control, since the password is included.

Now, I can create a code file and compile it with the keyboard shortcut ctrl+alt+b (cmd + alt+ b for Mac).

And, just to verify, in SQL Developer I refresh the package list and see my code file was in fact compiled to the database.

Saturday, 19 September 2015

Making connections to the Oracle Database from Golang

I posted the other day about getting going with Golang[1], and as mentioned am planning to do a series of posts on various aspects of the language - as a means to help with the learning process.

Being an Oracle developer, it seemed logical I would want to be able to make connections to the Oracle database. Built into the language core is an SQL interface (for issuing queries and statements) which is through the module "database/sql". The other side of it is that you need a valid driver. A list of available drivers is on the go wiki[2]. You will see that there are 2 listed for Oracle. How do I judge which project to use? First I see that one has considerably more stars and for another, the online commentary I see also seems to suggest that same package. And that is

Driver setup

Before we get to the driver, you need to make sure you have an Oracle client and the SDK installed on your system. For, this I followed the steps as per the Ubuntu wiki[3] - where you would at minimum want to install the instant client and the SDK. Once the installation is complete, you should end up with an $ORACLE_HOME that points to /usr/lib/oracle/11.2/client64 or something similar depending on your systems architecture and the version of Oracle you installed.

Within $ORACLE_HOME, you should have 3 folders:
  1. bin
  2. include
  3. lib
At this point, if you try to install the aforementioned driver, you will get an error:

$ go get
# pkg-config --cflags oci8
Package oci8 was not found in the pkg-config search path.
Perhaps you should add the directory containing `oci8.pc'
to the PKG_CONFIG_PATH environment variable
No package 'oci8' found
exit status 1

So, before you install the driver, you need to do the pkg-config set up. This application should be already installed on your system, but if not you can do so with sudo apt-get install pkg-config. This program is just a way to provide the necessary details for compiling and linking a program to a library[4].

The project itself does provide an example of a package config file for oci8, however it's example is for Windows, so the config file I came up with was:


Name: OCI
Description: Oracle database driver
Version: 11.2
Libs: -L${libdir} -lclntsh
Cflags: -I${includedir}

I just grabbed the path to $ORACLE_HOME and placed it in the variable prefixdir, since the config file doesn't know about environment variables.

Before installing the driver, you need to make this file available in a place that pkg-config knows about. So there are two options here. First, you can place it in the system wide pkg-config directory: /usr/lib/pkgconfig and the system will automatically find it. The other option if you have it some obscure location is to export that location into the environment variable PKG_CONFIG_PATH. Once that is set up, you should be able to successfully install the driver with: go get

You will now find that both the compiled version and source for that package in your GOPATH (in pkg and src folders respectively).

Connecting and querying database

Now that we have the driver available, we can begin with our program. Most of the aspects I describe here are also documented on the go wiki[5].

First, we want to open our connection. This is done with the sql.Open function[6], where you will pass in the name of the driver, and the connection string.

db, err := sql.Open("oci8", "hr/")
if err != nil {
defer db.Close()

Opening the connection is actually deferred until you start issuing statements - so for example, if you enter incorrect password, only when you attempt to query the database will you find out. So in this case, the Ping function[7] might be useful to test the connection is OK.

err = db.Ping()
if err != nil {
    fmt.Printf("Error connecting to the database: %s\n", err)

Then, to the actual querying. Here we have the functions Query[8] and QueryRow[9] depending on if you want return a row set or a single row respectively. You will more than likely want to use bind variables in your queries - the documentation suggests the use of `?` as placeholders. And I've also seen examples of `$1`. However, using either of those methods seemed to return the error:

sql: statement expects 0 inputs; got 1

What I've found works is what you would be used to use an Oracle developer - a number prefixed with a colon (:1). I'm assuming that's just the specific implementation of the driver. note: If you repeat the same bind number in your program, don't expect it to be re-used - it's just the position of the bind in the query, and then the respective parameter index. In the result set, you'll then want to declare variables of suitable data types to store the data in, which is fetched with the Scan function.

rows,err := db.Query("select employee_id, first_name from employees where employee_id < :1", 105)
if err != nil {
    fmt.Println("Error fetching employees")
defer rows.Close()

for rows.Next() {

    var emp_id int
    var first_name string
    rows.Scan(&emp_id, &first_name)
    println(emp_id, first_name)


var last_name string
err = db.QueryRow("select last_name from employees where employee_id = :1", 101).Scan(&last_name)
if err != nil {
    fmt.Println("Error fetching row")

fmt.Printf("Last name is %s\n", last_name)

If you are running a query that doesn't return anything (such as insert or create statements), you would typically use the Exec[10] function. And further, if you are repeating a statement, the Prepare[11] function.

Full program (main.go):

package main

import (
    _ ""

func main(){

    db, err := sql.Open("oci8", "hr/")
    if err != nil {
    defer db.Close()
    if err = db.Ping(); err != nil {
        fmt.Printf("Error connecting to the database: %s\n", err)

    rows,err := db.Query("select employee_id, first_name from employees where employee_id < :1", 105)
    if err != nil {
        fmt.Println("Error fetching employees")
    defer rows.Close()

    for rows.Next() {

        var emp_id int
        var first_name string
        rows.Scan(&emp_id, &first_name)
        println(emp_id, first_name)

    var last_name string
    err = db.QueryRow("select last_name from employees where employee_id = :1", 101).Scan(&last_name)
    if err != nil {
        fmt.Println("Error fetching row")
    fmt.Printf("Last name is %s\n", last_name)



Wednesday, 16 September 2015

Oracle developer choice awards

From June 21, Oracle opened up nominations for what they have dubbed Oracle developer choice awards, in 5 broad categories:

  1. SQL
  2. PL/SQL
  3. ORDS
  4. APEX
  5. Database Design
There has been a panel that has narrowed down the nominations from each category, and now the voting has opened up - until the 15th October. 

You are able to vote for more than one person in each category, the rules don't specify how many votes in each category, but I would encourage selecting a few of the people you think are most deserving in the community and giving them an up-vote. 

Please choose wisely, because the system doesn't allow you to undo your upvote - the only way to undo that vote, is to then down vote. So unless you feel very strongly that that person shouldn't be awarded and wish to down-vote them, I emplore you to choose wisely.

The APEX candidates

Jari Laine

Very active of the OTN APEX forum, from well before I even started working with APEX. The time he has spent assisting the community is really something to be admired. He has an APEX blog - - that he built in APEX, and open sourced! If you prefer to look at samples, go to one of his sample applications: or, both with countless examples.

Juergen Schuster

Juergen is really active promoting APEX, so much so that he created an APEX (apeks) sticker that many people are now rocking on their laptops (the word on the street is that he even sends them to people all over the world, at no charge!). He also recently started a talk back show speaking with prominent figures in the APEX community including the APEX development team - you can find existing podcasts listed here:

Paul MacMillan (fac586)

Also very active on the OTN forums, and in my opinion will be the first to bring anyone up on poor practices new people to APEX might be using in their systems. This can only be a good thing! He is constantly help people get their problems resolved - and definitely deserves some recognition for all his efforts!

Morten Braten

Have you ever heard the Alexandria PL/SQL utility? If you haven't, it's a large collection of pl/sql utilities in one spot! And Morten is the one behind this awesome project. If that's not a contribution to the APEX community, I don't know what is! The project was recently moved over to GitHub -, so if you haven't heard of it, go and check it out.

Kiran Pawar

Yet another member of the community that has become very active in the APEX forums of late (as well as other forums such as ORDS). Between Kiran, Jari and Paul, I think you should be pretty well covered with any questions you may ask on the forums! 

Karen Cannell

What better way giving back to the community the (co)authoring an APEX related book? Karen co-authored Agile Oracle Application Express, which is good supplementary material on how to leverage Application Express with agile methodologies. 

Trent Schafer

Oh hi there, that's me! I started working with APEX about 7 years ago now and I am a firm believer in giving back to the community, so I began answering where I could on the forums, and learning from the other posts I would come across. I honestly believe APEX has a great community! I started a blog as a mean to share back my knowledge to create hopefully a good reference for people. If you think I am worthy, I appreciate any votes you send my way!