Friday, August 29, 2014

Adding a regex QBE validator for numeric columns

I had a table containing a column that was a Number type.  If you tried to filter on a non numeric value a ConverterException would be thrown.   That was fixed by putting a Number converter on the filter input text to allow only numbers.   That worked except now you couldn't use the Query by Example (QBE) Search criteria Operators.  




These are the supported operators

Operator Description
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
AND And
OR Or




You can write a custom QBE adapter to fix this but that seemed like overkill.

To fix this I changed the filter to be an input text and added a  regular expression validator to allow these operators.  The pattern I used is below.   I didn't find a regex example for QBE Numeric filtering and I'm not a regex expert (is anyone?)  so it took a while to get the regex string just right.  Hopefully this will save someone some time.
Here's the pattern
^[ ]*[<>]?([<=]|[>=])?[ ]*[0-9]+[ ]?(?i)([ ]+AND[ ]+[<>]?[ ]*[0-9]*|[ ]+OR[ ]+[<>]?[ ]*[0-9]*)?[ ]*$


<af:column sortProperty="Count" filterable="true"     headerText="Count"  id="c6">
  
<f:facet name="filter">
         
<af:inputText  value="#{vs.filterCriteria.Count}" columns="8" id="Count">                                                 
            
<af:validateRegExp pattern="^[ ]*[<>]?([<=]|[>=])?[ ]*[0-9]+[ ]?(?i)([ ]+AND[ ]+[<>]?[ ]*[0-9]*|[ ]+OR[ ]+[<>]?[ ]*[0-9]*)?[ ]*$" 
                  messageDetailNoMatch="Please Enter Number Only"/>
        
</af:inputText>             
  
</f:facet>         
                            
    
<af:outputText value="#{row.Count}"    id="ot7" />      
 <af:column>

Examples of Things you can put in the filter
10
50
> 10
>10  AND <  50
> 10 and < 50
10 or 50

 If the column is a String type (even through it might contain numbers) you don't have this problem and wouldn't need to add a regex Validator. 



Wednesday, December 18, 2013

How to View Service Proxy Request/Response message in Jdeveloper

In order to view the XML SOAP envelope of an ADF service Proxy, add this line to your server startup and the XML will be dumped the jdeveloper console output.

-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true 
  In Jdeveloper, the server startup command line is accessed from

Run Menu
Choose Active Run Configuration
Manage Run Configurations 
Edit Default

Add the line to the end of the Java Options.

 Also if  you see a large work:WorkContext section in the SOAP header, you can remove that by adding this line to the startup.
-Dweblogic.wsee.workarea.skipWorkAreaHeader=true
 






Thursday, October 31, 2013

How to make popup that can be dragged past edge of browser window.

I had a large dialog that I wanted to be able to move out of the way so that I could see what was behind it without closing it.   Normally any part of the dialog cannot be dragged off the edge of the browser window.   Configuring this turned out to be pretty simple.  Just add an inline style for the margin and give negative numbers to the sides you want to drag off the edge of the screen.  In the example below I don't want the top to be draggable past the top edge (because the top bar wouldn't be visible to drag it back down)  The left and right I set to -200 so that I could drag it 200 pixels to the left or right of the windows edge and 300 pixels past the bottom of the window.   This allows me to move it mostly out of the way without having to close it.



   <af:popup id="ppcal" clientComponent="true">
    
<af:dialog id="d1" title="Calculator"
               modal="false" type="ok"
               styleClass="AFStretchWidth"
               inlineStyle="width:450px; margin:0px -200px -300px; padding:-200.0px>

Tuesday, September 10, 2013

Displaying external content in a IFRAME within a popup dialog

I recently had a requirement to display some non ADF content inside a popup dialog.   There are a number of blogs on how to do this (see this one)  so I won't rehash them here.  I did however run into one problem in that when you drag the dialog around on the page and the mouse cursor slips into the frame containing the external content, the mouse events get captured by the frame and the dialog stops dragging.  Then if you release the mouse button and move outside of the frame, the dialog is now stuck to the end of your mouse cursor because the page lost the mouse up event and still thinks the mouse button is pressed.   To fix this I had to write a javascript mouse event handler and attach it to the frame to propagate mouse events in the frame to the parent page.

I found the basis for my solution here.  mousemove-when-over-an-iframe

I modified this slightly in that my particular page didn't need to save the original onMouseMove and onMouseUp handlers.


To wire this up add a client listener to the popup
  <af:clientListener type="popupOpened"     method="popupOpened"/>
 


 
// This method attaches the frame with id of "fid" to the mouse event handler

 function popupOpened(e){
      var frame = document.getElementById( e.getSource().findComponent("fid").getClientId()+'::f');
      bubbleIframeMouseMove(frame);
  }

// iframe causes the page to lose the mouse events when dragging the dialog
// this fixes it by propagating mouse events in the iframe to the parent page

function bubbleIframeMouseMove(iframe){
 
     iframe.contentWindow.onmousemove = propagateToParent;
     iframe.contentWindow.onmouseup = propagateToParent;
      
      function propagateToParent(e){
        // Create a new event for the this window
        var evt = document.createEvent("MouseEvents");
        // We'll need this to offset the mouse move appropriately
        var boundingClientRect = iframe.getBoundingClientRect();
        // Initialize the event, copying exiting event values
        // for the most part
        evt.initMouseEvent(
            e.type,
            true, // bubbles
            false, // not cancelable
            window,
            e.detail,
            e.screenX,
            e.screenY,
            e.clientX + boundingClientRect.left,
            e.clientY + boundingClientRect.top,
            e.ctrlKey,
            e.altKey,
            e.shiftKey,
            e.metaKey,
            e.button,
            null // no related element
        );

        // Dispatch the mousemove event on the iframe element
        iframe.dispatchEvent(evt);
    };
}




