<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AMIS Technology Blog &#187; Frank Houweling</title>
	<atom:link href="http://technology.amis.nl/blog/author/frank-houweling/feed/" rel="self" type="application/rss+xml" />
	<link>http://technology.amis.nl</link>
	<description></description>
	<lastBuildDate>Wed, 22 May 2013 10:48:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>ADF DVT Speed Date: Interactive Bubble Graph</title>
		<link>http://technology.amis.nl/2013/03/13/adf-dvt-speed-date-interactive-bubble-graph/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=adf-dvt-speed-date-interactive-bubble-graph</link>
		<comments>http://technology.amis.nl/2013/03/13/adf-dvt-speed-date-interactive-bubble-graph/#comments</comments>
		<pubDate>Wed, 13 Mar 2013 22:06:09 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[AMIS]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Web/Java]]></category>
		<category><![CDATA[11g]]></category>
		<category><![CDATA[adf]]></category>
		<category><![CDATA[adf 11g]]></category>
		<category><![CDATA[adf faces]]></category>
		<category><![CDATA[data visualization]]></category>
		<category><![CDATA[dvt]]></category>
		<category><![CDATA[jdeveloper]]></category>
		<category><![CDATA[jsf]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/?p=22034</guid>
		<description><![CDATA[Recently the ADF SIG at AMIS organized an ADF DVT Speed Date. During this speed date six AMIS consultants presented their favorite DVT Component. In a series of blogposts we share the knowledge and findings. In this post you get introduced to the ADF DVT bubble graph. I will also show you how to  [...]]]></description>
				<content:encoded><![CDATA[<p>Recently the ADF SIG at AMIS organized an ADF DVT Speed Date. During this speed date six AMIS consultants presented their favorite DVT Component. In a series of blogposts we share the knowledge and findings. In this post you get introduced to the ADF DVT bubble graph. I will also show you how to make it interactive by clicking on the bubbles. The ability to make a graph interactive can be very usefull.</p>
<p>In the following bubble graph that we are going to create, the <strong>Life expectancy </strong>(y-axis), <strong>income a year</strong> (x-axis) and the <strong>population</strong> (bubble size) is shown. This in steps of 10 years, for the last 50 years (1970, 1980, 1990, 20000 and 2010). So for each country 5 bubbles are shown. The location of the bubble has a meaning; for example in Japan (grey) the life expectancy is the highest and in Pakistan the lowest (green).<br />
-Have developing countries moved forward their income?<br />
-Do they have longer lifes than 10, 20, 30, 40 or 50 years ago?<br />
A picture says more than thousand words &#8211; you can see it immediately in the graph.</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/1.png"><img class="alignnone size-full wp-image-22036" alt="1" src="http://technology.amis.nl/wp-content/uploads/2013/03/1.png" width="1007" height="487" /></a></p>
<p><span id="more-22034"></span></p>
<h2>Bubble Graph</h2>
<p>A bubble graph is a type of chart that displays three dimensions of data (three series of data). The bubbles are shown on the chart at their X and Y location and the third (Z) through its size. Bubble charts can facilitate the understanding of social, economical, medical, and other (scientific) relationships. For example, Hans Rosling shows <a href="http://www.ted.com/talks/hans_rosling_shows_the_best_stats_you_ve_ever_seen.html%20%20got%20amazing" target="_blank">here</a> amazing bubble charts. Use a bubble chart when you want specific values to be more visually represented in your chart by different bubble sizes.</p>
<h2 class="none">How to create a bubblegraph in ADF</h2>
<p class="none">Here are the steps I took:</p>
<p>Database:<br />
-Prepare the database: run<br />
<a href="http://technology.amis.nl/wp-content/uploads/2013/03/bubble_create_script.txt">bubble_create_script.sql</a><br />
This will create the database table and the country statistics that we are going to use for the bubble graph.</p>
<p>Model project:<br />
-Create a standard new Fusion Web Application<br />
-Create a new read-only ADF ViewObject called <strong>PopulationIncomeLifeExpectancyView</strong> with the following SQL query:</p>
<p>[code language="SQL"]<br />
select country,<br />
       year,<br />
       avg_life_exp avg_life_expectancy,<br />
       avg_income,<br />
       population<br />
from   total_population_by_ctr<br />
where  country = nvl(:p_country, country)<br />
and    year =nvl(:p_year,year)<br />
order by country, year<br />
[/code]</p>
<p>Further for this ViewObject:<br />
-Create a bind parameter: <strong>p_year</strong> (String)<br />
-Create a bind parameter: <strong>p_country</strong> (String)<br />
-Set the <strong>Year</strong> and the <strong>Country</strong> attribute as key attribute of the ViewObject</p>
<p>Next:<br />
-Create a new ApplicationModule<br />
-Add the new ViewObject <strong>PopulationIncomeLifeExpectancyView</strong> to your ApplicationModule<br />
-Add another usage of PopulationIncomeLifeExpectancyView &#8211; now called <strong>PopulationIncomeLifeExpectancyView1 -</strong> to your ApplicationModule</p>
<p>ViewController project:<br />
-Create a new JSF page called <strong>LifeExpectancyByCountry.jspx</strong>:<br />
-Drag and drop a af:panelStrechLayout and in that an af:panelGroupLayout component on the new page<br />
-Drag and drop the <strong>PopulationIncomeLifeExpectancyView</strong> from your dataControl on the JSPX page:<br />
-Choose <strong>Graph</strong> and <strong>Bubble</strong></p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/wizard2.png"><img class="alignnone size-full wp-image-22044" alt="wizard1" src="http://technology.amis.nl/wp-content/uploads/2013/03/wizard1.png" width="805" height="528" /></a></p>
<p>Set the X, Y, Z, color and tooltip properties as follows:</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/wizard2.png"><img class="alignnone size-full wp-image-22044" alt="wizard2" src="http://technology.amis.nl/wp-content/uploads/2013/03/wizard2.png" width="805" height="528" /></a></p>
<p>-After running the page, the result should look like this:</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/result1.png"><img class="alignnone size-full wp-image-22043" alt="result1" src="http://technology.amis.nl/wp-content/uploads/2013/03/result1.png" width="365" height="263" /></a></p>
<p>-Now lets make the graph a bit better looking by adding the following properties to the <strong>dvt:bubbleGraph</strong></p>
<p><strong><strong>styleClass=&#8221;AFStretchWidth&#8221;<br />
hideAndShowBehavior=&#8221;withRescale&#8221;<br />
dynamicResize=&#8221;DYNAMIC_SIZE&#8221;<br />
inlineStyle=&#8221;height:550px;&#8221;<br />
imageFormat=&#8221;PNG&#8221;</strong></strong></p>
<p>-Change the colors, We can do this by adding <strong>dvt:series</strong> in the <strong>dvt:serieSet</strong> component<br />
-We set a graph-, x-as- and y-as title<br />
-We set an x-as and y-as min and max scale<br />
-The legendarea we place at the bottom</p>
<p>The dvt:bubbleGraph code should look as follows:</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/code1.png"><img class="alignnone size-full wp-image-22058" alt="code1" src="http://technology.amis.nl/wp-content/uploads/2013/03/code1.png" width="624" height="586" /></a></p>
<p>If you run the page the page looks like this:</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/result21.png"><img class="alignnone size-full wp-image-22061" alt="result2" src="http://technology.amis.nl/wp-content/uploads/2013/03/result21.png" width="1096" height="489" /></a></p>
<p>&nbsp;</p>
<h2>Interactive Bubbles</h2>
<p>To make the bubbles interactive, add a <strong>clickListener</strong> to the bubbleGraph:</p>
<p><strong>clickListener=&#8221;#{LifeExpectancyBean.onClick}&#8221;</strong></p>
<p>and in our managed bean we retrieve the value of our ViewObject <strong>Country</strong> attribute. We need this (after a bubble-click):</p>
<p>[code language="Java"]<br />
    public void onClick(ClickEvent clickEvent) {<br />
        ComponentHandle componentHandle = clickEvent.getComponentHandle();<br />
        if (componentHandle instanceof DataComponentHandle) {<br />
            DataComponentHandle handle = (DataComponentHandle)componentHandle;<br />
            Attributes[] attr = (handle).getGroupAttributes();<br />
            for (int i = 0; i &lt; attr.length; i++) {<br />
                Attributes a = attr[i];<br />
                Object obj = a.getValue(a.ID_ATTRIBUTE);<br />
                //Check if we have our ViewObject ID attribute<br />
                if (&quot;Country&quot;.equals(obj.toString())) {<br />
                    selectedCountry = (String)a.getValue(a.ID_VALUE);<br />
                    System.out.println(&quot;selectedCountry=&quot; + selectedCountry);<br />
                }<br />
            }<br />
        }<br />
        //Do something interesting with selectedCountry<br />
        BindingContainer bindingContainer = BindingContext.getCurrent().getCurrentBindingsEntry();<br />
        OperationBinding operationBinding = bindingContainer.getOperationBinding(&quot;ExecuteWithParamsSelectedCountry&quot;);<br />
        operationBinding.getParamsMap().put(&quot;p_year&quot;, null);<br />
        operationBinding.getParamsMap().put(&quot;p_country&quot;, selectedCountry);<br />
        operationBinding.execute();<br />
        renderDetailGraph = true;<br />
        renderGraph = false;<br />
        AdfFacesContext.getCurrentInstance().addPartialTarget(panelStrech);<br />
    }<br />
[/code]</p>
<p>In the code above we execute a second usage of our ViewObject that is used for a second bubble graph &#8211; the detail bubble graph.<br />
We render the detail graph and do not render the master graph anymore. To make this example working, we refresh our panelStrechlayout component. Now, after clicking on a bubble, a detail bubble graph is shown that zooms in into the country:</p>
<p><a href="http://technology.amis.nl/wp-content/uploads/2013/03/result3.png"><img src="http://technology.amis.nl/wp-content/uploads/2013/03/result3.png" alt="result3" width="996" height="563" class="alignnone size-full wp-image-22114" /></a></p>
<p>Download <a href="http://technology.amis.nl/wp-content/uploads/2013/03/app.zip">here</a> the bubble demo app (JDeveloper 11.1.1.6)</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2013/03/13/adf-dvt-speed-date-interactive-bubble-graph/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Book review: JDeveloper 11g Handbook: A Guide to Fusion Web Development</title>
		<link>http://technology.amis.nl/2011/07/21/book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development</link>
		<comments>http://technology.amis.nl/2011/07/21/book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development/#comments</comments>
		<pubDate>Thu, 21 Jul 2011 10:31:18 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Web/Java]]></category>
		<category><![CDATA[adf 11g]]></category>
		<category><![CDATA[jdeveloper 11g]]></category>
		<category><![CDATA[task flow]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=12899</guid>
		<description><![CDATA[In this blog I will share with you my experiences with the Oracle JDeveloper11g Handbook &#8211; A Guide to Oracle Fusion Web Development (McGraw-Hill, 2010) &#8211; written by Duncan Mills, Peter Koletzke and Avrom Roy-Faderman. It is the successor of their previous book, JDeveloper 10g for Forms &#38; PL/SQL  [...]]]></description>
				<content:encoded><![CDATA[<p>In this blog I will share with you my experiences with the <em>Oracle JDeveloper11g Handbook &#8211; A Guide to Oracle Fusion Web Development</em> (McGraw-Hill, 2010) &#8211; written by Duncan Mills, Peter Koletzke and Avrom Roy-Faderman. It is the successor of their previous book, <em>JDeveloper 10g for Forms &amp; PL/SQL Developers</em>. This is a book to learn the basics of ADF Fusion development and a valuable guide for reference. If youâ€™re a starter, than the hands-on part in this book is a good and practical exercise.</p>
<p><a rel="attachment wp-att-12900" href="http://technology.amis.nl/blog/12899/book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development/voorkant-boek"><img class="alignnone size-full wp-image-12900" src="http://technology.amis.nl/wp-content/uploads/images/voorkant-boek.png" alt="" width="305" height="394" /></a></p>
<p><span id="more-12899"></span></p>
<h1>Part 1Â  &#8211; Overviews</h1>
<p>Chapter 1 starts with an overview of Fusion development and ADF. What is the Oracle Fusion brand, its history and architecture?Â  Itâ€™s good to have an overview how ADF relates to all the other technologies but to really understand the contents you must already have some knowledge of all the Oracle Fusion technologies.</p>
<p>Chapter 2 is a general introduction to the JDeveloper IDE. It is a good read for newbieâ€™s but also for experienced developers to browse &#8211; there is much possible in JDeveloper 11. For example a file comparison, keyboard shortcuts (tools/preferences), refactoring (renaming or moving files), working with Subversion, the help center (JDeveloper menu, context-sensitive help page: F1).</p>
<p>Chapter 3 is on JDeveloper tools; amongst others: Â the application navigator, the project panel, the new gallery, wizards, the structure window, the component palette and the property inspector. Also very useful to know: JavaScript editing, running/debugging PL/SQL code and the JDeveloper debugger: Â explained are all the various useful debug windows (smart data, data, ADF data, EL Evaluator, breakpoints).</p>
<p>Chapter 4 is a very general introduction to Java Enterprise Development. It describes the JEE architecture model; Java, HTTP, Servlets, AJAX and what level of knowledge people need to start working with the ADF Fusion technology.</p>
<h1>Part 2 &#8211; ADF Business Components</h1>
<p>This part (chapter 5, 6, 7 and 8 ) is an excellent introduction and extensive reference guide for ADF Business Components. Only for this part already this book is worth buying. Figure 5-1 on page 152 gives a good insight on the relationships that the different ADF BC objects have with each other. For example the differences between <em>Entity Object</em> <em>definitions, -instances and â€“usages</em>. Every subject of ADF BC (Entity Objects, associations, ViewObjects, ViewLinks, ApplicationModules) is described and explained well, also new ADF BC subjects like declarative SQL mode, View Accessors and ViewObject instances used as LOV.</p>
<h1>Part 3 &#8211; ADF View and Controller</h1>
<p>Part 3 starts with chapter 9 and 10 with an introduction to JavaSever faces (JSF) and a small hands-on on this subject.</p>
<p>Chapter 11 is on the ADF Controller and taskflows. This is the most important subject to understand when you work with an ADF Fusion application. It explains the problem with JSF and why the ADF Controller and taskflows are created, the different scopes (pageFlow, view, and backingBean, request, session), the taskflow components and advanced taskflow subjects. Unfortunately, after reading this chapter the whole concept of taskflows did not became clear to me, even not after reading it again. I think this chapter should have been more understandable and detailed about this crucial subject. The chapters in the <em>Fusion Developer Guide</em> are much more informative and give you insight on this subject.</p>
<p>Chapter 12 is on ADF Faces Rich Client. It gives you a good introduction and overview off all the components, different layout containers and facets that exist. A worthwhile read, if you want to be able to create a perfect layout.<strong> </strong></p>
<h1>Part 4 &#8211; ADF Model</h1>
<p>Chapter 13 is on ADF Model basics. It explains how you can make data-bound pages while dragging and dropping collections and attributes from the data control palette. Table 13-1 on page 468 is very informative.</p>
<p>Chapter 14 is on advanced bindings. This is not an easy subject and it is explained well with examples of the different types of bindings like attribute-, table-, tree-, list of values-, action-, method bindings-. Â Very helpful for reference.</p>
<p>Chapter 15 is on iterators and executables. Â The different types of executables are discussed (invokeAction-, taskFlow-, page-,searRegion executable) and how to control execution using their properties &#8211; valuable information. Â Also the Fusion lifecycle,Â  customizing error handling and Contextual Events are quickly discussed, but I think a little bit too quickly and could have been more extensive.</p>
<h1>Part 5 â€“ Developing the Sample Application</h1>
<p>In part 5 â€“ almost one third of the book â€“ is on the hands-on sample application called <em>The Ultimate Human Resources Application (TUHRA) </em>. The instructions are clear, well written and tested instructions, divided over nothing less than 250 pages.Â  First it starts in chapter 16 starts with a discussion about design principles and a typical Fusion page design and the design of the sample application. The rest of part 5 is a big hands-on: a basic CRUD application based on the HR schema:</p>
<p><a rel="attachment wp-att-12901" href="http://technology.amis.nl/blog/12899/book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development/prntscrns-tuhra"><img class="alignnone size-large wp-image-12901" src="http://technology.amis.nl/wp-content/uploads/images/prntscrns-tuhra-1024x617.png" alt="" width="1024" height="617" /></a></p>
<p>You can become familiar with many of the new concepts and techniques that are discussed in this book and that are typical of an ADF Fusion application, like taskflows, page templates, page fragments, ADF Faces RC components (layout, popup Â menu), Â new ADF BC subjects (ViewCriteria, ViewAccessors, List of values ), PPR, etc. Also by creating Â the sample application you learn to find your way around in JDeveloper; for example where to find all numerous properties on the property inspector, how to work with the structure window (dragging and dropping components, surrounding or converting components), get insight in the use of the different tabs (source, design, bindings) on a JSFF or JSPX file. Â In chapter 21 ADF security is discussed and added to the sample application.</p>
<p>Very valuable is also the last chapter (22) about the deployment process to a Weblogic server. This explains how you can setup your own standalone Weblogic Server for testing. It shows you how to create and run a Weblogic Domain, run the administration console, how to create a JDBC datasource, and how to deploy your application from a EAR or directly from JDeveloper.</p>
<p>Unfortunately I could make this sample application only with an old version of JDeveloper , version 11.1.1.1, as one crucial ViewObject (<em>AllEmployees</em> ) uses <em>Declarative SQL mode</em> that for some unexplainable reason did not work for me on newer JDeveloper versions. There is an <a href="https://www.samplecode.oracle.com/sf/go/page1312">errata</a> page, but I did not find this here. A good thing is that you can download all the specific completed sub-steps of the application so that you can skip parts if you want or the review your code.</p>
<h1>Conclusion</h1>
<p>All in all I think this is a book that you should have on your shelve as a ADF Fusion developer. A book to learn the basics and for reference of the JDeveloper IDE, and many ADF Fusion subjects like ADF Business Components and the ADF Model. If youâ€™re a starter with ADF Fusion development the hands-on part is a very valuable one to absorb the concepts and worth to take your time for it. It is like a complete starterâ€™s course in ADF Fusion development.</p>
<p>But it should not be the only book â€“ it still doesnâ€™t give you complete insight into difficult subjects like the ADF Controller and taskflows, the ADF Fusion lifecycle or Contextual Events. For real business problems and a more in depth discussion of the technology, the <a href="http://www.amazon.com/Oracle-Fusion-Developer-Guide-Applications/dp/0071622543/ref=sr_1_2?s=books&amp;ie=UTF8&amp;qid=1311221533&amp;sr=1-2">Fusion Developer Guide</a> is a clearer, more comprehensive (and advanced) book and should be the next step of mastering the ADF Fusion technology. Â I think both books should be on your shelf as an ADF developer.</p>
<p>You can buy the book <a href="http://www.amazon.com/dp/0071602380/ref=rdr_ext_tmb">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2011/07/21/book-review-jdeveloper-11g-handbook-a-guide-to-fusion-web-development/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to call a webservice directly from Java (without webservice library)</title>
		<link>http://technology.amis.nl/2011/06/29/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library</link>
		<comments>http://technology.amis.nl/2011/06/29/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 23:22:49 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[AMIS]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SOA & Oracle Fusion Middleware]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Web/Java]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[jdeveloper 11g]]></category>
		<category><![CDATA[soa]]></category>
		<category><![CDATA[web service]]></category>
		<category><![CDATA[weblogic]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=12531</guid>
		<description><![CDATA[

In this blog I will show you how you can call a webservice programmatically in Java without using a webservice library like JAX-WS or Apache Axis. Normally you would use of course a webservice library, but in some cases this can be useful and quick; for example when you have problems generating a  [...]]]></description>
				<content:encoded><![CDATA[<div>
<div>
<p>In this blog I will show you how you can call a webservice programmatically in Java without using a webservice library like JAX-WS or Apache Axis. Normally you would use of course a webservice library, but in some cases this can be useful and quick; for example when you have problems generating a client proxy with a webservice library or if you only need some small specific parts of the SOAP response XML tree. Â It shows that a SOAP call is <em>just XML over HTTP</em>, from a plain piece of Java code.Â Then, I will show you an example how you can use this and make your own servlet webservice-tester like a simple SoapUI in JDeveloper 11.1.1.3.</p>
</div>
</div>
<p><span id="more-12531"></span></p>
<h3>Calling a webservice programmatically without webservice library like JAX-WS or Apache Axis</h3>
<p>In this example I make use of a simple webservice: a weather webservice available on:Â <a href="http://www.deeptraining.com/webservices/weather.asmx?WSDL">http://www.deeptraining.com/webservices/weather.asmx?WSDL</a> .</p>
<p>The following method is an example how to create a SOAP message requestÂ and call a remote webservice using aÂ <em>HttpURLConnection </em>object, receiveÂ and process the SOAP message response. It returns the weather of a specific city.</p>
<p>[code language="Java"]<br />
    public String getWeather(String city) throws MalformedURLException,<br />
                                                 IOException {</p>
<p>        //Code to make a webservice HTTP request<br />
        String responseString = &quot;&quot;;<br />
        String outputString = &quot;&quot;;<br />
        String wsURL = &quot;http://www.deeptraining.com/webservices/weather.asmx&quot;;<br />
        URL url = new URL(wsURL);<br />
        URLConnection connection = url.openConnection();<br />
        HttpURLConnection httpConn = (HttpURLConnection)connection;<br />
        ByteArrayOutputStream bout = new ByteArrayOutputStream();<br />
        String xmlInput =<br />
            &quot;  &lt;soapenv:Envelope xmlns:soapenv=\&quot;http://schemas.xmlsoap.org/soap/envelope/\&quot; xmlns:web=\&quot;http://litwinconsulting.com/webservices/\&quot;&gt;\n&quot; +<br />
            &quot;   &lt;soapenv:Header/&gt;\n&quot; +<br />
            &quot;   &lt;soapenv:Body&gt;\n&quot; +<br />
            &quot;      &lt;web:GetWeather&gt;\n&quot; +<br />
            &quot;         &lt;!--Optional:--&gt;\n&quot; +<br />
            &quot;         &lt;web:City&gt;&quot; + city + &quot;&lt;/web:City&gt;\n&quot; +<br />
            &quot;      &lt;/web:GetWeather&gt;\n&quot; +<br />
            &quot;   &lt;/soapenv:Body&gt;\n&quot; +<br />
            &quot;  &lt;/soapenv:Envelope&gt;&quot;;</p>
<p>        byte[] buffer = new byte[xmlInput.length()];<br />
        buffer = xmlInput.getBytes();<br />
        bout.write(buffer);<br />
        byte[] b = bout.toByteArray();<br />
        String SOAPAction =<br />
            &quot;http://litwinconsulting.com/webservices/GetWeather&quot;;<br />
        // Set the appropriate HTTP parameters.<br />
        httpConn.setRequestProperty(&quot;Content-Length&quot;,<br />
                                    String.valueOf(b.length));<br />
        httpConn.setRequestProperty(&quot;Content-Type&quot;, &quot;text/xml; charset=utf-8&quot;);<br />
        httpConn.setRequestProperty(&quot;SOAPAction&quot;, SOAPAction);<br />
        httpConn.setRequestMethod(&quot;POST&quot;);<br />
        httpConn.setDoOutput(true);<br />
        httpConn.setDoInput(true);<br />
        OutputStream out = httpConn.getOutputStream();<br />
        //Write the content of the request to the outputstream of the HTTP Connection.<br />
        out.write(b);<br />
        out.close();<br />
        //Ready with sending the request.</p>
<p>        //Read the response.<br />
        InputStreamReader isr =<br />
            new InputStreamReader(httpConn.getInputStream());<br />
        BufferedReader in = new BufferedReader(isr);</p>
<p>        //Write the SOAP message response to a String.<br />
        while ((responseString = in.readLine()) != null) {<br />
            outputString = outputString + responseString;<br />
        }<br />
        //Parse the String output to a org.w3c.dom.Document and be able to reach every node with the org.w3c.dom API.<br />
        Document document = parseXmlFile(outputString);<br />
        NodeList nodeLst = document.getElementsByTagName(&quot;GetWeatherResult&quot;);<br />
        String weatherResult = nodeLst.item(0).getTextContent();<br />
        System.out.println(&quot;Weather: &quot; + weatherResult);</p>
<p>        //Write the SOAP message formatted to the console.<br />
        String formattedSOAPResponse = formatXML(outputString);<br />
        System.out.println(formattedSOAPResponse);<br />
        return weatherResult;<br />
    }<br />
    [/code]</p>
<p>In the code above I make use of two util methods (one that makes use of a Xerces.jar library, you can download it at <a href="http://xerces.apache.org/mirrors.cgi">http://xerces.apache.org/mirrors.cgi</a>):</p>
<p>[code language="Java"]<br />
    //format the XML in your String<br />
    public String formatXML(String unformattedXml) {<br />
        try {<br />
            Document document = parseXmlFile(unformattedXml);<br />
            OutputFormat format = new OutputFormat(document);<br />
            format.setIndenting(true);<br />
            format.setIndent(3);<br />
            format.setOmitXMLDeclaration(true);<br />
            Writer out = new StringWriter();<br />
            XMLSerializer serializer = new XMLSerializer(out, format);<br />
            serializer.serialize(document);<br />
            return out.toString();<br />
        } catch (IOException e) {<br />
            throw new RuntimeException(e);<br />
        }<br />
    }</p>
<p>    private Document parseXmlFile(String in) {<br />
        try {<br />
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();<br />
            DocumentBuilder db = dbf.newDocumentBuilder();<br />
            InputSource is = new InputSource(new StringReader(in));<br />
            return db.parse(is);<br />
        } catch (ParserConfigurationException e) {<br />
            throw new RuntimeException(e);<br />
        } catch (SAXException e) {<br />
            throw new RuntimeException(e);<br />
        } catch (IOException e) {<br />
            throw new RuntimeException(e);<br />
        }<br />
    }</p>
<p>[/code]</p>
<p>If you put this 3 methods together in a class with a main method, than you can simply call the weather webservice. Thats all!</p>
<p>[code language="Java"]<br />
public class WeatherWebserviceTester {<br />
    public static void main(String[] args) {<br />
        WeatherWebserviceTester weatherWebserviceTester =<br />
            new WeatherWebserviceTester();<br />
        try {<br />
            weatherWebserviceTester.getWeather(&quot;Washington&quot;);<br />
        } catch (MalformedURLException e) {<br />
            e.printStackTrace();<br />
        } catch (IOException e) {<br />
            e.printStackTrace();<br />
        }<br />
    }<br />
[/code]</p>
<p>Download this class <a rel="attachment wp-att-12650" href="http://technology.amis.nl/blog/12531/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/weatherwebservicetester">WeatherWebserviceTester</a>.java</p>
<pre class="wp-code-highlight prettyprint"></pre>
<h3>Create the servlet webservice tester</h3>
<p>On our project we have a challenge where calling a webservice directly from Java is useful:Â because of very strict security reasons our client proxy application can access a remote webservice from only one single IP-address. This address is the machine where our production Weblogic server (WLS11g) is located and where we need to deploy our client application. Â This webservice is new and unfortunately it has many child-diseases: we often need to test, analyze and adjust the exact XML exchange of the SOAP-messages. Â See also <a href="http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws">http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws</a>. Testing is very problematic if you donâ€™t have a webservice tester available. Every WLS normally contains a test webservice facility &#8211; like a simple SoapUI in the server. Â It should be standard available at <a href="http://host:port/wls_utc">http://host:port/wls_utc</a>. In my JDeveloperâ€™s locally embedded WLS I can directly find it but not use it &#8211; my IP-address is not authorized to get information from this webservice.Â  Unfortunately on our production WLS we cannot reach its internal WLS webservice tester.Â I will show you how to create a servlet webservice tester. After deploying this tester on our production WLS, we were able to test and analyze the SOAP message exchange.</p>
<p>The steps in JDeveloper:</p>
<ul>
<li>create a new application and a new project.</li>
<li>Use the wizard to make a new Servlet, check the doGet() and the doPost() methods:</li>
</ul>
<p><a rel="attachment wp-att-12546" href="http://technology.amis.nl/blog/12531/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/wizard-create-servlet"><img class="alignnone size-full wp-image-12546" src="http://technology.amis.nl/wp-content/uploads/images/wizard-create-servlet.png" alt="" width="380" height="284" /></a></p>
<ul>
<li>We will have to add HTML code to the servlet Â <em>doGet()</em> and <em>doPost()</em> method to let it write two textareaâ€™s â€“ one for the SOAP message request and one for the SOAP message response. Â Also an input field for the webservice endpoint and a checkbox whether to format the response in XML is needed. You can first quickly make a test HTML page to create the HTML you need for this:</li>
<p>[code language="XML"]<br />
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;<br />
    &lt;head&gt;<br />
        &lt;title&gt;Webservice tester&lt;/title&gt;<br />
    &lt;/head&gt;<br />
    &lt;body&gt;<br />
        &lt;form action=&quot;soaprequestservlet&quot; method=&quot;post&quot;&gt;<br />
            &lt;label for=&quot;wsdl&quot;&gt;Webservice endpoint&lt;/label&gt;<br />
            &lt;input type=&quot;text&quot; name=&quot;wsdl&quot; size=&quot;120&quot; id=&quot;wsdl&quot;<br />
                   style=&quot;font-size: 11px; color: blue;&quot;/&gt;<br />
            &lt;label for=&quot;FormatXML&quot;&gt;Format XML&lt;/label&gt;<br />
            &lt;input id=&quot;FormatXML&quot; type=&quot;checkbox&quot; name=&quot;formatXML&quot;<br />
                   value=&quot;formatXML&quot; checked=&quot;checked&quot;/&gt;<br />
            &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;<br />
                &lt;tr&gt;<br />
                    &lt;td width=&quot;45%&quot;&gt;<br />
                        &lt;h3&gt;SOAP Request&lt;/h3&gt;<br />
                        &lt;textarea style=&quot;font-size: 11px; color: blue;&quot;<br />
                                  name=&quot;soapmessage&quot; cols=&quot;80&quot; rows=&quot;40&quot;<br />
                                  title=&quot;SOAP MessageRequest&quot; id=&quot;soaprequest&quot;&gt;&lt;/textarea&gt;<br />
                    &lt;/td&gt;<br />
                    &lt;td width=&quot;45%&quot;&gt;<br />
                        &lt;h3&gt;SOAP Response&lt;/h3&gt;<br />
                        &lt;textarea style=&quot;font-size: 11px; color: blue;&quot;<br />
                                  name=&quot;soapmessageresponse&quot; cols=&quot;80&quot; rows=&quot;40&quot;<br />
                                  title=&quot;Soap Request&quot; id=&quot;soapresponse&quot;&gt;&lt;/textarea&gt;<br />
                    &lt;/td&gt;<br />
                &lt;/tr&gt;<br />
            &lt;/table&gt;<br />
            &lt;input type=&quot;submit&quot; name=&quot;Test SOAP Request&quot;<br />
                   value=&quot;Test SOAP Request&quot;/&gt;<br />
        &lt;/form&gt;<br />
    &lt;/body&gt;<br />
&lt;/html&gt;<br />
[/code]</ul>
<p>When you run this page you can check the exact HTML that you want to put later into your <em>doGet()</em> and <em>doPost()</em> methods of your servlet:</p>
<p><a rel="attachment wp-att-12544" href="http://technology.amis.nl/blog/12531/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/testxhtmlinbrowser"><img class="alignnone size-large wp-image-12544" src="http://technology.amis.nl/wp-content/uploads/images/testXHTMLinBrowser-1024x599.png" alt="" width="1024" height="599" /></a></p>
<ul>
<li>Add the HTML code of this page to both the servlet<em> doGet() </em>and <em>doPost()</em> methods in the <em>println()</em> method of the <em>PrintWriter</em>. Then we can now add the real code that calls the webservice. The most important is the <em>doPost()</em> method where the webservice is called with the request SOAP message and the endpoint destination that you entered in the input fields:</li>
</ul>
<p>[code language="Java"]<br />
    public void doPost(HttpServletRequest request,<br />
                       HttpServletResponse response) throws ServletException,<br />
                                                            IOException {<br />
        //Whether to format the SOAP message response or not.<br />
        String formatXML = request.getParameter(&quot;formatXML&quot;);</p>
<p>        //Get the endpoint<br />
        if (!request.getParameter(&quot;endpoint&quot;).equals(&quot;&quot;))<br />
            wsURL = request.getParameter(&quot;endpoint&quot;);<br />
        else<br />
            throw new ServletException(&quot;Missing endpoint location!&quot;);</p>
<p>        //Get the SOAP message request<br />
        String xmlInput = request.getParameter(&quot;soapmessage&quot;);<br />
        requestMessage = xmlInput;</p>
<p>        //Code to make a webservice HTTP request<br />
        URL url = new URL(wsURL);<br />
        URLConnection connection = url.openConnection();<br />
        HttpURLConnection httpConn = (HttpURLConnection)connection;<br />
        String responseString = &quot;&quot;;<br />
        String outputString = &quot;&quot;;<br />
        //Optional: set your action<br />
        //String SOAPAction =<br />
        //    &quot;http://litwinconsulting.com/webservices/GetWeather&quot;;<br />
        ByteArrayOutputStream bout = new ByteArrayOutputStream();<br />
        OutputStream out = null;<br />
        InputStreamReader isr = null;<br />
        BufferedReader in = null;<br />
        byte[] buffer = new byte[xmlInput.length()];<br />
        buffer = xmlInput.getBytes();<br />
        bout.write(buffer);<br />
        byte[] b = bout.toByteArray();</p>
<p>        // Set the appropriate HTTP parameters.<br />
        httpConn.setRequestProperty(&quot;Content-Length&quot;,<br />
                                    String.valueOf(b.length));<br />
        httpConn.setRequestProperty(&quot;Content-Type&quot;, &quot;text/xml; charset=utf-8&quot;);</p>
<p>       //Optional: set your action<br />
       //httpConn.setRequestProperty(&quot;SOAPAction&quot;, SOAPAction);<br />
httpConn.setRequestMethod(&quot;POST&quot;);<br />
 httpConn.setDoOutput(true);<br />
 httpConn.setDoInput(true);<br />
 out = httpConn.getOutputStream();</p>
<p> // write the content of the request to the outputstream of the HTTP Connection.<br />
 out.write(b);<br />
 out.close();<br />
 // ready with sending the request</p>
<p> // Read the response.<br />
 isr = new InputStreamReader(httpConn.getInputStream());<br />
 in = new BufferedReader(isr);</p>
<p> //Write the SOAP message response to a String.<br />
 while ((responseString = in.readLine()) != null) {<br />
 outputString =<br />
 outputString + responseString + (formatXML == null ? &quot;\n&quot; :<br />
 &quot;&quot;);<br />
 }<br />
 //Format the message when the checkbox is checked.<br />
 if (formatXML != null)<br />
 outputString = format(outputString);</p>
<p> //write the XHTML response.<br />
 response.setContentType(CONTENT_TYPE);<br />
 PrintWriter printWriter = response.getWriter();<br />
 printWriter.println(&quot;&lt;?xml version=\&quot;1.0\&quot;?&gt;&quot;);<br />
 printWriter.println(DOC_TYPE);<br />
 printWriter.println(&quot;&lt;html xmlns=\&quot;http://www.w3.org/1999/xhtml\&quot; xml:lang=\&quot;en\&quot; lang=\&quot;en\&quot;&gt;&quot;);<br />
 printWriter.println(&quot;&lt;head&gt;&lt;title&gt;Webservice tester&lt;/title&gt;&lt;/head&gt;&quot;);<br />
 printWriter.println(&quot;&lt;body&gt;&quot;);<br />
 printWriter.println(&quot;&lt;form action=\&quot;soaprequestservlet\&quot; method=\&quot;post\&quot;&gt;&quot;);<br />
 printWriter.println(&quot;&lt;label for=\&quot;wsdl\&quot;&gt;Webservice endpoint&lt;/label&gt;&quot;);<br />
 printWriter.println(&quot;&lt;input type=\&quot;text\&quot; name=\&quot;endpoint\&quot; value=\&quot;&quot; +<br />
 wsURL +<br />
 &quot;\&quot; size=\&quot;120\&quot; id=\&quot;wsdl\&quot; style= \&quot;; font-size: 12px; color: blue;\&quot; /&gt;&quot;);<br />
 printWriter.println(&quot;&lt;label for=\&quot;FormatXML\&quot;&gt;Format XML&lt;/label&gt;&quot;);<br />
 printWriter.println(&quot;&lt;input id=\&quot;FormatXML\&quot; type=\&quot;checkbox\&quot; name=\&quot;formatXML\&quot; value=\&quot;formatXML\&quot; checked=\&quot;checked\&quot;/&gt;&quot;);<br />
 printWriter.println(&quot;&lt;p/&gt;&lt;table cellspacing=\&quot;0\&quot; cellpadding=\&quot;0\&quot; border=\&quot;0\&quot;&gt;&quot;);<br />
 printWriter.println(&quot;&lt;tr&gt;&quot;);<br />
 printWriter.println(&quot;&lt;td width=\&quot;45%\&quot;&gt;&quot;);<br />
 printWriter.println(&quot;&lt;h3&gt;SOAP Message Request&lt;/h3&gt;&quot;);<br />
 printWriter.println(&quot;&lt;textarea style= \&quot;; font-size: 11px; color: blue\&quot;;  name=\&quot;soapmessage\&quot; cols=\&quot;80\&quot; rows=\&quot;40\&quot; title=\&quot;SOAP Message Request\&quot; id=\&quot;soaprequest\&quot;&gt;&quot; +<br />
 requestMessage + &quot;&lt;/textarea&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/td&gt;&quot;);<br />
 printWriter.println(&quot;&lt;td width=\&quot;45%\&quot;&gt;&quot;);<br />
 printWriter.println(&quot;&lt;h3&gt;SOAP Message Response&lt;/h3&gt;&quot;);<br />
 printWriter.println(&quot;&lt;textarea style= \&quot;; font-size: 11px; color: blue\&quot;; name=\&quot;soapmessageresponse\&quot; cols=\&quot;80\&quot; rows=\&quot;40\&quot;&quot;);<br />
 printWriter.println(&quot;title=\&quot;SOAP Message Response\&quot; id=\&quot;soapresponse\&quot;&quot;);</p>
<p> //write the SOAP message response to the textarea.<br />
 printWriter.println(outputString);</p>
<p> //Continue writing XHTML<br />
 printWriter.println(&quot;&lt;/textarea&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/td&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/tr&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/table&gt;&quot;);<br />
 printWriter.println(&quot;&lt;input type=\&quot;submit\&quot; name=\&quot;Test SOAP Request\&quot; value=\&quot;Test SOAP Request\&quot;/&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/form&gt;&quot;);<br />
 printWriter.println(&quot;&lt;/body&gt;&lt;/html&gt;&quot;);<br />
 printWriter.close();<br />
 }</p>
<p>[/code]</p>
<p>In the servlet, the doGet() method is called when you call the servlet for the first time. After clicking on the button to test the SOAP request, the doPost() method is called and the SOAP message request is send to the webservice endpoint . The SOAP message response is red and written in the second textarea. Your webservice tester is ready for real use !</p>
<p><a rel="attachment wp-att-12543" href="http://technology.amis.nl/blog/12531/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/printscreen-tester-in-browser"><img class="alignnone size-large wp-image-12543" src="http://technology.amis.nl/wp-content/uploads/images/printscreen-tester-in-browser-1023x614.png" alt="" width="1023" height="614" /></a></p>
<p>Download this whole servlet project <a rel="attachment wp-att-12669" href="http://technology.amis.nl/blog/12531/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/soaprequesttester">SoapRequestTester</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2011/06/29/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to remove unwanted SOAP header elements in JAX-WS</title>
		<link>http://technology.amis.nl/2011/05/16/how-to-remove-unwanted-soap-header-elements-in-jax-ws/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-remove-unwanted-soap-header-elements-in-jax-ws</link>
		<comments>http://technology.amis.nl/2011/05/16/how-to-remove-unwanted-soap-header-elements-in-jax-ws/#comments</comments>
		<pubDate>Mon, 16 May 2011 00:08:32 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SOA & Oracle Fusion Middleware]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[jdeveloper 11g]]></category>
		<category><![CDATA[web service]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=12004</guid>
		<description><![CDATA[In our current webservice project with JAX-WS in Â JDeveloper Â 11.1.1.3 we have a challenge with calling a webservice. This webservice from a remote organisation does not accept specific SOAP header elements our client application creates &#8211; although we followed the contract of the WSDL correctly.  [...]]]></description>
				<content:encoded><![CDATA[<p>In our current webservice project with JAX-WS in Â JDeveloper Â 11.1.1.3 we have a challenge with calling a webservice. This webservice from a remote organisation does not accept specific SOAP header elements our client application creates &#8211; although we followed the contract of the WSDL correctly. Of course this webservice must follow it as well as we have to, but for now we donâ€™t have a choice but to make a workaround. Â How can we remove unwanted elements from a SOAP header? In this blog I will show you how you can do that using a JAX-WS <em>SOAPHandler </em>that inspects the SOAP header and removes specific <em>addressing </em>elements. <span id="more-12004"></span></p>
<p>In the WSDL file the element Â <strong>&lt;wsaw:UsingAddressing wsdl:required=&#8221;true&#8221;/&gt;</strong> is present. Following the contract of the WSDL &#8211; this means that the SOAP header must contain addressing elements. The runtime libraries of JAX-WS take care of Â this and creates in the SOAP header the elements (see picture):</p>
<ul>
<li><strong>&lt;wsa:To&gt;</strong></li>
<li><strong>&lt;FaultTo&gt;</strong></li>
<li><strong>&lt;wsa:ReplyTo&gt;</strong></li>
<li><strong>&lt;wsa:MessageId&gt;</strong></li>
<li><strong>&lt;wsa:Action&gt;</strong></li>
</ul>
<p><a rel="attachment wp-att-12044" href="http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws/1-3"><img class="alignnone size-full wp-image-12044" src="http://technology.amis.nl/wp-content/uploads/images/111.png" alt="" width="939" height="424" /></a></p>
<p>This remote webservice cannot accept <strong>&lt;wsa:To&gt;, &lt;wsa:ReplyTo&gt;, &lt;FaultTo&gt; </strong>elements (validation of incoming SOAP requests will fail)<strong>, </strong>but<strong> &lt;wsa:MessageId&gt;</strong> and &lt;<strong>wsa</strong>:<strong>Action&gt; </strong>are mandatory<strong>. </strong>We cannot simply removeÂ  <em>&lt;wsaw:UsingAddressing wsdl:required=&#8221;true&#8221;/&gt;</em> from the WSDL and regenerate our client proxy in JDeveloper, because then we miss also the mandatory <em>MessageId </em>and <em>Action</em> elements.</p>
<p>We can use a JAX-WS<em> SOAPHandler</em> to inspectÂ  the SOAP header and remove certain elements. Â In the <em>handleMessage()</em> method we can get the SOAP header , retrieve the direct child elements of this header, inspect them and delete the unwanted ones:</p>
<div><a rel="attachment wp-att-12015" href="http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws/3-2"><img class="alignnone size-full wp-image-12015" src="http://technology.amis.nl/wp-content/uploads/images/32.png" alt="" width="614" height="634" /></a></div>
<p>Now the elements are removed from the SOAP header and we can call the webservice without validation errors:</p>
<p><a rel="attachment wp-att-12047" href="http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws/2-3"><img class="alignnone size-full wp-image-12047" src="http://technology.amis.nl/wp-content/uploads/images/211.png" alt="" width="895" height="306" /></a></p>
<p>Download this SoapHandler: Â <a rel="attachment wp-att-12022" href="http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws/soaphandler">SOAPHandler</a></p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2011/05/16/how-to-remove-unwanted-soap-header-elements-in-jax-ws/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hands-on: Synchronize your database from a webservice with JAX-WS and ADF Business Components</title>
		<link>http://technology.amis.nl/2011/03/27/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc</link>
		<comments>http://technology.amis.nl/2011/03/27/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 00:12:51 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[AMIS]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle Development Tools]]></category>
		<category><![CDATA[SOA & Oracle Fusion Middleware]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Web/Java]]></category>
		<category><![CDATA[adf 11g]]></category>
		<category><![CDATA[adf bc]]></category>
		<category><![CDATA[jax-ws]]></category>
		<category><![CDATA[jdeveloper]]></category>
		<category><![CDATA[web service]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=11343</guid>
		<description><![CDATA[This step-by-step starter hands-on provides an example how to make a JAX-WS webservice proxy in JDeveloper, and save retrieved data from this webservice in a batch-job to your own database with ADF Business Components.
Duration: 60 minutes.

For this hands-on example, imagine that your company  [...]]]></description>
				<content:encoded><![CDATA[<p><em>This step-by-step starter hands-on provides an example how to make a JAX-WS webservice proxy in JDeveloper, and save retrieved data from this webservice in a batch-job to your own database with ADF Business Components.<br />
Duration: 60 minutes.<br />
</em><br />
<em>For this hands-on example, imagine that your company wants to expand internationally and that reliable, up to date country information is absolutely critical. Recently there were some changes in the number of countries and there might be in the future. Since 1990, <a href="http://geography.about.com/cs/countries/a/newcountries.htm">33 new countries </a>have been created. A few months ago the world welcomed a new country (South-Sudan) and yet we donâ€™t know what will happen in Libya (maybe it will be separated in West and East-Libya?). Your company wants to weekly synchronise its internal countries database table with up-to-date country information from a recognised country-monitoring institution that delivers up-to-date country information by a webservice.</em></p>
<h1>Part 1 â€“ Create the country webservice client with JAX-WS</h1>
<p>We are going to create a webservice client proxy for a country webservice available on: <span id="more-11343"></span></p>
<p><a href="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL">http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL</a></p>
<p>Look at the wsdl file of this webservice and lets have a look at it so that we know to which webservice we talk to. Open de wsdl in de browser, for example in Firefox. At the bottom are all the wsdl operations that we are interested in:</p>
<p><a rel="attachment wp-att-11358" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/10-2"><img class="alignnone size-full wp-image-11358" src="http://technology.amis.nl/wp-content/uploads/images/101.png" alt="" width="557" height="623" /></a></p>
<p>These operations (for example <em>CountryIntPhoneCode</em>) have input (tns:CountryIntPhoneCodeSoapRequest) and output (tns:CountryIntPhoneCodeSoapResponse) messages. These messages are also in the wsdl defined:</p>
<p><a rel="attachment wp-att-11356" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/9-2"><img class="alignnone size-full wp-image-11356" src="http://technology.amis.nl/wp-content/uploads/images/91.png" alt="" width="522" height="566" /></a></p>
<p>The part â€˜parametersâ€™ is also referring to their own definition:</p>
<p><a rel="attachment wp-att-11354" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/8-2"><img class="alignnone size-full wp-image-11354" src="http://technology.amis.nl/wp-content/uploads/images/81.png" alt="" width="479" height="456" /></a></p>
<p>In this example a standard <strong>ISO country-code </strong>is submitted to the webservice as request parameter for the operation <em>CountryIntPhoneCode</em>. The webservice will give back the international telephone-code back. We are going to use also 3 other operations from this webservice.</p>
<p>1-Create in JDeveloper a new application and call it for example â€˜<em>CountriesBatchJobâ€™ </em>and the project â€˜<em>WsClientproxyâ€™</em>.</p>
<p><a rel="attachment wp-att-11345" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/1"><img class="alignnone size-full wp-image-11345" src="http://technology.amis.nl/wp-content/uploads/images/1.png" alt="" width="281" height="268" /></a></p>
<p>2-Create a webservice proxy (JAX-WS Style) for the wsdl describing the country webservice:</p>
<p><a href="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL">http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL</a></p>
<p><a rel="attachment wp-att-11346" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/2"><img class="alignnone size-full wp-image-11346" src="http://technology.amis.nl/wp-content/uploads/images/2.png" alt="" width="861" height="587" /></a></p>
<p><a rel="attachment wp-att-11347" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/3"><img class="alignnone size-full wp-image-11347" src="http://technology.amis.nl/wp-content/uploads/images/3.png" alt="" width="632" height="473" /></a></p>
<p>Give appropiate package names. Click next &#8211;&gt; next &#8211;&gt; finish.</p>
<p><a rel="attachment wp-att-11348" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/4"><img class="alignnone size-full wp-image-11348" src="http://technology.amis.nl/wp-content/uploads/images/4.png" alt="" width="631" height="473" /></a></p>
<p>Regenerate the webservice proxy in case you see any red crosses in the generated overview.</p>
<p><a rel="attachment wp-att-11350" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/5"><img class="alignnone size-large wp-image-11350" src="http://technology.amis.nl/wp-content/uploads/images/5-1024x479.png" alt="" width="1024" height="479" /></a></p>
<p>The client class <em>CountryInfoServiceSoapClient </em>will open. Save all.</p>
<p>3-Add in the main() method:</p>
<p><code>System.out.println("Code ZW; "+countryInfoServiceSoapType.countryName("ZW"));</code></p>
<p>Test the webservice. (select CountryInfoServiceSoapClient &#8211;&gt; right mouse &#8211;&gt; run)</p>
<p><a rel="attachment wp-att-11351" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/6"><img class="alignnone size-large wp-image-11351" src="http://technology.amis.nl/wp-content/uploads/images/6-1024x680.png" alt="" width="1024" height="680" /></a></p>
<p>OK, the client is ready en works!</p>
<h1>Part 2: ADF Business Components</h1>
<p>The current database table COUNTRIES from Oracleâ€™s HR schema is used in this example. Use might need to unlock it first. We will synchronise the rows of the COUNTRIES table with up-to-date countries data from the webservice.<br />
Fortunately the table has already a column COUNTRY_ID that is the PK and is the ISO-landcode.</p>
<p><a rel="attachment wp-att-11510" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/7-1"><img class="alignnone size-full wp-image-11510" src="http://technology.amis.nl/wp-content/uploads/images/7-1.png" alt="" width="680" height="676" /></a></p>
<p>1- Add columns to the table COUNTRIES with the following script:</p>
<p><code>alter table<br />
COUNTRIES<br />
add<br />
(<br />
CAPITAL varchar2(500) ,<br />
INTPHONECODE varchar2(500) ,<br />
COUNTRYFLAG varchar2(500) ,<br />
LANGUAGENAME varchar2(500)<br />
)</code></p>
<p><a rel="attachment wp-att-11511" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/7-2"><img class="alignnone size-full wp-image-11511" src="http://technology.amis.nl/wp-content/uploads/images/7-2.png" alt="" width="541" height="611" /></a></p>
<p>2-Add a new generic project in this application and call it for example â€˜ADFBCâ€™.</p>
<p><a rel="attachment wp-att-11353" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/8"><img class="alignnone size-full wp-image-11353" src="http://technology.amis.nl/wp-content/uploads/images/8.png" alt="" width="879" height="580" /></a></p>
<p>3-Start the wizard â€˜ADF Business Components from tablesâ€™ to create the objects for de Country table. Create a database connection in the wizard with the HR schema. Test it.</p>
<p><a rel="attachment wp-att-11355" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/9"><img class="alignnone size-full wp-image-11355" src="http://technology.amis.nl/wp-content/uploads/images/9.png" alt="" width="641" height="705" /></a></p>
<p>Walk through the wizard steps. We only need 1 EntityObject (call it: <em>Country</em>), 1 ViewObject (call it: <em>CountryVw</em>) and an ApplicationModule (call it: <em>AppModule</em>).</p>
<p><a rel="attachment wp-att-11357" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/10"><img class="alignnone size-full wp-image-11357" src="http://technology.amis.nl/wp-content/uploads/images/10.png" alt="" width="799" height="494" /></a></p>
<p><a rel="attachment wp-att-11359" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/10-1"><img class="alignnone size-full wp-image-11359" src="http://technology.amis.nl/wp-content/uploads/images/10-1.png" alt="" width="790" height="493" /></a></p>
<p><a rel="attachment wp-att-11360" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/11"><img class="alignnone size-full wp-image-11360" src="http://technology.amis.nl/wp-content/uploads/images/11.png" alt="" width="792" height="489" /></a></p>
<p>Click finish. In the end it should look like this:</p>
<p><a rel="attachment wp-att-11361" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/12"><img class="alignnone size-full wp-image-11361" src="http://technology.amis.nl/wp-content/uploads/images/12.png" alt="" width="189" height="349" /></a></p>
<p>4-Change the ViewObject usage name from <em>CountryVw1</em> to <em>CountryVw</em>. (Click the pencil on the right bottom)</p>
<p><a rel="attachment wp-att-11362" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/13"><img class="alignnone size-large wp-image-11362" src="http://technology.amis.nl/wp-content/uploads/images/13-1024x438.png" alt="" width="1024" height="438" /></a></p>
<p>5- Test the ApplicationModule <em>AppModule </em>(select AppModule in tree &#8211;&gt; right mouse &#8211;&gt; run):</p>
<p><a rel="attachment wp-att-11363" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/14"><img class="alignnone size-full wp-image-11363" src="http://technology.amis.nl/wp-content/uploads/images/14.png" alt="" width="996" height="752" /></a></p>
<p>6-Create a Java class. Call it <em>BatchJobSynchronizeCountries</em>. Deselect constructors and select main method;</p>
<p><a rel="attachment wp-att-11364" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/15"><img class="alignnone size-full wp-image-11364" src="http://technology.amis.nl/wp-content/uploads/images/15.png" alt="" width="716" height="615" /></a></p>
<p>7-Type â€˜<em>bc4jclientâ€™ </em>followed by CTRL + ENTER .<br />
Test-code is generated by JDeveloper:</p>
<p><a rel="attachment wp-att-11365" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/16"><img class="alignnone size-full wp-image-11365" src="http://technology.amis.nl/wp-content/uploads/images/16.png" alt="" width="773" height="189" /> </a></p>
<p><a rel="attachment wp-att-11366" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/17"><img class="alignnone size-full wp-image-11366" src="http://technology.amis.nl/wp-content/uploads/images/17.png" alt="" width="842" height="444" /></a></p>
<p>8-The generated names (<strong>amDef </strong>and <strong>config</strong>) need to be changed to your names. Look in bc4j.xcfg for the correct names: This file is in the common folder of your ADFBC project. On my computer:</p>
<p><em>C:\JDeveloper\mywork\CountriesBatchJob\ADFBC\src\nl\amis\services\common</em></p>
<p><em><br />
</em></p>
<p><a rel="attachment wp-att-11367" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/18"><img class="alignnone size-full wp-image-11367" src="http://technology.amis.nl/wp-content/uploads/images/18.png" alt="" width="914" height="449" /></a></p>
<p>The selected part are the (amDef and config names) we need. Use these names in <em>BatchJobSynchronizeCountries.java </em></p>
<p>Replace <em>ViewObject </em>to <em>CountryVw</em>:<br />
Add:<br />
<code>System.out.println("Number of countries in CountryVw: "+vo.getEstimatedRowCount());</code></p>
<p>9-Run the client:</p>
<p><a rel="attachment wp-att-11368" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/19"><img class="alignnone size-large wp-image-11368" src="http://technology.amis.nl/wp-content/uploads/images/19-1024x633.png" alt="" width="1024" height="633" /></a></p>
<p>Fortunately the call to the countries table succeeded.</p>
<p>10-Query and print all countries and country-codes. Add:</p>
<p><code>//Query and print all countries<br />
vo.executeQuery();<br />
int rownr = 0;<br />
while (vo.hasNext()) {<br />
rownr++;<br />
Row curCountry = vo.next();<br />
String isoCountryCode = (String)curCountry.getAttribute("CountryId");<br />
System.out.println("(" + rownr + ") isoCountryCode: " + isoCountryCode);<br />
}</code></p>
<p><a rel="attachment wp-att-11369" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/20"><img class="alignnone size-full wp-image-11369" src="http://technology.amis.nl/wp-content/uploads/images/20.png" alt="" width="700" height="722" /></a></p>
<p>Oracle comes standard with 25 country records in the sample Countries table in the HR schema.</p>
<h1>Part 3 â€“ Synchronize your countries table with data from the webservice</h1>
<p>Letâ€™s return to the client (proxy) project in JDeveloper.<br />
1-We see 2 lines of code that instantiate a proxy object. With this object we can later call the operations from the webservice. Copy these lines.</p>
<p><a rel="attachment wp-att-11370" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/21"><img class="alignnone size-large wp-image-11370" src="http://technology.amis.nl/wp-content/uploads/images/21-1024x522.png" alt="" width="1024" height="522" /></a></p>
<p>2-Return to our ADFBC project to <em>BatchJobSynchronizeCountries.java</em>.<br />
Paste the 2 copied lines under the code we just edited. We can see red compiler lines under our copied code:</p>
<p><a rel="attachment wp-att-11371" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/22"><img class="alignnone size-full wp-image-11371" src="http://technology.amis.nl/wp-content/uploads/images/22.png" alt="" width="868" height="770" /></a></p>
<p>This is because JDeveloper cannot find the previous generated client proxy classes. The ADFBC project doesnâ€™t know from the existence of our client project. Go to ADFBC project &#8211;&gt; right mouse &#8211;&gt; properties &#8211;&gt; dependencies.<br />
3-Add a dependency:</p>
<p><a rel="attachment wp-att-11372" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/23"><img class="alignnone size-large wp-image-11372" src="http://technology.amis.nl/wp-content/uploads/images/23-1024x593.png" alt="" width="1024" height="593" /></a></p>
<p>Save all. Now JDeveloper is able to find the classes and with ALT+ENTER you have can select the import we need and except for one the red lines disappear. It cannot find the variable countryInfoService. We need to declare it.</p>
<p>4- Add :</p>
<p><code>private static CountryInfoService countryInfoService;</code></p>
<p><a rel="attachment wp-att-11373" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/24"><img class="alignnone size-full wp-image-11373" src="http://technology.amis.nl/wp-content/uploads/images/24.png" alt="" width="835" height="510" /></a></p>
<p>Now the class will compile.</p>
<p>5-Add the following code under the proxy instantiation:</p>
<p><code>System.out.println("--- (" + rownr + ")\t: " + isoCountryCode+" country : "+countryInfoServiceSoapType.countryName(isoCountryCode));<br />
System.out.println("--- (" + rownr + ")\t: " + isoCountryCode+" capitalCity : "+countryInfoServiceSoapType.capitalCity(isoCountryCode));<br />
System.out.println("--- (" + rownr + ")\t: " + isoCountryCode+" countryFlag : "+countryInfoServiceSoapType.countryFlag(isoCountryCode));<br />
System.out.println("--- (" + rownr + ")\t: " + isoCountryCode+" IntPhoneCode: "+countryInfoServiceSoapType.countryIntPhoneCode(isoCountryCode));</code></p>
<p><a rel="attachment wp-att-11374" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/25"><img class="alignnone size-large wp-image-11374" src="http://technology.amis.nl/wp-content/uploads/images/25-1024x699.png" alt="" width="1024" height="699" /></a></p>
<p>Run this class.</p>
<p>Now, all country-codes are retrieved from the our database. For each country a request is send to the webservice for the country name, the capital city, the country flag and the international phone the data from this webservice is printed out:</p>
<p><a rel="attachment wp-att-11625" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/99"><img class="alignnone size-full wp-image-11625" src="http://technology.amis.nl/wp-content/uploads/images/99.png" alt="" width="706" height="790" /></a></p>
<p>6- Updating our COUNTRIES table with the data from the webservice</p>
<p>We need to update/synchronize all data from the webservice with our COUNTRIES table. Look at the specific ViewObjectRow attribute names in CountriesVw:</p>
<p><a rel="attachment wp-att-11376" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/27"><img class="alignnone size-large wp-image-11376" src="http://technology.amis.nl/wp-content/uploads/images/27-1024x473.png" alt="" width="1024" height="473" /></a></p>
<p>We need to use these names to map the values from the webservice to the Country ViewObject attributes.<br />
Replace the whole <code>main() </code>method with:</p>
<p><code>public static void main(String[] args) {<br />
String amDef = "nl.amis.adfbc.services.AppModule";<br />
String config = "AppModuleLocal";<br />
ApplicationModule am =<br />
Configuration.createRootApplicationModule(amDef, config);<br />
ViewObject countryVw = am.findViewObject("CountryVw");</code></p>
<p>// Work with your appmodule and view object here<br />
System.out.println(&#8220;Number of countries in CountryVw: &#8220;+countryVw.getEstimatedRowCount());</p>
<p>//Get generated webservice proxy classes form the client project<br />
countryInfoService = new CountryInfoService();<br />
CountryInfoServiceSoapType countryInfoServiceSoapType = countryInfoService.getCountryInfoServiceSoap();</p>
<p>//1- First update existing country rows in the COUNTRIES table<br />
countryVw.executeQuery();<br />
int rownr=0;<br />
while (countryVw.hasNext()) {<br />
rownr++;<br />
Row curCountry = countryVw.next();<br />
String isoCountryCode = (String)curCountry.getAttribute(&#8220;CountryId&#8221;);<br />
System.out.println(&#8220;&#8212; UPDATING (&#8221; + rownr + &#8220;)\t isoCountryCode: &#8221; + isoCountryCode+&#8221; country: &#8220;+countryInfoServiceSoapType.countryName(isoCountryCode));</p>
<p>//Put attributes on your ViewObject row<br />
curCountry.setAttribute(&#8220;Capital&#8221;, countryInfoServiceSoapType.capitalCity(isoCountryCode));<br />
curCountry.setAttribute(&#8220;Intphonecode&#8221;, countryInfoServiceSoapType.countryIntPhoneCode(isoCountryCode));<br />
curCountry.setAttribute(&#8220;Countryflag&#8221;, countryInfoServiceSoapType.countryFlag(isoCountryCode));<br />
curCountry.setAttribute(&#8220;Languagename&#8221;, countryInfoServiceSoapType.languageName(isoCountryCode));<br />
curCountry.setAttribute(&#8220;CountryName&#8221;, countryInfoServiceSoapType.countryName(isoCountryCode));<br />
}<br />
//commit transaction<br />
am.getTransaction().commit();<br />
System.out.println(&#8220;Country-batch SUCCEFULLY updated the COUNTRIES table&#8221;);<br />
Configuration.releaseRootApplicationModule(am, true);<br />
}</p>
<p><a rel="attachment wp-att-11377" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/27-1"><img class="alignnone size-large wp-image-11377" src="http://technology.amis.nl/wp-content/uploads/images/27-1-1024x656.png" alt="" width="1024" height="656" /></a></p>
<p>7-This will update all current country records we have in the COUNTRIES table with data from the webservice. Run the class.</p>
<p><a rel="attachment wp-att-11375" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/26"><img class="alignnone size-full wp-image-11375" src="http://technology.amis.nl/wp-content/uploads/images/26.png" alt="" width="586" height="493" /></a></p>
<p>This will update all our country records with the country information from the webservice and commit them. Our update-batch job has been successful!</p>
<p><a rel="attachment wp-att-11379" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/29"><img class="alignnone size-large wp-image-11379" src="http://technology.amis.nl/wp-content/uploads/images/29-1024x555.png" alt="" width="1024" height="555" /></a></p>
<h1>Part 4 &#8211; Adding new countries from the webservice</h1>
<p>Now, only existing records of the COUNTRIES table are updated. New countries are not yet added and we will do that now.</p>
<p>1-Add just above //commit transaction:</p>
<pre class="wp-code-highlight prettyprint">&lt;code&gt;//-----------------------START------------------------------
//Query all countries and put them in a HashMap.
//Purpose: separate an UPDATE and an INSERT in COUNTRIES table
countryVw.executeQuery();
HashMap landCodesMap = new HashMap();
while (countryVw.hasNext()) {
Row curCountry = countryVw.next();
landCodesMap.put(curCountry.getAttribute(&quot;CountryId&quot;),curCountry.getAttribute(&quot;CountryName&quot;));
}&lt;/code&gt;

//2- Insert new country rows in the COUNTRIES table
//Get all countrycodes from the webservice
ArrayOftCountryCodeAndName arrayOftCountryCodeAndName = countryInfoServiceSoapType.listOfCountryNamesByCode();
List tCountryCodeAndNameList = arrayOftCountryCodeAndName.getTCountryCodeAndName();
for(TCountryCodeAndName tCountryCodeAndName:tCountryCodeAndNameList){

String isoCountryCode = tCountryCodeAndName.getSISOCode();
//Add it country to table COUNTRIES when it does not yet exists
if (!landCodesMap.containsKey(tCountryCodeAndName.getSISOCode())) {
System.out.println(â€œâ€” INSERTING IN COUNTRIES TABLE isoCountryCode: â€œ+tCountryCodeAndName.getSISOCode()+â€ â€“ country: â€œ+tCountryCodeAndName.getSName());
// Create new row and add it to the rowset
Row newCounrtyRow = countryVw.createRow();
countryVw.insertRow(newCounrtyRow);

newCounrtyRow.setAttribute(â€œCountryIdâ€, tCountryCodeAndName.getSISOCode());
newCounrtyRow.setAttribute(â€œCapitalâ€, countryInfoServiceSoapType.capitalCity(isoCountryCode));
newCounrtyRow.setAttribute(â€œIntphonecodeâ€, countryInfoServiceSoapType.countryIntPhoneCode(isoCountryCode));
newCounrtyRow.setAttribute(â€œCountryflagâ€, countryInfoServiceSoapType.countryFlag(isoCountryCode));
newCounrtyRow.setAttribute(â€œLanguagenameâ€, countryInfoServiceSoapType.languageName(isoCountryCode));
newCounrtyRow.setAttribute(â€œCountryNameâ€, countryInfoServiceSoapType.countryName(isoCountryCode));
}
}
//â€”â€”â€”â€”â€”â€”â€”â€“END â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”</pre>
<p>First, we need to identify countries that do not exist yet in our COUNTRIES table. We need a collection (for example a HashMap) with all our current country-records. Later, if the webservice returns a countrycode our hashMap doesnâ€™t contain, we know that we have to insert that country in our table.</p>
<p><code>countryVw.executeQuery();<br />
HashMap landCodesMap = new HashMap();<br />
while (countryVw.hasNext()) {<br />
Row curCountry = countryVw.next();<br />
landCodesMap.put(curCountry.getAttribute("CountryId"),curCountry.getAttribute("CountryName"));</code></p>
<p>Secondly, we need to get all available country codes from the webservice:</p>
<p><code>ArrayOftCountryCodeAndName arrayOftCountryCodeAndName = countryInfoServiceSoapType.listOfCountryNamesByCode();<br />
List tCountryCodeAndNameList = arrayOftCountryCodeAndName.getTCountryCodeAndName();</code></p>
<p>Then, we are going to loop through all the country codes and check whether we need to insert it or not:</p>
<p><code>for(TCountryCodeAndName tCountryCodeAndName:tCountryCodeAndNameList){<br />
String isoCountryCode = tCountryCodeAndName.getSISOCode();<br />
//Add it country to table COUNTRIES when it does not yet exists<br />
if (!landCodesMap.containsKey(tCountryCodeAndName.getSISOCode())) {<br />
â€¦â€¦â€¦â€¦â€¦â€¦â€¦â€¦â€¦â€¦..<br />
â€¦â€¦â€¦â€¦â€¦..<br />
}<br />
}</code></p>
<p>Then we create a new row and add it to the rowset:</p>
<p><code>Row newCounrtyRow = countryVw.createRow();<br />
countryVw.insertRow(newCounrtyRow);</code></p>
<p>And we can set all attribute values:</p>
<p><code>newCounrtyRow.setAttribute("CountryId", tCountryCodeAndName.getSISOCode());<br />
newCounrtyRow.setAttribute("Capital", countryInfoServiceSoapType.capitalCity(isoCountryCode));<br />
newCounrtyRow.setAttribute("Intphonecode", countryInfoServiceSoapType.countryIntPhoneCode(isoCountryCode));<br />
newCounrtyRow.setAttribute("Countryflag", countryInfoServiceSoapType.countryFlag(isoCountryCode));<br />
newCounrtyRow.setAttribute("Languagename", countryInfoServiceSoapType.languageName(isoCountryCode));<br />
newCounrtyRow.setAttribute("CountryName", countryInfoServiceSoapType.countryName(isoCountryCode));</code></p>
<p>At the last moment we need to commit the transaction:</p>
<p><code>am.getTransaction().commit();</code></p>
<p>2-Run the class. Now, First existing countries are updated and then new countries from the webservice are inserted:</p>
<p><a rel="attachment wp-att-11380" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/30"><img class="alignnone size-large wp-image-11380" src="http://technology.amis.nl/wp-content/uploads/images/30-1023x678.png" alt="" width="1023" height="678" /></a></p>
<p>And when we look at our COUNTRIES table we see all the new countries from the webservice;</p>
<p><a rel="attachment wp-att-11381" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/attachment/31"><img class="alignnone size-full wp-image-11381" src="http://technology.amis.nl/wp-content/uploads/images/31.png" alt="" width="611" height="791" /></a></p>
<p>Our synchronize-batch task â€“ which took approximately 10 minutes to run &#8211; has succeeded!</p>
<p>Download this complete sample project from here: <a rel="attachment wp-att-11570" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/countriesbatchjob">CountriesBatchJob.zip</a><br />
Download this hands-on in word: <a rel="attachment wp-att-11638" href="http://technology.amis.nl/blog/11343/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc">Hands-on JAX-WS.doc</a></p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2011/03/27/hands-on-synchronize-your-database-from-a-webservice-using-jax-ws-and-adfbc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using a general superclass to refresh SQL-calculated attributes in your dirty ADFBC View Object</title>
		<link>http://technology.amis.nl/2009/03/23/using-a-general-superclass-to-refresh-sql-calculated-attributes-in-your-dirty-adf-view-object/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-a-general-superclass-to-refresh-sql-calculated-attributes-in-your-dirty-adf-view-object</link>
		<comments>http://technology.amis.nl/2009/03/23/using-a-general-superclass-to-refresh-sql-calculated-attributes-in-your-dirty-adf-view-object/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 13:37:38 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=5060</guid>
		<description><![CDATA[In our current ADF10g project we have many refresh issues. After an insert or update some view object attribute values are not shown. Many attributes of our entity based view objects get their value from the SQL statement that queries the data of the view object (SQL-calculated attribute). After an  [...]]]></description>
				<content:encoded><![CDATA[<p>In our current ADF10g project we have many refresh issues. After an insert or update some view object attribute values are not shown. Many attributes of our entity based view objects get their value from the SQL statement that queries the data of the view object (SQL-calculated attribute). After an insert or update, view objects with one or more SQL-calculated attribute needs to be requeried if you want their values to be evaluated again. In this article I will discuss how to make a general superclass that refreshes the data of a View object, but first checks whether this is necessary or not. This superclass can detect if a view object is &lsquo;dirty&rsquo; &#8211; an entity based view object is dirty in this article when any inserts or updates for the underlying entity objects are about to be posted to the database. If yes, this superclass will requery the view object after the database commit, and at the same time all SQL-calculated attribute values will be evaluated again. This superclass could also be used in general, to refresh a view object in cases when this is needed.<br />
<span id="more-5060"></span>&nbsp;</p>
<h3>Requery is needed with SQL-calculated attributes</h3>
<p>View objects can include SQL-calculated attributes. A calculated attribute is an attribute that gets its value from the SQL statement that queries the data of the View object. Therefore, anything you can conjure up in the &ldquo;SELECT&rdquo; part of an SQL statement can be used to fill this attribute, from simple concatenations or decodes to PLSQL function calls and entire sub-SELECT statements.<br />
&nbsp;</p>
<p>&nbsp;<img height="497" alt="" width="696" src="http://technology.amis.nl/blog/wp-content/uploads/image/Refresh_blog/VO_editor_employeesVw.PNG" /></p>
<p>&nbsp;</p>
<p>After an insert or update of an employee, the query needs to be executed again if we want to see the value of the calculated attribute:</p>
<p>&nbsp;</p>
<p>&nbsp;<img height="302" alt="" width="849" src="http://technology.amis.nl/blog/wp-content/uploads/image/Refresh_blog/Calculated_afterSave.PNG" /></p>
<p>&nbsp;</p>
<h3>Requery is sometimes needed when many attributes are set by database triggers</h3>
<p>If you know that the underlying column value will be updated by a database trigger during insert or update operations, you can check the &lsquo;refresh after insert&rsquo; or &lsquo;refresh after update&rsquo; checkboxes to have the framework automatically retrieve the modified value to keep the entity object and database row in sync. The entity object uses the Oracle SQL RETURNING INTO feature, while performing the insert or update to return the modified column back to your application in a single database round-trip.<br />
&nbsp;</p>
<p>&nbsp;</p>
<p><img height="498" alt="" width="697" src="http://technology.amis.nl/blog/wp-content/uploads/image/Refresh_blog/entity_object_editor_refreshafterinsert.PNG" /></p>
<p>&nbsp;</p>
<p>In nearly most cases this works very well. However, in some special cases this does not seem to work. For example, this happened in our case when we made a custom implementation (override) of some of the key ADFBC framework methods of an EntityImpl class. We had defined several updatable view objects that were referencing attributes from more than one updatable entity object, and we had overridden some key methods of the &lt;EntityName&gt;Impl.java like the postChanges() and refreshFKInNewContainees() method. In our special case, the &lsquo;refresh after insert&rsquo; or &lsquo;refresh after update&rsquo; did not update the value, and a requery was needed.<br />
&nbsp;</p>
<h3>Flow of the ADFBC View Object</h3>
<p>For a requery, we could call the standard view object method executeQuery(), but then a view object will lose its current row &#8211; after a call to executeQuery() on the view object, the current row will always be reset to the first row your view object iterator points to. If you need to keep the current row you can use a <a href="http://radio.weblogs.com/0118231/2004/11/22.html">refresh-but-stay-where-you-were requery</a> method &lsquo;refreshQueryKeepingCurrentRow()&rsquo; Steve Muench described in the afterCommit() method of your the view object. A big disadvantage of calling an executeQuery() or a refreshQueryKeepingCurrentRow() in the aftercommit() method is, that the requery will always be executed, even when their were no changes at all to the data of the view object. I tested this and noticed that the ADFBC framework method afterCommit() is called <em>for every view object that has already been queried once in the current session</em>, even for view objects that had nothing at all to save to the database. Apparently the ADFBC framework flow calls the afterCommit() method for every view object that has already been queried once (and for which entity objects exist in the entity cache). If we requery all these view objects, we will unnecessary query many of them again that did not have any changes at all. Of course this is not what we want. We need to recognize in the afterCommit() method whether the data of the view object was &lsquo;dirty&rsquo; or not before we requery it; did the view object had any new or updated underlying entity objects for which data was posted and committed to the database?</p>
<p>&nbsp;</p>
<h3>
Let your entity objects register themselves as dirty on the oracle.jbo.Session object</h3>
<p>How can we recognize a dirty view object? Unfortunately, a method like &lsquo;isDirty()&rsquo; does not exist on the ViewObjectImpl class. Neither does a method like getPostState() on the ViewRowImpl class that calls its status. But on the EntityImpl class we can get the status of an entity object by calling the getPostState() method, for example in the overridden framework method postChanges(). The EntityImpl framework method postChanges() will always be called when attribute values of a modified or new entity object are posted to the database. Your EntityImpl custom base class is a good place to override this postChanges() method and set a property on the session object that indicates that for this entity type dirty entity objects exists. A custom base class extends an ADF BC framework base class &ndash; for entity objects oracle.jbo.server.EntityImpl &ndash; to add a generic feature that all of your view objects need. This is a convenient place in the class hierarchy to add our overridden postChanges(), so now this method is called automatically for all your entity objects when they are new or have any changes. An oracle.jbo.Session object (NOT javax.servlet.http.HttpSession) represents a root application module&rsquo;s session, and an implementation of this interface is instantiated for each root application module. The session object is garbage collected when the root application module is garbage collected. This is exactly the scope we need for our dirty entity objects. First we can check in the postChanges() method whether the status of an entity object is new or modified by calling the getPostState():</p>
<p>&nbsp;</p>
<p><code>if (getPostState() == STATUS_NEW) {&hellip;}&nbsp; </code></p>
<p><code>if (getPostState() == STATUS_MODIFIED){&hellip;}</code></p>
<p>&nbsp;</p>
<p>and call the session object from the DBTransaction object:</p>
<p>&nbsp;</p>
<p><code>Session session = transactionEvent.getDBTransaction().getSession();</code></p>
<p>&nbsp;</p>
<p>Then we can get the userdata Hashtable object of the session by calling session.getUserData(), and set the current entity as being dirty by adding the current entity definition name to the session properties in the userData hashtable:</p>
<p>&nbsp;</p>
<p><code>session.getUserData().put(getEntityDef().getName(),&quot;dirty&quot;);</code></p>
<p>&nbsp;</p>
<p>Our complete EntityImpl custom-base class:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code><span>package HR.model.framework;<br />
import oracle.jbo.Session;<br />
import oracle.jbo.server.EntityImpl;<br />
import oracle.jbo.server.TransactionEvent;<br />
import org.apache.commons.logging.Log;<br />
import org.apache.commons.logging.LogFactory;</p>
<p>public class HREntityImpl extends EntityImpl {<br />
&nbsp;&nbsp;&nbsp; public HREntityImpl() {}<br />
&nbsp;&nbsp;&nbsp; private static Log sLog = LogFactory.getLog(HREntityImpl.class);&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Check whether the status of an entity object is new or modified by calling the getPostState().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * If the status is new or modified, call the session object from the DBTransaction object.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * The userdata hashtable of the session is retrieved by calling session.getUserData(), <br />
&nbsp;&nbsp;&nbsp;&nbsp; * and then the current entity is set as being dirty by adding the current entity definition name <br />
&nbsp;&nbsp;&nbsp;&nbsp; * to the session properties in the userData hashtable.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void postChanges(TransactionEvent transactionEvent) <br />
&nbsp;&nbsp;&nbsp; {&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (getPostState() == STATUS_NEW) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(getEntityDef().getName()+&quot; in postChanges()....STATUS_NEW&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.getUserData().put(getEntityDef().getName(),&quot;dirty&quot;);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (getPostState() == STATUS_MODIFIED) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(getEntityDef().getName()+&quot; in postChanges()....STATUS_MODIFIED&quot;); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.getUserData().put(getEntityDef().getName(),&quot;dirty&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.postChanges(transactionEvent);<br />
&nbsp;&nbsp;&nbsp; }<br />
}</span></code></p>
<p><span></p>
<p></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Make a view object superclass that recognizes when it&rsquo;s dirty</h3>
<p>We have to check for &lsquo;dirtiness&rsquo; <em>before</em> a commit is send to the database, because after a commit we cannot check the entity objects anymore whether they were new or had changed attribute values that were committed to the database or not. After a commit the status of all entity objects is &lsquo;STATUS_UNMODIFIED&rsquo;. We have to do the check before the commit, in an overridden view object framework method beforeCommit():</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;<span> </span><code><span>/**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Check if any entity object this view object is based on is 'dirty&rsquo; in the current transaction.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * A ViewObject is dirty when any of its underlying EntityImpl objects returns<br />
&nbsp;&nbsp;&nbsp;&nbsp; * STATUS_NEW or STATUS_MODIFIED on getPostState().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * They have already been set in the userData hashtable properties of the session object<br />
&nbsp;&nbsp;&nbsp;&nbsp; * in the custom base class of EntityImpl in postChanges().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Now we can check the userData hashtable if it contains any entity object names this view object is based on.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp; public void beforeCommit(TransactionEvent transactionEvent)<br />
&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.beforeCommit(transactionEvent); &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Call the oracle.jbo.Session object from the DBTransaction object:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a Set of all the keys (=dirty entity class names)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; set = session.getUserData().keySet();<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Get all the EntityDefImpl objects this view object is based on.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EntityDefImpl[] entityDefs = getEntityDefs();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Check the whether there exists dirty EntityImpl objects for this EntityDefImpl class,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // and if yes, mark this view object as dirty.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(EntityDefImpl entityDefImpl:entityDefs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(set.contains(entityDefImpl.getName()))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; will be requeried in afterCommit(), underlying entity &quot;+entityDefImpl.getName()+&quot; is DIRTY...&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }</span></code></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>First we call the oracle.jbo.Session object from the DBTransaction object and make a set of all the keys that represent the dirty EntityDefImpl class names in the current transaction:</p>
<p>&nbsp;</p>
<p><code>Session session = transactionEvent.getDBTransaction().getSession();<br />
Set&lt;String&gt; set = session.getUserData().keySet();</code></p>
<p>&nbsp;</p>
<p>Then we get all the EntityDefImpl objects this view object is based on:</p>
<p>&nbsp;</p>
<p><code>EntityDefImpl[] entityDefs = getEntityDefs();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></p>
<p>&nbsp;</p>
<p>Now, this view object checks whether there exists dirty EntityImpl objects for this EntityDefImpl class, and if yes, mark this whole view object as dirty:</p>
<p>&nbsp;<br />
<code><span>for(EntityDefImpl entityDefImpl:entityDefs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(set.contains(entityDefImpl.getName()))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; will be requeried in afterCommit(), underlying entity &quot;+entityDefImpl.getName()+&quot; is DIRTY...&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></code></p>
<p>&nbsp;</p>
<p>So if any entity object this view object is based on is new or modified the view object will mark itself as being dirty in the beforeCommit(). Then, in the overridden view object method afterCommit(), a view object can check whether it is marked as dirty or not and in case it&rsquo;s dirty execute a requery by calling refreshQueryKeepingCurrentRow(). After that, all old dirty EntityDef names must be removed from the session hashtable with userData to be reset for the next transaction:&nbsp;&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<span> </span><code><span>/**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Only requery when an entity this view object is bases on was 'dirty' in beforeCommit().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Then, remove all old dirty EntityDef names from the session userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void afterCommit(TransactionEvent transactionEvent)<br />
&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.afterCommit(transactionEvent);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(getCurrentRow()!=null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dirty==true)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; REQUERIED in afterCommit().&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; refreshQueryKeepingCurrentRow();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Remove all old dirty EntityDef names from the session userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Get the session&rsquo;s userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hashtable hashtable = session.getUserData();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></code></p>
<p><code><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Check if the hashtable contains any dirty entitydef names.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(hashtable.contains(&quot;dirty&quot;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a set with all the keys of the userData properties.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; setKeysUserData = session.getUserData().keySet(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a second set that contains all the names of the old dirty EntityDefs.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; setKeysOfDirtyEntities=new HashSet&lt;String&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(String key:setKeysUserData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hashtable.get(key).equals(&quot;dirty&quot;)) setKeysOfDirtyEntities.add(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Use the second set to remove the names of the old dirty EntityDefs.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(String key:setKeysOfDirtyEntities)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.remove(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; } &nbsp;<br />
}&nbsp;&nbsp;&nbsp; </span></code></p>
<p>&nbsp;</p>
<p>
I think it is a good idea to set your own custom project base class of the ViewObjectImpl base class as the superclass of this RefreshQueryAfterCommitViewObjectImpl class. In this code our base class is the HRViewObjectImpl class. Complete code of RefreshQueryAfterCommitViewObjectImpl:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code><span>package HR.model.framework;<br />
import java.util.HashSet;<br />
import java.util.Hashtable;<br />
import java.util.Set;<br />
import oracle.jbo.Session;<br />
import oracle.jbo.server.EntityDefImpl;<br />
import oracle.jbo.server.TransactionEvent;<br />
import org.apache.commons.logging.Log;<br />
import org.apache.commons.logging.LogFactory;</p>
<p>public class RefreshQueryAfterCommitViewObjectImpl extends HRViewObjectImpl<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; private boolean dirty=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp; private static Log sLog = LogFactory.getLog(RefreshQueryAfterCommitViewObjectImpl.class);<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; public RefreshQueryAfterCommitViewObjectImpl() {}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Check if any entity object this view object is based on is 'dirty&rsquo; in the current transaction.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * A ViewObject is dirty when any of its underlying EntityImpl objects returns<br />
&nbsp;&nbsp;&nbsp;&nbsp; * STATUS_NEW or STATUS_MODIFIED on getPostState().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * They have already been set in the userData hashtable properties of the session object<br />
&nbsp;&nbsp;&nbsp;&nbsp; * in the custom base class of EntityImpl in postChanges().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Now we can check the userData hashtable if it contains any entity object names this view object is based on.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp; public void beforeCommit(TransactionEvent transactionEvent)<br />
&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.beforeCommit(transactionEvent); &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Call the oracle.jbo.Session object from the DBTransaction object:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a Set of all the keys (=dirty entity class names)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; set = session.getUserData().keySet();<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Get all the EntityDefImpl objects this view object is based on.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EntityDefImpl[] entityDefs = getEntityDefs();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Check the whether there exists dirty EntityImpl objects for this EntityDefImpl class,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // and if yes, mark this view object as dirty.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(EntityDefImpl entityDefImpl:entityDefs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(set.contains(entityDefImpl.getName()))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; will be requeried in afterCommit(), underlying entity &quot;+entityDefImpl.getName()+&quot; is DIRTY...&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }</span></code></p>
<p><code>&nbsp;</code></p>
<p><code>&nbsp;</code></p>
<p><code><span></p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Only requery when an entity this view object is bases on was 'dirty' in beforeCommit().<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Then, remove all old dirty EntityDef names from the session userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void afterCommit(TransactionEvent transactionEvent)<br />
&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.afterCommit(transactionEvent);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(getCurrentRow()!=null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dirty==true)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; REQUERIED in afterCommit().&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; refreshQueryKeepingCurrentRow();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Remove all old dirty EntityDef names from the session userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Get the session&rsquo;s userData Hashtable object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session = transactionEvent.getDBTransaction().getSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hashtable hashtable = session.getUserData();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></code></p>
<p><code><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Check if the hashtable contains any dirty entitydef names.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(hashtable.contains(&quot;dirty&quot;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a set with all the keys of the userData properties.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; setKeysUserData = session.getUserData().keySet(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Make a second set that contains all the names of the old dirty EntityDefs.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set&lt;String&gt; setKeysOfDirtyEntities=new HashSet&lt;String&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(String key:setKeysUserData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hashtable.get(key).equals(&quot;dirty&quot;)) setKeysOfDirtyEntities.add(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Use the second set to remove the names of the old dirty EntityDefs.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(String key:setKeysOfDirtyEntities)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.remove(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; } &nbsp;<br />
}&nbsp;&nbsp; &nbsp;</span></code></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>You can add the refresh-but-stay-where-you-were functionality method refreshQueryKeepingCurrentRow() to this class or (better) add it to your own view object custom base class, so that all of your view objects in your project could call this very useful method of Steve Muench:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; <code>&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * refresh-but-stay-where-you-were functionality<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Steve Muench http://radio.weblogs.com/0118231/2004/11/22.html<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void refreshQueryKeepingCurrentRow() <br />
&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;refreshQueryKeepingCurrentRow().. &quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Row currentRow = getCurrentRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Key currentRowKey = currentRow.getKey();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rangePosOfCurrentRow = getRangeIndexOf(currentRow);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rangeStartBeforeQuery = getRangeStart();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executeQuery();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setRangeStart(rangeStartBeforeQuery);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rangePosOfCurrentRow &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; findAndSetCurrentRowByKey(currentRowKey,rangePosOfCurrentRow);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p></code></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Set the RefreshQueryAfterCommitViewObjectImpl class as the superclass of your view objects that need a requery</h3>
<p>Now you have a general solution for this type of refresh issues. When you are confronted with a refresh issues involving calculated attributes or involving attributes set by database triggers, the only thing you will have to do is to set this class as the superclass of your view object. In the hierarchy, you just place the RefreshQueryAfterCommitViewObjectImpl class between your own custom base class and the view object that you want to refresh:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img height="270" alt="" width="907" src="http://technology.amis.nl/blog/wp-content/uploads/image/Refresh_blog/klassendiagram.PNG" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>In JDeveloper you can do this in the View Object Editor:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img height="496" alt="" width="696" src="http://technology.amis.nl/blog/wp-content/uploads/image/Refresh_blog/extends_refreshquery_VO_editor.PNG" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Now your dirty view object will be refreshed after an insert or an update.</p>
<p>
&nbsp;</p>
<h3>Refreshing your view objects with SQL-Calculated attributes automatically without having to look after them</h3>
<p>Alternatively, you even don&rsquo;t have to set a new superclass for your view objects with SQL-Calculated attributes. Your ViewObject can detect automatically whether it contains SQL-Calculated attributes or not, and only requery when it does. A view object can ask for its attribute definitions and for each attribute definition it&#8217;s kind of attribute. If the kind is ATTR_SQL_DERIVED, it&#8217;s SQL-Calculated. You could add all the three methods beforeCommit(), afterCommit and refreshQueryKeepingCurrentRow() to your custom ViewObjectImpl base class and add an overridden create() method to it. This method is called by the framework every time a ViewObjectImpl object is created, and a good place for us to check whether this view object contains SQL-Calculated attributes or not:<br />
&nbsp;</p>
<p><code>private boolean hasSQLCalculatedAttribute=false;<br />
</code></p>
<p><code>protected void create() <br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.create(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code>//Get an array of all attribute definitions of this ViewObjectImpl. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AttributeDef[] attributeDefs = getAttributeDefs();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code>//Check whether any attribute definition exists that is SQL-Calculated.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(AttributeDef attributeDef:attributeDefs) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(<strong>attributeDef.getAttributeKind()==AttributeDef.ATTR_SQL_DERIVED</strong>) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; has SQL-Calculated attributes - if dirty, it's requeried after a commit.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>hasSQLCalculatedAttribute=true</strong>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
}</code></p>
<p>
&nbsp;</p>
<p>&nbsp;</p>
<p>Then, in the afterCommit() method, before the requery, also check whether it has SQL-Calculated attributes or not:</p>
<p>
&nbsp;</p>
<p><code>if(getCurrentRow()!=null)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; if(dirty==true)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>if(hasSQLCalculatedAttribute==true)</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;Viewobject &quot;+getName()+&quot; REQUERIED in afterCommit().&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; refreshQueryKeepingCurrentRow();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; </code></p>
<p>
&nbsp;<br />
Now all your view objects with SQL-Calculated attributes are refreshed automatically without having to look after them any more.<br />
&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2009/03/23/using-a-general-superclass-to-refresh-sql-calculated-attributes-in-your-dirty-adf-view-object/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How to let your user know his session has expired in an ADF10g application</title>
		<link>http://technology.amis.nl/2009/03/16/how-to-let-your-user-know-his-session-has-expired-in-an-adf10g-application/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-let-your-user-know-his-session-has-expired-in-an-adf10g-application</link>
		<comments>http://technology.amis.nl/2009/03/16/how-to-let-your-user-know-his-session-has-expired-in-an-adf10g-application/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 13:40:04 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=4992</guid>
		<description><![CDATA[In a proper and user-friendly application, it is a good idea to let your user know when his session has expired. Or to inform him that his session is about to be expired. How can you accomplish that in an ADF10g? In this article I will first show you how you can notify a user his session has  [...]]]></description>
				<content:encoded><![CDATA[<p>In a proper and user-friendly application, it is a good idea to let your user know when his session has expired. Or to inform him that his session is about to be expired. How can you accomplish that in an ADF10g? In this article I will first show you how you can notify a user his session has expired using a component I recently discovered in ADF Faces, an af:poll. This is a really cool component&nbsp;that can trigger a so called pollEvent after a specified interval, and is delivered at the server upon polling. Then I will show you another example where this component can be usefull:&nbsp;to maintain a user session while the application is still open in the browser.</p>
<p><span id="more-4992"></span></p>
<p>&nbsp;</p>
<p><img src="http://technology.amis.nl/blog/wp-content/uploads/image/session_poll_art/ART_FIREFOX_MESSAGE_JS.PNG" alt="" /></p>
<p>&nbsp;</p>
<p>Normally, in a Java web-application a session timeout is configured (in minutes) in the deployment descriptor (DD) web.xml. This means that if the client doesn&rsquo;t make any requests on this session for 35 minutes the application server will invalidate the session.</p>
<p>&nbsp;</p>
<p><code>&lt;web-app &hellip;&gt;<br />
&nbsp; &lt;servelet&gt;<br />
&nbsp; &hellip;<br />
&nbsp;&lt;/servlet&gt;<br />
&nbsp; &lt;session-config&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;session-timeout&gt;35&lt;/session-timeout&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/session-config&gt;<br />
&lt;/web-app&gt;</code></p>
<p>&nbsp;</p>
<p>We use a servlet filter to check the session and attributes on the session. When the session is no longer valid, the servlet container redirects the request to our configured Login page.</p>
<p>&nbsp;</p>
<h3>Javascript solution in the browser</h3>
<p>A very simple but for many ADF applications not yet complete solution could be that you add a single &lt;afh:script&gt; component to a region-JSPX that is included in every JSPX, for example a menu region. This &lt;afh:script&gt; component calls a JavaScript function (which calls another function):</p>
<p>&nbsp;</p>
<p><code>&lt;afh:script id=&quot;popupSessionTimeout&quot;&nbsp;</code><code>text=&quot;timerpopupSessionTimeout('Your session has expired.&nbsp;Do you want to go to the Login page?', '2100000');&quot; /&gt;</code></p>
<p>&nbsp;</p>
<p>With your message from your resourcebundle and the maximum inactive interval time red from a backing bean:</p>
<p>&nbsp;</p>
<p><code>&lt;afh:script id=&quot;popupSessionTimeout&quot;&nbsp;&nbsp;text=&quot;timerpopupSessionTimeout('#{nls['SESSION_TIMEOUT_MESSAGE']}', '#{SessionTimeout.maxInactiveIntervalInMilliSeconds}');&quot; /&gt;</code></p>
<p>&nbsp;</p>
<p>In JavaScript we can call a standard JavaScript function, setTimeout(), which calls the function specified in the first parameter, after an interval (in milliseconds) specified in the second parameter. In this case, setTimeout() calls our function popupSessionTimeout() after the number of milliseconds specified in the parameter maxInactiveIntervalInMilliSeconds (2.100.000 milliseconds&nbsp;is 35 minutes)&nbsp;. This is red by an EL expression from a backing bean who calls getMaxInactiveInterval() on the HttpSession object, which reflects the session-timeout time specified in the DD.</p>
<p>&nbsp;</p>
<p><code>var timeoutMessagePopup=null;<br />
function timerpopupSessionTimeout(timeoutMessage,maxInactiveIntervalInMilliSeconds)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeoutMessagePopup=timeoutMessage;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(&quot;popupSessionTimeout()&quot;, maxInactiveIntervalInMilliSeconds);<br />
}<br />
function popupSessionTimeout()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var answer = confirm(timeoutMessagePopup);<br />
&nbsp;if (answer){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;window.location = &quot;/myApplication/start&quot;;<br />
&nbsp;}<br />
}</code></p>
<p>&nbsp;</p>
<p>Now, every time a JSPX is rendered, the JavaScript function timerpopupSessionTimeout() is called, and a JavaScript confirm-popup is showed to the user after the session-timeout. <br />
&nbsp;</p>
<h3>&nbsp;</h3>
<h3>Problem with JavaScript-only solution</h3>
<p>This approach has one disadvantage: because of dialogs, Lists Of Values (LOV&#8217;s), &nbsp;and Partial Page Rendering (PPR) the session timeout time in the browser is not always reflecting the current inactive interval of the user in the application server. <br />
In our current application we have a lot of dialogs, LOV&#8217;s and PPR in the application.&nbsp;The ADF Faces Dialog and Process framework provides an easy way to jump to a page, or a series of pages, to get information from the user and then return to the original page to use that information.&nbsp;In ADF Faces this is called &quot;processes&quot;. One special type of process supported by ADF Faces is a &quot;dialog:&quot; it&#8217;s shown in a separate popup window instead of in the same window.&nbsp;&nbsp;</p>
<p>&nbsp;</p>
<p><img height="584" width="764" alt="" src="http://technology.amis.nl/blog/wp-content/uploads/image/session_poll_art/NIEUW_POPUP_Customize_mode(1).png" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>For example, when our &#8216;customize mode&#8217; link is clicked, the application shows a dialog&nbsp;with customizable prompts. When the user chooses and&nbsp;saves these prompts and closes the popup window, the server receives a request to save data and to close the window. But it will also reset the session timeout time, starting again from the beginning with the time in minutes specified in the DD, for example 35 minutes. At the same time in your browser, your afh:script component in the JSPX will not refresh and will not start over from the beginning but continues to count down and will be maybe already around 34 minutes. Now our popup message might come too early &#8211; we don&rsquo;t want smart users to click the message away and still continue with the application. We need to make sure the session is already invalidated when our message is displayed to the user. For the same reason Partial Page Rendering&nbsp;is a problem for this solution. PPR is a technology provided by ADF Faces that allows a portion of a page to be redrawn rather than reloading the entire page. If there are many components redrawn by PPR in a JSPX and our afh:script is not redrawn, the browser session timeout time won&rsquo;t be reset. We need a better and saver solution to make sure the session is invalidated. We can do that making use of the af:poll component.</p>
<p>&nbsp;</p>
<h3>Solution using an af:poll component</h3>
<p>&nbsp;</p>
<p>The main idea is this: An &lt;af:poll&gt; component can trigger an event (a so called PollEvent) after the time that is specified by the interval attribute. We will trigger a request just before (one minute) the session is about to be expired on the server. On the &lsquo;pollListener&rsquo; attribute we can specify with EL a listener in a backing bean to this pollEvent. In this listener we can set the rendered property an afh:script component to true. This afh:script that now will be rendered will call a slightly different version of the JavaScript function &lsquo;timerpopupSessionTimeout()&rsquo; from above and will display our message to the user. At the same time, the user session is invalidated in this backing bean.</p>
<p>&nbsp;</p>
<p><code>&lt;!--start: destroy a session after session timeout and show a popup window informing the user. --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;af:panelGroup id=&quot;pollPanelGroup&quot; partialTriggers=&quot;timer&quot;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;af:poll interval=&quot;#{PollListener.sessionTimeoutLaunchPopup}&quot; id=&quot;timer&quot; pollListener=&quot;#{PollListener.pollaction}&quot;/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;afh:script id=&quot;pollTriggeredPopupSessionTimeout&quot; rendered=&quot;#{PollListener.sessionTimeoutPopupRendered}&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; text=&quot;timerpopupSessionTimeout('#{nls['SESSION_TIMEOUT_MESSAGE']}');&quot;/&gt;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/af:panelGroup&gt;<br />
&nbsp; &lt;!--end: destroy a session after session timeout and show a popup window informing the user. --&gt;</code></p>
<p>&nbsp;</p>
<p>
This code could be added to each JSPX page. But most applications have a general region-JSPX that is part of every JSPX where they offer some general functionality (a region with menu- or help links). Then it can be added only to this page.<br />
After the interval, in our case 34 minutes, a pollEvent is triggered and the listener method is called in our backing bean called PollListener.java. We make this backing bean available by registering it in faces-config.xml:</p>
<p>&nbsp;</p>
<p><code>&lt;managed-bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;managed-bean-name&gt;pollListener&lt;/managed-bean-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;managed-bean-class&gt;HR.session.PollListener&lt;/managed-bean-class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt;<br />
&lt;/managed-bean&gt;</code></p>
<p>&nbsp;</p>
<p>If we want the af:poll component to trigger an event before the session is invalidated on the server, we must be sure to take enough time. There is a start-time difference between the time the container receives the request (=HttpSession. getLastAccessedTime(), from this point in time the server starts counting), and the time the poll-interval from the JSPX starts in the client&#8217;s browser. When, for example, a JSPX request with an af:poll component takes 30 seconds to respond and to display in the browser after the webcontainer (server) receives the user-request, the poll interval start-time in the browser begins 30 seconds LATER than the container starts the session inactive-interval. To be safe, we use 60 seconds because we have several JSPX pages that can take up to a 30 seconds before the browser receives a response and the browser interval starts. When a response takes even longer than 60 seconds, the pollEvent will be triggered after the session is invalidated by the container, and that is of course a situation we don&rsquo;t want.</p>
<p>First, in the constructor, we will set the HttpSession object and the attribute &lsquo;sessionTimeoutLaunchPopup&rsquo;. This attribute has a value binding with the &lsquo;interval&rsquo; attribute of the af:poll component. Its value is the maximum inactive interval in seconds that is specified in the DD (returned by session.getMaxInactiveInterval() ) multiplied by 1000 to get milliseconds and then subtract the result with 60.000 milliseconds (1 minute):</p>
<p>&nbsp;</p>
<p><code>public PollListener() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FacesContext ctx = FacesContext.getCurrentInstance();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session = request.getSession(false);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>int maxInactiveIntervalInSeconds = session.getMaxInactiveInterval();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionTimeoutLaunchPopup = ((maxInactiveIntervalInSeconds * 1000) - 60000);<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</code></p>
<p>&nbsp;</p>
<p>When the interval time of our af:poll component is passed, a pollEvent is triggered and our listener method is called:</p>
<p>&nbsp;</p>
<p><code>public void pollaction(PollEvent pe) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;pollaction()...&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>sessionTimeoutPopupRendered=true;&nbsp;<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread thread = new Thread(new SessionInvalidator());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread.start();<br />
&nbsp;&nbsp;&nbsp; }&nbsp;</code></p>
<p>&nbsp;</p>
<p>As you can see, the &lsquo;sessionTimeoutPopupRendered&rsquo; attribute in the listener is set to true, now the &lsquo;rendered&rsquo; property of the afh:script component will evaluate to true and will be rendered in response to the pollEvent:</p>
<p>&nbsp;</p>
<p><code>&lt;afh:script id=&quot;pollTriggeredPopupSessionTimeout&quot; </code><strong><code>rendered=&quot;#{PollListener.sessionTimeoutPopupRendered}&quot;</code></strong><code> text=&quot;timerpopupSessionTimeout('#{nls['SESSION_TIMEOUT_MESSAGE']}');&quot; /&gt;&nbsp;</code></p>
<p>&nbsp;</p>
<p>Note that we have set the &lsquo;partialTriggers&rsquo; attribute on the parent component af:panelGroup:</p>
<p>&nbsp;</p>
<p>&nbsp;<code>&lt;af:panelGroup id=&quot;pollPanelGroup&quot; <strong>partialTriggers=&quot;timer&quot;</strong> &gt;</code></p>
<p>&nbsp;</p>
<p>Now the timerpopupSessionTimeout(&#8216;#{nls['SESSION_TIMEOUT_MESSAGE']}&#8217;) JavaScript function is called which renders our message (Complete JavaScript code is coming below).</p>
<p>&nbsp;</p>
<p>We have still one problem: we have to make sure our session object is invalidated. If we do it straight away in the listener, our response won&rsquo;t be rendered because it needs a valid session object. Without a valid session object&nbsp;the essential FacesContext object won&rsquo;t be available anymore to render the response. The application will immediately go back to the Login page without showing the popup message. The response must be completed before the session can be made invalid. This pollEvent is a small PPR request, so the response won&rsquo;t take that long. We can make the session invalid in a separate thread and let it sleep for 5 seconds before the session is invalidated. This to first allow the PPR-response to be rendered and to show our JavaScript popup message:</p>
<p>&nbsp;</p>
<p><code>Thread thread = new Thread(new SessionInvalidator());<br />
thread.start();</code></p>
<p>&nbsp;</p>
<p>And with an inner class that implements Runnable the session can be made invalid:</p>
<p>&nbsp;</p>
<p><code>class SessionInvalidator implements Runnable {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;in run()... sleep 5 seconds before session is destroyed, to first allow a PPR-response to render a session-has-expired JavaScript popup message&hellip;&quot;);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Thread.sleep(5000);<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;exc: &quot;+e);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(session!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>session.invalidate();<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;in run()...session has been invalidated&quot;); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</code></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Our complete PollListener.java:</p>
<p>&nbsp;</p>
<p><code>package HR.session;<br />
import javax.faces.context.FacesContext;<br />
import javax.servlet.http.HttpServletRequest;<br />
import javax.servlet.http.HttpSession;<br />
import oracle.adf.view.faces.event.PollEvent;<br />
import org.apache.commons.logging.Log;<br />
import org.apache.commons.logging.LogFactory;</code></p>
<p><code>public class PollListener {<br />
&nbsp;&nbsp;&nbsp; private boolean sessionTimeoutPopupRendered = false;<br />
&nbsp;&nbsp;&nbsp; private int sessionTimeoutLaunchPopup;<br />
&nbsp;&nbsp;&nbsp; private HttpSession session;<br />
&nbsp;&nbsp;&nbsp; private static final Log sLog = LogFactory.getLog(PollListener.class);<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public PollListener() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FacesContext ctx = FacesContext.getCurrentInstance();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session = request.getSession(false);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int maxInactiveIntervalInSeconds = session.getMaxInactiveInterval();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionTimeoutLaunchPopup = ((maxInactiveIntervalInSeconds * 1000) - 60000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public void pollaction(PollEvent pe) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;pollaction()...&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionTimeoutPopupRendered=true; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread thread = new Thread(new SessionInvalidator());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread.start();<br />
&nbsp;&nbsp;&nbsp; }&nbsp;</code></p>
<p><code>&nbsp;&nbsp;&nbsp; public boolean isSessionTimeoutPopupRendered() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sessionTimeoutPopupRendered;<br />
&nbsp;&nbsp;&nbsp; }</code></p>
<p><code>&nbsp;&nbsp;&nbsp; public int getSessionTimeoutLaunchPopup() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sessionTimeoutLaunchPopup;<br />
&nbsp;&nbsp;&nbsp; }</code></p>
<p><code>&nbsp;&nbsp;&nbsp; class SessionInvalidator implements Runnable {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;in run()...sleep 5 seconds before session is destroyed, to first allow a PPR-response to render a session-has-expired JavaScript popup message...&quot;); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(5000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;exc: &quot;+e);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(session!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.invalidate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sLog.debug(&quot;in run()...session has been invalidated&quot;); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}</code></p>
<p>&nbsp;</p>
<p>Because we make the session invalid at the server, in a separate thread 5 seconds after the listener method is called, we must show our message in the browser 5 seconds later to make certain the session is already invalidated before the message is showed. We can do that by calling the standard JavaScript function setTimeout() and by specifying 5000 milliseconds in the second parameter (the same time the separate thread in Java sleeps):</p>
<p>&nbsp;</p>
<p><code>setTimeout(&quot;popupSessionTimeout()&quot;, 5000);</code></p>
<p>&nbsp;</p>
<p>Our final JavaScript file:</p>
<p>&nbsp;</p>
<p><code>var timeoutMessagePopup=null;<br />
function timerpopupSessionTimeout(timeoutMessage){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeoutMessagePopup=timeoutMessage;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(&quot;popupSessionTimeout()&quot;, 5000);<br />
}<br />
function popupSessionTimeout(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var answer = confirm(timeoutMessagePopup);<br />
&nbsp;if (answer){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;window.location = &quot;/myapplication/start&quot;;<br />
&nbsp;}<br />
}</code></p>
<p>&nbsp;</p>
<p>Now we are sure the session is already invalidated when the user sees our message. All the user has to do to return to the Login page is pressing the enter key. When &lsquo;Cancel&rsquo; is choosen, the application won&rsquo;t return to the login page but the session will &#8211; of course &#8211; still be invalid and the user won&rsquo;t be able to do anything before logging in again.</p>
<p>&nbsp;</p>
<p><img height="249" width="911" src="http://technology.amis.nl/blog/wp-content/uploads/image/session_poll_art/ART_message_and_loginpage(1).png" alt="" /><br />
&nbsp;<br />
&nbsp;</p>
<p>&nbsp;</p>
<h3>Maintaining a user session while the application is open in the browser</h3>
<p>&nbsp;</p>
<p>Maybe you don&rsquo;t want users to be thrown out of the application server, and maintain all user sessions while their application is open in the browser. One option is to set the session-timeout in the DD to the value of -1, and sessions won&rsquo;t timeout on the application server. But this option has a big disadvantage: if you have thousands and thousands of users and when they do close the application using the browser X close-button on the right upper side, the user session will unnecessary stay alive in the application server, and still use valuable memory space. Many users do not click on a logout link which should invalidate their session in the application server using HttpSession.invalidate().</p>
<p>&nbsp;</p>
<p>A second and in my opinion better option is to maintain a user session only when the application is open in the browser. We can also use an af:poll component for this:</p>
<p>&nbsp;</p>
<p><code>&lt;af:poll interval=&quot;2040000&quot;/&gt;</code></p>
<p>&nbsp;</p>
<p>As long as the application is open in the browser, you can trigger a request just before the session is about to be expired on the server. You simply specify an interval time a little bit smaller (for example 1 minute) than your maximum inactive interval time. In our case&nbsp;2.040.000 milliseconds could be specified on the af:poll component (34 minutes, our session timeout time minus 1). Now this af:poll will take care of triggering an event on the client and deliver it at the server, and the session timeout time will start from the beginning again and the session won&rsquo;t be invalidated. When a user closes his browser using the browser X close button, no more poll events will be triggered AND the application server will invalidate the session after 35 minutes and save valuable memory space.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2009/03/16/how-to-let-your-user-know-his-session-has-expired-in-an-adf10g-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Refreshing breadcrumbs in an ADF application that uses JHeadstart</title>
		<link>http://technology.amis.nl/2008/11/01/refreshing-breadcrumbs-in-an-adf-application-that-uses-jheadstart/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=refreshing-breadcrumbs-in-an-adf-application-that-uses-jheadstart</link>
		<comments>http://technology.amis.nl/2008/11/01/refreshing-breadcrumbs-in-an-adf-application-that-uses-jheadstart/#comments</comments>
		<pubDate>Sat, 01 Nov 2008 00:34:12 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java, JEE, OAS and WebLogic Server]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[adf]]></category>
		<category><![CDATA[bread crumbs]]></category>
		<category><![CDATA[jheadstart]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=3880</guid>
		<description><![CDATA[Breadcrumbs are a navigation technique used in many applications, and its popularity grows. Its purpose is to give users a way to keep track of their location. Breadcrumbs typically appear horizontally across the top of a webpage, usually below any title bars or headers. They provide links back to  [...]]]></description>
				<content:encoded><![CDATA[<p>Breadcrumbs are a navigation technique used in many applications, and its popularity <a href="http://www.useit.com/alertbox/breadcrumbs.html">grows</a>. Its purpose is to give users a way to keep track of their location. Breadcrumbs typically appear horizontally across the top of a webpage, usually below any title bars or headers. They provide links back to a previous page that the user navigated through in order to get to the current page, for hierarchical structures usually the parent pages of the current one. In hierarchical site layouts, like an ADF application that uses JHeadstart, breadcrumbs indicate the path back to the root page (or JHeadstart master group page) of the hierarchy with links:</p>
<p><img height="103" width="605" src="http://technology.amis.nl/blog/wp-content/uploads/image/2e_JHeadstart_demo_breadcrumbs.PNG" alt="" /></p>
<p>Currently we have a challenge in our JHeadstart ADF application;<span id="more-3880"></span></p>
<p>after an insert or update many of our precious breadcrumbs are missing or don&rsquo;t refresh to their updated value. In a JHeadstart application, items that are set as a group &lsquo;descriptor item&rsquo; can become a breadcrumb and appear on the breadcrumb stack. We have many descriptor items which values are set by a database trigger or are an <a href="http://download.oracle.com/docs/cd/B31017_01/web.1013/b25947/bcvoeo006.htm">SQL-calculated attribute</a> in the VO (View Object). For example: we have an address that is set by a trigger that concatenates the street name, street number, postal code and city. After each insert, update or delete our application navigates to a different JSPX called a &lsquo;Success Page&rsquo;, which (only) purpose is to tell the user that the insert, update or delete has been committed successfully. For example, If we want to change the first name of a &lsquo;kandidaat&rsquo; (English: candidate), lets say Boris Becker to Boris Brown, the application navigates to our &lsquo;Success&rsquo; JSPX.&nbsp; The breadcrumb is still on the breadcrumb stack, but the problem is that the breadcrumb still reflects the old last name! And our new organization name and organization address, both set by a database trigger, do not even appear at all on the stack! Of course this is not a desired situation.</p>
<p><img height="559" width="832" src="http://technology.amis.nl/blog/wp-content/uploads/image/OUDE%20SITUATIE%20BREADCRUMBS.PNG" alt="" /></p>
<p>In our application, its not a problem of the ADFBC layer; after a commit is executed, VO attributes set by a database trigger are already refreshed in the ADFBC layer by setting the &lsquo;refresh after insert&rsquo; and &lsquo;refresh after update&rsquo; on the EO (Entity Object). And for&nbsp;SQL-calculated attributes a requery is needed in the afterCommit() method of the VO; like a <a href="http://radio.weblogs.com/0118231/2004/11/22.html">refresh-but-stay-where-you-were requery</a> method &lsquo;refreshQueryKeepingCurrentRow()&rsquo; Steve Muench described.</p>
<h2>Implementation of Breadcrumbs by JHeadstart (version 10.1.3.2)</h2>
<p>First, before we can look for a solution we have to figure out how breadcrumbs are implemented in an ADF application that uses JHeadstart. Breadcrumbs are standard JHeadstart functionality. The only documentation I could find about JHS (JHeadstart) breadcrumbs was in an old JHeadstart developers guide (release 10.1.2.1, 2005, based on Jakarta Struts instead of JSF, but a major part of the breadcrumb documentation is still valid). It tells us that &ldquo;In (almost) 100% generated applications, chances are you&rsquo;ll never need to know how the mechanism behind the breadcrumbs functionality works, and how you can influence its behavior. However, if you are manually creating complex pageflows in a JHeadstart application, you might need to have some control over the way the breadcrumbs work.&rdquo; So, the first challenge is to understand how these breadcrumbs are implemented. I will explain only the relevant basic parts in relation to our issue.&nbsp;&nbsp;</p>
<h3>&lt;af:menuPath&gt; tag</h3>
<p><img height="224" width="712" src="http://technology.amis.nl/blog/wp-content/uploads/image/JSP_BREADCRUMAREA_JHS_CODE.PNG" alt="" /></p>
<p>In each JSPX file a breadcrumb area is generated with a &lt;af:menuPath&gt; tag. A menuPath component is used in hierarchical site layouts to indicate the path back to the root page of the hierarchy with links. A child representing the current page should be the last child. This menuPath tag has a value of #{jhsBreadcrumbStack}. The nodes in the breadcrumb stack are stamped out with the &#8216;nodeStamp&#8217; facet, which contains a commandLink component with their corresponding actions ( #{bc.goToDestination} ) (which uses the default JSF actionListener mechanism for page navigation), and labels ( #{bc.label} ).&nbsp; The EL expression #{jhsBreadcrumbStack} will result in a call to the JhsBeadcrumbStack managed bean which extends ViewIdPropertyMenuModel. A &#8216;MenuModel&#8217; object represents the menu structure of a page or application.</p>
<h3>&lt;ServiceName&gt;-Breadcrumb-beans.xml</h3>
<p>In &lt;ServiceName&gt;-Breadcrumb-beans.xml, JHeadstart creates for each JHeadstart group a managed bean called &lsquo;&lt;GroupName&gt;Breadcrumb&rsquo; of type BreadcrumbConfiguration.java. The JHS template &lsquo;breadcrumbFacesConfig.vm&rsquo; is used to create this managed bean. For example the AllEmployees group:</p>
<p><img height="390" width="819" src="http://technology.amis.nl/blog/wp-content/uploads/image/ServiceNameBreadcrumb-beans_BreadcrumbConfiguration.PNG" alt="" /></p>
<h3>Breadcrumb and BreadcrumbConfiguration</h3>
<p>A BreadcrumbConfiguration object is used for the creation of a Breadcrumb object. As we can see, 4 properties of a BreadcrumbConfiguration are set by the JSF Managed Bean facility: a (destination) page, a label (rendered as label for the breadcrumb commanLink), a label-parameter-expression (EL-expression, a parameter for the label), and a unique key (JSPX name without slash and .jspx). A BreadcrumbConfiguration object is a simple JavaBean with getters and setters for these properties and some other. The BreadcrumbManager, responsible for managing/processing the current stack of breadcrumbs, creates a Breadcrumb object by using the properties of a corresponding BreadcrumbConfiguration object. When a new Breadcrumb is created, his destination (a ViewId) is set using the page property, so that clicking on the breadcrumb link will execute the goToDestination() method on the Breadcrumb. The ViewId of the breadcrumb will be set as the new viewRoot and the application navigates to the page corresponding to its breadcrumb.</p>
<p>The label and label-parameter EL-expression of a breadcrumb is the text that that is shown to the end user in the page for this breadcrumb, and is therefore derived from the application&rsquo;s resource bundle to allow for internationalization. The key for the current breadcrumb is derived as follows:<br />
BREADCRUMB_&lt; JSPX name in uppercase&gt;.&nbsp; It is possible to have &lsquo;dynamic&rsquo; labels, by having the value in the resource bundle contain substitution parameters like {0}:</p>
<p><img height="177" width="597" src="http://technology.amis.nl/blog/wp-content/uploads/image/SQLDEVELOPER_BREADCRUMB.PNG" alt="" /></p>
<p>The EL expression of a JHS group descriptor item (generated in the labelParamExpressions property in &lt;ServiceName&gt;-Breadcrumb-beans.xml) will result in the substitution value for &lsquo;{0}&rsquo;, and pass them to the label of the breadcrumb.&nbsp;</p>
<p>Most important methods of a Breadcrumb object are:</p>
<ul>
<li>goToDestination() &ndash; The viewed of this Breadcrumb is set as the new ViewRoot of the application.</li>
<li>getLabel() &ndash; returns the current label and parameter value.</li>
<li>resetLabel() -&nbsp; This method reevaluates the label of the breadcrumb, reevaluates the parameters, and reconstructs the &#8216;label&#8217; based on the original key and the new parameter values. It calls deriveParamValues() that takes the &#8216;labelParamExpressions&#8217; property of the BreadcrumbConfiguration, and evaluates the EL expression(s) in it. It will take that EL expression, for example from the AllEmployeesBreadcrumb labelParamExpression &lsquo;bindings.AllEmployeesLastName.inputValue&rsquo; and evaluate it:</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <code>String paramExp = &quot;#{&quot;+paramExps+&quot;}&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paramValue = JsfUtils.getExpressionValue(paramExp);</code></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Soo, if you are updating employee Bates, the breadcrumb label &lsquo;Edit employee {0}&rsquo; should become &lsquo;Edit employee Bates&rsquo;.</p>
<p>A JHS template &#8216;common_labels.vm&#8217;&nbsp;creates these labels and &#8216;labelParamExpressions&#8217; in the resource bundle.&nbsp;In common_labels.vm there are 4 macros:</p>
<ul>
<li>BREADCRUMB_LABEL_FORM_PAGE</li>
<li>BREADCRUMB_LABEL_TABLE_PAGE,</li>
<li>BREADCRUMB_LABEL_SEARCH_PAGE</li>
<li>BREADCRUMB_LABEL_SELECT_PAGE</li>
</ul>
<p>For example:</p>
<p><code>#macro (BREADCRUMB_LABEL_FORM_PAGE $page)<br />
${JHS.nls(${page.group.displayTitleSingular}, &quot;BREADCRUMB_${page.nameUppercase}&quot;, &quot;EDIT_TITLE&quot;,false,true)}#end</code></p>
<p>&#8216;EDIT_TITLE&#8217; in the macro will be replaced by its value in GeneratorText.properties:<br />
EDIT_TITLE = Edit {0} &#8216;{&#8217;0}<br />
For Employees, the generated resource bundle entry will be &lsquo;Edit employee {0}&rsquo;.</p>
<h3>BreadcrumbStack</h3>
<p>Represents the current stack of breadcumbs (Breadcrumb objects &ndash; simple javaBean objects) for the current application&rsquo;s ViewRoot. BreadcrumbStack extends ViewIdPropertyMenuModel (which extends BaseMenuModel, which extends MenuModel), A BreadcrumbStack object can be treated as a MenuModel object what is exactly what a af:menuPath tag needs as its value, so an EL expression of #{jhsBreadcrumbStack} will return the collection of Breadcrumb objects. It is generated in JhsCommon-beans.xml and created/retrieved using the JSF Managed Bean facility. Don&rsquo;t forget to set the showBreadcrumbCurrentPage to true (default is false) if you want a breadcrumb representing your current page:</p>
<p><img height="260" width="781" src="http://technology.amis.nl/blog/wp-content/uploads/image/JhsCommonBeans_jhsBreadcrumbStack.PNG" alt="" /></p>
<p>&nbsp;Important methods:</p>
<ul>
<li>getBreadcrumbStack(). This static method will retrieve and if not present create a Breadcrumb stack object from the session.</li>
<li>Add(Object o). Adds a Breadcrumb object to the stack.</li>
</ul>
<h3>BreadcrumbManager</h3>
<p>Responsible for managing and processing the current stack of breadcrumbs. The BreadcrumbStack is created/retrieved using the JSF Managed Bean facility. Most important method:</p>
<ul>
<li>processBreadcrumbs() &#8211; This is the &#8216;main&#8217; method, it will create and remove breadcrumbs, process the Breadcrumb stack and perform any actions necessary on this stack needed to synchronize it with the current state of the application.</li>
</ul>
<h3>&nbsp;Algorithm<img height="866" width="911" src="http://technology.amis.nl/blog/wp-content/uploads/image/ALGORITME.PNG" alt="" /></h3>
<ol>
<li>JhsPageLifecycle calls, in its method prepareModel(), the &#8216;main&#8217; method of the BreadcrumbManager, that processes the breadcrumb stack.</li>
<li>BreadcrumbManager retrieves the current BreadcrumbStack object.</li>
<li>BreadcrumbManager gets the BreadcrumbConfiguration object for the requested page.</li>
<li>The BreadcrumbManager retrieves the BreadcrumbConfiguration object in the breadcrumbConfigs HashMap (corresponding to the requested page), creates a new Breadcrumb object (by setting the BreadcrumbConfiguration object as an argument in the constructor).&nbsp;The Breadcrumb uses the properties of the BreadcrumbConfiguration object to set its own properties like a (destination) page, a label, a label-parameter-expression, and a unique key (JSPX).</li>
<li>The Breadcrumb object is added to the stack. If the Breadcrumb is already on the stack, it is &#8216;rolled back&#8217; to the Breadcrumb before the one that is &#8216;the same&#8217; as the current breadcrumb, and then the current breadcrumb is added.</li>
<li>JhsPageLifecycle calls the &#8216;main&#8217; process-method of the BreadcrumbManager again, now in the prepareMode phase in prepareModel(). 2, 3, 4 and 5 are repeated.</li>
<li>The EL expression #{jhsBreadcrumbStack} in the JSPX is evaluated and the breadcrumb stack is rendered.</li>
</ol>
<h2>Solution</h2>
<p>OK, now that we have gained some insight how breadcrumbs are implemented in a JHeadstart application, we can figure out the solution. The main problem, in our case, is that breadcrumbs generated by JHeadstart are created and its labelParamexpressions (EL expressions) are evaluated too early in the ADF lifecycle; in the prepareModel phase. As we saw in the previous section, the JhsPageLifecycle instance calls in its method prepareModel() the method processBreadcrumbs() of the BreadcrumbManager object. This method creates the Breadcrumb instance, gets its label from the resourcebundle (by using the labelKey property) and evaluates the LabelParameter EL expression(s), and adds the Breadcrumb object to the BreadcrumbStack.</p>
<p>The JhsPageLifecycle instance calls, in the ADF prepareRender phase in prepareRender(), again the processBreadcrumbs() method of the BreadcrumbManager object. In a standard JHeadstart application, after an update or insert, the user navigates back to the same page, the processBreadcrumbs() is called twice in the ADF lifecycle and in the prepareRender phase the breadcrumb is nicely refreshed to the current state of the updated or new breadcrumb. This is in most cases desired behavior when you use the standard JHeadstart pageflow. In our application, we use a different pageflow, and our breadcrumbs are not evaluated again to reflect current row changes, because we don&rsquo;t navigate to the same page. Our current ViewId changes after an update or insert and we navigate to a new JSPX file, in our application called a &lsquo;Success&rsquo;-page (we give the user a new page with a message that the insert, update or delete has been successful).</p>
<p>In our application, refreshing is not possible anymore in the prepareRender phase, because we navigate to a new JSPX file (our Success.jspx), and in the prepareRender phase the BindingContainer object does not contain the reference values of the binding objects of the previous JSPX anymore. Values that binding objects refer to have request-scope: they are only valid during a request in which that binding container has been prepared by the ADF lifecycle. If the application is navigating to a different viewed, in the prepareRender phase the BindingContainer has already been prepared by the ADF lifecycle to contain the binding objects and the values they reference to serve the new JSPX, and the values of the binding objects of the previous JSPX are released and not accessible anymore.</p>
<p>So, reevaluation of breadcrumbs must be done earlier in the ADF lifecycle phase. After the invokeApplication phase seems to be the right time.&nbsp;</p>
<p><img height="487" width="1049" src="http://technology.amis.nl/blog/wp-content/uploads/image/ADF_LIFECYCLE%20FASES_PHASELISTENER.PNG" alt="" /><br />
The reference values of the binding objects of the BindingContainer are still accessible for our page, and are now able to access the refreshed values from the ADFBC layer. In the JSF invokeApplication phase new or updated rows are send to the database, a commit is executed, VO attribute values are refreshed in the ADFBC layer by a &lsquo;refresh after insert&rsquo; on the EO, an executeQuery() method on the VO or a refresh() method on the EO or VO. If we make a JSF PhaseListener, that listens for the JSF invokeApplication phase, we can access ADFBC&rsquo;s refreshed values directly after the invokeApplication phase in the afterPhase() method of this PhaseListener. In our case after an update or insert, the ViewId() is changed between the&nbsp; between the beforePhase() and&nbsp; afterPhase() of the invokeApplication phase, so we should set the previous ViewId() in the beforePhase() method, and we can use it in the afterPhase() method:</p>
<p><code>BreadcrumbManager bcm = (BreadcrumbManager)BreadcrumbManager.getBreadcrumbManager();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(getOldViewId()!=null) bcm.processBreadcrumbs(null, getOldViewId() , null, null);</code></p>
<p>Now the label and the EL expression of its parameter(s) are reevaluated (in reality removed from stack and newly created).</p>
<p>&nbsp;</p>
<pre class="wp-code-highlight prettyprint">&lt;p&gt;public class BreadcrumbRefreshPhaseListener implements PhaseListener {&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;private String oldViewId = null;&lt;br /&gt;private static final Log sLog = LogFactory.getLog(BreadcrumbRefreshPhaseListener.class);&lt;/p&gt;&lt;p&gt;public BreadcrumbRefreshPhaseListener() {}&lt;/p&gt;&lt;p&gt;public PhaseId getPhaseId() {&lt;br /&gt;         	return PhaseId.INVOKE_APPLICATION;&lt;br /&gt; 	}&lt;br /&gt;&lt;br /&gt;public void beforePhase(PhaseEvent e) {&lt;br /&gt;		sLog.debug(&amp;quot;PhaseId.INVOKE_APPLICATION - beforePhase() - ViewId() now: &amp;quot;+getCurrentViewId());&lt;br /&gt;		setOldViewId(getCurrentViewId());&lt;br /&gt;	}&lt;/p&gt;&lt;p&gt;public void afterPhase(PhaseEvent e) {&lt;br /&gt;		sLog.debug(&amp;quot;PhaseId.INVOKE_APPLICATION - afterPhase() - ViewId() now: &amp;quot;+getCurrentViewId());&lt;br /&gt;		BreadcrumbManager bcm = (BreadcrumbManager)BreadcrumbManager.getBreadcrumbManager();&lt;br /&gt;		bcm.processBreadcrumbs(null, getOldViewId(), null, null);&lt;br /&gt;	}&lt;/p&gt;&lt;p&gt;public static String getCurrentViewId() {&lt;br /&gt;		return FacesContext.getCurrentInstance().getViewRoot().getViewId();&lt;br /&gt;	}&lt;/p&gt;&lt;p&gt;public void setOldViewId(String oldViewId) {&lt;br /&gt;		this.oldViewId = oldViewId;&lt;br /&gt;	}&lt;/p&gt;&lt;p&gt;public String getOldViewId() {&lt;br /&gt;		return oldViewId;&lt;br /&gt;	}&lt;br /&gt;}&lt;/p&gt;</pre>
<p>&nbsp;</p>
<p>We also have to register this phaseListener in JhsCommonBeans.xml (and in the JHS template JhsCommonBeans.vm) :</p>
<pre class="wp-code-highlight prettyprint">&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;code&gt;&amp;lt;lifecycle&amp;gt;&lt;br /&gt;    &amp;lt;phase-listener&amp;gt;oracle.jheadstart.controller.jsf.lifecycle.JhsADFPhaseListener&amp;lt;/phase-listener&amp;gt;&lt;br /&gt;    &amp;lt;phase-listener&amp;gt;nl.myproject.jheadstart.controller.BreadcrumbRefreshPhaseListener&amp;lt;/phase-listener&amp;gt;&lt;br /&gt;&amp;lt;/lifecycle&amp;gt;&lt;/code&gt;&lt;/p&gt;</pre>
<p>&nbsp;</p>
<p>Now, our breadcrumbs are added or refreshed after an insert or update when we navigate to the Success.jspx:</p>
<p><img height="528" width="852" src="http://technology.amis.nl/blog/wp-content/uploads/image/NIEUWE%20SITUATIE%20BREADCRUMBS.PNG" alt="" /></p>
<p>
&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2008/11/01/refreshing-breadcrumbs-in-an-adf-application-that-uses-jheadstart/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to maintain entity validation (JboException) and ORA-20xxx messages in a central resource bundle in your ADF application that uses JHeadstart</title>
		<link>http://technology.amis.nl/2008/02/21/how-to-maintain-adf-bcs-exception-jboexception-and-ora-20xxxsqlexception-messages-in-your-jheadstart-resourcebundle/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-maintain-adf-bcs-exception-jboexception-and-ora-20xxxsqlexception-messages-in-your-jheadstart-resourcebundle</link>
		<comments>http://technology.amis.nl/2008/02/21/how-to-maintain-adf-bcs-exception-jboexception-and-ora-20xxxsqlexception-messages-in-your-jheadstart-resourcebundle/#comments</comments>
		<pubDate>Thu, 21 Feb 2008 15:38:43 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=2870</guid>
		<description><![CDATA[As you can imagine, with many validators on many entity objects you will end up with equally many generated message bundles. When you start localizing the error messages, that means you have to maintain many classes. Keeping those messages consistent can become an error-prone task. In this article  [...]]]></description>
				<content:encoded><![CDATA[<p>As you can imagine, with many validators on many entity objects you will end up with equally many generated message bundles. When you start localizing the error messages, that means you have to maintain many classes. Keeping those messages consistent can become an error-prone task. In this article I will first describe how to use one single resource bundle (generated by JHeadstart) so that you only have to localize one resource bundle, and keeping entity validation error messages consistent becomes easy. Then I will show that this resource bundle can also be used to maintain ORA-20xxx (SQLException, user-defined PL/SQL error) messages, and finally that this is also possible for any other custom JBO exception thrown from the BC layer.&nbsp;<img src="wp-content/plugins/xinha4wp/xinha_core/plugins/InsertMore/img/ed_more.png" alt="...." /><span id="more-2870"></span></p>
<h3>Entity validation error messages</h3>
<p>By default, the built-in validators of ADF BC throw subclasses of JboException, AttrValException (attributelevel validation) and ValidationException (entity-instance-level validation). Depending on whether the exception is an attribute-level or entity-instance-level validator they are automatically called during the set&lt;Attribute&gt; or validateEntity() method respectively. When an error occurs, a message you specified in the entity object editor is displayed to the user, which includes the error message you specified for the validator in the entity object editor, including a reference to the class name of the exception.</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/standaard_eo_validation.bmp" /></p>
<p>Any message you specify when creating a built-in validator or method validator is stored in an entity-specific, automatically generated message (resource) bundle, for example &lsquo;HR.model.entities.EmployeesImplMsgBundle&rsquo;.</p>
<p>&nbsp;<img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/eoimplmsgbundle.bmp" /></p>
<p>For our current project what we would like to have instead is an <em>errorcode</em> in the validation rule error-message, as a key to a text error-message later retrieved from a centralized resource bundle. This errorcode will be saved in the standard &lt;EOImpl&gt;MsgBundle file. We want our (custom) key format code to be &lsquo;CXS-xxxxx&rsquo;. Now JboExceptions thrown by entity validation will provide the NLS key <em>as the message text</em>:</p>
<p>&nbsp;<img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/eo_cxs_validation_rule.bmp" /></p>
<p>&nbsp;</p>
<h4>Resource bundle</h4>
<p>A resource bundle is a Java class that contains a two-dimensional array of key-value pairs representing fixed &ldquo;boilerplate text&rdquo;, for example prompts, labels, titels but it can also contain error messages, for example:</p>
<p>package mypackage; import java.util.ListResourceBundle; public class MyMessageBundle extends ListResourceBundle { private static final Object[][] sMessageStrings = new String[][] ( {&quot;CXS-00001&quot;, &quot;Telephone number not more than 15 numbers, please!&quot;}, {&quot;CXS-00002&quot;, &quot;Job must be CLERK, MANAGER, PRESIDENT, or SALESMAN&quot;}, {&quot;TABLE_TITLE_ALLEMPLOYEES&quot;, &quot;All Employees&quot;} ); protected Object[][] getContents() { return sMessageStrings; } }</p>
<p>When using the newest JHeadstart version (10.1.3.2) on your project, you can specify whether the resource bundle is generated as a property file, a Java class or a database table. In this article we use a database table, but the other 2 resource bundle types could be used as well. In fact any resource bundle could be used. Using a database table, JHeadstart generates a Java resource bundle as well. This Java class resource bundle acts as a &ldquo;fa&ccedil;ade&rdquo; to our database table.</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/applicationresourcesclass.PNG" /></p>
<p>The Java resource bundle class delegates retrieval of the translatable strings to its JHeadstart superclass, TranslationTableresourceBundle, which uses a ViewObject in the nested JhsModelService to read the translatable text strings from the JHS_TRANSLATIONS table for the given locale. &nbsp;For each user session all key-value pairs from this table are queried and are available at the ApplicationResources object (the Java fa&ccedil;ade resource bundle) on the session context. Calling the method protected<em> </em>getContents()<em> </em>on the ApplicationResources object will cause this method to be invoked on its super class, TranslationTableResources, and return the two-dimensional array of key-value pairs.</p>
<p>Button labels, page header titles, database constraints and other fixed text generated by JHeadstart are generated into this resource bundle. Now we want to maintain our error-code and error-text messages from the EO validation as well in this database table. &nbsp;To do this ErrorReportingUtils, a class generated by JHeadstart, must be extended.&nbsp;</p>
<h4>ErrorReportingUtils</h4>
<p>Exceptions thrown by any part of an ADF application, so also by EO validation, are by default caught by the binding container. When an exception is encountered, the binding container routes the exception to the application&rsquo;s active error handler, which by default is the DCErrorHandlerImpl class. The reportException() method on this class passes the exception to the binding container to process. The binding container then processes the exception by placing it on the exception list in a cache. During the Prepare Render phase, the ADF lifecycle executes the reportErrors() method. By default, the reportErrors() method on the FacesPageLifecycle class accesses the exception list from the binding container, calls the addError() method, which creates and adds the messages to the FacesContext and clears the exceptions list in the binding container.</p>
<p>JHeadstart customizes this default framework behavior by having created a custom ADF lifecycle class, JhsPageLifecycle, which extends the default ADF Faces lifecycle and changes how the lifecycle reports errors by overriding the reportErrors() method:</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/jhspagelifecycle_reporterrors.bmp" /></p>
<p>As you can see a custom error handler, ErrorReportingUtils (a managed bean), is created. This class will transform exceptions into Faces error messages. It will do this only for certain types of exceptions, which can be configured in JhsCommon-beans.xml:</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/jhscommonbeans_original.PNG" /></p>
<p>ErrorReportingUtils accesses the exception list from the binding container. For all existing exceptions ErrorReportingUtils will process each exception individually and will finally add the exception message(s) to the FacesContext. It will recursively process detail exceptions wrapped inside a JboException (often a JboException has detail exceptions). In our case, the most important methods of ErrorReportingUtils are:</p>
<ul>
<li>reportErrors() // accesses the exception list from the binding container. For each individual exception the method translateExceptionToFacesErrors(<em>exception</em>,..,..) will be called.</li>
<li>translateExceptionToFacesErrors() // translates exceptions to the FacesContext. First this method will call processException(<em>exception</em>,..,..,..,..) for this exception to do all the process to get the error message. This method will finally add the exception error message(s) to the FacesContext.</li>
<li>processException() // Processes each exception individually. This method looks what kind of exception it is and populates a list of error messages for current exception. For JboExceptions, and in our case the subclasses AttrValException and ValidationException, this method calls getMessage(<em>exception</em>,..) to get the exception error message.</li>
<li>getMessage() // returns the complete exception message:&nbsp; {productCode}-{errorCode}: {messageBody}</li>
</ul>
<p>A proper entry point in this class is needed to intercept our specific EO validation JboException where the {messageBody} part of the message has our errorcode with our syntax &lsquo;CXS-xxxxx&rsquo;. Then, we could subclass ErrorReportingUtils and retrieve the corresponding errortext from our resourceBundle.</p>
<p>In our case, the best place for interception is (and to override in a subclass) the getMessage() method. This method calls the method getLocalizedMessage() on the Exception and returns the complete message for the current locale:</p>
<p><img alt="" src="http://technology.amis.nl/wp-content/uploads/images/getmessage_errorreportingutils.bmp" /></p>
<p><em>method getMessage() in ErrorReportingUtils</em></p>
<p>To do this we must create and then configure our subclass called HRErrorReportingUtils in JhsCommon-beans.xml (to replace ErrorReportingUtils):</p>
<p>&nbsp;<img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/jhscommon-beans.bmp" /></p>
<p>You have to make a JHS template to generate the correct values in JhsCommon-beans.xml. In our case: HR\misc\facesConfig: JhsCommon-beans.vm.</p>
<p>&nbsp;</p>
<p><img height="735" width="840" src="http://technology.amis.nl/blog/wp-content/uploads/image/1.PNG" alt="" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>In the getMessage() method of our subclass we have access to the error message of the Exception, we can check whether this error message starts with our {productCode}, &lsquo;CXS-&lsquo;. In that case we can create an object instance of a custom subclass of JboException, called HRMyCustomException:</p>
<p>HRMyCustomException mcex = new HRMyCustomException(productAndErrorCode);</p>
<p>All Exceptions thrown from the ADF BC framework should be subclasses of JboException. Translation of a message&#8217;s text occurs at the time the exception calls getLocalizedMessage(). JboExceptions have an attribute that stores the {productCode} part of a message.&nbsp; A subclass of a JboException could be provided with a value for the error code (product- and error code as one String) in a specialized constructor and, importantly, an own resource bundle.</p>
<p>In our custom subclass, we hard-coded our resource bundle (ApplicationResources.class) in the constructor. When the method getLocalizedMessage() is called on a HRMyCustomException object instance, ApplicationResources.class is used as message bundle, and returns the complete message corresponding to the productAndErrorCode key. The constructor has a product- and error code as one String (first 9 characters) as parameter, and calls his super class constructor (JboException) with our hard-coded resource bundle:</p>
<p>&nbsp; public HRMyCustomException(String productAndErrorCode)<br />
&nbsp; {&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; super(<strong>ApplicationResources.class</strong>, productAndErrorCode, null);&nbsp;&nbsp;&nbsp; <br />
&nbsp; }&nbsp;</p>
<p>The super class of our resource bundle, TranslationTableResourceBundle, extends the (standard) java.util.ListResourceBundle to format its messages, and supports NLS translation.</p>
<p>&nbsp;</p>
<p><img height="545" width="840" alt="" src="http://technology.amis.nl/blog/wp-content/uploads/image/2.PNG" /></p>
<p>&nbsp;</p>
<p>Finally, the last thing you have to do is copy the error text-messages from all the entity-specific message bundles to the JHS_TRANSLATION table, and give the entity object validators in the entity object editor a specific &lsquo;CXS-xxxxx&rsquo; errorcode.</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/toad_jhs_translations.bmp" /></p>
<p><em>Our JHS_TRANSLATIONS database table in Toad.</em></p>
<p>When our entity validator throws an exception, now our exception error message is derived from the JHS_TRANSLATIONS table.</p>
<p>&nbsp;<img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/prtscr_cxsxxxxx.bmp" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>ORA-20xxx error messages</h3>
<p>For our current project we also want to use our centralized resource bundle for ORA-20xxx error messages. ORA-20xxx errors are SQLExceptions in the range from ORA-20000 to ORA-20999, which is reserved for user-defined PL/SQL raise_application_errors.</p>
<p>Just like the getmessage() of ErrorReportingUtils method is a great entry point to override and modify JboExceptions (as is shown previously for entity validation exceptions), the method &nbsp;getOra20xxx(SQLException) in the same class ErrorReportingUtils is a perfect entry point for ORA-20xxx exceptions, because all SQLExceptions are passing trough it.</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/getora20xxx_errorreportingutils.bmp" /></p>
<p><em>Method </em><em>getOra20xxx()</em><em> in </em><em>ErrorReportingUtils</em></p>
<p>This method can be overridden (like we did before with the getMessage() method) in our subclass, HRErrorReportingUtils. The same kind of solution as with entity validation is chosen: when the overridden method getOra20xxx(SQLException) is called in our subclass, we know that a SQLException has arrived, and we can substitute our HRMyCustomException for the SLQException.</p>
<p>&nbsp;</p>
<p><img height="595" width="564" src="http://technology.amis.nl/blog/wp-content/uploads/image/4.PNG" alt="" /></p>
<p>&nbsp;</p>
<p>To get a message from our centralized resource bundle we can call our previously created getMessage() method in the same class, HRErrorReportingUtils (explained above&nbsp;in &#8216;entity validation error messages&#8217;, overridden from ErrorReportingUtils):</p>
<p>String sqlMessage = this.getMessage(sqlException,userLocale);</p>
<p>Now the if-condition in getMessage() of HRErrorReportingUtils can be adjusted to also recognize &lsquo;ORA-20xxx&rsquo; exceptions by checking the first part of the errorcode (&lsquo;ORA-20&rsquo;):</p>
<p>if (message.startsWith(&quot;CXS-&quot;)&nbsp;&nbsp;&nbsp; ||  &nbsp;&nbsp;&nbsp;&nbsp; <strong>message.startsWith(&quot;ORA-20&quot;)</strong> )  &nbsp;&nbsp;&nbsp; &nbsp;{&hellip;//as previously &hellip;}&nbsp;</p>
<p>Exactly the same as for the entity validation errors is done, a HRMyCustomException object is created, with the product-code (ORA) and specific error-code(20xxxx) as a String parameter. Then the super.getMessage() method is called (at ErrorReportingUtils) that will return the localized message, but now derived from our database resourcebundle.</p>
<p>We can easily test our application whether our ORA-20xxx errors will have error messages from our centralized resource bundle or not. To do this, you can make a simple database procedure:</p>
<p>create procedure testORA20xxx( p in number := 20001 ) is begin raise_application_error( &#8211; p, &#8216;Hallo&#8217; ); end;</p>
<p>In JDeveloper a trigger can be made, for example one an after update trigger for the email attribute of the employees entity object (Connections Navigator, Your database, Triggers, New):</p>
<p>TRIGGER TRIGGERTEST AFTER UPDATE OF EMAIL ON EMPLOYEES  BEGIN &nbsp; testORA20xxx; END;&nbsp;</p>
<p>And finally, the corresponding error-message will be retrieved out of the centralized database resource bundle:</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/ora_prtscr_engmp.bmp" />&nbsp;</p>
<h3>&nbsp;</h3>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Custom JboException error messages</h3>
<p>The simplest method for displaying your own error messages is to throw a JboException:</p>
<p>throw new oracle.jbo.JboException(&quot;&lt;your message&gt;&quot;);</p>
<p>This stops the transaction and displays your error message text. But most likely you don&rsquo;t want to hard-code your error messages. You can throw this JboException for example from a custom method on your application module (AM) or from another object from your BC layer. The strategy described above can also be applied to these kind of custom JBOExceptions. The JboException will be intercepted by our HRErrorreportingUtils class in the getMessage() method, and we can get the error message out of our centralized&nbsp;resource bundle.</p>
<p>public void testCXEException() throws JboException &nbsp; { &nbsp;&nbsp; throw new JboException(&quot;CXS-00003&quot;); &nbsp; }&nbsp;&nbsp;&nbsp;</p>
<p>But you could also make a custom method on an AM that can be called for example by a backing bean that adds a product- and error code as parameter:</p>
<p>public void throwHRMyCustomExceptionByProductAndErrorCode(String productAndErrorCode) throws JboException &nbsp; { &nbsp;&nbsp; throw new JboException(productAndErrorCode); &nbsp; }</p>
<p>The product- and error code code can be anything as long as it is in the format &lsquo;XXX-xxxxx&rsquo;. So&nbsp;arbitrary&nbsp;codes like&nbsp; &lsquo;NGN-00001&rsquo; are possible. You only need to add your specific start-part (officially called &lsquo;product&rsquo; code) of &lsquo;XXX-xxxxx&rsquo; to the if-condition in the getMessage() method in HRErrorReportingUtils. For example &lsquo;NGN-&rsquo;:</p>
<p>if (message.startsWith(&quot;CXS-&quot;)&nbsp;&nbsp;&nbsp; ||  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message.startsWith(&quot;ORA-20&quot;)&nbsp; ||  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>message.startsWith(&quot;NGN-&quot;))</strong>&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&hellip;//as previously &hellip;}</p>
<p>Then you can call your AM custom method from another method on your AM or from a backing bean&nbsp; and throw a JboException with your specific product- and error code:<br />
(For this example, the custom operation throwHRMyCustomExceptionByProductAndErrorCode must be present in the pageDefinition)</p>
<p>&nbsp;</p>
<p>&nbsp;<img height="330" width="742" src="http://technology.amis.nl/blog/wp-content/uploads/image/5.PNG" alt="" /></p>
<p></p>
<p>The corresponding error-message will now be retrieved out of the centralized database resource bundle.</p>
<p><img hspace="0" border="0" align="bottom" alt="" src="http://technology.amis.nl/wp-content/uploads/images/ngn_prtscr.bmp" /></p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2008/02/21/how-to-maintain-adf-bcs-exception-jboexception-and-ora-20xxxsqlexception-messages-in-your-jheadstart-resourcebundle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fear for renaming (refactoring) ADF BC objects in JDeveloper 10.1.3.3 is not unfounded</title>
		<link>http://technology.amis.nl/2008/02/15/fear-for-renaming-refactoring-adf-bc-objects-in-jdeveloper-is-not-unfounded/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=fear-for-renaming-refactoring-adf-bc-objects-in-jdeveloper-is-not-unfounded</link>
		<comments>http://technology.amis.nl/2008/02/15/fear-for-renaming-refactoring-adf-bc-objects-in-jdeveloper-is-not-unfounded/#comments</comments>
		<pubDate>Fri, 15 Feb 2008 17:23:27 +0000</pubDate>
		<dc:creator>Frank Houweling</dc:creator>
				<category><![CDATA[ADF & JHeadstart]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[J(2)EE/Java]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://technology.amis.nl/blog/?p=2859</guid>
		<description><![CDATA[Growing insight during development of a project often results in a wish to rename a BC object (entity object, view object, association, view object attribute, alias, usage, etc.) in JDeveloper. Or in JHeadstart to rename objects like a&#160;group, item or a region.&#160;Often, developers are not renaming  [...]]]></description>
				<content:encoded><![CDATA[<p>Growing insight during development of a project often results in a wish to rename a BC object (entity object, view object, association, view object attribute, alias, usage, etc.) in JDeveloper. Or in JHeadstart to rename objects like a&nbsp;group, item or a region.&nbsp;Often, developers are not renaming objects because it is not clear to them what the impact will be, and the amount of work which might be involved in case unpredicted errors arise. And the fear for incorrect renaming/refactoring in JDeveloper is certainly not unfounded. <img alt="...." src="http://technology.amis.nl/blog/wp-content/plugins/xinha4wp/xinha_core/plugins/InsertMore/img/ed_more.png" /><span id="more-2859"></span> &nbsp; In this article I will give a table overview of what JDeveloper does for each BC object you rename, and what happens when you rename a JHeadstart group, item and region:</p>
<ul>
<li>Which files are updated correctly? </li>
<li>Which files, if any, are <strong>NOT</strong> updated correctly by JDeveloper (bugs)? </li>
<li>Solutions &#8211; in case JDeveloper does not correctly update your renamed object. </li>
<li>Does renaming an ADF BC object have any consequence when using JHeadstart? </li>
</ul>
<p>When you rename an object, it is best to rename only one object at a time, and then test whether your application still works fine. For ADF BC objects you can test it directly in de JDeveloper test-browser. &nbsp; </p>
<p>&nbsp;</p>
<p><strong>Overview of issues and bugs when refactoring (or renaming) ADFBC objects in JDeveloper 10.1.3.3</strong>&nbsp; &nbsp; </p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td valign="top"><strong>ADF-BC object</strong></td>
<td valign="top"><strong>Refactor issues? </strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>Impact</strong></td>
<td valign="top"><strong>What happens during refactoring?</strong></td>
<td valign="top"><strong>Consequences when using JHeadstart?</strong></td>
</tr>
<tr>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>entity object (EO) </li>
</ul>
</td>
<td valign="top"><strong>YES</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Impact: medium</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;EO&gt;.xml </li>
<li>&lt;associationName&gt;.xml (all &lt;association&gt;.xml files involved for this renamed EO) </li>
<li>&lt;EO&gt;Impl.java </li>
<li>entities.xml </li>
<li>&lt;VO&gt;.xml (all &lt;VO&gt;.xml files based on this EO) </li>
<li>&lt;VO&gt;.RowImpl.java&nbsp;&nbsp; </li>
</ul>
<p><strong>NOT CORRECTLY REFACTORED:</strong></p>
<ul>
<li>&lt;destinationEOofAssoc&gt;.xml in case your renamed EO is the source EO in an association. To be precise: any EO which has an association with your renamed EO and has an accessor which returns a single entity row of type &lt;yourRenamedEO&gt;Impl (and doesnâ€™t return an object of type RowIterator). </li>
</ul>
<p>For details see the ADF-BC solutions table below.&nbsp; </p>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change: </p>
<ul>
<li>an entity alias in a VO that use this EO </li>
<li>VO name based on this EO. </li>
</ul>
<p>If so, check this table for issues involving renaming an entity alias in a view object or a VO name.
        </td>
<td valign="top">
<p><strong>YES </strong>(Impact: very small)</p>
<p>You only have to regenerate. ApplicationResources_&lt; ServiceName&gt;.sql is correctly updated and updates rows in the JHS_TRANSLATIONS table where the TEXT column is updated for the KEY1 column (these are rows referring to errortext of all FK constraints regarding this EO).</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>entity association </li>
</ul>
</td>
<td valign="top">-</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;associationName&gt;.xml </li>
<li>&lt;sourceEO&gt;.xml </li>
<li>&lt;destinationEO&gt;.xml </li>
<li>entities.xml </li>
<li>&lt;associationName|<em>without</em> <em>â€˜Assocâ€™</em>|&gt;Link.xml </li>
</ul>
</td>
<td valign="top">-</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>entity association accessors (source and destination accessors) </li>
</ul>
</td>
<td valign="top">-</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;associationName&gt;.xml </li>
<li>&lt;sourceEO&gt;.xml </li>
<li>&lt;destinationEO&gt;.xml </li>
<li>&lt;sourceEO&gt;Impl.java </li>
</ul>
</td>
<td valign="top">-</td>
</tr>
<tr>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
<td valign="top">&nbsp;</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>view object (VO) </li>
</ul>
</td>
<td valign="top"><strong>YES</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Impact:small</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;serviceName&gt;.xml </li>
<li>&lt;VL&gt;.xml (involving this VO, more than one &lt;VL&gt;.xml files possible) </li>
<li>&lt;VO&gt;.xml </li>
<li>&lt;VO&gt;Impl.java </li>
<li>&lt;VO&gt;RowImpl.java </li>
<li>&lt;VO&gt;DefImpl.java </li>
<li>views.xml&nbsp;&nbsp; </li>
</ul>
<p><strong>NOT CORRECTLY REFACTORED:</strong></p>
<ul>
<li>&lt;ServiceName&gt;Impl.java. The return type of &lt;VOInstance&gt; getter methods that return your renamed &lt;VO&gt;Impl still reflect the old &lt;VO&gt;Impl name.&nbsp;&nbsp; </li>
</ul>
<p>For details see the ADF-BC solutions table below.&nbsp; </p>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change a VO instance (or usage) name based on this renamed VO. If so, check this table for issues involved with refactoring VO instance names. </p>
</td>
<td valign="top">
<p><strong>YES</strong> (impact: very small and not fatal)&nbsp;&nbsp;&nbsp;</p>
<p>Refresh corresponding JHS â€˜data collection implementationâ€™ by refreshing the â€˜data collectionâ€™. No need to regenerate. For details see the ADF-BC solutions table below. &nbsp;</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>view object attributes </li>
</ul>
</td>
<td valign="top">
<p><strong>YES*</strong></p>
<p>(*only in case&nbsp; JHeadstart is not used. Impact: medium)
        </td>
<td valign="top">
<p>refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<ul>
<li>&lt;VO&gt;.xml </li>
<li>&lt;VO&gt;RowImpl.java&nbsp;&nbsp; </li>
</ul>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change the corresponding JHS item name after changing the VO attribute name. </p>
<p><strong>ISSUE in case you donâ€™t use JHeadstart</strong>: </p>
<p>Be aware that (!) refactoring a VO attribute does NOT rename any object in any pageDefinition or jspx file! Refactoring any BC object is NOT updated in the ADF model layer, which is correct (but maybe not expected) because the BC and model are separated layers. After refactoring, the old VO attribute name could still be used&nbsp;in the element â€˜<em>attributeValuesâ€™</em> (sub-element â€˜<em>AttrNamesâ€™</em>) in corresponding pageDef files or in JSF components in .jspx files.&nbsp;This is also the case if you do use JHeadstart but has unchecked the JHS group setting â€˜Generate Page Definitionâ€™.
        </td>
<td valign="top">
<p><strong>YES</strong> (impact: small)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Refresh corresponding JHS â€˜itemâ€™ in JHS group and regenerate. For details see the ADF-BC solutions table below.</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>view object instance (VO usage) </li>
</ul>
</td>
<td valign="top">
<p><strong>YES*</strong></p>
<p>(*only in case&nbsp; JHeadstart is not used. Impact: medium)
        </td>
<td valign="top">
<p>refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<ul>
<li>&lt;serviceName&gt;.xml </li>
<li>&lt;serviceName&gt;Impl.java&nbsp;<strong>&nbsp;</strong> </li>
</ul>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change the corresponding JHS group name after changing the VO instance name. If so, check the issues involved in the table for renaming JHS objects. </p>
<p><strong>ISSUE in case you donâ€™t use JHeadstart</strong>: </p>
<p>Be aware that (!) refactoring&nbsp; a VO instance does NOT rename any object in any pageDefinition file ! Refactoring any BC object is NOT updated in the ADF model layer, which is correct (but maybe not expected) because the BC and model are separated layers.&nbsp;This is also the case if you do use JHeadstart but has unchecked the JHS group setting â€˜Generate Page Definitionâ€™. After refactoring, the old VO instance name is still used in the element â€˜iteratorâ€™ (attribute â€˜Bindsâ€™) and element â€˜actionâ€™ (attribute â€˜InstanceNameâ€™) of:</p>
<ul>
<li>&lt;parentVOInstance&gt;PageDef.xml </li>
<li>&lt;VOInstance&gt;PageDef.xml&gt; </li>
</ul>
</td>
<td valign="top">
<p><strong>YES</strong> (impact: small)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Refresh corresponding JHS â€˜data collectionâ€™ and regenerate. For details see the ADF-BC solutions table below.</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>entity alias in view object </li>
</ul>
</td>
<td valign="top"><strong>YES</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Impact:small</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;VO&gt;.xml </li>
<li>&lt;VO&gt;RowImpl.java </li>
<li>SQL-query (the SELECT list and FROM clause, in case expert mode is not used)&nbsp;&nbsp; </li>
</ul>
<p><strong>NOT CORRECTLY REFACTORED:</strong></p>
<ul>
<li>SQL-query, when a custom query clause (where, order by, group by) is present. Be aware that in expert-mode it is not possible to rename the entity alias because it is read-only.&nbsp;&nbsp; </li>
</ul>
<p>For details see the ADF-BC solutions table below. </p>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change the VO name after changing the entity alias. If so, check this table for issues involved with refactoring VO names. </p>
</td>
<td valign="top">-</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>viewLink (VL) </li>
</ul>
</td>
<td valign="top">-</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;serviceName&gt;.xml </li>
<li>&lt;serviceName&gt;Impl.java </li>
<li>&lt;sourceVO&gt;.xml </li>
<li>&lt;VL&gt;.xml </li>
<li>views.xml </li>
</ul>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) to change the VO instance (or usage) name after renaming the VL. If so, check this table for issues involved with refactoring VO instance names.
        </td>
<td valign="top">-</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>viewLink accessor (VL source- and destination accessor) </li>
</ul>
</td>
<td valign="top"><strong>YES</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Impact:small</td>
<td valign="top">refactored correctly:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;destinationVO&gt;RowImpl.java (in case you change source accessor) </li>
<li>&lt;sourceVO&gt;RowImpl.java (in case you change destination accessor) </li>
<li>&lt;VL&gt;.xml </li>
</ul>
<p><strong>NOT CORRECTLY REFACTORED:</strong></p>
<ul>
<li>&lt;destinationVO&gt;.xml (in case you change source accessor). The â€˜nameâ€™ attribute of element â€˜ViewLinkAccessorâ€™ is not updated. </li>
<li>&lt;sourceVO&gt;.xml (in case you change destination accessor) The â€˜nameâ€™ attribute of element â€˜ViewLinkAccessorâ€™ is not updated.&nbsp;&nbsp; </li>
</ul>
<p>For details see the ADF-BC solutions table below.&nbsp; </p>
<p>Note: After renaming this object you could consider (but is absolutely not necessary) tochange the VO instance (or usage) name after renaming a VL accessor. If so, check this table for issues involved with refactoring VO instance names. </p>
</td>
<td valign="top">-</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>Solution details for issues when refactoring (or renaming) ADFBC objects in JDeveloper 10.1.3.3</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td valign="top">
<ul>
<li>entity object (EO) </li>
</ul>
<p>&nbsp;
        </td>
<td valign="top">
<p>The file &lt;EO&gt;.xml, which represents an EO that has an association to your renamed EO is not updated correctly in case this EO has an accessor which returns an entity row of type &lt;yourRenamedEO&gt;Impl (and doesnâ€™t return an object of type RowIterator). This is especially the case in hierarchical entity relations described by entity associations.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>For example, a Countries entity object has a hierarchical association with a Locations entity object. A Country is composed of Location entries, and it does not make sense for a Location entity row to exist independently from a Country. When you refactor a Countries entity object to â€˜MyCountriesâ€™, Location.xml is not updated correctly and will still contain a reference to the old name of the Java &lt;EO&gt;Impl. file, â€˜CountryImplâ€™ instead of â€˜MyCountriesImplâ€™ in the â€˜Typeâ€™ attribute of the â€˜AccessorAttributeâ€™ element:</p>
<p><img hspace="0" src="http://technology.amis.nl/wp-content/uploads/images/entityobjectrefactor.bmp" align="bottom" border="0" /> </p>
<p>Because all &lt;EO&gt;.xml files are protected or read-only in JDeveloper, you must open Location.xml in your own editor, for example Notepad, and rename the â€˜Typeâ€™ attribute of the â€˜AccessorAttributeâ€™ element to the correct new &lt;EO&gt;Impl name. Refactor not more than one EO at a time, and test it in the BC-test browser in JDeveloper. An entity object may have multiple (hierarchical) associations. </p>
<p>Note: As you can see in the image, there seems to be still a reference to the old EO name, &#8216;Countries&#8217; (attribute &#8216;AssociationEnd&#8217; in the element &#8216;AccessorAttribute&#8217;) and this can be confusing. In reality, this name is a reference to the AssociationEnd &#8216;Name&#8217; attribute in de file &lt;associationName&gt;.xml, in this case &#8216;LocCidFkAssoc&#8217;. JDeveloper maintains this name correctly. In the file &#8216;LocCidFkAssoc&#8217;.xml is also an attribute &#8216;Owner&#8217; (in the element &#8216;AssociationEnd&#8217;) which points correctly to the renamed EO.</p>
<p>&nbsp;</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>View Object (VO) </li>
</ul>
</td>
<td valign="top">
<p>When you refactor a view object your renamed view object is not changed in your applicationModule file, &lt;yourServiceName&gt;Impl.java. For each of your view object instances (or usages) a get&lt;nameUsageVO&gt;() method is created in &lt;yourServiceName&gt;Impl.java, which returns an object of type of your renamed &lt;VO&gt;Impl. After refactoring, this return type is not corrected by JDeveloper so you have to correct this yourself.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>For example, an â€˜AllCountriesâ€™ VO is refactored to â€˜All_MY_Countriesâ€™. As you can see in the image below, the return type is not updated (still of type AllCountriesImpl instead of All_MY_CountriesImpl. JDeveloper can not find the old &lt;VO&gt;Impl file anymore and shows you by the red lines. You have to rename the return type (and the cast) yourself to the new &lt;VO&gt;Impl name for all the VO instance-getters that return your renamed VO.</p>
<p><img hspace="0" src="http://technology.amis.nl/wp-content/uploads/images/vo_refactor.bmp" align="bottom" border="0" /></p>
<p>&nbsp;</p>
<p><strong>JHeadstart</strong> </p>
<p>Has a very small consequence for JHeadstart. It is not fatal, the application will still work, but it is a good practice to refresh the corresponding â€˜data collection implementationâ€™ (this is the ADFBC VO definition) for the JHS groups (or detail groups) that use this renamed view object. To refresh you only have go to the selected groups in the JHS application definition editor and go to query settings, and property â€˜data collectionâ€™ (this is the view object usage or instance). Click at this â€˜data collectionâ€™ dropdown-list once and select the new &lt;VO&gt; name and (at the read-only) â€˜data collection implementationâ€™ will automatically be refreshed.</p>
<p><img src="http://technology.amis.nl/wp-content/uploads/images/jhs_vo.bmp" align="bottom" /> &nbsp; &nbsp; </p>
<p>It is not necessary to regenerate the application. *If you already had the JHeadstart application definition editor opened, just close and reopen it and the list will be refreshed and contain your new view object name. &nbsp;</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>view object instance (VO usage) </li>
</ul>
</td>
<td valign="top">
<p><strong>JHeadstart</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Renaming a VO instance has a medium consequence for JHeadstart. It is fatal, the application will not work. You have to refresh the corresponding â€˜data collectionâ€™ for the JHS groups (or detail groups) that use this renamed view object. To refresh you only have go to the selected groups in the JHS application definition editor and go to query settings, and property â€˜data collectionâ€™ (this is the view object usage or instance). Click at this â€˜data collectionâ€™ dropdown-list once and the new &lt;VOInstance&gt; name will automatically appear. &nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;<img src="http://technology.amis.nl/wp-content/uploads/images/jhs_vo.bmp" align="bottom" />&nbsp; </p>
<p>Then you have to regenerate the application. </p>
<p>*If you already had the JHeadstart application definition editor opened, just close and reopen it and the list will be refreshed and contain your new view object instance name. &nbsp;</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>view object attribute name </li>
</ul>
</td>
<td valign="top">
<p><strong>JHeadstart</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Renaming a VO attribute name has a small consequence for JHeadstart. Go to the JHS group which corresponds to the VO of the attribute name you changed, and go the corresponding JHS item. You only have to refresh, in the JHS editor, this item by clicking on the dropdown-list and selecting the new name, which is automatically available. For example, you changed the â€˜CountryNameâ€™ attribute name of the VO â€˜AllCountriesâ€™ view object to â€˜MY_CountryNameâ€™ (â€˜RegionCountriesâ€™ is a VO instance of the VO â€˜AllCountriesâ€™).</p>
<p><img hspace="0" src="http://technology.amis.nl/wp-content/uploads/images/nieuw_vo_attribute_jhs.bmp" align="bottom" border="0" /></p>
<p>Then you have to regenerate the application. *If you already had the JHeadstart application definition editor opened, just close and reopen it and the list will be refreshed and contain your new attribute name.&nbsp;</p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>viewLink accessor (VL source- and destination accessor) </li>
</ul>
</td>
<td valign="top">
<p>When you refactor a VL accessor your renamed VL accessor is not changed in your &lt;VODestination&gt;.xml (or &lt;VOSource&gt;.xml, depending whether you change the source or destination accessor).&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Correct the â€˜nameâ€™ attribute, which reflects still the old VL accessor name, of the â€˜ViewLinkAccessorâ€™ element in the &lt;VODestination&gt;.xml (or &lt;VOSource&gt;.xml) file with your new VL accessor name. You have to correct this in your own editor, for example Notepad, as this file is protected (read-only) in JDeveloper.</p>
<p>&nbsp;</p>
<p><img src="http://technology.amis.nl/wp-content/uploads/images/vl_accessor.bmp" /></p>
<p></p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>entity alias in view object </li>
</ul>
</td>
<td valign="top">
<p>When you rename an entity alias in a view object, your renamed entity alias should be corrected in your SQL query. In case you have made any custom query clauses, the entity alias is not updated by JDeveloper, you have to correct this yourself.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>For example, if you renamed an entity alias â€˜Countriesâ€™ to â€˜MY_Countriesâ€™, the SELECT-clause is correctly updated, but not the custom WHERE-clause (all custom clauses, so also the ORDER BY or GROUP BY clause). &nbsp; </p>
<p>&nbsp;<img src="http://technology.amis.nl/wp-content/uploads/images/entityaliasinvouuuuuuuu.bmp" align="bottom" /></p>
<p>Be aware that in expert-mode it is not possible to rename the entity alias because it is read-only.</p>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp; </p>
<p>&nbsp;</p>
<p><strong>Overview of issues when renaming a group-, item- and region&nbsp;name in JHeadstart 10.1.3.2.51</strong> </p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td valign="top"><strong>JHeadstart (JHS) object</strong></td>
<td valign="top"><strong>Renaming issues? </strong><strong>Impact</strong></td>
<td valign="top"><strong>What happens during refactoring?</strong></td>
</tr>
<tr>
<td valign="top">
<ul>
<li>group name </li>
</ul>
</td>
<td valign="top"><strong>YES</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; impact: medium to big</td>
<td valign="top">New files created:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul>
<li>&lt;newGroupName&gt;.jspx </li>
<li>&lt;newGroupName&gt;Table.jspx (in case your group has layout style â€˜table-formâ€™.) </li>
<li>&lt;newGroupName&gt;.pageDef.xml </li>
<li>&lt;newGroupName&gt;-beans.xml </li>
</ul>
<p>Files correctly updated:</p>
<ul>
<li>&lt;serviceName&gt;ApplicationDefinition.xml </li>
<li>&lt;parentGroupName&gt;.pageDef.xml in case your renamed group is a detailgroup in a region of this parent group. </li>
<li>&lt;parentGroupName&gt;.jspx in case your renamed group is a detailgroup in a region of this parent group. </li>
<li>&lt;detailGroupName&gt;.jspx in case your renamed group is a parentgroup and has a this detail group in a region. </li>
<li>&lt;serviceName&gt;-Breadcrumb-beans.xml </li>
<li>faces-config.xml </li>
<li>ApplicationResources_&lt;serviceName&gt;.sql (also other locales, for example ApplicationResources_nl_&lt;serviceName&gt;.sql) </li>
<li>&lt;serviceName&gt;MenuTabs.jspx </li>
<li>&lt;serviceName&gt;&lt;nameTopParentGroup&gt;Menu2Tabs.jspx (if present) </li>
</ul>
<p>Files correctly added with new elements <strong>BUT NOW HAVE OBSOLETE ELEMENTS:</strong></p>
<ul>
<li>DataBindings.cpx (new and old (obsolete) elements in this file, &lt;pageMap&gt; and &lt;pageDefinitionUsages&gt;, referring to the new- and old &lt;GroupName&gt;.jspx and &lt;GroupName&gt;.pageDef files) </li>
<li>web.xml (one new and one old (obsolete) entry in the attribute &lt;param-value&gt; in the element &lt;context-param&gt; (with param-name â€˜javax.faces.CONFIG_FILESâ€™) referring to &lt;newGroupname&gt;-beans.xml and the obsolete &lt;oldGroupname&gt;-beans.xml) </li>
<li>JHS_TRANSLATIONS table (the file ApplicationResources_&lt;ServiceName&gt;.sql is correctly updated and inserts new rows in the JHS_TRANSLATIONS table but it does not delete (obsolete) rows referring to the old group name (titels, labels)) </li>
</ul>
<p><strong>OBSOLETE FILES:</strong></p>
<ul>
<li>&lt;oldGroupName&gt;.pageDef.xml </li>
<li>&lt;oldGroupName&gt;.jspx </li>
<li>&lt;oldGroupName&gt;Table.jspx </li>
<li>&lt;oldGroupName&gt;-beans.xml&nbsp;&nbsp; </li>
</ul>
<p><strong>Important</strong>: Realize JHS will generate a complete new pageDefinition for your renamed group and if you made custom post generation changes in your &lt;oldGroupName&gt;PageDef.xml file, these changes (of course) wonâ€™t be in the &lt;newGroupName&gt;PageDef.xml, you have to make your post generation changes yourself again! </p>
<p>After you have renamed the group name you must regenerate the application. The application will still work fine, but now you have a lot of obsolete code and files that you donâ€™t need to maintain anymore, and these files or parts of files are recommended to be removed: </p>
<ul>
<li>Obsolete files&nbsp;can be deleted in JDeveloper. </li>
<li>Removing obsolete elements in DataBindings.cpx and one element web.xml is&nbsp;straightforward but you have to&nbsp;localize&nbsp;the elements&nbsp;yourself and remove them manually in JDeveloper. </li>
<li>Removing rows from the JHS_TRANSLATIONS table is also straightforward. You can&nbsp;manually remove the obsolete rows or you can run the following SQL script: &quot;&nbsp; delete from jhs_translations where key1 like &#8216;%&lt;oldGroupName -<em>minus&nbsp;last character of oldGroupName</em>&gt;%&nbsp; &quot;. </li>
</ul>
<p>Note: If your group that you want to rename is detailgroup that is presented in a region, you also have to correct the group name for that region. </p>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>item name </li>
</ul>
</td>
<td valign="top">
<p>-<strong>YES</strong></p>
<p>impact:&nbsp;very small</p>
</td>
<td valign="top">
<p>Only one very small issue: If the item you rename is on&nbsp;<em>group-level</em> the value for a &#8216;Default Search Item&#8217; and/or a &#8216;Descriptor Item&#8217;, you have to refresh these values by selecting the new name in the dropdown-list. And then regenerate. There are no obsolete files or obsolete elements in files.</p>
<p>Files correctly updated:&nbsp;&nbsp;</p>
<ul>
<li>&lt;parentGroupOfGroupOfItem&gt;.pageDef.xml in case the group of your renamed item is a detailgroup in a region of this parent group. </li>
<li>&lt;parentGroupOfGroupOfItem&gt;.jspx in case the group of your renamed item is a detailgroup in a region of this parent group. </li>
<li>&lt;childGroupOfGroupOfItem&gt;.jspx in case the group of your renamed item is a parentgroup and has a region containing this child group. </li>
<li>&lt;GroupOfItem&gt;.jspx </li>
<li>&lt;GroupOfItem&gt;.pageDef.xml </li>
<li>&lt;GroupOfItem&gt;-beans.xml </li>
<li>&lt;serviceName&gt;-Breadcrumb-beans.xml </li>
<li>&lt;serviceName&gt;ApplicationDefinition.xml </li>
</ul>
</td>
</tr>
<tr>
<td valign="top">
<ul>
<li>region name </li>
</ul>
</td>
<td valign="top">-</td>
<td valign="top">
<p>Files correctly updated:</p>
<ul>
<li>&lt;serviceName&gt;ApplicationDefinition.xml&nbsp; </li>
<li>&lt;groupOfRegion&gt;.jspx&nbsp; </li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.amis.nl/2008/02/15/fear-for-renaming-refactoring-adf-bc-objects-in-jdeveloper-is-not-unfounded/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
