Thursday, December 16, 2010

Modeler Custom Transformations

This is a follow up to the transformation I mentioned earlier where I mentioned how to write custom transformation in javascript for the design.  This is based on a java's pluggable script which means almost anything can be plugged in instead of javascript.  See here for details on the available languages.

This is the beginning of what I plan on building up over time which is a library of functions for use to make custom script very easily.  This is an example of adding the standard who columns to every table in the model.    

The first two functions are to delete and add columns to a table.

// import actual java classes for use later
importPackage(javax.swing);
// variable to keep a status message for later
var msg="";
/*
  Delete function takes in the table and name of the column to delete
*/

function deleteColumn(table,colName){ 
    columns = table.getElements();
 
 // iterate columns looking for the one to remove
    for (var i = 0; i < columns.length; i++) {
 if ( columns[i].getName().toUpperCase() == colName ){
   columns[i].remove();
   msg += "Deleted from "+ table.getName() + " : " + colName + "\n"; 
        }
  }
}
/*
  checkOrCreate function takes in the table and name of the column to add. This checks for the existence of the column before addin
*/

function checkOrCreate(table,colName,typeName,typeSize){ 
 hasCol = false;
 columns = table.getElements();
 
 for (var i = 0; i < columns.length; i++) {
 column = columns[i];
 if ( column.getName().toUpperCase() == colName ){
   hasCol=true;
 }
 }
  // if the column is not present add it
  if (! hasCol ) {
      newCol = table.createColumn();
      newCol.setName(colName);
      newCol.setUse(1);
   // lookup the logical datatype based on the name
   type = model.getDesign().getLogicalDatatypeSet().getLogTypeByName(typeName);
      newCol.setLogicalDatatype(type);
      if (typeSize != null  ) {
        newCol.setDataTypeParameter("size",typeSize);
      }
      msg += "Added to "+ table.getName() + " : " + colName+ "\n";
 }  
}

// grab all the table in the model as an array
tables = model.getTableSet().toArray();

for (var t = 0; t < tables.length;t++){
 // remove all these from the table
 deleteColumn(tables[t],"CREATED_BY");
 deleteColumn(tables[t],"CREATED_ON");
 deleteColumn(tables[t],"UPDATED_BY");
 deleteColumn(tables[t],"UPDATED_ON");
 
 // add them back with the specified datatypes
 checkOrCreate(tables[t],"CREATED_BY",   "VARCHAR",200);
 checkOrCreate(tables[t],"CREATED_ON",   "DATE");
 checkOrCreate(tables[t],"UPDATED_BY",   "VARCHAR",200);
 checkOrCreate(tables[t],"UPDATED_ON",   "DATE");
}

// notify the user what happened
JOptionPane.showMessageDialog(null, msg);

The end result of running this will be a dialog that shows all the actions performed.


Friday, December 10, 2010

APEX Listener startup/shutdown script

David asked me for a way to keep the listener up and running when a box is rebooted.  There may very well be better ways to do this but this script can be used to start, stop, get status, and tail the log file.  Also it can be dropped in as an init.d script to have the Listener start when the box starts.  Since we don't have access to init.d for David's case, we are just going to put in a cron job to check status and start if not already going.  The start function checks to ensure it's not already running before trying to start it up.  You should be able to use this but just changing the location variables in the top of the file.

The one addition over a normal init.d is the log command I added ( which is very simple).  Just do ./listener.sh log and it will tail the log file.


#!/bin/sh
#
. /etc/rc.d/init.d/functions
NAME="Oracle Application Express Listener"
JAVA="/my/install/path/to/jdk/jre/bin/java"
APEXWAR="/my/install/path/to/apex_listener/apex.war"


OPTIONS="-Xmx1024m -Xms256m  -jar $APEXWAR"

LOGFILE=/tmp/apex_listener.log
PIDFILE=/tmp/apex_listener.pid
start() {
        echo -n "Starting $NAME: "
        if [ -f $PIDFILE ]; then
                PID=`cat $PIDFILE`
                echo APEX Listener already running: $PID
                exit 2;
        else
                nohup $JAVA $OPTIONS 2>&1 > $LOGFILE  &
                RETVAL=$!
                echo Started PID: $RETVAL
                echo
                echo $RETVAL >>$PIDFILE
                return $RETVAL
        fi

}

status() {
        echo -n "Status $NAME: "
        if [ -f $PIDFILE ]; then
                PID=`cat $PIDFILE`
                echo APEX Listener already running: $PID
                ps -ef | grep $PID
        else
                echo APEX Listener not running
        fi
}

stop() {
        if [ -f $PIDFILE ]; then
                PID=`cat $PIDFILE`
                echo -n "Shutting down $NAME "
                echo
                kill $PID
                rm -f $PIDFILE
        else
                echo APEX Listener not running
        fi
        return 0
}

log() {
        tail -f $LOGFILE
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart)
        stop
        start
        ;;
    log)
        log
        ;;
    *)
        echo "Usage:  {start|stop|status|restart|log}"
        exit 1
        ;;
esac
exit $?

Thursday, November 11, 2010

