<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6139250371277978964</id><updated>2012-01-24T06:01:06.767-08:00</updated><category term='APEX'/><category term='cloud'/><category term='s3'/><category term='ec2'/><category term='REST'/><category term='Amazon'/><category term='Web Services'/><title type='text'>Application Express Nuggets</title><subtitle type='html'>(The views expressed here are my own and do not necessarily reflect the views of Oracle.)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-7103924607095910643</id><published>2011-10-21T10:50:00.001-07:00</published><updated>2011-10-21T10:58:31.785-07:00</updated><title type='text'>Three New Web Service Demos Available on the OLL</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;One of my colleagues at Oracle, &lt;a href='http://marcieyoung.blogspot.com/'&gt;Marcie Young&lt;/a&gt;, has created three new &lt;a href='https://apex.oracle.com/pls/apex/f?p=44785:24:0::NO::P24_CONTENT_ID,P24_PREV_PAGE:5818,1'&gt;excellent demonstrations&lt;/a&gt; of consuming web services in Application Express 4.1.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The first demonstration called "Creating and Using a Manual SOAP Web Service in Your Application" takes you step by step through creating a manual web service reference, and then using the Create Form and Report on Web Service wizard to create the page to interact with the service. The ability to use that wizard on a manual web reference was a new feature on 4.0. (This demonstration even exposed a slight branching inconvenience that I am going to file and fix in 4.1.1.)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;"Creating and Using a RESTful Web Service with an XML Response" uses the Google Geocoder v3 web service and is a classic example of consuming a RESTful style web service in Application Express.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Finally, "Creating and Using a RESTful Web Service with an XML Response and a Bind Variable" is a great example of consuming a RESTful service where the parameter is passed as part of the URI path (not part of the query string), like http://someservice.com/employees/{id}, where {id} is the employee that you want to retrieve. This can be accomplished by using &amp;amp;ITEM_NAME. syntax when you specify the URL endpoint in the RESTful web service reference.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;All of these demonstrations reinforce your need to learn to write XPath expressions to traverse an XML document. If you don't know what I am talking about, there is an excellent &lt;a href='http://www.w3schools.com/xpath/default.asp'&gt;XPath tutorial&lt;/a&gt; at &lt;a href='http://www.w3schools.com'&gt;www.w3schools.com&lt;/a&gt;.  &lt;br /&gt;&lt;/p&gt;&lt;p&gt;So check these demonstrations out (they are nice videos) and give your mad props to Marcie!&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-7103924607095910643?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/7103924607095910643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=7103924607095910643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/7103924607095910643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/7103924607095910643'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2011/10/three-new-web-service-demos-available.html' title='Three New Web Service Demos Available on the OLL'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-3066201602515305421</id><published>2011-01-03T07:02:00.001-08:00</published><updated>2011-01-03T07:53:31.688-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='APEX'/><category scheme='http://www.blogger.com/atom/ns#' term='Amazon'/><title type='text'>Building an Amazon S3 Client with Application Express 4.0 White Paper Available</title><content type='html'>&lt;div&gt;&lt;font xmlns=""&gt;&lt;br /&gt;&lt;p&gt;If you have seen me present about web services and Oracle Application Express 4.0 in the last year (at APEXposed, OOW, or ODTUG Kaleidoscope), you have probably heard me say that a white paper about building an Amazon S3 client with APEX was forthcoming. I am happy to announce the paper is &lt;a href="http://www.oracle.com/technetwork/developer-tools/apex/application-express/integration-086636.html"&gt;now available&lt;/a&gt; along with a corresponding sample application. The best part is with the &lt;a href="http://aws.amazon.com/free/"&gt;AWS Free Usage Tier&lt;/a&gt;, you can try everything out for free!&lt;/p&gt;&lt;/font&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-3066201602515305421?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/3066201602515305421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=3066201602515305421' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3066201602515305421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3066201602515305421'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2011/01/building-amazon-s3-client-with.html' title='Building an Amazon S3 Client with Application Express 4.0 White Paper Available'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-1118851555019040020</id><published>2010-09-14T09:47:00.001-07:00</published><updated>2010-09-14T11:48:08.187-07:00</updated><title type='text'>Adding a Context Menu to a Tree Region</title><content type='html'>&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span xmlns=""&gt;&lt;p&gt;One of the nice new features of Application Express is the new tree region. It is based on &lt;a href="http://www.jstree.com/"&gt;jsTree&lt;/a&gt; and supports features such as tool-tips. jsTree is the same tree used for the new tree view of the Application Builder Page Definition page. That page supports a right click context menu which is missing from the current version of the Application Express new tree region. With a little help from &lt;a href="http://www.inside-oracle-apex.com/"&gt;Patrick&lt;/a&gt;, I was able to add a context menu to a tree region I was working on for an update to the Document Library packaged application. The purpose of this article is to describe how to do this for your tree regions. I will use the EMP table as a simple example. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Patrick wanted me to mention that we may change the implementation of the tree in the future, so you may have to adjust the JavaScript code listed here in future versions of Application Express.&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Let's start by creating a copy of the emp table, emp2, so you don't actually mess with the emp data. Use the SQL Workshop SQL Command Processor and the code in listing 1 to create emp2.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 1&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create table emp2 as select * from emp&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;alter table emp2 add constraint emp2_pk primary key (empno)&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;alter table emp2 add constraint emp2_fk foreign key (mgr) references emp2(empno)&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Create Application and Tree&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;With emp2 in place you are ready to create an application. Simply run the create application wizard and create a form and report on emp2. You will replace the report on page 1 with a tree region. After the application is created, edit page 1. Delete the report region and then create a new tree region specifying the following options:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Display Attributes, Title: &lt;strong&gt;Employees&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tree Template: &lt;strong&gt;Default&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Table/View: &lt;strong&gt;EMP2&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Confirm that all values are defaulted on the Query step&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tooltip: &lt;strong&gt;Database Column&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tooltip Column: &lt;strong&gt;HIREDATE&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p&gt;Run the page and confirm that your tree appears. When you right click on a node, you should only see that standard right click options of whatever browser you are using.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Create Context Menu&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Now for the magic! By sprinkling a little JavaScript on the page here and there, we will get a nice right click context menu. First edit the tree region and give the region a static ID of EMP2 as in figure 1. We need this static ID to make it easier to write JavaScript and select this region with jQuery.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Figure 1&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_VnsRKsEcy_c/TI-n1DAFESI/AAAAAAAAADg/ndbzS9et404/s1600/staticID.png"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 160px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5516812598332690722" border="0" alt="" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/TI-n1DAFESI/AAAAAAAAADg/ndbzS9et404/s400/staticID.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now you just need to sprinkle a little JavaScript on the page! Edit the page definition of page one and add the code in code listing 2 into the Function and Global Variable Declaration text area and the code in code listing 3 into the Execute when Page Loads text area.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 2&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;&lt;br /&gt;function doAction(pNode,pTree,a){&lt;br /&gt;  var l_action;&lt;br /&gt;  var l_id;&lt;br /&gt;&lt;br /&gt;  l_id = pNode.attr("id");&lt;br /&gt;&lt;br /&gt;  if (a=="create") { l_action = "f?p="+$v('pFlowId')+":2:"+$v('pInstance')+":::2:P2_MGR:"+l_id }&lt;br /&gt;  if (a=="delete") { deleteEmp(pNode,l_id); }&lt;br /&gt;  if (a=="edit") { l_action = "f?p="+$v('pFlowId')+":2:"+$v('pInstance')+"::::P2_EMPNO:"+l_id }&lt;br /&gt;&lt;br /&gt;  if (l_action != null) {document.location.href=l_action; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 3&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;&lt;br /&gt;var lTreeContextMenu={&lt;br /&gt;    items:{create:false,rename:false,remove:false,&lt;br /&gt;        contextmenu_create:{&lt;br /&gt;            label:"&lt;strong&gt;Add Employee&lt;/strong&gt;",&lt;br /&gt;            icon: "",&lt;br /&gt;            visible: true,&lt;br /&gt;            action: function(pNode, pTree){doAction(pNode, pTree, "create");}&lt;br /&gt;        },&lt;br /&gt;        contextmenu_delete:{&lt;br /&gt;            label:"&lt;strong&gt;Delete&lt;/strong&gt;",&lt;br /&gt;            icon: "",&lt;br /&gt;            visible: true,&lt;br /&gt;            action: function(pNode, pTree){doAction(pNode, pTree, "delete");}&lt;br /&gt;        },&lt;br /&gt;        contextmenu_edit:{&lt;br /&gt;            label:"&lt;strong&gt;Edit&lt;/strong&gt;",&lt;br /&gt;            icon: "",&lt;br /&gt;            visible: true,&lt;br /&gt;            action: function(pNode, pTree){doAction(pNode, pTree, "edit");}&lt;br /&gt;        }&lt;br /&gt;}};&lt;br /&gt;&lt;br /&gt;        // use jsTree to render the tree&lt;br /&gt;        var lTreeSel = apex.jQuery("#EMP2").find("div.tree");&lt;br /&gt;        var lTreeId = lTreeSel.attr("id");&lt;br /&gt;        var lDataId = lTreeId.replace("tree","");&lt;br /&gt;        var lTreeData = eval("l"+lDataId+"Data");&lt;br /&gt;        var lTree = lTreeSel.tree({&lt;br /&gt;          data:{&lt;br /&gt;            type:"json",&lt;br /&gt;            async:true,&lt;br /&gt;            opts:{&lt;br /&gt;              "static":lTreeData,&lt;br /&gt;              isTreeLoaded:false,&lt;br /&gt;              method:"POST",&lt;br /&gt;              url:"wwv_flow.show"&lt;br /&gt;            }&lt;br /&gt;          },&lt;br /&gt;          root:{&lt;br /&gt;            draggable:false,&lt;br /&gt;            valid_children: "folder"&lt;br /&gt;          },&lt;br /&gt;          folder:{&lt;br /&gt;            valid_children: "file"&lt;br /&gt;          },&lt;br /&gt;          file:{&lt;br /&gt;            valid_children: "none",&lt;br /&gt;            max_children: 0,&lt;br /&gt;            max_depth:0&lt;br /&gt;          },&lt;br /&gt;          opened:["7839"],&lt;br /&gt;          plugins:{contextmenu:lTreeContextMenu}&lt;br /&gt;          });&lt;br /&gt;&lt;br /&gt;        $.showTooltip = function(pEvent) {&lt;br /&gt;        var lAction = apex.jQuery(pEvent.target).attr("tooltip");&lt;br /&gt;        if (lAction &amp;&amp; lAction != "") {&lt;br /&gt;            toolTip_enable(pEvent,this,apex.jQuery(this).attr("tooltip"));&lt;br /&gt;        }&lt;br /&gt;        }; // showTooltip&lt;br /&gt;&lt;br /&gt;        // Bind Tooltips for tree nodes&lt;br /&gt;        apex.jQuery('a[tooltip]', lTreeSel).bind("mouseover", $.showTooltip);&lt;br /&gt;&lt;br /&gt;        // Hack for right click problem on selected node&lt;br /&gt;        apex.jQuery("#EMP2").find("a").live("mouseup",function() {apex.jQuery("#EMP2").find("a").removeClass()});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now when you run the page you should see a right click context menu when you right click on a node in your tree, like figure 2. Note that the Add Employee and Edit actions are implemented and working. The delete action is not yet working, that will be added next.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Figure 2&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_VnsRKsEcy_c/TI-n1dN8X8I/AAAAAAAAADo/3_VotFFtp7k/s1600/contextMenu.png"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 210px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5516812605370163138" border="0" alt="" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/TI-n1dN8X8I/AAAAAAAAADo/3_VotFFtp7k/s400/contextMenu.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Implement Delete Action&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;Technically the delete action is already implemented. You could edit the employee and just click delete on the next page. What sounds like more fun is to call an on demand process using AJAX from some JavaScript, and then use jQuery to remove the node from the tree, display a confirmation message, all without doing a page submit. First things first though, create a region that will hold the message specifying the following options:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Region Type: &lt;strong&gt;HTML&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Title: &lt;strong&gt;Message Container&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Region Template: &lt;strong&gt;No Template&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Sequence: &lt;strong&gt;5&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Region Source: See Code Listing 4&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 4&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;pre class="html" name="code"&gt;&lt;br /&gt;&amp;lt;div class="success" id="success-message" style="display:none;"&amp;gt;&lt;br /&gt;  &amp;lt;img src="#IMAGE_PREFIX#delete.gif" onclick="apex.jQuery('#success-message').hide()" style="float:right;" class="remove-message" alt="" /&amp;gt;&lt;br /&gt;&amp;lt;div id="theMessage"&amp;gt;This is a placeholder for messages&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now we have a place for messages. Next, create a process on page 1 with the following options:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Process Type: &lt;strong&gt;PL/SQL&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Name: &lt;strong&gt;DELETE_EMPLOYEE&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Point: &lt;strong&gt;On Demand – Run this process when requested by AJAX&lt;/strong&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PL/SQL Page Process: See Code Listing 5&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 5&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;begin&lt;br /&gt;    delete from emp2 where empno = apex_application.g_x01;&lt;br /&gt;    owa_util.mime_header('text/xml', FALSE );&lt;br /&gt;    htp.p('Cache-Control: no-cache');&lt;br /&gt;    htp.p('Pragma: no-cache');&lt;br /&gt;    owa_util.http_header_close;&lt;br /&gt;    htp.p('{result:"success",message:"Employee successfully deleted"}');&lt;br /&gt;exception when others then&lt;br /&gt;    owa_util.mime_header('text/xml', FALSE );&lt;br /&gt;    htp.p('Cache-Control: no-cache');&lt;br /&gt;    htp.p('Pragma: no-cache');&lt;br /&gt;    owa_util.http_header_close;&lt;br /&gt;    htp.p('{result:"failed",message:"Error deleting employee: '||sqlerrm||'"}');&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finally, you add the JavaScript to do the AJAX call, display the result message, and remove the node from the tree. Edit the page attributes and add the code in code listing 6 in the Function and Global Variable Declaration text area before the existing doAction function.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Code Listing 6&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;&lt;br /&gt;function confirmSubmit(){&lt;br /&gt;var agree=confirm("Are you sure you wish to continue and delete?");&lt;br /&gt;if (agree)&lt;br /&gt; return true ;&lt;br /&gt;else&lt;br /&gt; return false ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function deleteEmp(pNode,pId){&lt;br /&gt;  var lTest = confirmSubmit();&lt;br /&gt;  if (lTest) {&lt;br /&gt;    var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=DELETE_EMPLOYEE',$v('pFlowStepId'));&lt;br /&gt;    get.addParam('x01',pId);&lt;br /&gt;    gReturn = get.get();&lt;br /&gt;    var j = eval("("+gReturn+")");&lt;br /&gt;    apex.jQuery("#theMessage").text(j.message);&lt;br /&gt;    apex.jQuery("#success-message").show();&lt;br /&gt;    if (j.result == "success") {&lt;br /&gt;        pNode.remove();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    get = null;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now run the page and unroll Clark. Right click on Miller and choose delete. Confirm the delete and the result should be similar to figure 3.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Figure 3&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_VnsRKsEcy_c/TI-n14BBrUI/AAAAAAAAADw/-BrKeApVTVs/s1600/delete.png"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 339px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5516812612563742018" border="0" alt="" src="http://2.bp.blogspot.com/_VnsRKsEcy_c/TI-n14BBrUI/AAAAAAAAADw/-BrKeApVTVs/s400/delete.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-1118851555019040020?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/1118851555019040020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=1118851555019040020' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/1118851555019040020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/1118851555019040020'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2010/09/adding-context-menu-to-tree-region.html' title='Adding a Context Menu to a Tree Region'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VnsRKsEcy_c/TI-n1DAFESI/AAAAAAAAADg/ndbzS9et404/s72-c/staticID.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-2594738721994894069</id><published>2010-07-06T11:53:00.000-07:00</published><updated>2011-01-04T13:19:47.875-08:00</updated><title type='text'>Application Express 4.0 Web Services Evaluation Guide</title><content type='html'>I just returned from &lt;a href="http://www.odtugkaleidoscope.com/"&gt;ODTUG Kaliedoscope 2010&lt;/a&gt;, (awesome event, best one I have been to), and promised during my presentation that the Application Express 4.0 Web Services Evaluation Guide would be posted on the &lt;a href="http://www.oracle.com/technetwork/developer-tools/apex/application-express/integration-086636.html"&gt;Application Express Web Services Integration&lt;/a&gt; page on OTN. Well it now is, so I kept my promise. ;)&lt;br /&gt;&lt;br /&gt;If you missed me at ODTUG, you can see me give a very similar presentation this year at &lt;a href="http://www.oracle.com/us/openworld/index.htm"&gt;Oracle Open World&lt;/a&gt;. The session is at 12:30 on Thursday September 23rd, so don't get too crazy at the appreciation event the night before!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update 7/28/2010: &lt;/strong&gt;A patch set exception was created for the issue the Roel reported in the comments below. Log on to Metalink and search for 9848562.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-2594738721994894069?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/2594738721994894069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=2594738721994894069' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2594738721994894069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2594738721994894069'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2010/07/application-express-40-web-services.html' title='Application Express 4.0 Web Services Evaluation Guide'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-6843342823550558669</id><published>2010-02-26T13:06:00.000-08:00</published><updated>2010-02-26T13:21:30.574-08:00</updated><title type='text'>Application Express 4.0  Early Adopter Phase II (EA2) Available</title><content type='html'>The &lt;a href="http://tryapexnow.com/apex"&gt;Application Express 4.0&lt;/a&gt; Early Adopter Phase II (EA2) is now available. Like EA1, this instance is running on Amazon EC2. The beauty of Amazon's &lt;a href="http://aws.amazon.com/ec2/#features"&gt;elastic &lt;span id="SPELLING_ERROR_0" class="blsp-spelling-error"&gt;IP&lt;/span&gt; &lt;/a&gt;feature is that we could work on the EA2 instance and get it completely ready, then associate the elastic &lt;span id="SPELLING_ERROR_1" class="blsp-spelling-error"&gt;IP&lt;/span&gt; with the new instance, making the switch in less than 60 seconds. You can still access &lt;a href="http://184.73.244.154/apex"&gt;EA1 &lt;/a&gt;for the next couple of weeks in case you need anything from that instance. You will need to sign up for a new workspace on EA2.&lt;br /&gt;&lt;br /&gt;One nugget I would pass on is that if you run Oracle in the cloud and use &lt;a href="http://aws.amazon.com/ebs/"&gt;Elastic Block Storage &lt;/a&gt;for your &lt;span id="SPELLING_ERROR_2" class="blsp-spelling-corrected"&gt;data files&lt;/span&gt;, you should also change the parameter &lt;em&gt;diagnostic_&lt;span id="SPELLING_ERROR_3" class="blsp-spelling-error"&gt;dest&lt;/span&gt;&lt;/em&gt; to point to your &lt;span id="SPELLING_ERROR_4" class="blsp-spelling-error"&gt;EBS&lt;/span&gt; volume instead of the volatile volume that only lives with the instance. The reason is that you could fill up that volume pretty quickly if there is a lot of action on your instance and cause your database to shutdown.&lt;br /&gt;&lt;br /&gt;Have fun with EA2 and especially kicking the tires of &lt;a href="http://www.oracle.com/technology/products/database/application_express/apex_sod.html"&gt;&lt;span id="SPELLING_ERROR_5" class="blsp-spelling-error"&gt;Websheets&lt;/span&gt;&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-6843342823550558669?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/6843342823550558669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=6843342823550558669' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6843342823550558669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6843342823550558669'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2010/02/application-express-40-early-adopter.html' title='Application Express 4.0  Early Adopter Phase II (EA2) Available'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-6027028047172038627</id><published>2010-01-08T05:52:00.000-08:00</published><updated>2010-01-08T06:07:24.590-08:00</updated><title type='text'>OTN Developer Days in NYC</title><content type='html'>Are you in the NY, NY area? If so you should definitely attend the free &lt;a href="http://www.oracle.com/webapps/events/EventsDetail.jsp?p_eventId=101955&amp;amp;src=6773869&amp;amp;src=6773869&amp;amp;Act=85"&gt;OTN Developer Day- Hands-on Oracle Database 11g Applications Development&lt;/a&gt; event at the New York Marriot Marquis on January 13, 2010. I will not be there, but much smarter colleagues of mine will like Mike Hichwa (VP of Development Tools, father of Application Express), Marc Sewtz, David Peake and Christina Cho.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bring your own laptop for the labs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_VnsRKsEcy_c/S0c6nJAjXHI/AAAAAAAAACk/5D2-ls7UauQ/s1600-h/odd_apex.png"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 148px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5424368720298597490" border="0" alt="" src="http://1.bp.blogspot.com/_VnsRKsEcy_c/S0c6nJAjXHI/AAAAAAAAACk/5D2-ls7UauQ/s400/odd_apex.png" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-6027028047172038627?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/6027028047172038627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=6027028047172038627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6027028047172038627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6027028047172038627'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2010/01/otn-developer-days-in-nyc.html' title='OTN Developer Days in NYC'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_VnsRKsEcy_c/S0c6nJAjXHI/AAAAAAAAACk/5D2-ls7UauQ/s72-c/odd_apex.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-3740929763192305276</id><published>2009-12-21T11:30:00.001-08:00</published><updated>2009-12-21T11:34:44.936-08:00</updated><title type='text'>Application Express 4.0 EA Running on Amazon EC2</title><content type='html'>The Application Express 4.0 evaluation instance is running on an Amazon EC2 instance. You can access it at &lt;a href="http://tryapexnow.com/"&gt;http://tryapexnow.com&lt;/a&gt;. You may also be interested in checking out the APEX 4.0 Web Services Evaluation Guide &lt;a href="http://tryapexnow.com/APEX40WebServicesEvaluationGuide.doc"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-3740929763192305276?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/3740929763192305276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=3740929763192305276' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3740929763192305276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3740929763192305276'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/12/application-express-40-ea-running-on.html' title='Application Express 4.0 EA Running on Amazon EC2'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-879417734146503310</id><published>2009-11-20T08:00:00.000-08:00</published><updated>2009-11-20T08:12:28.099-08:00</updated><title type='text'>flex_ws_api now on samplecode.oracle.com</title><content type='html'>&lt;a href="http://tylermuth.wordpress.com/"&gt;Tyler &lt;/a&gt;recently made me aware of &lt;a href="http://samplecode.oracle.com/"&gt;http://samplecode.oracle.com/&lt;/a&gt;. It is a great place to share code projects, allow others to contribute and comment through discussion forums. I have set up a project for the &lt;a href="https://flex-ws-api.samplecode.oracle.com/"&gt;flex_ws_api&lt;/a&gt; and all further development will take place there. I have created discussions for general questions, bug reports, and enhancement requests. Feel free to participate there. All you need is an OTN account to login.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-879417734146503310?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/879417734146503310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=879417734146503310' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/879417734146503310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/879417734146503310'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/11/flexwsapi-no-on-samplecodeoraclecom.html' title='flex_ws_api now on samplecode.oracle.com'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-8345988877547762316</id><published>2009-10-23T13:36:00.001-07:00</published><updated>2009-10-26T06:38:03.554-07:00</updated><title type='text'>REST Now Supported in flex_ws_api and Other Good Stuff</title><content type='html'>&lt;span xmlns=""&gt;&lt;p&gt;I have finally added support for consuming RESTful Web services in the &lt;a href="http://jastraub.blogspot.com/2008/06/flexible-web-service-api.html"&gt;flex_ws_api API&lt;/a&gt;. I have also added new globals in the API to keep track of cookies, HTTP headers and the response code returned from a service. There is also a global you can populate prior to calling any of the make_request procedure/functions that will send cookies along with the request to the Web service.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;To demonstrate using the new features of the API, I will walk you through creating a new application that will call the RESTful version of &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2432&amp;amp;categoryID=19"&gt;Amazon's Product Advertising API&lt;/a&gt;. You may recall &lt;a href="http://jastraub.blogspot.com/2009/07/hmacsha256-in-plsql.html"&gt;from a previous post&lt;/a&gt; that Amazon now requires that all requests to this API are signed with the developer's secret key. This example will assume that you have compiled the following in your schema: the new flex_ws_api, the java source hmacSHA256, the pl/sql function hmacSHA256, and finally the amazon_signature function.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;First create a new application with one blank page called Product Search. Modify the application attributes and add the following substitutions:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;AWSACCESSKEY&lt;br /&gt;&lt;/li&gt;&lt;li&gt;ASSOCIATETAG&lt;br /&gt;&lt;/li&gt;&lt;li&gt;AWSSECRETKEY&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Enter the appropriate values with the values that match your AWS credentials. You will need to sign up for an &lt;a href="http://aws.amazon.com/"&gt;AWS Access Key ID&lt;/a&gt; which will also give you your secret code and you also should sign up to be an &lt;a href="http://associates.amazon.com/exec/panama/associates/apply"&gt;associate&lt;/a&gt; which will give you your associate tag.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Next create an HTML region called Product Search (if it was not already created by the create application wizard) and place the following items in that region:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Name: &lt;strong&gt;P1_KEYWORDS&lt;/strong&gt;, Display As: &lt;strong&gt;Text Field&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Name: &lt;span style=";font-family:Arial;font-size:9;color:black;"   &gt;&lt;strong&gt;P1_SEARCHINDEX&lt;/strong&gt;, Display As: &lt;strong&gt;Select List&lt;/strong&gt;, List of Values – Display Extra Values: &lt;strong&gt;No&lt;/strong&gt;, List of values definition: &lt;strong&gt;STATIC2:All;All,Apparel;Apparel,Automotive;Automotive,Baby;Baby,Beauty;Beauty,Books;Books,Classical;Classical,DigitalMusic;DigitalMusic,DVD;DVD,Electronics;Electronics,GourmetFood;GourmetFood,HealthPersonalCare;HealthPersonalCare,HomeGarden;HomeGarden,Industrial;Industrial,Jewelry;Jewelry,KindleStore;KindleStore,Kitchen;Kitchen,Magazines;Magazines,Merchants;Merchants,Miscellaneous;Miscellaneous,MP3Downloads;MP3Downloads,Music;Music,MusicalInstruments;MusicalInstruments,MusicTracks;MusicTracks,OfficeProducts;OfficeProducts,OutdoorLiving;OutdoorLiving,PCHardware;PCHardware,PetSupplies;PetSupplies,Photo;Photo,Shoes;Shoes,SilverMerchants;SilverMerchants,Software;Software,SportingGoods;SportingGoods,Tools;Tools,Toys;Toys,UnboxVideo;UnboxVideo,VHS;VHS,Video;Video,VideoGames;VideoGames,Watches;Watches,Wireless;Wireless,WirelessAccessories;WirelessAccessories&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:Arial;font-size:9;color:black;"   &gt;Name: &lt;strong&gt;P1_TIMESTAMP&lt;/strong&gt;, Display As: &lt;strong&gt;Hidden and Protected&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;   &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Create a Submit button on the page that submits the page and branches back to page 1.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You must compute the value of P1_TIMESTAMP to a format that Amazon is expecting. The computation includes a GMT offset at the end so your computation will depend on where your database server is relative to GMT. For me it was -08:00. Create a computation on page 1 with the following attributes:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Item Name: &lt;strong&gt;P1_TIMESTAMP&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Type: &lt;strong&gt;PL/SQL Function Body&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Computation Point: &lt;strong&gt;After Submit&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Computation: &lt;strong&gt;return to_char(sysdate + 8/24,'YYYY-MM-DD')||'T'||to_char(sysdate,'hh24:mi:ss')||'-08:00';&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now you create the process on that page that uses the flex_ws_api to call the Amazon Product Advertising API REST Web service. Create a process on the page with the following attributes:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Name: &lt;strong&gt;Call Amazon Product Search API&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Type: &lt;strong&gt;PL/SQL anonymous block&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Process Point: &lt;strong&gt;On Submit – After Computations and Validations&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Source: &lt;strong&gt;&amp;lt;see code listing 1&amp;gt;&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Conditional Processing, When Button Pressed: &lt;strong&gt;SUBMIT&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Code Listing 1, Call Amazon Product Search API Process&lt;br /&gt;&lt;/h2&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;declare&lt;br /&gt;  l_signature     varchar2(4000);&lt;br /&gt;  l_response      clob;&lt;br /&gt;  l_parm_name_tab wwv_flow_global.vc_arr2;&lt;br /&gt;  l_parm_val_tab  wwv_flow_global.vc_arr2;&lt;br /&gt;  i number;&lt;br /&gt;  secure varchar2(1);&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;  --compute the signature&lt;br /&gt;  l_signature := amazon_signature('GET'||chr(10)||'ecs.amazonaws.com'||chr(10)||'/onca/xml'||chr(10)||'AWSAccessKeyId='||:AWSACCESSKEY||'&amp;amp;AssociateTag='||:ASSOCIATETAG||'&amp;amp;Keywords='||replace(:P1_KEYWORDS,' ','%20')||'&amp;amp;Operation=ItemSearch&amp;amp;ResponseGroup=ItemAttributes%2CImages&amp;amp;SearchIndex='||:P1_SEARCHINDEX||'&amp;amp;Service=AWSECommerceService&amp;amp;Timestamp='||apex_util.url_encode(:P1_TIMESTAMP)||'&amp;amp;Version=2009-03-31',:AWSSECRETKEY);&lt;br /&gt;&lt;br /&gt;  --create the tables of parameter names and values&lt;br /&gt;  l_parm_name_tab := apex_util.string_to_table('Service:Version:Operation:Keywords:SearchIndex:AWSAccessKeyId:AssociateTag:ResponseGroup:Timestamp:Signature');&lt;br /&gt;  --need to use ~ instead of : for separator since timestamp will contain :&lt;br /&gt;  l_parm_val_tab := apex_util.string_to_table('AWSECommerceService~2009-03-31~ItemSearch~'||:P1_KEYWORDS||'~'||:P1_SEARCHINDEX||'~'||:AWSACCESSKEY||'~'||:ASSOCIATETAG||'~ItemAttributes,Images~'||:P1_TIMESTAMP,'~');&lt;br /&gt;  --need to add l_signature to the table separately, it may contain any character&lt;br /&gt;  l_parm_val_tab(l_parm_val_tab.count + 1) := l_signature;&lt;br /&gt;&lt;br /&gt;  --make the REST request&lt;br /&gt;  l_response := flex_ws_api.make_rest_request(&lt;br /&gt;      p_url =&gt; 'http://ecs.amazonaws.com/onca/xml',&lt;br /&gt;      p_http_method =&gt; 'GET',&lt;br /&gt;      p_parm_name =&gt; l_parm_name_tab,&lt;br /&gt;      p_parm_value =&gt; l_parm_val_tab );&lt;br /&gt;&lt;br /&gt;  --populate a collection with the response&lt;br /&gt;  apex_collection.create_or_truncate_collection('P1_ITEMSEARCH_RESPONSE');&lt;br /&gt;  apex_collection.add_member(&lt;br /&gt;      p_collection_name   =&gt; 'P1_ITEMSEARCH_RESPONSE',&lt;br /&gt;      p_clob001           =&gt; l_response );&lt;br /&gt;&lt;br /&gt;  --populate a collection for any response http headers returned&lt;br /&gt;  apex_collection.create_or_truncate_collection('P1_RESP_HEADERS');&lt;br /&gt;&lt;br /&gt;  for i in 1.. flex_ws_api.g_headers.count loop&lt;br /&gt;    apex_collection.add_member(&lt;br /&gt;      p_collection_name =&gt; 'P1_RESP_HEADERS',&lt;br /&gt;      p_c001 =&gt; flex_ws_api.g_headers(i).name,&lt;br /&gt;      p_c002 =&gt; flex_ws_api.g_headers(i).value,&lt;br /&gt;      p_c003 =&gt; flex_ws_api.g_status_code);&lt;br /&gt;  end loop;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Next you create two SQL Report regions. The first one reports on the response from the Web service and shows the products that match the search term and the second shows the HTTP headers that are returned with the response. Create a SQL Report region with the following attributes:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Title: &lt;strong&gt;Results&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Type: &lt;strong&gt;SQL Query&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Source: &lt;strong&gt;&amp;lt;see code listing 2&amp;gt;&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Conditional Display, Condition Type: &lt;strong&gt;PL/SQL Expression&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Conditional Display, Expression 1: apex_collection.collection_exists('P1_ITEMSEARCH_RESPONSE')&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Code Listing 2, Results SQL Query&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;select extractValue(value(t),'/*/ASIN','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"') ASIN&lt;br /&gt;   , extractValue(value(t),'/*/DetailPageURL','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"') DetailPageURL&lt;br /&gt;   , extractValue(value(t),'/*/ItemAttributes/Title','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"') Title&lt;br /&gt;   , '&amp;lt;img src="'||nvl(extractValue(value(t),'/*/SmallImage/URL','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"'),'http://ec1.images-amazon.com/images/G/01/x-locale/detail/thumb-no-image._V47060337_.gif')||'" width="'||nvl(extractValue(value(t),'/*/SmallImage/Width','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"'),'50')||'" height="'||nvl(extractValue(value(t),'/*/SmallImage/Height','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"'),'60')||'" /&amp;gt;' "Image"&lt;br /&gt;   , extractValue(value(t),'/*/ItemLinks/ItemLink[4]/URL','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"') Link&lt;br /&gt;from wwv_flow_collections c,&lt;br /&gt;    table(xmlsequence(extract(xmltype.createxml(c.clob001),'//Item','xmlns="http://webservices.amazon.com/AWSECommerceService/2009-03-31"'))) t&lt;br /&gt;where c.collection_name = 'P1_ITEMSEARCH_RESPONSE'&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The query above pulls out the ASIN, detail page URL, title, small image and wish list link from the XML document. You want to create links for the title point to the detail page and a link for the wishlist in your report. Make the following changes to the Results report by click on the Report link on the page definition.&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Uncheck Show for the column DETAILPAGEURL&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Enter the following HTML Expression for TITLE column: &lt;strong&gt;&amp;lt;a href="#DETAILPAGEURL#"&amp;gt;#TITLE#&amp;lt;/a&amp;gt;&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Enter the following HTML Expression for LINK column: &lt;strong&gt;&amp;lt;a href="#LINK#"&amp;gt;[Add to Wishlisth]&amp;lt;/a&amp;gt;&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Create a SQL Report region for the HTTP headers with the following attributes:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Title: &lt;strong&gt;Headers&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Type: &lt;strong&gt;SQL Query&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Source: &lt;strong&gt;&amp;lt;see code listing 3&amp;gt;&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Conditional Display, Condition Type: &lt;strong&gt;PL/SQL Expression&lt;/strong&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;Conditional Display, Expression 1: apex_collection.collection_exists('P1_RESP_HEADERS')&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Code Listing 3, Header SQL Query&lt;br /&gt;&lt;/h2&gt;&lt;pre class="sql" name="code"&gt; select c001 name, c002 value, c003 status_code&lt;br /&gt;from apex_collections&lt;br /&gt;where collection_name = 'P1_RESP_HEADERS'&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now run the page, enter a search term, choose a category and click Submit. You should see a page similar to the one below. That's all there is to it!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_VnsRKsEcy_c/SuIUyYm1j1I/AAAAAAAAACc/dj9I5CMcABY/s1600-h/AmazonProductAPIBlogPost1.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 240px;" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/SuIUyYm1j1I/AAAAAAAAACc/dj9I5CMcABY/s400/AmazonProductAPIBlogPost1.jpg" alt="" id="BLOGGER_PHOTO_ID_5395898159374634834" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-8345988877547762316?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/8345988877547762316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=8345988877547762316' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/8345988877547762316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/8345988877547762316'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/10/rest-now-supported-in-flexwsapi-and.html' title='REST Now Supported in flex_ws_api and Other Good Stuff'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VnsRKsEcy_c/SuIUyYm1j1I/AAAAAAAAACc/dj9I5CMcABY/s72-c/AmazonProductAPIBlogPost1.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-635427358613647378</id><published>2009-07-24T08:34:00.001-07:00</published><updated>2009-07-24T08:55:32.160-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='APEX'/><title type='text'>HMAC_SHA256 in PL/SQL</title><content type='html'>&lt;span xmlns=""&gt;&lt;p&gt;I have been working on an Application Express 4.0 feature to support consuming REST Web services. REST Web services use a simpler architecture than the popular SOAP style Web services. Instead of posting some big XML document wrapped in a SOAP Envelope, REST requests are typically done by passing name/value pairs in the query string of a URL.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;To prove that the support for REST I am building in Application Express is useful, I have been working with popular public REST Web services offered by Yahoo, Google and Amazon. I built a similar application to the &lt;a href="http://www.oracle.com/technology/products/database/application_express/packaged_apps/integration.html"&gt;Amazon Store&lt;/a&gt; sample application using the REST APIs. Everything was going great until I received the following email from Amazon.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;"Dear Product Advertising API Developer,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We wanted to remind you that all Product Advertising API developers will be required to authenticate all calls to the Product Advertising API by August 15, 2009. We noticed that requests with your AWS Access Key ID are not being signed and, while you have more than 60 days until the date on which authentication is required, we are, as a courtesy, sending you this email to remind you of the new authentication requirement. Please remember that calls to the Product Advertising API that are not signed will not be processed after August 15, 2009."&lt;br /&gt;&lt;/p&gt;&lt;p&gt;What do they mean I need to sign my requests? Luckily they provided some links for &lt;a href="http://www.amazon.com/gp/r.html?R=16V6GMZOI82UF&amp;amp;C=2VEYJ1HBZV7BE&amp;amp;H=LATBAM3EYCAQTANAALJJRR7GI5WA&amp;amp;T=C&amp;amp;U=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fr.html%2Fref%3Dpe_53700_12281680%3FR%3D3Q89S9WPYQKE1%26C%3D3SOKYNFG0JD02%26H%3DAFX3IIIM5CBYLVKZ1KBCMMEKQNOA%26T%3DTC%26U"&gt;developer resources&lt;/a&gt; on how to construct signed requests. In a nutshell, you must byte order all of your parameters, add a Timestamp parameter and then you create a base64-encoded HMAC_SHA256 signature using your &lt;a href="https://aws-portal.amazon.com/gp/aws/developer/registration/index.html"&gt;AWS secret key&lt;/a&gt;. Should not be a problem. I recently added support for parameters in REST requests to be populated by the result of a function and I am somewhat familiar with the DBMS_CRYPTO package. Unfortunately I quickly found out that DBMS_CYRPTO only supports HMAC_SHA1 and I not so quickly found out that HMAC_SHA1 is not the same as HMAC_SHA256. Am I stuck?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I &lt;a href="http://www.bing.com/"&gt;binged&lt;/a&gt; (Google gets enough love and Microsoft can use the help after their most recent earnings results) for HMAC_SHA256 and PL/SQL and found &lt;a href="http://www.orafaq.com/forum/t/71097/2/"&gt;this&lt;/a&gt; forum post. This guy wanted to do exactly what I need to do. Someone suggested that he create a Java stored procedure and then he responded with some Java code example with and hmacSHA256 function. Unfortunately no-one could give him an example of exactly how to create that Java stored procedure and then use it in PL/SQL. That's when I remembered that my good friend and colleague Joel Kallman &lt;a href="http://joelkallman.blogspot.com/2008/04/zip-it.html"&gt;wrote&lt;/a&gt; about creating a Java stored procedure to create a zip file of BLOB's.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Well, surely I can follow Joel's example as a cookbook and do the same thing with this hmacSHA256 function, right? The answer is yes, after spending more time than I probably should have (don't tell Joel if you see him), but hey, I had to prove that this REST stuff would actually be useful to customers. If they can't sign their requests, they won't be able to use Application Express to build cool applications that interact with Amazon Web Services. (At least that is my attempt at invoking what another colleague calls The Oracle Justification Server.)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;First, start by compiling the following Java source.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Code listing 1, java source hmacSHA256&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create or replace and compile java source named hmacSHA256 as&lt;br /&gt;&lt;br /&gt;import java.io.*;&lt;br /&gt;import java.net.*;&lt;br /&gt;import java.security.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;&lt;br /&gt;public class hmacSHA256 {&lt;br /&gt;    public static String encrypt(&lt;br /&gt;                        String message,&lt;br /&gt;                        String keyStr) {&lt;br /&gt;&lt;br /&gt;            //get the bytes of the keyStr&lt;br /&gt;            byte[] key = keyStr.getBytes();&lt;br /&gt;            // Start by getting an object to generate SHA-256 hashes with.&lt;br /&gt;            MessageDigest sha256 = null;&lt;br /&gt;            try {&lt;br /&gt;                sha256 = MessageDigest.getInstance("SHA-256");&lt;br /&gt;            } catch (NoSuchAlgorithmException e) {&lt;br /&gt;                throw new java.lang.AssertionError(".hmacSHA256(): SHA-256 algorithm not found!");&lt;br /&gt;            }&lt;br /&gt;            // Hash the key if necessary to make it fit in a block (see RFC 2104).&lt;br /&gt;            if (key.length &gt; 64) {&lt;br /&gt;               sha256.update(key);&lt;br /&gt;                key = sha256.digest();&lt;br /&gt;                sha256.reset();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Pad the key bytes to a block (see RFC 2104).&lt;br /&gt;            byte block[] = new byte[64];&lt;br /&gt;            for (int i = 0; i &lt; key.length; ++i) block[i] = key[i];&lt;br /&gt;            for (int i = key.length; i &lt; block.length; ++i) block[i] = 0;&lt;br /&gt;&lt;br /&gt;            // Calculate the inner hash, defined in RFC 2104 as&lt;br /&gt;            // SHA-256(KEY ^ IPAD + MESSAGE)), where IPAD is 64 bytes of 0x36.&lt;br /&gt;            for (int i = 0; i &lt; 64; ++i) block[i] ^= 0x36;&lt;br /&gt;            sha256.update(block);&lt;br /&gt;            try {&lt;br /&gt;                sha256.update(message.getBytes("UTF-8"));&lt;br /&gt;            } catch (UnsupportedEncodingException e) {&lt;br /&gt;                throw new java.lang.AssertionError(&lt;br /&gt;                        "ITunesU.hmacSH256(): UTF-8 encoding not supported!");&lt;br /&gt;            }&lt;br /&gt;            byte[] hash = sha256.digest();&lt;br /&gt;            sha256.reset();&lt;br /&gt;&lt;br /&gt;            // Calculate the outer hash, defined in RFC 2104 as&lt;br /&gt;            // SHA-256(KEY ^ OPAD + INNER_HASH), where OPAD is 64 bytes of 0x5c.&lt;br /&gt;            for (int i = 0; i &lt; 64; ++i) block[i] ^= (0x36 ^ 0x5c);&lt;br /&gt;            sha256.update(block);&lt;br /&gt;            sha256.update(hash);&lt;br /&gt;            hash = sha256.digest();&lt;br /&gt;&lt;br /&gt;            // The outer hash is the message signature...&lt;br /&gt;            // convert its bytes to hexadecimals.&lt;br /&gt;            char[] hexadecimals = new char[hash.length * 2];&lt;br /&gt;            for (int i = 0; i &lt; hash.length; ++i) {&lt;br /&gt;                for (int j = 0; j &lt; 2; ++j) {&lt;br /&gt;                    int value = (hash[i] &gt;&gt; (4 - 4 * j)) &amp; 0xf;&lt;br /&gt;                    char base = (value &lt; 10) ? ('0') : ('a' - 10);&lt;br /&gt;                    hexadecimals[i * 2 + j] = (char)(base + value);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Return a hexadecimal string representation of the message signature.&lt;br /&gt;            return new String(hexadecimals);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Next you create a standard PL/SQL function that uses the java source as in the following code listing.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Code listing 2, PL/SQL hmacSHA256 function&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create or replace function hmacSHA256(&lt;br /&gt;    p_string    in varchar2,&lt;br /&gt;    p_key       in varchar2) return varchar2&lt;br /&gt;as language java&lt;br /&gt;    name 'hmacSHA256.encrypt(&lt;br /&gt;          java.lang.String,&lt;br /&gt;          java.lang.String) return String';&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Finally, you create a function that takes in the string to sign, your AWS Secret Key, and then creates the HMAC_SHA256 signature.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Code listing 3, amazon_signature function&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create or replace function amazon_signature(&lt;br /&gt;    p_string    in varchar2,&lt;br /&gt;    p_key       in varchar2) return varchar2&lt;br /&gt;as&lt;br /&gt;    encrypted_raw   raw(2000);&lt;br /&gt;    output_string   varchar2(32000);&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    encrypted_raw := hmacSHA256(p_string,p_key);&lt;br /&gt;    output_string := UTL_I18N.RAW_TO_CHAR (utl_encode.base64_encode(encrypted_raw), 'AL32UTF8');&lt;br /&gt;&lt;br /&gt;    return output_string;&lt;br /&gt;&lt;br /&gt;end amazon_signature;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Now let's test all this out. Amazon provides a nice self contained Web page &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2609&amp;amp;categoryID=14"&gt;utility&lt;/a&gt; that uses Javascript to help you create signed requests. I will use 123456 as my AWS Access Key ID and abcdefg as my AWS Secret Access Key. Plug in the following URL in the Unsigned URL text area:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://ecs.amazonaws.com/onca/xml?Timestamp=2009-07-24T06%3A35%3A14-08%3A00&amp;amp;Service=AWSECommerceService&amp;amp;Version=2009-03-31&amp;amp;Operation=ItemSearch&amp;amp;ResponseGroup=ItemAttributes,Images&amp;amp;Keywords=liberty+and+tryanny&amp;amp;SearchIndex=Books&amp;amp;AWSAccessKeyId=123456&amp;amp;AssociateTag=apex30-20"&gt;http://ecs.amazonaws.com/onca/xml?Timestamp=2009-07-24T06%3A35%3A14-08%3A00&amp;amp;Service=AWSECommerceService&amp;amp;Version=2009-03-31&amp;amp;Operation=ItemSearch&amp;amp;ResponseGroup=ItemAttributes,Images&amp;amp;Keywords=liberty+and+tryanny&amp;amp;SearchIndex=Books&amp;amp;AWSAccessKeyId=123456&amp;amp;AssociateTag=apex30-20&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This will come up with the following string to sign:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;GET&lt;br /&gt;&lt;/p&gt;&lt;p&gt;ecs.amazonaws.com&lt;br /&gt;&lt;/p&gt;&lt;p&gt;/onca/xml&lt;br /&gt;&lt;/p&gt;&lt;p&gt;AWSAccessKeyId=123456&amp;amp;AssociateTag=apex30-20&amp;amp;Keywords=liberty%20and%20tryanny&amp;amp;Operation=ItemSearch&amp;amp;ResponseGroup=ItemAttributes%2CImages&amp;amp;SearchIndex=Books&amp;amp;Service=AWSECommerceService&amp;amp;Timestamp=2009-07-24T06%3A35%3A14-08%3A00&amp;amp;Version=2009-03-31&lt;br /&gt;&lt;/p&gt;&lt;p&gt;And will produce the following Signature parameter:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:red;"&gt;uMJX4cN6EXHyTUrC03Ae9hAcGdTnAHI0KqtovwQUHP8%3D&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;If I take the same string to sign and AWS Secret Key of abcdefg and run it through amazon_signature, I get the following results:&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Code listing 4, result of amazon_signature function&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;jason@APX11W&gt; declare&lt;br /&gt;  2      l_token varchar2(4000);&lt;br /&gt;  3  begin&lt;br /&gt;  4      l_token := amazon_signature('GET&lt;br /&gt;  5  ecs.amazonaws.com&lt;br /&gt;  6  /onca/xml&lt;br /&gt;  7  AWSAccessKeyId=123456&amp;amp;AssociateTag=apex30-20&amp;amp;Keywords=liberty%20and%20tryanny&amp;amp;Operation=ItemSearch&amp;amp;ResponseGroup=It&lt;br /&gt;emAttributes%2CImages&amp;amp;SearchIndex=Books&amp;amp;Service=AWSECommerceService&amp;amp;Timestamp=2009-07-24T06%3A35%3A14-08%3A00&amp;amp;Version=20&lt;br /&gt;09-03-31','abcdefg');&lt;br /&gt;  8      dbms_output.put_line(l_token);&lt;br /&gt;  9  end;&lt;br /&gt; 10  /&lt;br /&gt;uMJX4cN6EXHyTUrC03Ae9hAcGdTnAHI0KqtovwQUHP8=&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The only difference in the result is the very end. Prior to using the signature, it must be URL encoded. If you run the string uMJX4cN6EXHyTUrC03Ae9hAcGdTnAHI0KqtovwQUHP8= through wwv_flow_utilities.url_encode2, you will get uMJX4cN6EXHyTUrC03Ae9hAcGdTnAHI0KqtovwQUHP8%3D. &lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-635427358613647378?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/635427358613647378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=635427358613647378' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/635427358613647378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/635427358613647378'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/07/hmacsha256-in-plsql.html' title='HMAC_SHA256 in PL/SQL'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-3453162948086187490</id><published>2009-04-14T06:59:00.000-07:00</published><updated>2009-04-14T07:09:30.187-07:00</updated><title type='text'>New Web Services Integration White Paper and Sample Application on OTN</title><content type='html'>Late last year I &lt;a href="http://jastraub.blogspot.com/2008/12/more-changes-to-flexwsapi.html"&gt;promised &lt;/a&gt;a white paper and sample application on integrating Application Express and BI Publisher through Web services. Well five months later (hey, that's less than 1/2 a year), it is now available on the &lt;a href="http://www.oracle.com/technology/products/database/application_express/packaged_apps/integration.html"&gt;Application Express Web Services Integration &lt;/a&gt;page on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;OTN&lt;/span&gt;. The sample application allows you to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;login&lt;/span&gt; to a BI Publisher instance as a BI Publisher defined user, browse the folders and reports available to that user, and provides the ability to download the report all from within the Application Express application. The white paper describes in detail how to build the application using PL/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;SQL&lt;/span&gt; and the &lt;a href="http://jastraub.blogspot.com/2008/06/flexible-web-service-api.html"&gt;flex_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;ws&lt;/span&gt;_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;api&lt;/span&gt; package&lt;/a&gt;. I hope you find it useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-3453162948086187490?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/3453162948086187490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=3453162948086187490' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3453162948086187490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3453162948086187490'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/04/new-web-services-integration-white.html' title='New Web Services Integration White Paper and Sample Application on OTN'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-2302654326855835424</id><published>2009-03-13T08:45:00.001-07:00</published><updated>2009-03-13T13:07:52.930-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cloud'/><category scheme='http://www.blogger.com/atom/ns#' term='s3'/><category scheme='http://www.blogger.com/atom/ns#' term='APEX'/><category scheme='http://www.blogger.com/atom/ns#' term='ec2'/><title type='text'>20 cents an hour! Who's got that kind of dough?</title><content type='html'>&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;In these trying economic times, I thought it would be prudent to try to save some money on the cost of my Cloud experiment. (Although a colleague of mine pointed out that my actions were "anti-stimulative.") I wanted to downsize my machine to the 10 cent per hour machine described as:&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;Small Instance (Default) 1.7 GB of memory, 1 EC2 Compute Unit (1 virtual core with 1 EC2 Compute Unit), 160 GB of instance storage, 32-bit platform&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;I didn't want to have to start from scratch; I wanted to keep the database and all the applications that I installed intact. But how could I do that? I knew full well that once I shut my instance down everything was gone. This is where the beauty of Amazon's &lt;a href="http://aws.amazon.com/ebs/"&gt;&lt;span style="TEXT-DECORATION: underline;color:blue;" &gt;Elastic Block Storage&lt;/span&gt;&lt;/a&gt; (EBS) comes in. It allows you to create persistent volumes that you can then attach, format, and mount on an EC2 instance. If you shutdown the EC2 instance for any reason your EBS volume persists and you can then mount it on another EC2 instance.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;EBS has its own charges and I estimated it would cost me about $18 per month for my 10GB volume. But I am saving about $72 month by decreasing my hourly costs by 10 cents, so my net savings will be more than $50 a month. Not bad.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;So the idea is that I create an EBS volume, move all the database files necessary to run the database to that volume, and then start a database using those data files on the cheaper machine. With some help from my friends at the &lt;a href="http://www.oracle.com/technology/tech/cloud/index.html"&gt;&lt;span style="TEXT-DECORATION: underline;color:blue;" &gt;Oracle Cloud Computing Center&lt;/span&gt;&lt;/a&gt;, I was able to do just that and I have detailed the steps below.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;First I needed to create my EBS volume. This is very simple using &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=609"&gt;&lt;span style="TEXT-DECORATION: underline;color:blue;" &gt;Elasticfox&lt;/span&gt;&lt;/a&gt; and detailed in the &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1797"&gt;&lt;span style="TEXT-DECORATION: underline;color:blue;" &gt;Elasticfox Getting Started Guide&lt;/span&gt;&lt;/a&gt;. Click on the Volumes and Snapshots tab and then the create icon. Enter the size in GB (I chose 10) and also choose an availability zone. This is important since you can only attach EBS volumes in the same availability zone as your EC2 instance. My instance was in the us-east-1b zone so I chose that. &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;Now that I have the EBS volume I attached it to my instance by going to the Instances tab in Elasticfox, right clicking on my instance, and choose Attach an EBS volume. I gave it a device name of /dev/sdf1. Next I need to format the volume as a file system before I can use it so I issue (as root):&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ mkfs.ext3 /dev/sdf1&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_VnsRKsEcy_c/SbqKLU6x6cI/AAAAAAAAACM/VLV84NuvG0o/s1600-h/CreateVolume.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5312710637635365314" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 175px" alt="" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/SbqKLU6x6cI/AAAAAAAAACM/VLV84NuvG0o/s400/CreateVolume.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;&lt;strong&gt;Figure 1, Create an EBS volume&lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;Mount it to a temporary place, like:&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ mount /dev/sdf1 /mnt&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;My instance had a mount point of /u02 which contained all of the file necessary for my database including the datafiles, control files, redo log files, etc.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ df -m&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;Filesystem 1M-blocks Used Available Use% Mounted on&lt;br /&gt;/dev/sda1 9647 7116 2042 78% /&lt;br /&gt;none 871 539 332 62% /dev/shm&lt;br /&gt;/dev/sda2 342668 3000 322262 1% /u02&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;I copied all those files to the temporary mount point on /mnt. First I shutdown the database or the files will be unusable.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ su - oracle&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ sqlplus / as sysdba&lt;br /&gt;SQL&amp;gt; shutdown immediate&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;SQL&amp;gt; exit&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ cp /u02/* /mnt/&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ exit #this will return me to the root user&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;Finally I un-mounted the current /u02 mount point and remount /dev/sdf1 to /u02. I only did this to prove I can start the database using the EBS volume with these data files. If I can't start the database using this EBS volume mounted as /u02, I don't want to proceed until I can.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ umount /dev/sda2&lt;br /&gt;$ umount /dev/sdf1&lt;br /&gt;$ mount /dev/sdf1 /u02&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ su - oracle&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ sqlplus / as sysdba&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;SQL&amp;gt; startup&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;In my case, the database started up so I did a shutdown immediate. I un-mounted /dev/sdf1 and then detached the EBS volume from this instance. I kept this instance available until I successfully started the database on the new smaller instance.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;SQL&amp;gt; shutdown immediate&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;SQL&amp;gt; exit&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ exit&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:12;"&gt;&lt;span style="font-family:Courier New;"&gt;$ umount /dev/sdf1&lt;/span&gt;&lt;span style="font-family:Georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;With the database shutdown and the EBS volume detached, I created a snapshot of the volume. The snapshot is a point-in-time backup of the EBS volume and it is stored using Amazon's &lt;a href="http://aws.amazon.com/s3/"&gt;&lt;span style="TEXT-DECORATION: underline;color:blue;" &gt;S3&lt;/span&gt;&lt;/a&gt;. Once I have a snapshot, I can create new EBS volumes based on that snapshot. This gives me the flexibility of shutting down all instances and deleting my EBS volume, and then I only pay S3 storage charges. I can create a new EBS volume based on this snapshot sometime in the future, start an EC2 instance, attach the EBS volume and I am good to go. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_VnsRKsEcy_c/SbqKK9L3iVI/AAAAAAAAACE/b_1Z1lf9sWc/s1600-h/CreateSnapshot.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5312710631264586066" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 201px" alt="" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/SbqKK9L3iVI/AAAAAAAAACE/b_1Z1lf9sWc/s400/CreateSnapshot.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;&lt;strong&gt;Figure 2, Create a snapshot of the EBS volume&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;Next, I started a new instance using the same 11gR1 32 bit AMI on a smaller instance with Elasticfox. It was important that I chose the same availability zone as my EBS volume, us-east-1b. &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_VnsRKsEcy_c/SbqKLu66QiI/AAAAAAAAACU/CxkD8QdsTeI/s1600-h/LaunchSmaller.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5312710644615234082" style="WIDTH: 349px; CURSOR: hand; HEIGHT: 400px" alt="" src="http://1.bp.blogspot.com/_VnsRKsEcy_c/SbqKLu66QiI/AAAAAAAAACU/CxkD8QdsTeI/s400/LaunchSmaller.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;&lt;strong&gt;Figure 3, Launch the smaller EC2 instance&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;I connected to the instance using Putty and chose "No" when asked if I wanted to create a database at this time. This gave me an instance with the Oracle software installed in an Oracle home, but without a database. Now for the magic. I created a /u02 mount point under /, attached the EBS volume to this instance as /dev/sdf1, and then mounted it to /u02. To start the database on this instance I also needed to set my ORACLE_SID environment variable and create symlinks in $ORACLE_HOME/dbs to the spfile and password file in the admin directory on /u02.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ mkdir /u02&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ mount /dev/sdf1 /u02&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ su – oracle&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ export ORACLE_SID=orcl&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ cd $ORACLE_HOME/dbs&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ ln -s /u02/admin/orcl/dbs/spfileorcl.ora spfileorcl.ora&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ ln -s /u02/admin/orcl/dbs/orapworcl orapworcl&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;$ sqlplus / as sysdba&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:12;"&gt;SQL&amp;gt; startup&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Georgia;font-size:12;"&gt;And my database started on the new 10 cent/hour machine!&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-2302654326855835424?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/2302654326855835424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=2302654326855835424' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2302654326855835424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2302654326855835424'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/03/20-cents-hour-whose-got-that-kind-of.html' title='20 cents an hour! Who&apos;s got that kind of dough?'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VnsRKsEcy_c/SbqKLU6x6cI/AAAAAAAAACM/VLV84NuvG0o/s72-c/CreateVolume.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-6263207882130273556</id><published>2009-03-03T13:38:00.000-08:00</published><updated>2010-02-25T08:09:34.384-08:00</updated><title type='text'>Test Drive Oracle Application Express 3.2 for 60 cents (USD)</title><content type='html'>Would you like to kick the tires of Oracle Application Express 3.2 on your own instance but do not have the spare hardware? Do you have 60 cents (USD)? Read on.&lt;br /&gt;&lt;br /&gt;Amazon has a service called the &lt;a href="http://aws.amazon.com/ec2/"&gt;Elastic Compute Cloud&lt;/a&gt; (EC2) where you can fire up virtual machines in the cloud on a whim. They have partnered with other software vendors to provide images with pre-configured software. Oracle is one of those vendors and you can read about the offerings at the &lt;a href="http://www.oracle.com/technology/tech/cloud/index.html"&gt;Oracle Cloud Computing Center &lt;/a&gt;on OTN. Oracle has an image which contains Enterprise Linux and Oracle Database 11g R1.&lt;br /&gt;&lt;br /&gt;The purpose of this post is to describe how I started an 11g R1 instance in the cloud, upgraded it to Application Express 3.2, and then completed the "Converting Your Oracle Forms Applications to Application Express 3.2" and "Utilizing Improved Security Enhancements in Application Express 3.2" Oracle By Example tutorials (OBEs). If you can spare 60 cents you may wish to try this yourself at home.&lt;br /&gt;&lt;p&gt;First, you need to get your &lt;a href="https://aws-portal.amazon.com/gp/aws/developer/registration/index.html"&gt;AWS &lt;/a&gt;account in order. Sign up for AWS at the previous link and then sign up for &lt;a href="http://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?productCode=AmazonEC2"&gt;EC2&lt;/a&gt;. Review the &lt;a href="http://aws.amazon.com/ec2/#pricing"&gt;EC2 pricing &lt;/a&gt;and then establish a &lt;a href="http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=edit-payment-method"&gt;payment method&lt;/a&gt;. If you already are a customer of Amazon.com you can choose one of the credit cards you have on file or establish a new one. Unfortunately, there is no infrastructure in place for you to insert two quarters and a dime for this test drive.&lt;/p&gt;&lt;p&gt;Now you are going to need to get some software to startup an instance, manage it, and transfer files to it. Get the &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=609"&gt;Elasticfox&lt;/a&gt; Firefox plug-in and review the &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1797"&gt;Getting Started Guide&lt;/a&gt;. The Getting Started Guide will give detailed instructions on associating your AWS EC2 account with Elasticfox and also creating a KeyPair that you can use to identify yourself when connecting to the machine. You need to download &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html"&gt;Putty &amp;amp; PuttyGen &lt;/a&gt;to connect to your instance via SSH. You should download &lt;a href="http://winscp.net/eng/download.php"&gt;WinSCP&lt;/a&gt; to transfer files to your instance. Finally you need to download &lt;a href="http://www.oracle.com/technology/products/database/application_express/download.html"&gt;Application Express 3.2&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The keypair that you created when reviewing the Elasticfox Getting Started Guide needs to be converted to a format that can be used by Putty and WinSCP. You can use PuttyGen to create this key. Simply start PuttyGen, click load and browse to find the .pem keypair file you created with Elasticfox, then click Save private key to save it as a .ppk file.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFPrZRLm3I/AAAAAAAAABM/YC7w3Q_3sWA/s1600-h/PuttyGen.jpg"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 385px" id="BLOGGER_PHOTO_ID_5310113042582444914" border="0" alt="" src="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFPrZRLm3I/AAAAAAAAABM/YC7w3Q_3sWA/s400/PuttyGen.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 1, Creating a .ppk from your .pem with PuttyGen.&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You are ready to view &lt;a href="http://www.oracle.com/technology/tech/cloud/demos/oracle_on_ec2_viewlet_swf.htm"&gt;Deploying Oracle Database in the Cloud&lt;/a&gt; viewlet that is available on the &lt;a href="http://www.oracle.com/technology/tech/cloud/index.html"&gt;Oracle Cloud Computing Center&lt;/a&gt; page on OTN. The viewlet will show you how to find and start image ami-cecb2fa7 which is 32bit Enterprise Linux with 11g. It will take you through creating and configuring the database. &lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;I chose to start a c1.medium instance type which costs 20 cents/hr and is described as:&lt;/p&gt;&lt;p&gt;High-CPU Medium Instance 1.7 GB of memory, 5 EC2 Compute Units (2 virtual cores with 2.5 EC2 Compute Units each), 350 GB of instance storage, 32-bit platform &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFTbZ9fiWI/AAAAAAAAABc/4MGKDYibtTo/s1600-h/InstanceDetails.jpg"&gt;&lt;img style="WIDTH: 333px; HEIGHT: 400px" id="BLOGGER_PHOTO_ID_5310117165936904546" border="0" alt="" src="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFTbZ9fiWI/AAAAAAAAABc/4MGKDYibtTo/s400/InstanceDetails.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;strong&gt;Figure 2, Instance Details&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You manage the instance by connecting via SSH and you can use Putty as the viewlet demonstrated. Before you can connect to the machine on port 22 from your computer you will have to specifically allow it from your IP address. In Elasticfox first identify the Security Group used to start the instance. It is most likely called "default" unless you added another Security Group. Click the Security Group tab, highlight default and then click the green checkmark under the Group Permissions pane to add a permission. You can either allow a specific host or a network range. Allow your host to connect on port 22 and then create another permission to allow anyone to connect on port 8080 wich is the default port that EPG will be listening for HTTP requests. You choose Network and allow 0.0.0.0/0.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFpgu1e4ZI/AAAAAAAAABk/JXFRQx4-Oy8/s1600-h/SecurityGroup.jpg"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 339px" id="BLOGGER_PHOTO_ID_5310141446695608722" border="0" alt="" src="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFpgu1e4ZI/AAAAAAAAABk/JXFRQx4-Oy8/s400/SecurityGroup.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;Figure 3, Creating a Security Group&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Before logging in to Oracle Application Express on this instance, I had to change the password for the Application Express ADMIN account by following these steps (which changed the password to oracle):&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;su - oracle&lt;br /&gt;sqlplus / as sysdba&lt;br /&gt;SQL&gt; @?/apex/apxxepwd oracle&lt;/span&gt;&lt;/p&gt;Login to Oracle Application Express and create a workspace.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFq6jSKwAI/AAAAAAAAABs/URkFzSjiA-A/s1600-h/CreateWorkspace.jpg"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 306px" id="BLOGGER_PHOTO_ID_5310142989782925314" border="0" alt="" src="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFq6jSKwAI/AAAAAAAAABs/URkFzSjiA-A/s400/CreateWorkspace.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Figure 4, Create a Workspace&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Now for the fun part. Start WinSCP and connect to your instance and copy apex_3.2.zip there.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFsK9rxsTI/AAAAAAAAAB0/YSnpsAlSje8/s1600-h/Copyapex32.jpg"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 306px" id="BLOGGER_PHOTO_ID_5310144371259191602" border="0" alt="" src="http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFsK9rxsTI/AAAAAAAAAB0/YSnpsAlSje8/s400/Copyapex32.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Figure 5, Copy apex_3.2.zip to your instance&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Return to your Putty terminal session connected to your instance and install Oracle Application Express 3.2:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;su - oracle&lt;br /&gt;unzip apex_3.2.zip&lt;br /&gt;cd apex&lt;br /&gt;sqlplus / as sysdba&lt;br /&gt;SQL&gt;@apexins SYSAUX SYSAUX TEMP /i/&lt;br /&gt;SQL&gt;@apxldimg /home/oracle&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Follow Joel's &lt;a href="http://joelkallman.blogspot.com/2009/02/make-all-of-your-apex-applications-run.html"&gt;blog post&lt;/a&gt; on making Application Express run faster. You are ready to complete the &lt;a href="http://www.oracle.com/technology/obe/apex32/apex32frmmigr.htm"&gt;Converting Your Oracle Forms Applications to Application Express 3.2&lt;/a&gt; and &lt;a href="http://www.oracle.com/technology/obe/apex32/apex32sec.htm"&gt;Utilizing Improved Security Enhancements in Application Express 3.2&lt;/a&gt; Oracle by Example (OBE) tutorials. An easy way to get the files for the Forms OBE to your machine is to run the following command in your terminal session:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;wget &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;http://www.oracle.com/technology/obe/apex32/files/forms_conversion.zip&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_VnsRKsEcy_c/SbFwOCTKl1I/AAAAAAAAAB8/n5rkpzyUe4E/s1600-h/32Instance.jpg"&gt;&lt;img style="WIDTH: 400px; HEIGHT: 306px" id="BLOGGER_PHOTO_ID_5310148822084261714" border="0" alt="" src="http://2.bp.blogspot.com/_VnsRKsEcy_c/SbFwOCTKl1I/AAAAAAAAAB8/n5rkpzyUe4E/s400/32Instance.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 6, Application Express 3.2 in the Cloud!&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So there you have it. Test drive your own instance of Oracle Application Express 3.2 for around 60 cents (USD). For a limited time (until my manger finds out), you can try out my cloud instance using the following application linked below. I have configured my cloud instance to use the APEX Listener, which is a Java based HTTP listener that should release with the next version of Oracle Application Express.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-6263207882130273556?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/6263207882130273556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=6263207882130273556' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6263207882130273556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/6263207882130273556'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/03/test-drive-oracle-application-express.html' title='Test Drive Oracle Application Express 3.2 for 60 cents (USD)'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VnsRKsEcy_c/SbFPrZRLm3I/AAAAAAAAABM/YC7w3Q_3sWA/s72-c/PuttyGen.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-4933292741879835308</id><published>2009-02-20T11:05:00.000-08:00</published><updated>2009-02-26T06:30:32.228-08:00</updated><title type='text'>RMOUG, Kaleidoscope 2009, Slight Change to flex_ws_api</title><content type='html'>I know that I am horribly overdue for a post. I was out at the &lt;a href="http://rmoug.org/training.htm"&gt;RMOUG Training Days &lt;/a&gt;last week and presented on Integrating Web Services and Application Express. The presentation should be linked from the referenced page soon. Unfortunately I only had 60 minutes to present 90 minutes worth of material. I presented on integrating Web services created from JDeveloper, XDB Native Web Services, BPEL Web services and finally integration with Oracle Content Server (formerly Stellent). The presentation was supposed to end with a discussion of debugging techniques using a variety of tools such as &lt;a href="http://www.soapui.org/"&gt;SOAPUI&lt;/a&gt;, &lt;a href="http://www.pocketsoap.com/tcptrace/pt.aspx"&gt;ProxyTrace &lt;/a&gt;and &lt;a href="http://www.altova.com/products/xmlspy/xml_editor.html"&gt;XMLSpy&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Luckily, I will be presenting at the &lt;a href="http://www.odtugkaleidoscope.com/index.html"&gt;ODTUG Kaleidoscope 2009 &lt;/a&gt;in Monterey California in June. I have 90 minutes so I will be able to get to the debugging topics. Please join me if you can swing it.&lt;br /&gt;&lt;br /&gt;Lastly, I have made a couple of minor tweeks to flex_ws_api. The changes allow for a more graceful response from parse_xml and parse_xml_clob if the node is not found using the supplied Xpath expression. It now simply returns null.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-4933292741879835308?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/4933292741879835308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=4933292741879835308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/4933292741879835308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/4933292741879835308'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2009/02/rmoug-kaleidoscope-2009-slight-change.html' title='RMOUG, Kaleidoscope 2009, Slight Change to flex_ws_api'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-4453346675323227298</id><published>2008-12-04T13:46:00.000-08:00</published><updated>2008-12-04T14:10:05.098-08:00</updated><title type='text'>More Changes to flex_ws_api</title><content type='html'>I added three new functions to the flex_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;ws&lt;/span&gt;_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;api&lt;/span&gt;. The most significant is the new make_request function which is just like the procedure with the same name but returns an XML type instead of storing the results in a collection. It became apparent to me that you may want to make a request without storing the results in a collection. In my particular case, I was working on a sample application for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;BiPublisher&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;BiPublisher&lt;/span&gt; has a service called the &lt;a href="http://download.oracle.com/docs/cd/E10383_01/doc/bip.1013/e10416/bip_webservice_101331.htm"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;PublicReportService&lt;/span&gt;&lt;/a&gt;. Tyler &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Muth&lt;/span&gt; has &lt;a href="http://tylermuth.wordpress.com/2008/03/31/call-bi-publisher-web-services-from-apex/"&gt;blogged about&lt;/a&gt; using the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;scheduleReport&lt;/span&gt; operation to schedule a report to be run and delivered vi email or ftp from an Application Express interface. But what if you want the report right now and allow for downloading it directly from that application? There is a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;runReport&lt;/span&gt; operation of the service to allow just that. It returns the report base64 encoded, and you just have to write a process to convert that to a BLOB and download it. No problem!&lt;br /&gt;&lt;br /&gt;I set out to build a sample application that would do just that. I noticed that there was an operation called &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;validateLogin&lt;/span&gt; so I thought maybe I could create a custom authentication scheme using flex_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ws&lt;/span&gt;_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;api&lt;/span&gt; to validate the user by making a call to the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;PublicReportService&lt;/span&gt;. That is when I realized that storing the result in a collection won't do any good if the user does not have a valid session yet. So there was a need for a function to return the results as an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;XMLType&lt;/span&gt;. I also added two functions to parse out the results of the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;XMLType&lt;/span&gt;, parse_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;xml&lt;/span&gt; and parse_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;xml&lt;/span&gt;_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;clob&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I was successful in building the custom authentication scheme after I added these functions. I was also successful in building the rest of the application. You &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;login using the validateLogin operation&lt;/span&gt;, view and traverse folders from the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;BiPublisher&lt;/span&gt; repository using the getFolderContents operation, and click on links to download the report using the runReport operation, all in an Application Express application. I plan to make the sample application &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_19"&gt;available&lt;/span&gt; on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;OTN&lt;/span&gt; along with a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_21"&gt;white paper&lt;/span&gt; on how it was built. Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-4453346675323227298?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/4453346675323227298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=4453346675323227298' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/4453346675323227298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/4453346675323227298'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/12/more-changes-to-flexwsapi.html' title='More Changes to flex_ws_api'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-3547874992190460268</id><published>2008-11-10T11:46:00.000-08:00</published><updated>2008-11-11T07:10:24.733-08:00</updated><title type='text'>The New flex_ws_api and SOAP 1.2 Example</title><content type='html'>Before I make wild claims like the one I made on October 22, where I said "flex_ws_api now supports SOAP 1.2" I probably should have tested the code against a SOAP 1.2 service. I can now say that I have tested it with a SOAP 1.2 service and I learned a couple of things.&lt;br /&gt;&lt;br /&gt;Firstly, when setting the content-type header, the action must appear after the charset declaration or you will get an unsupported media type error from the service. Secondly, there may be an occasion where you have base 64 encoded character data and you want to convert that into binary data, for example, providing the ability to download a document.&lt;br /&gt;&lt;br /&gt;Based on these two findings, I have updated the flex_ws_api code available below to set the content-type header properly and added a function called clobbase642blob that takes in a base64 encoded clob and returns a blob.&lt;br /&gt;&lt;br /&gt;The services that I tested with are the &lt;a href="http://download.oracle.com/docs/cd/E13789_01/bh.100/e13800/web_services_intro.htm#sthref18"&gt;Oracle Beehive web services&lt;/a&gt;. Oracle Beehive "is a collaborative environment built on a unique model that combines the various communication and coordination services into a comprehensive platform." You can test these services via an HTTP interface which came in very handy when I needed to know the structure of the SOAP 1.2 envelope that each service expected. The services that I interacted with were the WorkspaceService to get a list of folders in a workspace and the DocumentService to get a list of documents in a particular folder.&lt;br /&gt;&lt;br /&gt;The application I built was a simple three page application. The first page showed a list of folders in the workspaces that the logged in user belongs to. Each folder linked to the second page which would then show the contents of that folder. Each document linked to the third page which has a before header process that downloads the document.&lt;br /&gt;&lt;br /&gt;Start by creating an Application Express application with one blank page. Make sure you have compiled the new flex_ws_api in the schema associated with this workspace. Call the blank page something like Get Folders. The first thing to do is to create a before header process on the page to use the flex_ws_api and call the WorkspaceService, operation GetWorkspaces based on the currently logged in user. See the code listing.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code Listing 1, Call GetWorkspaces Before Header Process on Page 1&lt;/strong&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;declare&lt;br /&gt;  l_env clob;&lt;br /&gt;begin&lt;br /&gt;  l_env := '&amp;lt;soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&amp;gt;&amp;lt;soap:Header&amp;gt;&amp;lt;wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:env="http://www.w3.org/2003/05/soap-envelope" soap:mustUnderstand="1"&amp;gt;&amp;lt;wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&amp;gt;&amp;lt;wsse:Username&amp;gt;'||:APP_USER||'&amp;lt;/wsse:Username&amp;gt;&amp;lt;wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"&amp;gt;Welcome1&amp;lt;/wsse:Password&amp;gt;&amp;lt;/wsse:UsernameToken&amp;gt;&amp;lt;/wsse:Security&amp;gt;&amp;lt;/soap:Header&amp;gt;&lt;br /&gt;    &amp;lt;soap:Body xmlns:ns1="http://oracle.bee.platform.webservice/"&amp;gt;&lt;br /&gt;        &amp;lt;ns1:GetWorkspaces&amp;gt;&lt;br /&gt;            &amp;lt;ns1:uID xmlns:ns2="http://www.w3.org/2001/XMLSchema-instance" ns2:nil="true"/&amp;gt;&lt;br /&gt;            &amp;lt;ns1:wspType&amp;gt;TEAM&amp;lt;/ns1:wspType&amp;gt;&lt;br /&gt;            &amp;lt;ns1:wspFilter xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:nil="true"/&amp;gt;&lt;br /&gt;        &amp;lt;/ns1:GetWorkspaces&amp;gt;&lt;br /&gt;    &amp;lt;/soap:Body&amp;gt;&lt;br /&gt;&amp;lt;/soap:Envelope&amp;gt;';&lt;br /&gt;&lt;br /&gt;  flex_ws_api.make_request(&lt;br /&gt;    p_url =&gt; 'http://localhost:7777/ws/WorkspaceService',&lt;br /&gt;    p_version =&gt; '1.2',&lt;br /&gt;    p_collection_name =&gt; 'GETWORKSPACES_RESPONSE',&lt;br /&gt;    p_envelope =&gt; l_env );&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One thing to note about the process above is that we are passing the username in the envelope using :APP_USER to reference the currently logged in user. Whatever authentication method your application uses will have to also be a user in the Beehive world. The second thing to note is that the password is hardcoded to Welcome1. You will obviously need to change this to be dynamic and based on the user. Finally, we are storing the response from the Beehive service in an Application Express collection called GETWORKSPACES_RESPONSE.&lt;br /&gt;&lt;br /&gt;Now that the page has a process to call the web service you create a report region to show the folders in the workspace for this particular user based on the web service result. You do this by writing a query that first casts the clob001 column in the Application Express collection to an xmltype and then use the table command to shred the document. See the code listing.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code Listing 2, Report on Result to Show Folders, Page 1&lt;/strong&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;select wwv_flow_utilities.url_encode2(extractValue(value(t),'/*/id','xmlns="http://oracle.bee.platform.webservice/"')) "id"&lt;br /&gt;     , extractValue(value(t),'/*/name','xmlns="http://oracle.bee.platform.webservice/"') "name"&lt;br /&gt;     , extractValue(value(t),'/*/description','xmlns="http://oracle.bee.platform.webservice/"') "description"&lt;br /&gt; from wwv_flow_collections c,&lt;br /&gt;      table(xmlsequence(extract(xmltype.createxml(c.clob001),'//GetWorkspacesResponse/return/libraryIDList','xmlns="http://oracle.bee.platform.webservice/"'))) t&lt;br /&gt;where c.collection_name = 'GETWORKSPACES_RESPONSE'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One thing to note is that the id column might contain colons and slashes, so the report calls wwv_flow_utilities.url_encode2 to encode these characters. You will modify this report slightly to hide the id column and then link the folder name to page 2 which makes the encoding trick necessary. You first create page two.&lt;br /&gt;&lt;br /&gt;Page two of the application calls the DocumentService and the GetDocumentsInFolder operation based on the value of a hidden item to hold the ID of the folder.&lt;br /&gt;&lt;br /&gt;First create a new blank page (page 2). Add a before header process that uses the flex_ws_api to call the DocumentService as in the following code listing.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code Listing 3, Call GetDocumentsInFolder Before Header Process, Page 2&lt;/strong&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;declare&lt;br /&gt;  l_env clob;&lt;br /&gt;begin&lt;br /&gt;  l_env := '&amp;lt;soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&amp;gt;&amp;lt;soap:Header&amp;gt;&amp;lt;wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:env="http://www.w3.org/2003/05/soap-envelope" soap:mustUnderstand="1"&amp;gt;&amp;lt;wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&amp;gt;&amp;lt;wsse:Username&amp;gt;'||:APP_USER||'&amp;lt;/wsse:Username&amp;gt;&amp;lt;wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"&amp;gt;Welcome1&amp;lt;/wsse:Password&amp;gt;&amp;lt;/wsse:UsernameToken&amp;gt;&amp;lt;/wsse:Security&amp;gt;&amp;lt;/soap:Header&amp;gt;&lt;br /&gt;    &amp;lt;soap:Body xmlns:ns1="http://oracle.bee.platform.webservice/"&amp;gt;&lt;br /&gt;        &amp;lt;ns1:GetDocumentsInFolder&amp;gt;&lt;br /&gt;            &amp;lt;ns1:folderID&amp;gt;&lt;br /&gt;                &amp;lt;ns1:type xmlns:ns2="http://www.w3.org/2001/XMLSchema-instance" ns2:nil="true"/&amp;gt;&lt;br /&gt;                &amp;lt;ns1:description xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:nil="true"/&amp;gt;&lt;br /&gt;                &amp;lt;ns1:name xmlns:ns4="http://www.w3.org/2001/XMLSchema-instance" ns4:nil="true"/&amp;gt;&lt;br /&gt;                &amp;lt;ns1:id&amp;gt;'||wwv_flow_utilities.url_decode2(:P2_FOLDER_ID)||'&amp;lt;/ns1:id&amp;gt;&lt;br /&gt;            &amp;lt;/ns1:folderID&amp;gt;&lt;br /&gt;            &amp;lt;ns1:docFilter xmlns:ns5="http://www.w3.org/2001/XMLSchema-instance" ns5:nil="true"/&amp;gt;&lt;br /&gt;        &amp;lt;/ns1:GetDocumentsInFolder&amp;gt;&lt;br /&gt;    &amp;lt;/soap:Body&amp;gt;&lt;br /&gt;&amp;lt;/soap:Envelope&amp;gt;';&lt;br /&gt;&lt;br /&gt;  flex_ws_api.make_request(&lt;br /&gt;    p_url =&gt; 'http://localhost:7777/ws/DocumentService',&lt;br /&gt;    p_version =&gt; '1.2',&lt;br /&gt;    p_collection_name =&gt; 'GETDOCUMENTS_RESPONSE',&lt;br /&gt;    p_envelope =&gt; l_env );&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the process calls wwv_flow_utilities.url_decode2 to decode the folder id, which we needed to encode on the prior page, because it was being passed as part of the link. The response is stored in a collection called GETDOCUMENTS_RESPONSE.&lt;br /&gt;&lt;br /&gt;The next thing to do is the create a report region that reports on the results of the web service much like page one. See the code listing.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code Listing 4, Report on GetDocumentsInFolder Result to List Documents&lt;/strong&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;select wwv_flow_utilities.url_encode2(extractValue(value(t),'/*/contentID/id','xmlns="http://oracle.bee.platform.webservice/"')) "id"&lt;br /&gt;     , extractValue(value(t),'/*/content/name','xmlns="http://oracle.bee.platform.webservice/"') "name"&lt;br /&gt;     , extractValue(value(t),'/*/mimeMultipartType','xmlns="http://oracle.bee.platform.webservice/"') "type"&lt;br /&gt; from wwv_flow_collections c,&lt;br /&gt;      table(xmlsequence(extract(xmltype.createxml(c.clob001),'//GetDocumentsInFolderResponse/return','xmlns="http://oracle.bee.platform.webservice/"'))) t&lt;br /&gt;where c.collection_name = 'GETDOCUMENTS_RESPONSE'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, create a hidden item on page two called P2_FOLDER_ID for the folder id.&lt;br /&gt;&lt;br /&gt;Now we return to page one and edit the report region to link the folder name to page two, populating the P2_FOLDER_ID item. To accomplish this:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Click the Report link next to the Folders region&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uncheck the Show check box corresponding to the id column&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click the edit icon next to the name column&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Scroll down to the Column Link region&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click the [name] quick link below the Link Text field &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose Page in this Application from the Target list&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Enter 2 in the Page field&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose P2_FOLDER_ID for Item 1 from the pop-up list&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose #id# for Value from the pop-up list&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click Apply Changes&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 1, Column Link Attributes for Folder Name&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_VnsRKsEcy_c/SRilX18xm9I/AAAAAAAAAAM/uimwS9tHVUs/s1600-h/BeehiveFigure1.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5267141593247357906" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 208px" alt="" src="http://3.bp.blogspot.com/_VnsRKsEcy_c/SRilX18xm9I/AAAAAAAAAAM/uimwS9tHVUs/s400/BeehiveFigure1.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;At this point, you should be able to run the application, see a list of folders, click on a folder, and see the contents of the folder.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 2, List of Folders&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_VnsRKsEcy_c/SRioiqvsWsI/AAAAAAAAAAU/FgNxelWw-eE/s1600-h/BeehiveFigure2.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5267145077753141954" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 221px" alt="" src="http://1.bp.blogspot.com/_VnsRKsEcy_c/SRioiqvsWsI/AAAAAAAAAAU/FgNxelWw-eE/s400/BeehiveFigure2.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 3, List of Contents of Folder&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_VnsRKsEcy_c/SRioi78UBtI/AAAAAAAAAAc/Qzci7cxcJXo/s1600-h/BeehiveFigure3.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5267145082369476306" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 224px" alt="" src="http://2.bp.blogspot.com/_VnsRKsEcy_c/SRioi78UBtI/AAAAAAAAAAc/Qzci7cxcJXo/s400/BeehiveFigure3.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;The response from calling the DocumentService GetDocumentsInFolder operation is not only a listing of the documents there but also the data of the documents encoded in base64. Luckily, we can now convert the base64 clob into a blob which allows us to create another page in the application which will download the document.&lt;br /&gt;&lt;br /&gt;Create a new blank page (3) in the application. Create an empty HTML region to hold a hidden item for the document ID. Create a hidden item on page 3 called P3_DOCUMENT_ID.&lt;br /&gt;&lt;br /&gt;Now create a before header process that will parse the response of GetDocumentsInFolder and determine the size, mime type, name and base64 encoded data. Convert the base64 encoded data to a blob, and then use wpg_docload.download_file procedure to download the file. Use the code in the following listing to create the process.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Code listing 5, Download Document Before Header Process, Page 3&lt;/strong&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;declare&lt;br /&gt;  l_mime      varchar2(48);&lt;br /&gt;  l_name      varchar2(4000);&lt;br /&gt;  l_base64    clob;&lt;br /&gt;  l_blob      blob;&lt;br /&gt;  l_size      varchar2(255);&lt;br /&gt;begin&lt;br /&gt;  l_size := flex_ws_api.parse_response('GETDOCUMENTS_RESPONSE','//ns0:GetDocumentsInFolderResponse/ns0:return[ns0:contentID/ns0:id/text()="'||wwv_flow_utilities.url_decode2(:P3_DOCUMENT_ID)||'"]/ns0:content/ns0:size/text()','xmlns:ns0="http://oracle.bee.platform.webservice/"');&lt;br /&gt;&lt;br /&gt;  l_mime := flex_ws_api.parse_response('GETDOCUMENTS_RESPONSE','//ns0:GetDocumentsInFolderResponse/ns0:return[ns0:contentID/ns0:id/text()="'||wwv_flow_utilities.url_decode2(:P3_DOCUMENT_ID)||'"]/ns0:content/ns0:mediaType/text()','xmlns:ns0="http://oracle.bee.platform.webservice/"');&lt;br /&gt;&lt;br /&gt;  l_name := flex_ws_api.parse_response('GETDOCUMENTS_RESPONSE','//ns0:GetDocumentsInFolderResponse/ns0:return[ns0:contentID/ns0:id/text()="'||wwv_flow_utilities.url_decode2(:P3_DOCUMENT_ID)||'"]/ns0:content/ns0:name/text()','xmlns:ns0="http://oracle.bee.platform.webservice/"');&lt;br /&gt;&lt;br /&gt;  l_base64 := flex_ws_api.parse_response_clob('GETDOCUMENTS_RESPONSE','//ns0:GetDocumentsInFolderResponse/ns0:return[ns0:contentID/ns0:id/text()="'||wwv_flow_utilities.url_decode2(:P3_DOCUMENT_ID)||'"]/ns0:content/ns0:data/text()','xmlns:ns0="http://oracle.bee.platform.webservice/"');&lt;br /&gt;&lt;br /&gt;  l_blob := flex_ws_api.clobbase642blob(l_base64);&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;  htp.init;&lt;br /&gt;&lt;br /&gt;  owa_util.mime_header( nvl(l_mime,'application/octet'), FALSE );&lt;br /&gt;  htp.p('Content-length: '||l_size);&lt;br /&gt;  htp.p('Content-Disposition:  attachment; filename="'||replace(replace(l_name,chr(10),null),chr(13),null)||'"');&lt;br /&gt;  owa_util.http_header_close;&lt;br /&gt;  wpg_docload.download_file( l_blob );&lt;br /&gt; &lt;br /&gt;  apex_application.g_unrecoverable_error := true;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The final step is to modify the report attributes of the report region on page 2, hide the id column and link the name column to page 3, populating the P3_DOCUMENT_ID item like you did on page one for the link from the folder name. Once you have completed this step, you will have a simple three page application the shows a list of folders of workspaces that the currently logged in user belongs to, shows the contents of the folders when click on, and then downloads the document when clicked on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-3547874992190460268?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/3547874992190460268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=3547874992190460268' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3547874992190460268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3547874992190460268'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/11/new-flexwsapi-and-soap-12-example.html' title='The New flex_ws_api and SOAP 1.2 Example'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VnsRKsEcy_c/SRilX18xm9I/AAAAAAAAAAM/uimwS9tHVUs/s72-c/BeehiveFigure1.jpg' height='72' width='72'/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-251207001566944879</id><published>2008-10-22T12:47:00.000-07:00</published><updated>2008-10-22T13:01:57.722-07:00</updated><title type='text'>flex_ws_api Now Supports SOAP 1.2</title><content type='html'>I recently became aware that not only is the message and envelope format of SOAP 1.2 different from SOAP 1.1, but also the Content-Type HTTP header as well. If you send the Content-Type of a SOAP 1.1 message, text/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;xml&lt;/span&gt; to a SOAP 1.2 document, you will get a message back, formatted in SOAP 1.1 saying that there is a version mismatch. SOAP 1.2 expects a Content-Type HTTP Header like the following (note the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SOAPAction&lt;/span&gt; is also on this line and shortened to action):&lt;br /&gt;&lt;br /&gt;Content-Type: application/soap+&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;xml&lt;/span&gt;; action=initiate; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;charset&lt;/span&gt;="&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;utf&lt;/span&gt;-8"&lt;br /&gt;&lt;br /&gt;The flex_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;ws&lt;/span&gt;_&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;api&lt;/span&gt; now accepts a p_version &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_7"&gt;parameter&lt;/span&gt; which is defaulted to '1.1', but if '1.2' is passed, the proper Content-Type header will be sent for a SOAP 1.2 message.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-251207001566944879?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/251207001566944879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=251207001566944879' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/251207001566944879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/251207001566944879'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/10/flexwsapi-now-supports-soap-12.html' title='flex_ws_api Now Supports SOAP 1.2'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-2814430393288780802</id><published>2008-09-30T12:23:00.000-07:00</published><updated>2008-10-02T07:27:24.412-07:00</updated><title type='text'>APEXposed 2008</title><content type='html'>I will be presenting at APEXposed 2008, October 29 - 30, at Chicago O'Hare Wyndham. I am going to present on everything Application Express and Web services. You can view the abstract here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.odtugapextraining.com/presentations.html#IntegratingWebServices"&gt;http://www.odtugapextraining.com/presentations.html#IntegratingWebServices&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Register for the event here:&lt;br /&gt;&lt;br /&gt;&lt;a title="blocked::http://www.technicalconferencesolutions.com/ODTUG_OPP_registration.html" href="http://www.technicalconferencesolutions.com/ODTUG_OPP_registration.html"&gt;http://www.technicalconferencesolutions.com/ODTUG_OPP_registration.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Hope you can make it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-2814430393288780802?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/2814430393288780802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=2814430393288780802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2814430393288780802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2814430393288780802'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/09/apexposed-2008.html' title='APEXposed 2008'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-874955882659383311</id><published>2008-06-13T09:57:00.000-07:00</published><updated>2008-06-13T10:03:13.981-07:00</updated><title type='text'>NTLM and Application Express Whitepaper</title><content type='html'>There is now an official &lt;a href="http://www.oracle.com/technology/products/database/application_express/pdf/apex_ntlm_authentication_wp.pdf"&gt;whitepaper on OTN &lt;/a&gt;written about NTLM authentication and Application Express by a colleague of mine, Priyanka Sharma. The paper is very good and gives a good introduction and definition of NTLM. The page sentry function is based on the NTLM posting here with some fine contributions by &lt;a href="http://www.inside-oracle-apex.com/"&gt;Patrick Wolf&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-874955882659383311?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/874955882659383311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=874955882659383311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/874955882659383311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/874955882659383311'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/06/ntlm-and-application-express-whitepaper.html' title='NTLM and Application Express Whitepaper'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-3976833452947771665</id><published>2008-06-06T12:12:00.000-07:00</published><updated>2010-06-04T10:38:36.983-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='APEX'/><title type='text'>Flexible Web Service API</title><content type='html'>&lt;strong&gt;Update 11/20/2009: &lt;/strong&gt;The flex_ws_api is now managed and updated at &lt;a href="https://flex-ws-api.samplecode.oracle.com/"&gt;https://flex-ws-api.samplecode.oracle.com/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have often been hounded by a colleague, &lt;a href="http://tylermuth.wordpress.com/"&gt;Tyler Muth&lt;/a&gt;, about creating some type of programmatic support for Web services in Application Express. Tyler's reasons are good ones, for example, being able to call a Web service to populate a temporary table that is used for an LOV in an application. He has had other customers that want to create an authentication scheme based on a Web service. And finally, the reason that actually got me to work on a flexible Web service API, is that you cannot post large base64 encoded binary information to a Web service because you are limited to 32K when you reference an item value in Application Express.&lt;br /&gt;&lt;br /&gt;I worked with some other colleagues on creating an Application Express application that can checkin a document to a Stellent repository through Stellent's Web service API's. We wanted to be able to checkin documents whose base64 encoding was larger than 32K bytes. I could not use Application Express's built-in support for Web services because of that requirement. My only option was to hand code a PL/SQL process that does all the necessary things to post a very large SOAP envelope to a service, and parse out the response.&lt;br /&gt;&lt;br /&gt;I recently revisited that PL/SQL code and created a flexible Web service API that can be used to call any Web service programmatically with Application Express. You are responsible for building up the request envelope as a CLOB. I use a tool called &lt;a href="http://soapui.org/"&gt;SOAPUI&lt;/a&gt; to help me build a SOAP request envelope. You create a new project based on a WSDL, and the tool will create shell envelopes for all operations that the service supports as defined in the WSDL.&lt;br /&gt;&lt;br /&gt;The API supports basic HTTP authentication, a proxy server override (great for debugging), wallets for contacting services with HTTPS, and a colon delimited list of name value pairs that will be sent as HTTP headers with the request. This was added for maximum flexibility to support custom authentication with Web services among other things. See the code listing below. It also contains helper functions to take a BLOB and base64 encode it into a CLOB (very useful if you have a service that you need to pass a document or attachment to) as well as functions to anaylze a response and return the text in varchar or clob format.&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create or replace package flex_ws_api&lt;br /&gt;as&lt;br /&gt;&lt;br /&gt;empty_vc_arr wwv_flow_global.vc_arr2;&lt;br /&gt;&lt;br /&gt;g_request_cookies   utl_http.cookie_table;&lt;br /&gt;g_response_cookies  utl_http.cookie_table;&lt;br /&gt;&lt;br /&gt;type header is record (name varchar2(256), value varchar2(1024));&lt;br /&gt;type header_table is table of header index by binary_integer;&lt;br /&gt;&lt;br /&gt;g_headers           header_table;&lt;br /&gt;g_request_headers   header_table;&lt;br /&gt;&lt;br /&gt;g_status_code       pls_integer;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function blob2clobbase64 (&lt;br /&gt;    p_blob in blob ) return clob;&lt;br /&gt;&lt;br /&gt;function clobbase642blob (&lt;br /&gt;    p_clob in clob ) return blob;&lt;br /&gt;&lt;br /&gt;procedure make_request (&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_action            in varchar2 default null,&lt;br /&gt;    p_version           in varchar2 default '1.1',&lt;br /&gt;    p_collection_name   in varchar2 default null,&lt;br /&gt;    p_envelope          in clob,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null,&lt;br /&gt;    p_extra_headers     in wwv_flow_global.vc_arr2 default empty_vc_arr );&lt;br /&gt;&lt;br /&gt;function make_request (&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_action            in varchar2 default null,&lt;br /&gt;    p_version           in varchar2 default '1.1',&lt;br /&gt;    p_envelope          in clob,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null,&lt;br /&gt;    p_extra_headers     in wwv_flow_global.vc_arr2 default empty_vc_arr ) return xmltype;&lt;br /&gt;&lt;br /&gt;function make_rest_request(&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_http_method       in varchar2,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_body              in clob default empty_clob(),&lt;br /&gt;    p_body_blob         in blob default empty_blob(),&lt;br /&gt;    p_parm_name         in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_parm_value        in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_http_headers      in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_http_hdr_values   in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null ) return clob;&lt;br /&gt;&lt;br /&gt;function parse_xml (&lt;br /&gt;    p_xml               in xmltype,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return varchar2;&lt;br /&gt;&lt;br /&gt;function parse_xml_clob (&lt;br /&gt;    p_xml               in xmltype,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return clob;&lt;br /&gt;&lt;br /&gt;function parse_response (&lt;br /&gt;    p_collection_name   in varchar2,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return varchar2;&lt;br /&gt;&lt;br /&gt;function parse_response_clob (&lt;br /&gt;    p_collection_name   in varchar2,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return clob;&lt;br /&gt;&lt;br /&gt;end flex_ws_api;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;br /&gt;create or replace package body flex_ws_api&lt;br /&gt;as&lt;br /&gt;&lt;br /&gt;function blob2clobbase64 (&lt;br /&gt;    p_blob in blob ) return clob&lt;br /&gt;is&lt;br /&gt;    pos         pls_integer         := 1;&lt;br /&gt;    buffer      varchar2 (32767);&lt;br /&gt;    res         clob;&lt;br /&gt;    lob_len     integer             := dbms_lob.getlength (p_blob);&lt;br /&gt;    l_width     pls_integer         := (76 / 4 * 3)-9;&lt;br /&gt;begin&lt;br /&gt;    dbms_lob.createtemporary (res, true);&lt;br /&gt;    dbms_lob.open (res, dbms_lob.lob_readwrite);&lt;br /&gt;&lt;br /&gt;    while (pos &lt; lob_len) loop&lt;br /&gt;        buffer :=&lt;br /&gt;                utl_raw.cast_to_varchar2&lt;br /&gt;                 (utl_encode.base64_encode (dbms_lob.substr (p_blob, l_width, pos)));&lt;br /&gt;&lt;br /&gt;        dbms_lob.writeappend (res, length (buffer), buffer);&lt;br /&gt;&lt;br /&gt;        pos := pos + l_width;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    return res;&lt;br /&gt;&lt;br /&gt;end blob2clobbase64;&lt;br /&gt;&lt;br /&gt;function clobbase642blob (&lt;br /&gt;    p_clob in clob ) return blob&lt;br /&gt;is&lt;br /&gt;    pos         pls_integer         := 1;&lt;br /&gt;    buffer      raw(36);&lt;br /&gt;    res         blob;&lt;br /&gt;    lob_len     integer             := dbms_lob.getlength (p_clob);&lt;br /&gt;    l_width     pls_integer         := (76 / 4 * 3)-9;&lt;br /&gt;begin&lt;br /&gt;    dbms_lob.createtemporary (res, true);&lt;br /&gt;    dbms_lob.open (res, dbms_lob.lob_readwrite);&lt;br /&gt;&lt;br /&gt;    while (pos &lt; lob_len) loop&lt;br /&gt;        buffer := utl_encode.base64_decode(utl_raw.cast_to_raw(dbms_lob.substr (p_clob, l_width, pos)));&lt;br /&gt;&lt;br /&gt;        dbms_lob.writeappend (res, utl_raw.length(buffer), buffer);&lt;br /&gt;&lt;br /&gt;        pos := pos + l_width;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    return res;&lt;br /&gt;&lt;br /&gt;end clobbase642blob;&lt;br /&gt;&lt;br /&gt;procedure make_request (&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_action            in varchar2 default null,&lt;br /&gt;    p_version           in varchar2 default '1.1',&lt;br /&gt;    p_collection_name   in varchar2 default null,&lt;br /&gt;    p_envelope          in clob,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null,&lt;br /&gt;    p_extra_headers     in wwv_flow_global.vc_arr2 default empty_vc_arr )&lt;br /&gt;is&lt;br /&gt;    l_clob clob;&lt;br /&gt;    l_http_req utl_http.req;&lt;br /&gt;    l_http_resp utl_http.resp;&lt;br /&gt;    l_amount binary_integer := 8000;&lt;br /&gt;    l_offset integer := 1;&lt;br /&gt;    l_buffer varchar2(32000);&lt;br /&gt;    l_db_charset   varchar2(100);&lt;br /&gt;    l_env_lenb integer := 0;&lt;br /&gt;    i integer := 0;&lt;br /&gt;    l_headers wwv_flow_global.vc_arr2;&lt;br /&gt;    l_response varchar2(2000);&lt;br /&gt;    l_name          varchar2(256);&lt;br /&gt;    l_hdr_value     varchar2(1024);&lt;br /&gt;    l_hdr           header;&lt;br /&gt;    l_hdrs          header_table;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    -- determine database characterset, if not AL32UTF8, conversion will be necessary&lt;br /&gt;    select value into l_db_charset from nls_database_parameters where parameter='NLS_CHARACTERSET';&lt;br /&gt;&lt;br /&gt;    -- determine length for content-length header&lt;br /&gt;    loop&lt;br /&gt;        exit when wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767) is null;&lt;br /&gt;        if l_db_charset = 'AL32UTF8' then&lt;br /&gt;            l_env_lenb := l_env_lenb + lengthb(wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767));&lt;br /&gt;        else&lt;br /&gt;            l_env_lenb := l_env_lenb + utl_raw.length(&lt;br /&gt;                    utl_raw.convert(utl_raw.cast_to_raw(wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767)),&lt;br /&gt;                        'american_america.al32utf8','american_america.'||l_db_charset));&lt;br /&gt;        end if;&lt;br /&gt;        i := i + 1;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    -- set a proxy if required&lt;br /&gt;    if apex_application.g_proxy_server is not null and p_proxy_override is null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; apex_application.g_proxy_server);&lt;br /&gt;    elsif p_proxy_override is not null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; p_proxy_override);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    utl_http.set_persistent_conn_support(true);&lt;br /&gt;    utl_http.set_transfer_timeout(600);&lt;br /&gt;&lt;br /&gt;    -- set wallet if necessary&lt;br /&gt;    if instr(lower(p_url),'https') = 1 then&lt;br /&gt;        utl_http.set_wallet(p_wallet_path, p_wallet_pwd);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set cookies if necessary&lt;br /&gt;    begin&lt;br /&gt;        if g_request_cookies.count &gt; 0 then&lt;br /&gt;            utl_http.clear_cookies;&lt;br /&gt;            utl_http.add_cookies(g_request_cookies);&lt;br /&gt;        end if;&lt;br /&gt;    exception when others then&lt;br /&gt;        raise_application_error(-20001,'The provided cookie is invalid.');&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    -- begin the request&lt;br /&gt;    if wwv_flow_utilities.db_version like '9.%' then&lt;br /&gt;        l_http_req := utl_http.begin_request(p_url, 'POST', 'HTTP/1.0');&lt;br /&gt;    else&lt;br /&gt;        l_http_req := utl_http.begin_request(p_url, 'POST');&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set basic authentication if required&lt;br /&gt;    if p_username is not null then&lt;br /&gt;        utl_http.set_authentication (&lt;br /&gt;            r =&gt; l_http_req,&lt;br /&gt;            username =&gt; p_username,&lt;br /&gt;            password =&gt; p_password,&lt;br /&gt;            scheme =&gt; 'Basic',&lt;br /&gt;            for_proxy =&gt; false );&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set standard HTTP headers for a SOAP request&lt;br /&gt;    utl_http.set_header(l_http_req, 'Proxy-Connection', 'Keep-Alive');&lt;br /&gt;    if p_version = '1.2' then&lt;br /&gt;        utl_http.set_header(l_http_req, 'Content-Type', 'application/soap+xml; charset=UTF-8; action="'||p_action||'";');&lt;br /&gt;    else&lt;br /&gt;        utl_http.set_header(l_http_req, 'SOAPAction', p_action);&lt;br /&gt;        utl_http.set_header(l_http_req, 'Content-Type', 'text/xml; charset=UTF-8');&lt;br /&gt;    end if;&lt;br /&gt;    utl_http.set_header(l_http_req, 'Content-Length', l_env_lenb);&lt;br /&gt;&lt;br /&gt;    -- set additional headers if supplied, these are separated by a colon (:) as name/value pairs&lt;br /&gt;    for i in 1.. p_extra_headers.count loop&lt;br /&gt;        l_headers := apex_util.string_to_table(p_extra_headers(i));&lt;br /&gt;        utl_http.set_header(l_http_req, l_headers(1), l_headers(2));&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    --set headers from g_request_headers&lt;br /&gt;    for i in 1.. g_request_headers.count loop&lt;br /&gt;        utl_http.set_header(l_http_req, g_request_headers(i).name, g_request_headers(i).value);&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    -- read the envelope, convert to UTF8 if necessary, then write it to the HTTP request&lt;br /&gt;    begin&lt;br /&gt;        loop&lt;br /&gt;            dbms_lob.read( p_envelope, l_amount, l_offset, l_buffer );&lt;br /&gt;            if l_db_charset = 'AL32UTF8' then&lt;br /&gt;                utl_http.write_text(l_http_req, l_buffer);&lt;br /&gt;            else&lt;br /&gt;                utl_http.write_raw(l_http_req,utl_raw.convert(utl_raw.cast_to_raw(l_buffer),'american_america.al32utf8','american_america.'||l_db_charset));&lt;br /&gt;            end if;&lt;br /&gt;            l_offset := l_offset + l_amount;&lt;br /&gt;            l_amount := 8000;&lt;br /&gt;        end loop;&lt;br /&gt;    exception&lt;br /&gt;        when no_data_found then&lt;br /&gt;            null;&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    -- get the response&lt;br /&gt;    l_http_resp := utl_http.get_response(l_http_req);&lt;br /&gt;&lt;br /&gt;    -- set response code, response http header and response cookies global&lt;br /&gt;    g_status_code := l_http_resp.status_code;&lt;br /&gt;    utl_http.get_cookies(g_response_cookies);&lt;br /&gt;    for i in 1..utl_http.get_header_count(l_http_resp) loop&lt;br /&gt;        utl_http.get_header(l_http_resp, i, l_name, l_hdr_value);&lt;br /&gt;        l_hdr.name := l_name;&lt;br /&gt;        l_hdr.value := l_hdr_value;&lt;br /&gt;        l_hdrs(i) := l_hdr;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    g_headers := l_hdrs;&lt;br /&gt;&lt;br /&gt;    -- put the response in a collection if necessary&lt;br /&gt;    if p_collection_name is not null then&lt;br /&gt;&lt;br /&gt;        apex_collection.create_or_truncate_collection(p_collection_name);&lt;br /&gt;&lt;br /&gt;        dbms_lob.createtemporary( l_clob, FALSE );&lt;br /&gt;        dbms_lob.open( l_clob, dbms_lob.lob_readwrite );&lt;br /&gt;        begin&lt;br /&gt;            loop&lt;br /&gt;                utl_http.read_text(l_http_resp, l_buffer);&lt;br /&gt;                dbms_lob.writeappend( l_clob, length(l_buffer), l_buffer );&lt;br /&gt;            end loop;&lt;br /&gt;        exception&lt;br /&gt;            when others then&lt;br /&gt;                if sqlcode &lt;&gt; -29266 then&lt;br /&gt;                    raise;&lt;br /&gt;                end if;&lt;br /&gt;        end;&lt;br /&gt;&lt;br /&gt;        apex_collection.add_member(&lt;br /&gt;            p_collection_name   =&gt; p_collection_name,&lt;br /&gt;            p_clob001           =&gt; l_clob);&lt;br /&gt;    end if;&lt;br /&gt;    --&lt;br /&gt;    utl_http.end_response(l_http_resp);&lt;br /&gt;&lt;br /&gt;end make_request;&lt;br /&gt;&lt;br /&gt;function make_request (&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_action            in varchar2 default null,&lt;br /&gt;    p_version           in varchar2 default '1.1',&lt;br /&gt;    p_envelope          in clob,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null,&lt;br /&gt;    p_extra_headers     in wwv_flow_global.vc_arr2 default empty_vc_arr ) return xmltype&lt;br /&gt;is&lt;br /&gt;    l_clob clob;&lt;br /&gt;    l_http_req utl_http.req;&lt;br /&gt;    l_http_resp utl_http.resp;&lt;br /&gt;    l_amount binary_integer := 8000;&lt;br /&gt;    l_offset integer := 1;&lt;br /&gt;    l_buffer varchar2(32000);&lt;br /&gt;    l_db_charset   varchar2(100);&lt;br /&gt;    l_env_lenb integer := 0;&lt;br /&gt;    i integer := 0;&lt;br /&gt;    l_headers wwv_flow_global.vc_arr2;&lt;br /&gt;    l_response varchar2(2000);&lt;br /&gt;    l_name          varchar2(256);&lt;br /&gt;    l_hdr_value     varchar2(1024);&lt;br /&gt;    l_hdr           header;&lt;br /&gt;    l_hdrs          header_table;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    -- determine database characterset, if not AL32UTF8, conversion will be necessary&lt;br /&gt;    select value into l_db_charset from nls_database_parameters where parameter='NLS_CHARACTERSET';&lt;br /&gt;&lt;br /&gt;    -- determine length for content-length header&lt;br /&gt;    loop&lt;br /&gt;        exit when wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767) is null;&lt;br /&gt;        if l_db_charset = 'AL32UTF8' then&lt;br /&gt;            l_env_lenb := l_env_lenb + lengthb(wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767));&lt;br /&gt;        else&lt;br /&gt;            l_env_lenb := l_env_lenb + utl_raw.length(&lt;br /&gt;                    utl_raw.convert(utl_raw.cast_to_raw(wwv_flow_utilities.clob_to_varchar2(p_envelope,i*32767)),&lt;br /&gt;                        'american_america.al32utf8','american_america.'||l_db_charset));&lt;br /&gt;        end if;&lt;br /&gt;        i := i + 1;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    -- set a proxy if required&lt;br /&gt;    if apex_application.g_proxy_server is not null and p_proxy_override is null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; apex_application.g_proxy_server);&lt;br /&gt;    elsif p_proxy_override is not null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; p_proxy_override);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    utl_http.set_persistent_conn_support(true);&lt;br /&gt;    utl_http.set_transfer_timeout(600);&lt;br /&gt;&lt;br /&gt;    -- set wallet if necessary&lt;br /&gt;    if instr(lower(p_url),'https') = 1 then&lt;br /&gt;        utl_http.set_wallet(p_wallet_path, p_wallet_pwd);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set cookies if necessary&lt;br /&gt;    begin&lt;br /&gt;        if g_request_cookies.count &gt; 0 then&lt;br /&gt;            utl_http.clear_cookies;&lt;br /&gt;            utl_http.add_cookies(g_request_cookies);&lt;br /&gt;        end if;&lt;br /&gt;    exception when others then&lt;br /&gt;        raise_application_error(-20001,'The provided cookie is invalid.');&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    -- begin the request&lt;br /&gt;    if wwv_flow_utilities.db_version like '9.%' then&lt;br /&gt;        l_http_req := utl_http.begin_request(p_url, 'POST', 'HTTP/1.0');&lt;br /&gt;    else&lt;br /&gt;        l_http_req := utl_http.begin_request(p_url, 'POST');&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set basic authentication if required&lt;br /&gt;    if p_username is not null then&lt;br /&gt;        utl_http.set_authentication (&lt;br /&gt;            r =&gt; l_http_req,&lt;br /&gt;            username =&gt; p_username,&lt;br /&gt;            password =&gt; p_password,&lt;br /&gt;            scheme =&gt; 'Basic',&lt;br /&gt;            for_proxy =&gt; false );&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set standard HTTP headers for a SOAP request&lt;br /&gt;    utl_http.set_header(l_http_req, 'Proxy-Connection', 'Keep-Alive');&lt;br /&gt;    if p_version = '1.2' then&lt;br /&gt;        utl_http.set_header(l_http_req, 'Content-Type', 'application/soap+xml; charset=UTF-8; action="'||p_action||'";');&lt;br /&gt;    else&lt;br /&gt;        utl_http.set_header(l_http_req, 'SOAPAction', p_action);&lt;br /&gt;        utl_http.set_header(l_http_req, 'Content-Type', 'text/xml; charset=UTF-8');&lt;br /&gt;    end if;&lt;br /&gt;    utl_http.set_header(l_http_req, 'Content-Length', l_env_lenb);&lt;br /&gt;&lt;br /&gt;    -- set additional headers if supplied, these are separated by a colon (:) as name/value pairs&lt;br /&gt;    for i in 1.. p_extra_headers.count loop&lt;br /&gt;        l_headers := apex_util.string_to_table(p_extra_headers(i));&lt;br /&gt;        utl_http.set_header(l_http_req, l_headers(1), l_headers(2));&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    --set headers from g_request_headers&lt;br /&gt;    for i in 1.. g_request_headers.count loop&lt;br /&gt;        utl_http.set_header(l_http_req, g_request_headers(i).name, g_request_headers(i).value);&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    -- read the envelope, convert to UTF8 if necessary, then write it to the HTTP request&lt;br /&gt;    begin&lt;br /&gt;        loop&lt;br /&gt;            dbms_lob.read( p_envelope, l_amount, l_offset, l_buffer );&lt;br /&gt;            if l_db_charset = 'AL32UTF8' then&lt;br /&gt;                utl_http.write_text(l_http_req, l_buffer);&lt;br /&gt;            else&lt;br /&gt;                utl_http.write_raw(l_http_req,utl_raw.convert(utl_raw.cast_to_raw(l_buffer),'american_america.al32utf8','american_america.'||l_db_charset));&lt;br /&gt;            end if;&lt;br /&gt;            l_offset := l_offset + l_amount;&lt;br /&gt;            l_amount := 8000;&lt;br /&gt;        end loop;&lt;br /&gt;    exception&lt;br /&gt;        when no_data_found then&lt;br /&gt;            null;&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    -- get the response&lt;br /&gt;    l_http_resp := utl_http.get_response(l_http_req);&lt;br /&gt;&lt;br /&gt;    -- set response code, response http header and response cookies global&lt;br /&gt;    g_status_code := l_http_resp.status_code;&lt;br /&gt;    utl_http.get_cookies(g_response_cookies);&lt;br /&gt;    for i in 1..utl_http.get_header_count(l_http_resp) loop&lt;br /&gt;        utl_http.get_header(l_http_resp, i, l_name, l_hdr_value);&lt;br /&gt;        l_hdr.name := l_name;&lt;br /&gt;        l_hdr.value := l_hdr_value;&lt;br /&gt;        l_hdrs(i) := l_hdr;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    g_headers := l_hdrs;&lt;br /&gt;&lt;br /&gt;    -- put the response in a clob&lt;br /&gt;    dbms_lob.createtemporary( l_clob, FALSE );&lt;br /&gt;    dbms_lob.open( l_clob, dbms_lob.lob_readwrite );&lt;br /&gt;    begin&lt;br /&gt;        loop&lt;br /&gt;            utl_http.read_text(l_http_resp, l_buffer);&lt;br /&gt;            dbms_lob.writeappend( l_clob, length(l_buffer), l_buffer );&lt;br /&gt;        end loop;&lt;br /&gt;    exception&lt;br /&gt;        when others then&lt;br /&gt;            if sqlcode &lt;&gt; -29266 then&lt;br /&gt;                raise;&lt;br /&gt;            end if;&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    utl_http.end_response(l_http_resp);&lt;br /&gt;&lt;br /&gt;    return xmltype.createxml(l_clob);&lt;br /&gt;&lt;br /&gt;exception when others then&lt;br /&gt;    if sqlcode = -31011 then -- its not xml&lt;br /&gt;        return null;&lt;br /&gt;    end if;&lt;br /&gt;end make_request;&lt;br /&gt;&lt;br /&gt;function make_rest_request(&lt;br /&gt;    p_url               in varchar2,&lt;br /&gt;    p_http_method       in varchar2,&lt;br /&gt;    p_username          in varchar2 default null,&lt;br /&gt;    p_password          in varchar2 default null,&lt;br /&gt;    p_proxy_override    in varchar2 default null,&lt;br /&gt;    p_body              in clob default empty_clob(),&lt;br /&gt;    p_body_blob         in blob default empty_blob(),&lt;br /&gt;    p_parm_name         in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_parm_value        in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_http_headers      in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_http_hdr_values   in wwv_flow_global.vc_arr2 default empty_vc_arr,&lt;br /&gt;    p_wallet_path       in varchar2 default null,&lt;br /&gt;    p_wallet_pwd        in varchar2 default null )&lt;br /&gt;return clob&lt;br /&gt;is&lt;br /&gt;    l_http_req      utl_http.req;&lt;br /&gt;    l_http_resp     utl_http.resp;&lt;br /&gt;    --&lt;br /&gt;    l_body          clob default empty_clob();&lt;br /&gt;    i               integer;&lt;br /&gt;    l_env_lenb      number  := 0;&lt;br /&gt;    l_db_charset    varchar2(100) := 'AL32UTF8';&lt;br /&gt;    l_buffer        varchar2(32767);&lt;br /&gt;    l_raw           raw(48);&lt;br /&gt;    l_amount        number;&lt;br /&gt;    l_offset        number;&lt;br /&gt;    l_value         clob;&lt;br /&gt;    l_url           varchar2(32767);&lt;br /&gt;    l_parm_value    varchar2(32767);&lt;br /&gt;    l_name          varchar2(256);&lt;br /&gt;    l_hdr_value     varchar2(1024);&lt;br /&gt;    l_hdr           header;&lt;br /&gt;    l_hdrs          header_table;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    -- determine database characterset, if not AL32UTF8, conversion will be necessary&lt;br /&gt;    select value into l_db_charset from nls_database_parameters where parameter='NLS_CHARACTERSET';&lt;br /&gt;&lt;br /&gt;    -- set a proxy if required&lt;br /&gt;    if apex_application.g_proxy_server is not null and p_proxy_override is null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; apex_application.g_proxy_server);&lt;br /&gt;    elsif p_proxy_override is not null then&lt;br /&gt;        utl_http.set_proxy (proxy =&gt; p_proxy_override);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    utl_http.set_persistent_conn_support(TRUE);&lt;br /&gt;    utl_http.set_transfer_timeout(180);&lt;br /&gt;&lt;br /&gt;    if instr(lower(p_url),'https') = 1 then&lt;br /&gt;        utl_http.set_wallet(p_wallet_path, p_wallet_pwd);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    if dbms_lob.getlength(p_body) = 0 then&lt;br /&gt;        for i in 1.. p_parm_name.count loop&lt;br /&gt;            if p_http_method = 'GET' then&lt;br /&gt;                l_parm_value := apex_util.url_encode(p_parm_value(i));&lt;br /&gt;            else&lt;br /&gt;                l_parm_value := p_parm_value(i);&lt;br /&gt;            end if;&lt;br /&gt;            if i = 1 then&lt;br /&gt;                l_body := p_parm_name(i)||'='||l_parm_value;&lt;br /&gt;            else&lt;br /&gt;                l_body := l_body||'&amp;'||p_parm_name(i)||'='||l_parm_value;&lt;br /&gt;            end if;&lt;br /&gt;        end loop;&lt;br /&gt;    else&lt;br /&gt;        l_body := p_body;&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    i := 0;&lt;br /&gt;&lt;br /&gt;    l_url := p_url;&lt;br /&gt;&lt;br /&gt;    if p_http_method = 'GET' then&lt;br /&gt;        l_url := l_url||'?'||wwv_flow_utilities.clob_to_varchar2(l_body);&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- determine length in bytes of l_body;&lt;br /&gt;    if dbms_lob.getlength(p_body_blob) &gt; 0 then&lt;br /&gt;        l_env_lenb := dbms_lob.getlength(p_body_blob);&lt;br /&gt;    else&lt;br /&gt;        loop&lt;br /&gt;            exit when wwv_flow_utilities.clob_to_varchar2(l_body,i*32767) is null;&lt;br /&gt;            if l_db_charset = 'AL32UTF8' then&lt;br /&gt;                l_env_lenb := l_env_lenb + lengthb(wwv_flow_utilities.clob_to_varchar2(l_body,i*32767));&lt;br /&gt;            else&lt;br /&gt;                l_env_lenb := l_env_lenb + utl_raw.length(&lt;br /&gt;                    utl_raw.convert(utl_raw.cast_to_raw(wwv_flow_utilities.clob_to_varchar2(l_body,i*32767)),&lt;br /&gt;                        'american_america.al32utf8','american_america.' || l_db_charset));&lt;br /&gt;            end if;&lt;br /&gt;            i := i + 1;&lt;br /&gt;        end loop;&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;    -- set cookies if necessary&lt;br /&gt;    begin&lt;br /&gt;        if g_request_cookies.count &gt; 0 then&lt;br /&gt;            utl_http.clear_cookies;&lt;br /&gt;            utl_http.add_cookies(g_request_cookies);&lt;br /&gt;        end if;&lt;br /&gt;    exception when others then&lt;br /&gt;        raise_application_error(-20001,'The provided cookie is invalid.');&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    begin&lt;br /&gt;        l_http_req := utl_http.begin_request(l_url, p_http_method);&lt;br /&gt;        -- set basic authentication if necessary&lt;br /&gt;        if p_username is not null then&lt;br /&gt;             utl_http.set_authentication(l_http_req, p_username, p_password);&lt;br /&gt;        end if;&lt;br /&gt;        utl_http.set_header(l_http_req, 'Proxy-Connection', 'Keep-Alive');&lt;br /&gt;        if p_http_method != 'GET' then&lt;br /&gt;            utl_http.set_header(l_http_req, 'Content-Length', l_env_lenb);&lt;br /&gt;        end if;&lt;br /&gt;        -- set additional headers if supplied, these are separated by a colon (:) as name/value pairs&lt;br /&gt;        for i in 1.. p_http_headers.count loop&lt;br /&gt;            utl_http.set_header(l_http_req, p_http_headers(i), p_http_hdr_values(i));&lt;br /&gt;        end loop;&lt;br /&gt;    exception when others then&lt;br /&gt;        raise_application_error(-20001,'The URL provided is invalid or you need to set a proxy.');&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;    --set headers from g_request_headers&lt;br /&gt;    for i in 1.. g_request_headers.count loop&lt;br /&gt;        utl_http.set_header(l_http_req, g_request_headers(i).name, g_request_headers(i).value);&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    --&lt;br /&gt;    l_amount := 8000;&lt;br /&gt;    l_offset := 1;&lt;br /&gt;    if p_http_method != 'GET' then&lt;br /&gt;        if dbms_lob.getlength(l_body) &gt; 0 then&lt;br /&gt;            begin&lt;br /&gt;                loop&lt;br /&gt;                    dbms_lob.read( l_body, l_amount, l_offset, l_buffer );&lt;br /&gt;                    if l_db_charset = 'AL32UTF8' then&lt;br /&gt;                        utl_http.write_text(l_http_req, l_buffer);&lt;br /&gt;                    else&lt;br /&gt;                        utl_http.write_raw(l_http_req,&lt;br /&gt;                                           utl_raw.convert(utl_raw.cast_to_raw(l_buffer),&lt;br /&gt;                                                           'american_america.al32utf8',&lt;br /&gt;                                                           'american_america.' || l_db_charset&lt;br /&gt;                                       )&lt;br /&gt;                        );&lt;br /&gt;                    end if;&lt;br /&gt;                    l_offset := l_offset + l_amount;&lt;br /&gt;                    l_amount := 8000;&lt;br /&gt;                end loop;&lt;br /&gt;            exception&lt;br /&gt;                when no_data_found then&lt;br /&gt;                    null;&lt;br /&gt;            end;&lt;br /&gt;        elsif dbms_lob.getlength(p_body_blob) &gt; 0 then&lt;br /&gt;            begin&lt;br /&gt;                l_amount := 48;&lt;br /&gt;                while (l_offset &lt; l_env_lenb) loop&lt;br /&gt;                    dbms_lob.read(p_body_blob, l_amount, l_offset, l_raw);&lt;br /&gt;                    utl_http.write_raw(l_http_req, l_raw);&lt;br /&gt;                    l_offset := l_offset + l_amount;&lt;br /&gt;                end loop;&lt;br /&gt;            exception&lt;br /&gt;                when no_data_found then&lt;br /&gt;                    null;&lt;br /&gt;            end;&lt;br /&gt;        end if;&lt;br /&gt;    end if;&lt;br /&gt;    --&lt;br /&gt;    begin&lt;br /&gt;        l_http_resp := utl_http.get_response(l_http_req);&lt;br /&gt;    exception when others then&lt;br /&gt;        raise_application_error(-20001,'The URL provided is invalid or you need to set a proxy.');&lt;br /&gt;    end;&lt;br /&gt;    --&lt;br /&gt;&lt;br /&gt;    -- set response code, response http header and response cookies global&lt;br /&gt;    g_status_code := l_http_resp.status_code;&lt;br /&gt;    utl_http.get_cookies(g_response_cookies);&lt;br /&gt;    for i in 1..utl_http.get_header_count(l_http_resp) loop&lt;br /&gt;        utl_http.get_header(l_http_resp, i, l_name, l_hdr_value);&lt;br /&gt;        l_hdr.name := l_name;&lt;br /&gt;        l_hdr.value := l_hdr_value;&lt;br /&gt;        l_hdrs(i) := l_hdr;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    g_headers := l_hdrs;&lt;br /&gt;&lt;br /&gt;    --&lt;br /&gt;    dbms_lob.createtemporary( l_value, FALSE );&lt;br /&gt;    dbms_lob.open( l_value, dbms_lob.lob_readwrite );&lt;br /&gt;&lt;br /&gt;    begin&lt;br /&gt;        loop&lt;br /&gt;            utl_http.read_text(l_http_resp, l_buffer);&lt;br /&gt;            dbms_lob.writeappend( l_value, length(l_buffer), l_buffer );&lt;br /&gt;        end loop;&lt;br /&gt;    exception&lt;br /&gt;        when others then&lt;br /&gt;            if sqlcode &lt;&gt; -29266 then&lt;br /&gt;                raise;&lt;br /&gt;            end if;&lt;br /&gt;    end;&lt;br /&gt;    --&lt;br /&gt;    utl_http.end_response(l_http_resp);&lt;br /&gt;&lt;br /&gt;    return l_value;&lt;br /&gt;&lt;br /&gt;end make_rest_request;&lt;br /&gt;&lt;br /&gt;function parse_xml (&lt;br /&gt;    p_xml               in xmltype,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return varchar2&lt;br /&gt;is&lt;br /&gt;    l_response          varchar2(32767);&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    l_response := dbms_xmlgen.convert(p_xml.extract(p_xpath,p_ns).getstringval(),1);&lt;br /&gt;&lt;br /&gt;    return l_response;&lt;br /&gt;&lt;br /&gt;exception when others then&lt;br /&gt;    if sqlcode = -30625 then -- path not found&lt;br /&gt;        return null;&lt;br /&gt;    end if;&lt;br /&gt;end parse_xml;&lt;br /&gt;&lt;br /&gt;function parse_xml_clob (&lt;br /&gt;    p_xml               in xmltype,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return clob&lt;br /&gt;is&lt;br /&gt;    l_response          clob;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    l_response := p_xml.extract(p_xpath,p_ns).getclobval();&lt;br /&gt;&lt;br /&gt;    return l_response;&lt;br /&gt;&lt;br /&gt;exception when others then&lt;br /&gt;    if sqlcode = -30625 then -- path not found&lt;br /&gt;        return null;&lt;br /&gt;    end if;&lt;br /&gt;end parse_xml_clob;&lt;br /&gt;&lt;br /&gt;function parse_response (&lt;br /&gt;    p_collection_name   in varchar2,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return varchar2&lt;br /&gt;is&lt;br /&gt;    l_response          varchar2(32767);&lt;br /&gt;    l_xml               xmltype;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    for c1 in (select clob001&lt;br /&gt;                 from apex_collections&lt;br /&gt;                where collection_name = p_collection_name ) loop&lt;br /&gt;        l_xml := xmltype.createxml(c1.clob001);&lt;br /&gt;        exit;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    l_response := parse_xml(l_xml, p_xpath, p_ns);&lt;br /&gt;&lt;br /&gt;    return l_response;&lt;br /&gt;&lt;br /&gt;exception when others then&lt;br /&gt;    if sqlcode = -31011 then -- its not xml&lt;br /&gt;        return null;&lt;br /&gt;    end if;&lt;br /&gt;end parse_response;&lt;br /&gt;&lt;br /&gt;function parse_response_clob (&lt;br /&gt;    p_collection_name   in varchar2,&lt;br /&gt;    p_xpath             in varchar2,&lt;br /&gt;    p_ns                in varchar2 default null ) return clob&lt;br /&gt;is&lt;br /&gt;    l_response          clob;&lt;br /&gt;    l_xml               xmltype;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    for c1 in (select clob001&lt;br /&gt;                 from apex_collections&lt;br /&gt;                where collection_name = p_collection_name ) loop&lt;br /&gt;        l_xml := xmltype.createxml(c1.clob001);&lt;br /&gt;        exit;&lt;br /&gt;    end loop;&lt;br /&gt;&lt;br /&gt;    l_response := parse_xml_clob(l_xml, p_xpath, p_ns);&lt;br /&gt;&lt;br /&gt;    return l_response;&lt;br /&gt;&lt;br /&gt;exception when others then&lt;br /&gt;    if sqlcode = -31011 then -- its not xml&lt;br /&gt;        return null;&lt;br /&gt;    end if;&lt;br /&gt;end parse_response_clob;&lt;br /&gt;&lt;br /&gt;end flex_ws_api;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;Now, with this API, it is very easy to check a document into a Stellent repository. I simply created a page with one HTML region and two items, P1_FILE (of type File Browse) and P1_RES_MSG, and one submit button. Then I created an after submit PL/SQL process that makes calls to the flex_ws_api package.&lt;br /&gt;&lt;br /&gt;The process first queries APEX_APPLICATION_FILES to get the BLOB of the file I just uploaded. It calls flex_ws_api.blob2clobbase64 to encode that blob into a base64 encoded CLOB. That clob is used as a parameter in the SOAP envelope that is built up next in a local CLOB in the process. The process then calls flex_ws_api.make_request with the necessary parameters and specifies a collection to store the response in. Finally flex_ws_api.parse_response is called to get the response code from the Stellent server.&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;declare&lt;br /&gt; l_filename varchar2(255);&lt;br /&gt; l_BLOB BLOB;&lt;br /&gt; l_CLOB CLOB;&lt;br /&gt; l_envelope CLOB;&lt;br /&gt; l_response_msg varchar2(32767);&lt;br /&gt;BEGIN&lt;br /&gt; IF :P1_FILE IS NOT NULL THEN&lt;br /&gt;    SELECT filename, BLOB_CONTENT&lt;br /&gt;      INTO l_filename, l_BLOB&lt;br /&gt;      FROM APEX_APPLICATION_FILES&lt;br /&gt;      WHERE name = :P1_FILE;&lt;br /&gt;&lt;br /&gt;    l_CLOB := flex_ws_api.blob2clobbase64(l_BLOB);&lt;br /&gt;&lt;br /&gt;   l_envelope := q'!&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;!';&lt;br /&gt;   l_envelope := l_envelope '&amp;lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:chec="http://www.stellent.com/CheckIn/"&amp;gt;&lt;br /&gt;  &amp;lt;soapenv:Header/&amp;gt;&lt;br /&gt;  &amp;lt;soapenv:Body&amp;gt;&lt;br /&gt;     &amp;lt;chec:CheckInUniversal&amp;gt;&lt;br /&gt;        &amp;lt;chec:dDocName&amp;gt;'||l_filename||'&amp;lt;/chec:dDocName&amp;gt;&lt;br /&gt;        &amp;lt;chec:dDocTitle&amp;gt;'||l_filename||'&amp;lt;/chec:dDocTitle&amp;gt;&lt;br /&gt;        &amp;lt;chec:dDocType&amp;gt;Document&amp;lt;/chec:dDocType&amp;gt;&lt;br /&gt;        &amp;lt;chec:dDocAuthor&amp;gt;GM&amp;lt;/chec:dDocAuthor&amp;gt;&lt;br /&gt;        &amp;lt;chec:dSecurityGroup&amp;gt;Public&amp;lt;/chec:dSecurityGroup&amp;gt;&lt;br /&gt;        &amp;lt;chec:dDocAccount&amp;gt;&amp;lt;/chec:dDocAccount&amp;gt;&lt;br /&gt;        &amp;lt;chec:CustomDocMetaData&amp;gt;&lt;br /&gt;           &amp;lt;chec:property&amp;gt;&lt;br /&gt;              &amp;lt;chec:name&amp;gt;&amp;lt;/chec:name&amp;gt;&lt;br /&gt;              &amp;lt;chec:value&amp;gt;&amp;lt;/chec:value&amp;gt;&lt;br /&gt;           &amp;lt;/chec:property&amp;gt;&lt;br /&gt;        &amp;lt;/chec:CustomDocMetaData&amp;gt;&lt;br /&gt;        &amp;lt;chec:primaryFile&amp;gt;&lt;br /&gt;           &amp;lt;chec:fileName&amp;gt;'||l_filename||'&amp;lt;/chec:fileName&amp;gt;&lt;br /&gt;           &amp;lt;chec:fileContent&amp;gt;'||l_CLOB||'&amp;lt;/chec:fileContent&amp;gt;&lt;br /&gt;        &amp;lt;/chec:primaryFile&amp;gt;&lt;br /&gt;        &amp;lt;chec:alternateFile&amp;gt;&lt;br /&gt;           &amp;lt;chec:fileName&amp;gt;&amp;lt;/chec:fileName&amp;gt;&lt;br /&gt;           &amp;lt;chec:fileContent&amp;gt;&amp;lt;/chec:fileContent&amp;gt;&lt;br /&gt;        &amp;lt;/chec:alternateFile&amp;gt;&lt;br /&gt;        &amp;lt;chec:extraProps&amp;gt;&lt;br /&gt;           &amp;lt;chec:property&amp;gt;&lt;br /&gt;              &amp;lt;chec:name&amp;gt;&amp;lt;/chec:name&amp;gt;&lt;br /&gt;              &amp;lt;chec:value&amp;gt;&amp;lt;/chec:value&amp;gt;&lt;br /&gt;           &amp;lt;/chec:property&amp;gt;&lt;br /&gt;        &amp;lt;/chec:extraProps&amp;gt;&lt;br /&gt;     &amp;lt;/chec:CheckInUniversal&amp;gt;&lt;br /&gt;  &amp;lt;/soapenv:Body&amp;gt;&lt;br /&gt;&amp;lt;/soapenv:Envelope&amp;gt;';&lt;br /&gt;&lt;br /&gt;flex_ws_api.make_request(&lt;br /&gt;   p_url               =&amp;gt; 'http://127.0.0.1/idc/idcplg',&lt;br /&gt;   p_action            =&amp;gt; 'http://www.stellent.com/CheckIn/',&lt;br /&gt;   p_collection_name   =&amp;gt; 'STELLENT_CHECKIN',&lt;br /&gt;   p_envelope          =&amp;gt; l_envelope,&lt;br /&gt;   p_username          =&amp;gt; 'sysadmin',&lt;br /&gt;   p_password          =&amp;gt; 'welcome1' );&lt;br /&gt;&lt;br /&gt; l_response_msg := flex_ws_api.parse_response(p_collection_name=&amp;gt;'STELLENT_CHECKIN',p_xpath=&amp;gt;'//idc:CheckInUniversalResponse/idc:CheckInUniversalResult/idc:StatusInfo/idc:statusMessage/text()',p_ns=&amp;gt;'xmlns:idc="http://www.stellent.com/CheckIn/"');&lt;br /&gt;&lt;br /&gt; :P1_RES_MSG := l_response_msg;&lt;br /&gt;&lt;br /&gt; END IF;&lt;br /&gt;END;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;In the Process Success Message text area I put &amp;amp;P1_RES_MSG. so the process success message will be the response from the Stellent server. When I checkin a new document, I get a response like "Successfully checked in content item 'TEST.DOC'."&lt;br /&gt;&lt;br /&gt;The Stellent process is only an example. This API should be flexible enough to call any Web service and store its response into a collection you specify. Let me know if you feel there is missing functionality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-3976833452947771665?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/3976833452947771665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=3976833452947771665' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3976833452947771665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/3976833452947771665'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/06/flexible-web-service-api.html' title='Flexible Web Service API'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-2844336103763744842</id><published>2008-04-01T13:13:00.000-07:00</published><updated>2008-04-01T13:31:01.004-07:00</updated><title type='text'>Application Express Web Services Integration Page on OTN</title><content type='html'>I have written a number of white papers and sample applications about Web services integration with Application Express and they are now hosted on their very own page on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;OTN&lt;/span&gt;. Check it out &lt;a href="http://www.oracle.com/technology/products/database/application_express/packaged_apps/integration.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;My &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;colleague&lt;/span&gt;, &lt;a href="http://sathishkumarjs.blogspot.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Sathish&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Kumar&lt;/span&gt;&lt;/a&gt;, wrote the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;YouTube&lt;/span&gt; sample application. It was his work with that application which led to the discovery that the Manual Web references feature of Application Express works with XML-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;RPC&lt;/span&gt; style Web services and inspired the white paper with the same title.&lt;br /&gt;&lt;br /&gt;Also, while we are talking about Web services and Application Express, check out &lt;a href="http://tylermuth.wordpress.com/2008/03/31/call-bi-publisher-web-services-from-apex/"&gt;Tyler's post &lt;/a&gt;on integrating Application Express with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;BiPublisher&lt;/span&gt; through the same Manual Web references feature of Application Express. It is a very nice and useful example.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-2844336103763744842?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/2844336103763744842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=2844336103763744842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2844336103763744842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/2844336103763744842'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/04/application-express-web-services.html' title='Application Express Web Services Integration Page on OTN'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6139250371277978964.post-9208528174775975367</id><published>2008-03-17T09:13:00.000-07:00</published><updated>2009-08-14T07:06:30.250-07:00</updated><title type='text'>NTLM HTTP Authentication and Application Express</title><content type='html'>I think for my first blog post ever, I should start with a light topic, such as &lt;a href="http://msdn2.microsoft.com/en-us/library/aa378749(VS.85).aspx"&gt;NTLM Authentication &lt;/a&gt;in Application Express...&lt;br /&gt;&lt;br /&gt;Many customers have expressed interest in using NTLM with Application Express. The argument is that they are already using this authentication in their .NET intranet applications and users of those applications do not have to supply their domain credentials again, the application simply knows who they are. I know many customers have deployed Apache and mod_ntlm, and used a custom authentication scheme described in the following paper:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.greenit.li/website/content/OracleApplicationExpressProofOfConceptNTLM.doc"&gt;http://www.greenit.li/website/content/OracleApplicationExpressProofOfConceptNTLM.doc&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There have been some problems reported with using mod_ntlm such as configuration and users getting prompted for username and password periodically. I decided to do some investigation to see if there have been any Java or .NET code examples of doing NTLM authentication to see if I could rewrite the code in PL/SQL. I found the following JSP:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.rgagnon.com/javadetails/java-0441.html"&gt;http://www.rgagnon.com/javadetails/java-0441.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is a problem with the JSP implementation when you are using a browser that won't support NTLM. You get prompted for a username and password and the JSP will just accept whatever is typed in. Luckily though, you can detect that the user was prompted by the size of the token. I kept that in mind when trying to reverse engineer into a PL/SQL solution.&lt;br /&gt;&lt;br /&gt;Through some brute force debugging and examination the HTTP traffic, I was able to successfully write some PL/SQL that does essentially the same thing as the JSP. I used the code in the mod_ntlm page sentry function from the white paper referenced above as a starting point. Unlike the JSP, this function will set the username to "nobody" if it detects that the browser prompted the user for their credentials instead of just silently negotiating them. You can then write authorization schemes that deny access to the "nobody" user.&lt;br /&gt;&lt;br /&gt;First you need to configure your DAD used for Application Express so that mod_plsql can be aware of a CGI environment variable called "Authorization." To do this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Find the file that contains the DAD description used for Application Express (most likely $OH/Apache/modplsql/conf/dads.conf)&lt;/li&gt;&lt;li&gt;Edit the DAD entry for Application Express adding &lt;strong&gt;PlsqlCGIEnvironmentList AUTHORIZATION&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Save the file&lt;/li&gt;&lt;li&gt;Stop and start Apache/ Oracle HTTP Server&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now you can access the CGI environment variable "Authorization." Next you compile a function that will be used as a page sentry function for a custom authentication scheme. Compile this function in the same schema as your application.&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;create or replace function ntlm_page_sentry&lt;br /&gt;return boolean&lt;br /&gt;is&lt;br /&gt;    l_username      varchar2(512);&lt;br /&gt;    l_session_id    number;&lt;br /&gt;    l_raw           raw(1000);&lt;br /&gt;    l_domain        varchar2(128);&lt;br /&gt;    l_user          varchar2(128);&lt;br /&gt;    l_auth          varchar2(512);&lt;br /&gt;    l_decode        varchar2(2000);&lt;br /&gt;    l_off           pls_integer := 0;&lt;br /&gt;    l_length        pls_integer;&lt;br /&gt;    l_offset        pls_integer;&lt;br /&gt;    l_htp_buffer    htp.htbuf_arr;&lt;br /&gt;    l_htp_rows      INTEGER;&lt;br /&gt;    l_url           VARCHAR2(500);&lt;br /&gt;    l_charset       VARCHAR2(128);&lt;br /&gt;begin&lt;br /&gt;    -- check to ensure that we are running as the correct database user.&lt;br /&gt;    if user != 'APEX_PUBLIC_USER' then&lt;br /&gt;        return false;&lt;br /&gt;    end if;&lt;br /&gt;    -- get sessionid.&lt;br /&gt;    l_session_id := wwv_flow_custom_auth_std.get_session_id_from_cookie;&lt;br /&gt;    -- check application session cookie.&lt;br /&gt;    if wwv_flow_custom_auth_std.is_session_valid then&lt;br /&gt;        apex_application.g_instance := l_session_id;&lt;br /&gt;        l_username := wwv_flow_custom_auth_std.get_username;&lt;br /&gt;        wwv_flow_custom_auth.define_user_session(p_user =&gt; l_username,&lt;br /&gt;                p_session_id =&gt; l_session_id);&lt;br /&gt;        return true;&lt;br /&gt;    else&lt;br /&gt;        -- get username using NTLM&lt;br /&gt;        l_auth := owa_util.get_cgi_env('AUTHORIZATION');&lt;br /&gt;        if l_auth is null then&lt;br /&gt;            owa_util.status_line(nstatus =&gt; 401,&lt;br /&gt;                    creason =&gt; 'Unauthorized',&lt;br /&gt;                    bclose_header =&gt; false);&lt;br /&gt;            htp.p('WWW-Authenticate: NTLM');&lt;br /&gt;            owa_util.mime_header('text/html', false, 'utf-8');&lt;br /&gt;            owa_util.http_header_close;&lt;br /&gt;            wwv_flow.g_unrecoverable_error := TRUE;&lt;br /&gt;            return false;&lt;br /&gt;        end if;&lt;br /&gt;        if substr(l_auth,1,5) = 'NTLM ' then&lt;br /&gt;            l_decode := utl_encode.text_decode(buf =&gt; substr(l_auth,6), encoding =&gt; UTL_ENCODE.BASE64);&lt;br /&gt;            l_raw := utl_raw.cast_to_raw(l_decode);&lt;br /&gt;            if utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,14,1)) != 130 then&lt;br /&gt;                if utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,9,1)) = 1 then&lt;br /&gt;                    owa_util.mime_header('text/html', false, 'utf-8');&lt;br /&gt;                    owa_util.status_line(nstatus =&gt; 401,&lt;br /&gt;                            creason =&gt; 'Unauthorized',&lt;br /&gt;                            bclose_header =&gt; false);&lt;br /&gt;                    htp.p('WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAAAICAgAAAAAAAAAAAAAAAA==');&lt;br /&gt;                    owa_util.http_header_close;&lt;br /&gt;                    wwv_flow.g_unrecoverable_error := TRUE;&lt;br /&gt;                    return false;&lt;br /&gt;                end if;&lt;br /&gt;                -- Determine DB charset and convert raw to WE8MSWIN1252, thanks to Andrew Barbaccia&lt;br /&gt;                select value into l_charset from nls_database_parameters where parameter='NLS_CHARACTERSET';&lt;br /&gt;                l_length := utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,32,1))*256 + utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,31,1));&lt;br /&gt;                l_offset := utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,34,1))*256 + utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,33,1));&lt;br /&gt;                l_domain := replace(replace(substr(convert(utl_raw.cast_to_varchar2(l_raw),l_charset,'WE8MSWIN1252'),l_offset + 1,l_length),chr(0),null),chr(15),null);&lt;br /&gt;                l_length := utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,40,1))*256 + utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,39,1));&lt;br /&gt;                l_offset := utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,42,1))*256 + utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,41,1));&lt;br /&gt;                l_user := replace(substr(convert(utl_raw.cast_to_varchar2(l_raw),l_charset,'WE8MSWIN1252'),l_offset,l_length),chr(0),null);&lt;br /&gt;                l_username := l_domain'\'l_user;&lt;br /&gt;            else&lt;br /&gt;                l_username := 'nobody';&lt;br /&gt;            end if;&lt;br /&gt;        end if;&lt;br /&gt;        -- application session cookie not valid --&gt; define a new apex session.&lt;br /&gt;        wwv_flow_custom_auth.define_user_session(p_user =&gt; l_username,&lt;br /&gt;            p_session_id =&gt; wwv_flow_custom_auth.get_next_session_id);&lt;br /&gt;        -- tell apex engine to quit.&lt;br /&gt;        apex_application.g_unrecoverable_error := true;&lt;br /&gt;        if owa_util.get_cgi_env('REQUEST_METHOD') = 'GET'  then&lt;br /&gt;            wwv_flow_custom_auth.remember_deep_link(p_url =&gt; 'f?'&lt;br /&gt;            wwv_flow_utilities.url_decode2(owa_util.get_cgi_env('QUERY_STRING')));&lt;br /&gt;        else&lt;br /&gt;        wwv_flow_custom_auth.remember_deep_link(p_url =&gt; 'f?p='&lt;br /&gt;          to_char(apex_application.g_flow_id)':'&lt;br /&gt;          to_char(nvl(apex_application.g_flow_step_id, 0))':'&lt;br /&gt;          to_char(apex_application.g_instance));&lt;br /&gt;      end if;&lt;br /&gt;      -- register the session in apex sessions table, set cookie, redirect back.&lt;br /&gt;      wwv_flow_custom_auth_std.post_login(p_uname =&gt; l_username,&lt;br /&gt;        p_session_id =&gt; nv('APP_SESSION'), p_flow_page =&gt; apex_application.g_flow_id&lt;br /&gt;        ':'nvl(apex_application.g_flow_step_id, 0), p_preserve_case =&gt; true);&lt;br /&gt;        -- get HTP output wwv_flow_custom_auth_std.post_login has written,&lt;br /&gt;        -- it contains the session cookie we need.&lt;br /&gt;        -- Thanks to Patrick Wolf for the following code&lt;br /&gt;        l_htp_rows := 15; /* where and how to get an actual value for irows???? */&lt;br /&gt;        htp.get_page&lt;br /&gt;          ( thepage =&gt; l_htp_buffer&lt;br /&gt;          , irows   =&gt; l_htp_rows&lt;br /&gt;          );&lt;br /&gt;        -- reset the HTP buffer so that we can write our own header, ...&lt;br /&gt;        htp.init;&lt;br /&gt;        -- See http://www.nabble.com/Empty-POST-requests-on-IE-td15332680.html&lt;br /&gt;        -- We have to trick IE that he thinks the authentication fails, otherwise&lt;br /&gt;        -- he doesn't send any data when issueing a POST because he wants to&lt;br /&gt;        -- do the NTLM stuff again&lt;br /&gt;        owa_util.status_line&lt;br /&gt;          ( nstatus =&gt; 401,&lt;br /&gt;            creason =&gt; 'Unauthorized',&lt;br /&gt;            bclose_header =&gt; FALSE&lt;br /&gt;          );&lt;br /&gt;        -- write the session cookie into our output&lt;br /&gt;        FOR ii IN 1 .. l_htp_rows&lt;br /&gt;        LOOP&lt;br /&gt;            IF l_htp_buffer(ii) LIKE 'Set-Cookie:%'&lt;br /&gt;            THEN&lt;br /&gt;                htp.p(rtrim(l_htp_buffer(ii), CHR(10)));&lt;br /&gt;            END IF;&lt;br /&gt;        END LOOP;&lt;br /&gt;        --&lt;br /&gt;        l_url := 'f?p='&lt;br /&gt;                 apex_application.g_flow_id':'&lt;br /&gt;                 nvl(apex_application.g_flow_step_id, 0)':'&lt;br /&gt;                 apex_application.g_instance;&lt;br /&gt;        --&lt;br /&gt;        IF WWV_Flow.get_browser_version = 'NSCP'&lt;br /&gt;        THEN&lt;br /&gt;            -- Firefox: redirect can be set with a HTTP header attribute&lt;br /&gt;            htp.p('Location: 'l_url);&lt;br /&gt;            owa_util.http_header_close;&lt;br /&gt;        ELSE&lt;br /&gt;            -- For IE: The javascript is required so that we are redirected to the page as&lt;br /&gt;            -- the wwv_flow_custom_auth_std.post_login would normally do with the&lt;br /&gt;            -- HTTP 302 redirect&lt;br /&gt;            owa_util.http_header_close;&lt;br /&gt;            htp.p('&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;script type="text/javascript"&amp;gt;');&lt;br /&gt;            htp.p('  location.href="'l_url'";');&lt;br /&gt;            htp.p('&amp;lt;/script&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;noscript&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;meta http-equiv="Refresh" content="0; URL="'l_url'"&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;/noscript&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;/head&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;body&amp;gt;');&lt;br /&gt;            htp.p('You were logged in successfully. Click &amp;lt;a href="'l_url'"&amp;gt;here&amp;lt;/a&amp;gt; to continue.');&lt;br /&gt;            htp.p('&amp;lt;/body&amp;gt;');&lt;br /&gt;            htp.p('&amp;lt;/html&amp;gt;');&lt;br /&gt;        END IF;&lt;br /&gt;      return false;&lt;br /&gt;    end if;&lt;br /&gt;end ntlm_page_sentry;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The last step is to create a custom authentication scheme that uses the above function as the page sentry function. To create a custom authentication scheme:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Click &lt;strong&gt;Shared Components&lt;/strong&gt; from the Application Builder home page&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Authentication Schemes&lt;/strong&gt; under Security&lt;/li&gt;&lt;li&gt;Click Create &gt;&lt;/li&gt;&lt;li&gt;Choose &lt;strong&gt;From scratch&lt;/strong&gt; and click Next &gt;&lt;/li&gt;&lt;li&gt;Enter &lt;strong&gt;NTLM&lt;/strong&gt; in the Name field and click Next &gt;&lt;/li&gt;&lt;li&gt;Enter &lt;strong&gt;return ntlm_page_sentry&lt;/strong&gt; in the Page Sentry Function text area and click Next &gt;&lt;/li&gt;&lt;li&gt;Click Next &gt; until the Confirm step&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Create Scheme&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Change Current&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Choose &lt;strong&gt;NTLM&lt;/strong&gt; and Click Next &gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Make Current&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Run the application and you should see your username in the format of DOMAIN\username provided you are using a browser that is configured to support NTLM negotiation. &lt;/p&gt;&lt;p&gt;Now, a couple of notes about browser support and NTLM. (Of course if you are already using NTLM for authentication with other applications, you are well aware of these notes). In order for Internet Explorer to automatically negotiate NTLM, the security settings of the browser must be set to Medium-low or Low. By default, IE is set to Medium-low for local intranet sites, and this authentication really only makes sense for local intranet sites.&lt;/p&gt;&lt;p&gt;Firefox will work with NTLM, but each browser has to be configured to trust each server where you want to employ NTLM. To configure Firefox to negotiate NTLM with a specific server:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Type &lt;strong&gt;about:config&lt;/strong&gt; in the address bar&lt;/li&gt;&lt;li&gt;Type &lt;strong&gt;ntlm&lt;/strong&gt; in the filter text box&lt;/li&gt;&lt;li&gt;Double click the preference &lt;strong&gt;network.automatic-ntlm-auth.trusted-uri's&lt;/strong&gt; and enter a comma separated list of trusted servers on your network&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Vista has local security policies that, by default, do not allow browser negotiation of NTLM authentication. (Again, you already know this if you have Vista and NTLM auth employed with applications in your environment). The link that follows contains information on how to change this.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.jimmah.com/vista/Networking/ntlm.aspx"&gt;http://www.jimmah.com/vista/Networking/ntlm.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If you are now thinking to yourself, "wow, I can't believe I would have to change this setting on every Vista client in my organization," then you should familiarize yourself with the notion of &lt;a href="http://msdn2.microsoft.com/en-us/library/aa374177.aspx"&gt;group policy&lt;/a&gt; and the following document:&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms814176.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms814176.aspx&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Again, NTLM authentication is really only relevant for clients that are part of an Active Directory domain, and therefore, group policy would apply.&lt;/p&gt;&lt;p&gt;Finally, it is possible (with any application that authenticates with NTLM, not just this example) for someone to sniff traffic on your network, see the NTLM authorization token for a specific user, and then use that token to spoof the identity of someone and use your application. You should:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Find out who these people are and fire them or get them fired&lt;/li&gt;&lt;li&gt;Use SSL &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;strong&gt;Update 3/19/2008:&lt;/strong&gt; I should mention that this solution only works with Apache/ Oracle HTTP Server and is not supported by the XDB HTTP Server with the embedded PL/SQL gateway (EPG), yet...&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 4/17/2008:&lt;/strong&gt; For more information on why this solution will not work with the embedded PL/SQL gateway, see the section titled "Configuring Static Authentication with DBMS_EPG" in the following document:&lt;/p&gt;&lt;p&gt;&lt;a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28424/adfns_web.htm#BGBCFIIB"&gt;http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28424/adfns_web.htm#BGBCFIIB&lt;/a&gt;&lt;/p&gt;&lt;p&gt;"The database rejects access if the browser user attempts to connect explicitly with the HTTP Authorization header."&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 5/8/2008:&lt;/strong&gt; &lt;a href="http://www.inside-oracle-apex.com/"&gt;Patrick Wolf&lt;/a&gt; discovered an issue described at the following post:&lt;/p&gt;&lt;p&gt;&lt;a href="http://forums.oracle.com/forums/thread.jspa?messageID=2511974&amp;amp;#2511974"&gt;http://forums.oracle.com/forums/thread.jspa?messageID=2511974&amp;amp;#2511974&lt;/a&gt;&lt;/p&gt;&lt;p&gt;He also came up with a very elegant solution described in the same post. I guess I should have tested this method with a more complex application (like one that posts a page). ;) Anyway, thanks to Patrick and I have included his fix in an updated version of the function.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 5/14/2008:&lt;/strong&gt; &lt;a href="http://jes.blogs.shellprompt.net/"&gt;John Scott &lt;/a&gt;may have discovered a way to use this authentication mechanism with the EPG, using Apache to proxy requests to EPG and rewriting the Authorization header:&lt;/p&gt;&lt;p&gt;&lt;a href="http://forums.oracle.com/forums/thread.jspa?threadID=652805&amp;amp;start=15&amp;amp;tstart=0"&gt;http://forums.oracle.com/forums/thread.jspa?threadID=652805&amp;amp;start=15&amp;amp;tstart=0&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 8/20/2008:&lt;/strong&gt; It seems that checking the length of the NTLM token has proven unreliable to detect the case where the browser prompted for a username and password. I have found that when the browser prompts the user, the token "NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=" is consistently passed by the client. I have altered the PL/SQL code to test for this token instead of the token length.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Update 11/17/2008:&lt;/strong&gt; I have updated the function to include two changes. The first is a suggestion from Andrew Barbaccia about character set conversion. See the comments below and the referenced forum discussion.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The second modification is how we detect when the browser prompted for username and password. I noticed that recenlty, the token changed in this case when using IE7, although the token was the same in FF. Ilmar in his comments below has come accross the same issue. I did a little more investigation and have found that the binary integer equivalent of the 14th byte of the NTLM token is equal to 130 when the browser is prompted. I will go with that for now.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 07/13/2009:&lt;/strong&gt; It seems that Microsoft published the following which will make the ntlm_page_sentry function no longer work:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;"Cumulative Security Update for Internet Explorer 7 for Windows Vista (KB963027)Security issues have been identified that could allow an attacker to compromise a system that is running Microsoft Internet Explorer and gain control over it. You can help protect your system by installing this update from Microsoft. After you install this item, you may have to restart your computer. This update is provided to you and licensed under the Windows Vista License Terms.&lt;/p&gt;&lt;p&gt;More information: &lt;a href="http://go.microsoft.com/fwlink/?LinkId=146659"&gt;http://go.microsoft.com/fwlink/?LinkId=146659&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Help and Support: &lt;a href="http://support.microsoft.com/"&gt;http://support.microsoft.com/&lt;/a&gt;"&lt;/p&gt;&lt;p&gt;&lt;br /&gt;One workaround is to de-install this update. I don't recommend that option. Another workaround listed in the comments below is to comment out the following check:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;if utl_raw.cast_to_binary_integer(utl_raw.substr(l_raw,14,1) != 130&lt;/p&gt;&lt;p&gt;&lt;br /&gt;I don't recommend that option either. The purpose of the check above is to detect the case where the browser prompted for Username and Password. This will happen if someone visits your site using the ntlm_page_sentry function and your site is not listed as in the local intranet. If the above is commented out, users that visit your application where the browser thinks it is not the local intranet will be able to type in any username they want and be that user.I have spent some time trying to figure out a workaround but I don't have one. If any of you have any ideas, please post a comment.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 07/14/2009:&lt;/strong&gt; A registry hack was provided at the following forum post which can be applied via group policy:&lt;/p&gt;&lt;p&gt;&lt;a href="http://forums.oracle.com/forums/thread.jspa?forumID=137&amp;amp;threadID=921524"&gt;http://forums.oracle.com/forums/thread.jspa?forumID=137&amp;amp;threadID=921524&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 08/14/2009: &lt;/strong&gt;I also want to point out some text from the whitepaper based on this article to make it clear what this function does (decodes an NTLM token) and does not do (negotiate anything with any domain controller).&lt;/p&gt;&lt;p&gt;"This paper presents a pure PL/SQL code solution for decoding an NTLM token and using that decoded value as the authenticated user in APEX applications. The function will set the username to "nobody" if it detects that the browser prompted the user for their credentials instead of just silently negotiating them. You can then write authorization schemes that deny access to the "nobody" user. Note that unlike the mod_ntlm Apache module, this solution does not pass along credentials to a domain controller for authentication. This solution requests that the browser present an NTLM authentication token and decodes the username and domain from that token."&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6139250371277978964-9208528174775975367?l=jastraub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jastraub.blogspot.com/feeds/9208528174775975367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6139250371277978964&amp;postID=9208528174775975367' title='84 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/9208528174775975367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6139250371277978964/posts/default/9208528174775975367'/><link rel='alternate' type='text/html' href='http://jastraub.blogspot.com/2008/03/ntlm-http-authentication-and.html' title='NTLM HTTP Authentication and Application Express'/><author><name>Jason Straub</name><uri>http://www.blogger.com/profile/12627913070109819002</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://2.bp.blogspot.com/_VnsRKsEcy_c/TAkKJ69v6TI/AAAAAAAAAC4/YXfZS9Z8I0I/S220/IMG_3946.JPG'/></author><thr:total>84</thr:total></entry></feed>
