Monday, 21 September 2009

Installing Oracle APEX in run-time only mode.

I recently learned it is possible to install Oracle Application Express on two different ways.

  1. Developer install : The normal install of Oracle APEX, including APEX administration console and all the developer features.

  2. Run-time install : Completely stripped version of Oracle APEX without any developer features or administration console.


Usually I install APEX using the first option. However with all the new stuff I've learned over the last couple of months I thought.. Why don't I give the run-time only install a try ? Perhaps it's not a bad idea to use this type of configuration for production systems ?

Well today I tried it. And it turned out to be not that difficult.

APEX installation to Oracle XE

  1. This is basically the most important step. Normally I use @apexins.sql to install. But for the run-time version I use a different sql file.
    @apxrtins.sql SYSAUX SYSAUX TEMP /i/


  2. Then change the default password
    @apxchpwd.sql


  3. This is an optional step : Install the necessary images. This isn't mandatory but if you plan on using any theme I suggest you install this.
    @apxldimg.sql /opt/apex


  4. Then change the password one more time
    @apxchpwd.sql



Now after this our APEX run-time version is installed. I pointed my browser to http://localhost:8080/apex/
And all I saw... was an error. Err-1014 Application not found

Meaning absolutely nothing was installed.

Now I wanted to test a the installation of a new application. This proved to be a bit more difficult, because every change to the APEX administration needs to be done using a PL/SQL command, and not the console (which doesn't exist). For more information concerning this API : http://download.oracle.com/docs/cd/E10513_01/doc/apirefs.310/e12855/apex_instance.htm

Using the following steps I installed the Oracle Event Packaged application

  1. Create demo user (add some grants offcourse : CONNECT,RESOURCE, etc..)
    CREATE USER demo IDENTIFIED BY demopwd;


  2. Create a new workspace (with the matching workspace id from the SQL file)
    BEGIN

          APEX_INSTANCE_ADMIN.ADD_WORKSPACE(269990401159459463,'WKS_DEMO','DEMO','');

    END;


  3. Load the SQL file. (I performed this as SYSDBA, however it is a lot smarted to create a specific APEX deployment user. Using the APEX_ADMINISTRATOR_ROLE privilege)
    @events_installer_1.0.sql



As by magic the application is deployed an available at the url http://localhost:8080/apex/f?p=180 without having used the administration console.

Well I hope you folks found it useful and there are a lot of extra functions available using the ADMIN API so check em out to make your APEX environment a bit more secure.

Note : This was just a small selection of the features that are "disabled" in the run-time mode. For more information read the APEX_INSTANCE_ADMIN documentation or ask on the Oracle forum.

Sunday, 6 September 2009

Perform APEX administration tasks straight from PL/SQL

Recently I had to find a way to create new APEX users without having an admin manually creating them or having to create some sort of request page.
Now the easy way was to let the users do that themselves... Small hick-up though, you need to be an APEX Workspace administrator to create new end users. Meaning that 'normal' users had to be admin before being allowed to create new users.

Now in order to bypass this I just created a small batch that checks a simple table every now and then to see if new usernames where requested. A special administrator then automatically creates this user.

However in order to perform this task, I had to create a piece of PL/SQL code that would be able to run, connect to APEX without being integrated in a valid APEX session (from browser).  I used (a more complex version of) the following code to set the correct workspace, log in as the JOB_MANAGER APEX ADMIN and create the new user.

declare
  l_workspace VARCHAR2 := 'WORKSPACE';
  l_wks_id NUMBER;
begin
  -- find workspace security id
  l_wks_id := apex_util.find_security_group_id (p_workspace => l_workspace);
  dbms_output.put_line('Workspace id : ' || l_workspace);
  -- set workspace security id
  wwv_flow_api.set_security_group_id (l_wks_id);
  -- login user
  apex_custom_auth.login (p_uname       => 'JOB_MANAGER',
                          p_password    => 'welcome1',
                          p_session_id  => V('APP_SESSION'));
  -- create user
  apex_util.create_user (p_user_name       => 'username',
                         p_first_name      => 'first_name',
                         p_last_name       => 'last_name',
                         p_description     => 'description',
                         p_web_password    => 'welcome1',
                         p_email_address   => 'first.last@mail.com');
end;
/


A very short post but hope you guys find it useful.

Saturday, 20 June 2009

Disable APEX applications after installation

When exporting an application the export file contains exactly the same configuration as your development platform. Thank god. However when moving an application from development to test or production environments you might want some features disabled.

Recently I created a script that after deployment disables some development features.
Here is a short script that disables the following features from all running applications

  • disable DEBUG mode.

  • disable developer toolbar + edit links.

  • sets application alias to application id.

  • places the application in RUN only mode.



DECLARE
      CURSOR c_apps
      IS
        select application_id as app_id
        from apex_applications;

      l_flow_status VARCHAR2(100) := 'AVAILABLE';
      l_debug       VARCHAR2(10) := '0'; -- 0 = NO, 1 = YES
      l_app_alias   VARCHAR2(10);
BEGIN
      -- IDENTIFY FLOW_APPLICAITON SECURITY GROUP
      wwv_flow_api.set_security_group_id(p_security_group_id=>9999999999999999);

      FOR r_app IN c_apps
      LOOP
        l_app_alias := to_char(r_app.app_id);
        -- SET APPLICATION
        wwv_flow.g_flow_id := r_app.app_id;
        wwv_flow_api.g_id_offset := 0;

        -- DISABLE DEBUGGING
        wwv_flow_api.set_enable_app_debugging(P_FLOW_ID => wwv_flow.g_flow_id,
                                              P_DEBUGGING  => l_debug);
        -- SET APPLICATION TO ONLY AVAILABLE
        wwv_flow_api.set_flow_status(P_FLOW_ID => wwv_flow.g_flow_id,
                                      P_FLOW_STATUS => l_flow_status);                                 
        -- REWRITE APPLICATION ALIAS
        wwv_flow_api.SET_APPLICATION_ALIAS(P_FLOW_ID => wwv_flow.g_flow_id,
                                           P_ALIAS => l_app_alias);
        -- SET APPLICATION RUN ONLY
        wwv_flow_api.SET_BUILD_STATUS_RUN_ONLY(P_FLOW_ID => wwv_flow.g_flow_id);
      END LOOP;
      COMMIT;
END;
/

Sunday, 17 May 2009

Use Oracle APEX as user interface for Oracle BPM using the PAPI Webservice

The last couple of weeks I've been messing around with Oracle BPM (former ALBPM) 10g version. More information on this product can be found on http://www.oracle.com/technologies/bpm/index.html

When I had some free time I tried messing around with the different activities, gateways and events. This turns out to be incredibly easy and you can develop a complex workflow in a matter of minutes. However when it comes to testing the actual workflow you always end up with those pop-ups... the standard input/display presentation layouts. At the beginning I didn't really mind because I was overwhelmed by the shear power of the BPM application but after some time I started to look for better ways of representing the flows.

As I'm currently assigned on an APEX project I thought it might be a nice idea to have APEX render the user interface and let the workflow be represented by Oracle BPM. After doing some research there are three ways to communicate with the BPM engine (user interface wise).

  1. Standard presentation/workspace

  2. Custom JSF

  3. Process API


None of these 3 features are supported natively by Oracle Application Express, thus rendering my idea useless. After looking at the PAPI features I stumbled on this little button.

Start PAPI WS



Turns out the Process API is completely exposed as a webservice. Suddenly Oracle APEX is back on the table.

After starting the PAPI Webservice from the engine preferences, I copied the wsdl url into the create web service reference feature of APEX.
Unfortunately after running a minute or so it returned with the WSDL can't be parsed error.

unable to read wsdl
At this point I thought I might as well put in a service bus (Oracle Service Bus) to act as a connection between APEX and BPM. This allows for some extra control over which functions are exposed to the user and gives me the freedom to create webservices that would otherwise require multiple calls.

The first webservice I extracted from the PAPI service.s was the processesGetInstancesByFilter operation. This should supply me with enough information to create a kind of inbox of the currently still open instances.

Now before creating the business service in OSB, make sure you selected the appropriate authentication settings in the BPM engine. When accessing the BPM Web Service Console, I selected HTTP Basic Authentication, since this is natively supported by APEX webservices.

After having the WSDL file its no problem creating the business service. However take into account that you'll be doing the webservice authentication from APEX to BPM. This means selecting BASIC as Authentication when creating the business service and creating a Service Account that has Pass Through as resource type

WS resource type


WS service account




This is the only business service that is required to connect apex to bpm. From now on we'll only need proxy services. For the creation of the proxy service we'll need a WSDL file. This isn't a requirement, since we'll be using manual webservice creation later (in apex) but it first much better in the SOA story if we create one.

Since I'm basically rerouting the new webservice to the PAPI service I decided to use the same IN/OUT elements as the original operation. Thus reducing the time required to create the webservice.

Creating a proxy service from the wsdl file is a piece of cake. Just select the port or binding and of we go. No need to set the HTTP Transport settings since these are handled by APEX. I decided to go with processesGetInstancesByFilter in this post because it's different that the other service I created. It actually does something useful in the message flow.

OSB Message flow

The first assign takes the processID from the request and stores it to a local variable. The replace in the request action of the Route node is where we find a little difference.

Replace action

Basically I'm replacing the entire body (not best practice I know) with a new xml structure. Where I've taken the local variable and added the searchScope. The response of this message gives me all the currently in process instances that the requested user has acces to.
Can you see the inbox growing ?

Now that we have the webservice exposed with OSB we can move to APEX.
One more remark though.. If you attempt to test the proxy webservice with the OSB console you'll receive a Participant not authentication response from BPM. This will probably be because there were no HTTP basic authentication headers supplied. For quick testing just set the Service account to static and enter a username/password. Now the webservice should work.

Next up. APEX.
After doing the normal administration tasks like creating workspace, application etc. go to shared components -> Web service references -> Create.

Since we won't be using a UDDI for this small setup, select no on the first question.
Now there are two options.

  1. Create webservice reference by using the wsdl

  2. Create web service reference manually


Well It turns out that the second option works much better with me. Using the WSDL doesn't always work and gives you less freedom in your SOAP request.
So select Create Web Service Reference Manually from the right side of the page.

  • Name : duh . I went for processesGetInstancesByFilter.

  • Url : pretty straight forward and it needs the enpoint uri. Should be something like http://<hostname>:<port>/<endpoint-uri>

  • Action : you can write anything in this field. But this is placed in the soap action header.

  • Proxy : in case you use a proxy service to access your OSB

  • Basic authentication : select yes, since we'll be using this to authenticate with BPM

  • SOAP Envelope : This is the most important field of all. Here we put the xml message that is send to the webservice. To make the xml dynamic use page items between # characters. When the webservice is called the current value will be placed there.

  • SOA Response : All response are stored in apex_collections. Supply the name of this collection. This collection doesn't need to exist it is created automatically when the web service is called.


Now that the webservice is created we can test to see whether it works. Edit the soap envelope, supply the username and password and by magic you'll receive a response.

Next comes the really easy part. Calling the webservice from a page process.
The easiest way would be to create a from/report from a webservice however... This doesn't work with manually created services... Oké we'll create a new blank page and add a page process. Create this process based on a web service. Select On Load as point moment to make you're life a little bit easier for now.

Select the appropriate web service reference and supply static authentication parameters. You can link this to page items, so there is always a possibility to link this to the login, but for now supply static parameters.
Create a page item that holds the same name as the parameter used in the SOAP envelope. For now just give it a static value.
Note: the process id looks like this /<processName>#<Variation>-<version> or in my case /ExpenseReporting#Default-1.0
You can check this with the processesGetIds operation using e.g. SOAPUI.

Now when running the page the webservice will be called on load. If it works from the first time be happy. Otherwise check all the steps or drop a line in the comments. Now that we've managed to request data from the webserice... We need to interpret the response.

Create a new report based on a sql query. You can use a report from webservice but the created select doesn't work for me. It never supplies a query that works, always returning nothing.

Below I've added the query I used to generate a report. Adopt it to fit your own instance needs.
select  extractValue(value(b),'/instances/activityName') as activity,
extractValue(value(b),'/instances/author') as creator,
extractValue(value(b),'/instances/creationTime') as creationTime,
extractValue(value(b),'/instances/description') as description,
extractValue(value(b),'/instances/priority') as priority,
extractValue(value(b),'/instances/state') as state,
replace(extractValue(value(b),'/instances/id'),'#','%23') as instanceID
from wwv_flow_collections c,
table(xmlsequence(extract(xmltype(c.clob001), '//instances/instances'))) b
where c.collection_name = 'FILTER_BY_INSTANCE'

After the creation of the report you should end up with a page showing an inbox with all the open instances.
And thus the connection between APEX and BPM is completed.

Now you can do the same with the other services like, processCreateInstance, activityExecute and any other operation you might need.
You can let APEX create rows in tables and send the id's back to bpm or store everything in BPM and let the application store it in the database.
You're choose but keep in mind that APEX is meant to be used with a direct link to the database.

Now I can hear some you thinking, 'Won't the fact that we're using apex force us to develop our flow twice ? Once in BPM and again in APEX ?'
The answer to this question is NO. At least from my point of view. If you use Page aliases that are equivalent to activity or task names and just use the activity name as branch alias. Thus no need to start messing around with page numbers etc. And if you ever change the order of activities they will be automatically used in the apex application. And for new activities you just have to create a new page with the appropriate alias and the branching/urls do the rest.

When I was attempting this integration I found little to info on this subject. This leads me to believe there is either not need for this integration or no-one has tried it. But seeing the low complexity of this I can't see the second being true....

I hope you folks found this useful and if you have any suggestions/questions/remarks don't hesistate to let me know.

Beo.

Sunday, 1 February 2009

Installing Oracle XE on Ubuntu 8.10 - x86_64

Today my goal was to install Oracle XE on my Laptop. For those who don't know, Oracle XE is the free version of the Oracle 10g database, with some limitations.

This should be pretty straight forward since the installer comes in debian packaging format and the site even says it's supported on Ubuntu. Oh but did I mention I'm running the amd64 version of Ubuntu. This is how I managed to successfully install Oracle XE

First download the Oracle XE debian package from the official site (the x86 version)
http://www.oracle.com/technology/software/products/database/xe/index.html

Whether you need the universal or the western-europe version depends on the applications you intend to run.

While this file is downloading you can start looking for the libaio 32bit library which is required to install the database.
Download the appropriate deb file
wget -c http://oss.oracle.com/debian/dists/unstable/main/binary-i386/libaio_0.3.104-1_i386.deb

After downloading both the library and the database file you can continue to install them with the debian package manager
sudo dpkg -i --force-architecture libaio_0.3.104-1_i386.deb
sudo dpkg -i --force-architecture oracle-xe-universal_10.2.0.1-1.1_i386.deb

The --force-architecture argument should prevent the package manager from exiting with the incompatible architecture error.

When the installation is complete you'll have to run the /etc/init.d/oraclexe configure script. When you aren't sure what you are doing it's best to leave everything to it's default setting. Meaning http port 8080 and database listener port 1521.

Once the script has been executing the Oracle XE database will be up and running and you can surf to http://localhost:8080/ to see if it's working.

Now the installation of the database is complete you can start developing your own application.  But before doing this you should take a look at Oracle Application Express, which is pre-installed with the Oracle XE database. Go to http://localhost:8080/apex/ and log in using system and the password you supplied during the configuration script. For more information about this product point your browser to http://apex.oracle.com/

Note: Before you start developing using apex, upgrade to the latest version (3.1.2). Oracle XE comes with version 2.x and there are many new features available in the lastest version. Read the How to upgrade at the bottom of this page http://www.oracle.com/technology/products/database/application_express/html/3.1_and_xe.html

Any question ask away in the comments.