Adding mail processing to your database app

   I'm not sure how many people know that part of the APEX team, Sharon Kennedy,  runs ProMedmail  which is probably one of the scariest and most active internet APEX applications.  It is "The global electronic reporting system for outbreaks of emerging infectious diseases & toxins, open to all sources."  So by a scary APEX app I mean you can get your latest updates on Anthrax in BangladeshDengue Fever , and about everything else going on in the world.

  The reason the "mail" part is in the name is that as you may have guess it's a mail list which anyone can subscribe to here.   It ends up on the website by some custom code that reads the an inbox and inserts that into a table in the database which is then exposed by APEX.  I've taken that custom code and made it quite generic.  I'm going to make this available on  samplecode.oracle.com in a project named email2sql so http://email2sql.samplecode.oracle.com.  This is working and it's a really easy way to add email processing to any application.

To try this out there's just a couple steps.
1) Checkout the project
2) Edit the settings.xml for email and sql
2.5)  If you use the tables in the settings.xml already create the table with the mail.sql
3) Run "ant run"  ( if you need ant it's at http://ant.apache.org/bindownload.cgi )


In the settings.xml is 2 entries sql and attachment.sql, these control what to do and have all the binds available in the example.  This can be plsql instead of sql also.

<entry key="sql">
 insert into mail(id,to_address,subject,msg_body,rcvd_date,sent_date,msgid,from_address) 
values(:ID,:TO_ADDRESS,:SUBJ,:BODY,:RCVD_DATE,:SENT_DATE,:MSGID,:FROM_ADDRESS)</entry>
<entry key="attachment.sql">
insert into mail_attachments(id,content,filename,content_type,content_size) 
values(:ID,:CONTENT,:FILENAME,:CONTENT_TYPE,:CONTENT_SIZE)</entry>

Also for Promedmail we use hudson to schedule this to run every 5 minutes.  If you've not looked into hudson it's very simple to get started with also.  I did a talk on this back in Feb at RMOUG.  But more on that later.


Please let me know of any issues or suggestions.

Wednesday, October 27, 2010

Fine Tuning SQL Developer

Someone recently told me they didn't know you could turn off extensions you don't use in sqldev so I thought a quick blog may be in order.

Since SQL Developer and jDeveloper are based on the concept of extensions, they can do things like check for updates or install new extensions very easily.  The other side of that is that you can disable the extensions you don't use.  A couple example of things we include by default but you may not use are the modeler, migrations, and times ten support.  All you have to do is goto Tools->Preferences in the main menu and then uncheck the ones you don't want.  The result is some menus don't get installed, some code is now not running at startup and you have a slimmer IDE since you turned off the parts you don't use anyway.




Wednesday, October 20, 2010

Apex Listener EA and more

In case anyone missed it, the new APEX Listener 1.1 EA is out.  The big new feature in there is the Resource Templates.  If you are interested in this feature and have not found it yet, you should really start following Colm's blog.  You can learn about it from Colm: here and my post last week: here.  It will let you get data out via REST with less development than ever before.  The Developer's Guide goes into all the details of this new set of features.

Another thing in this EA is that the APEX Export and Splitter have been combined in the apex.jar which is included.  Once the apex.war is deployed the apex.jar is expanded out however if you want to use just this issue this to pull it out.  I'll clean this step up in upcoming releases but for now here's how to test it out.

jar xvf  apex.war WEB-INF/lib/apex.jar

Then you just issue the commands as normal.  The new part is that they are joined and in one command line you can export and split.


$> java -cp apex.jar:/path/to/ojdbc6.jar  oracle.dbtools.apex.utilities.APEXExport

Usage APEXExport -db  -user  -password  -applicationid  -workspaceid -instance -skipExportDate -expSavedReports -debug  
 -db               : Database connect url in JDBC format 
-user             : Database username
-password         : Database password
-useAliasFileName : use alias.sql instead of f12345.sql
-application      : ID or name for application to be exported
-workspace        : Workspace ID or Name for which all applications to be exported
-outDir           : Directory to export to        
-instance         : Export all applications
-skipExportDate   : Exclude export date from application export files
-expSavedReports  : Export all user saved interactive reports
-split            : Split the export files
-flat             : Split into a Flat file structure
-update           : < create update file >
-nochecksum       : < don't check for changes >

Application Example: 
   APEXExport -db candy.us.oracle.com:1521:ORCL -user scott -password tiger -application 31500 
Workspace  Example: 
   APEXExport -db candy.us.oracle.com:1521:ORCL -user scott -password tiger -workspace 9999 
Instance Example:
   APEXExport -db candy.us.oracle.com:1521:ORCL -user flows_020200 -password apex -instance 

The other things new here are from a request from John Scott. There's a flag to name the files based on the alias instead of just the id. The application name or workspace name can be passed instead of the id.

The splitter has a few options:

-split
This is the main switch to turn on the splitting

-flat
Instead of directories it will use a single directory to put all the split up files.

-update
This will create an update.sql based on what changed from the last split that was done. It uses a checksum on the new and old to determine if there was a change in that section

-nochecksum
If you split f100.sql, you get all the split files. Normally, it will checksum that if page1.sql didn't change it will not update the timestamp on the file. If you turn checksum off it will always update the timestamp. The checksumming to update the timestamp is nice for things like checking into version control. Only the page/item/tab/.. sql scripts that changed will changed so you can see quickly what has and has not changed.