Friday, July 19, 2013

Using XML data in ADF View Object

I recently was tasked with creating a generic preferences table that can be used to story any type of web site preference.   This needed to be generic enough so that new types of preferences can be added without requiring a data model change.  Using XML in the value column was the perfect solution for this.

This is how the table is defined


  CREATE TABLE "USER_PREFERENCE"
   (
     "USER_PREFERENCE_ID" NUMBER(38,0) NOT NULL ENABLE,
    "USER_ID" NUMBER(38,0) NOT NULL ENABLE,
    "PREFERENCE" VARCHAR2(40 BYTE) NOT NULL ENABLE,
    "VALUE" VARCHAR2(4000 BYTE) NOT NULL ENABLE
}

The first type of preference I needed to add was a URL link. I defined this in XML


<url >
 
<label>Yahoo </label>
  <location>http://yahoo.com/location>
  <open>defaultBrowser</open>
  <sortorder>1</sortorder>
</url>

I insert this xml into the value column and "CUSTOMLINK" into the preference column along  with the USER_ID and primary key USER_PREFERENCE_ID sequence.


Here is the query I used to retrieve my custom url links.  Notice that I'm not actually returning any column from the table.   All of the columns returned are coming from the xml nodes in the value column.  This query uses a feature of Oracle available since 10.2 (XMLTABLE).  You can think of it as a table within a column that the row is being joined to.  "url "is the alias for this table containing all of the xml elements as table columns.



    SELECT
           url.label,
           url.location,
           url.open,
           url.sortorder
    FROM USER_PREFERENCE ,
    --  XMLTable defines a join with contents of value column treating it like a table
              XMLTable('url'
                       PASSING XMLTYPE(USER_PREFERENCE.value) 
                       COLUMNS
                       label  VARCHAR2(40) PATH 'label',
                       location  VARCHAR2(1025) PATH 'location',
                       open VARCHAR2(40) PATH 'open',
                       sortorder VARCHAR2(4) PATH 'sortorder',
                       permission VARCHAR2(40) PATH 'permission'
                       ) as url
   
    WHERE PREFERENCE = 'CUSTOMLINK'
    AND  USER_ID = :UserIdBind
    order by sortorder




I used a read only view object for this.   I could have created a entity based view object and use expert mode to insert similar sql.   For storing and committing data in the value column I would need to add custom code to the setters for the 4 xml based columns and there construct the xml containing the values from all of these columns and then set that xml into the value column.

This gives me great flexibility for adding additional columns to my query without making any changes to the data model.  Querying XML will probably not perform well if you have a huge result sets but  is a great solution for queries that return a small number of rows as this one does.

Thursday, May 2, 2013

Hot deploy in R1

ADF Release 1 of jdeveloper has limited support for hot deploying java code.  When running the integrated Weblogic server in debug mode, JSPX/JSFF files will hot deploy as soon as you save and reload the page.    You are also allowed to make changes to java methods as long as you don't change the structure of the class.  This means you can't add or remove methods, change method signatures or add or remove class properties or static members but you can change the code inside a method and instantly deploy the change while the server is running.   To do this hit CTRL+SHFT+F9 key combination.   This will compile and deploy the single java class that has been changed.   If it is successful you will see the message
"Redefined all recompiled classes that are loaded in the debuggee process.” 

 For a long time I had been using CTRL+F9 which performs a full build and hot deploy of the application.   Our application is very large and this would take over a minute to complete but  CTRL+SHFT+F9  will hot deploy a single file in about 1 second.  I don't know why this key combination is not front and center on the build menu (since CTRL+F9 is).   It is listed in the context menu that displays when you right click on a Page. (see image)  but I never noticed that the "Make" on the context menu was different than the "Make" on the Build menu so didn't pay attention to the hot keys listed.    It is a huge time saver but the only way to learn that this is a "single file" make command is to browse the Tools Menu (Preferences/Shortcut Keys) to find it.   CTRL+SHFT+F9  is now my most favorite keystroke.

Release 2 has much betters support for hot deploy.  I'm not using release 2 yet but here is blog that describes What works and what doesn't.




Tuesday, April 2, 2013

How to make each item in stragg list display on separate line



The stragg database function is useful for converting a subquery returning multiple rows into a single column containing a comma separated list of values.

I often use this function to display one of the columns in a row of data.  I recently had to format this so that each stragged item in the list displayed on it's own line.

This is the technique I used

The example subquery below will return a comma separated list of labels for a customer.  I'm only showing this one column selected for brevity but this would be one of many in the select clause.
The code in red was added to append a line feed character "chr(10)" to the beginning of each element in the list.  The substr(val,2) removes it from the 1st element so that it doesn’t begin with a line feed.


SELECT....
(SELECT  substr(stragg(chr(10) || label  ),2)
      FROM customer_label
      WHERE customer_label.account_id  = account.account_id
 ) labels,
 .... 

 FROM ....

 
Line feed characters are normally ignored in html but you can force them to be honored by applying a style of “white-space: pre-line”

add a style of pre to your output text within your table column


   <af:outputText value="#{row.label} styleClass="pre" />


The pre style is defined in SkinBasic.css (or whatever name is your custom skin)

/*** make line feed characters wrap.  For displaying line feed in table column ***/
.pre
{
  white-space: pre-line;
}

You could have also used inline style 
 <af:outputText value="#{row.label} inlineStyle="white-space: pre-line;" />