Friday Aug 30, 2013

Dealing with ADF_FACES-30214

Whilst doing some work on a separate blog entry using the demo Summit application in 12c I noticed a message repeated again and again in the WebLogic log in the console. Nothing annoys me more that constantly repeating messages that obscure the stuff I really want to see (I've wrapped the message to fit here) :

 <Warning> <> 
   <ADF_FACES-30214> <The setting to enable version display will be ignored 
   because the application is running in production mode.>

Switching this message off is super easy, as we'll see, but what does it relate to?

Well, this is all to do with the following context parameter defined in your web.xml file

    <description>Whether the 'Generated by...' comment at the bottom of ADF Faces HTML pages should contain version number information.</description>

This parameter defines if the generated page output contains detailed information about the ADF version. This information is useful in development and QA evironments but is not something that you want in a production environment as it is of potential use to a Hacker. So, to see the version information we need to explicitly include this context paramter and set the value to false so as not to hide the version info.

Now in JSF 2 we have an additional factor come into play to complicate matters, which is the Project Stage (there are several articles on Project Stage that you can find with your favorite search engine, but this one covers the basics). Basically Project Stage is a way that you can define an application as being in Development, Test or Production mode and effect changes accordingly (both in the declarative sense as we have an example of here, but also in terms of code and behaviors). 

Now the problem that all this relates to, the unwanted log message, is a reflection of the fact that if the Project Stage is not explicitly defined then it's going to default to Production mode (hopefully the message begins to make sense now?) . So we kind of have two mutually exclusive settings in this app.  On one hand I'm asking for Development time version information, and on the other hand the app thinks it's in production mode. The result is this message, and, if you look at the actual source of the page in the browser you'll see this:

<!--Created by Oracle ADF (Version information hidden), 
    accessibility (mode:null, contrast:standard, size:medium), 
    skin:skyros-v1.desktop (skyros)-->

The fix?  Well I do want to see the version information so I need to tell the application that it's in Development mode, not Production mode. To do this I just have to add a Project Stage entry into web.xml:


(Note the value is capitalized "Development")  

Now when the application is re-deployed, the pesky message has gone and the page source contains oodles of version information:

<!--Created by Oracle ADF (ADF RichClient API - ABRAMS (custom: 
  / ADF RichClient Impl - ABRAMS (custom: 
  / ADF-Controller{Oracle-BuildSystem=Linux - java - 1.7.0_10-b18, 
  Oracle-Version=, Created-By=23.6-b04 (Oracle Corporation), 
  Oracle-Builder=Official Builder, Oracle-Label=JDEVADF_12., 
  Oracle-BuildTimestamp=2013-06-09 02:39:02 -0700} 
  ADF-Model{Oracle-BuildSystem=Linux - java - 1.7.0_10-b18, 
  Oracle-Version=, Created-By=23.6-b04 (Oracle Corporation), 
  Oracle-Builder=Official Builder, Oracle-Label=JDEVADF_12., 
  Oracle-BuildTimestamp=2013-06-09 01:58:04 -0700} 
  ADF-Share{Oracle-BuildSystem=Linux - java - 1.7.0_10-b18, 
  Oracle-Version=, Created-By=23.6-b04 (Oracle Corporation), 
  Oracle-Builder=Official Builder, Oracle-Label=JDEVADF_12., 
  Oracle-BuildTimestamp=2013-06-09 12:47:43 -0700}  / powered by JavaServer Faces -, 
  accessibility (mode:null, contrast:standard, size:medium), skin:skyros-v1.desktop (skyros)--> 

Next time I show how you can use a WebLogic Deployment Plan to update the Project Stage as you deploy your application 

Tuesday Jul 30, 2013

(Adventures in) ADF Logging in 12c

An offline conversation with Andrejus Baranovskis the other day alerted me to a difference in behavior with the ADF Logger in 12.1.2. It seems that the logging output is not being output to the console as it was in 11g, although it's certainly being written to the log file OK.

I did a little testing and digging on this, and the issue it turns out is pretty simple.

The root cause is in the default definition of the console hander in the logging.xml file. In 11g, this handler is configured to let everything through level="ALL".  In 12c the default configuration is only to pass more significant issues through to the console level="WARNING:32".  The reason for this change is, I'm guessing to reduce the amount of general noise that you see when WebLogic is started. 

So it's trivial to switch back to the verboseness of 11g if you'd like to:

  1. From the console choose Actions --> Configure Oracle Diagnostic Logging to open the logging.xml view
  2. Switch to source view and locate the <log_handler name='console-handler' ... entry
  3. Change the WARNING:32 value to ALL

If you are feeling more creative, and want the best of both worlds, you can of course define a second handler for the console with this more permissive value and assign that explicitly to just your loggers - then you can get the verbose output for your logging without everything else.  

For example;

1. Define a custom handler 

<log_handler name='demo-console-handler' 

2. Use the custom handler for your root logger:

<logger name="oracle.demo" level="FINEST" useParentHandlers='false'>
  <handler name='odl-handler'/>
  <handler name='wls-domain'/>
  <handler name='demo-console-handler'/>  

Monday Jul 22, 2013

Setting up a standalone WebLogic 12c install for ADF Without a Database

One change that many folks have encountered with the 12c (12.1.2) release of WebLogic and ADF concerns the setup of stand-alone WebLogic instances extended with JRF for ADF Application deployment. 

The main problem comes when creating the JRF extended domain.  On page 6 of the config process screen you are confronted by the following:

Configure Database Screen

Note here that you need to provide information for the database that OPSS should use. 

Now this connection has a real purpose, the Oracle Platform security infrastructure for 12c needs to store it's information within a proper database so as to correctly (and supportably) manage itself across multiple servers in a cluster.  However, if like me, you just wanted to stand up a single unclustered ADF enabled WebLogic for testing deployments etc. This could be a bit of a pain, particularly in my case as the database version I'm currently running is not of the correct version.  So here I'm documenting the steps for avoiding this requirement on a single standalone server, although I stress, as far as I am aware, this is not a supported configuration for production usage.

The Steps to Install Without Needing a Database 

  1. First of all install WebLogic (wls_121200.jar) and the ADF runtime (fmw_infra_121200.jar) into the same 12c Oracle Home using their respective installers. At the end of each of the WebLogic install make sure you uncheck the Configuration Wizard launch option as we'll be doing that manually later. 
  2. Start a shell / command prompt in $MW_HOME/wlserver/common/bin
  3. Set the environment variable QS_TEMPLATES to point to $MW_HOME/wlserver/common/templates/wls/wls_jrf.jar
  4. Run and define the name of the domain that you want to create (e.g. add_domain) along with the usual WebLogic passwords and ports that you require. Finish the Quick Start wizard without starting the new domain. 
  5. Now run the conventional and on the first page choose "Update an Existing Domain" rather than "Create a new domain". The new domain (e.g. adf_domain) should now be listed for selection.
  6. On the second screen choose the templates that you wish to apply, e.g. Oracle JRF, Oracle Enterprise Manager etc.  and move on through the wizard. 
  7. On the Database Configuration Type screen this time you will see an extra option where Embedded Database (JavaDB) is offered and pre-selected. Select that and continue with the domain setup as usual with whatever managed servers you need.

Again to re-iterate this is only a setup that I would recommend for a development / testing environment and of course you should not take this approach if you're setting up any kind of clustered environment, even for testing, as the shared database has a real purpose in that case. Also consider that if your application uses MDS then you'll most likely need an database repository anyway, so again, in that instance don't use this technique.  

The fact that the normal install for the ADF Web Runtime does not offer this non-database option should be taken a a strong hint as to how supported you will be running with this configuration in a production environment.  Don't ask me for certification or support guidance, please contact Oracle Support for that information.  

Further Reading

The use of an external RDBMS Security Store for WebLogic (the configuration that  this article bypasses) is discussed in the WebLogic Documentation:

Read that chapter for a better understanding of why the default JRF install asks you to define a database connection for this purpose and why I talk about only using the technique that I've outlined here for development purposes. 

Wednesday Jun 26, 2013

Adaptive Connections For ADFBC

Some time ago I wrote an article on Adaptive Bindings showing how the pageDef for a an ADF UI does not have to be wedded to a fixed data control or collection / View Object. This article has proved pretty popular, so as a follow up I wanted to cover another "Adaptive" feature of your ADF applications, the ability to make multiple different connections from an Application Module, at runtime.
Now, I'm sure you'll be aware that if you define your application to use a data-source rather than a hard-coded JDBC connection string, then you have the ability to change the target of that data-source after deployment to point to a different database. So that's great, but the reality of that is that this single connection is effectively fixed within the application right?  Well no, this it turns out is a common misconception.

To be clear, yes a single instance of an ADF Application Module is associated with a single connection but there is nothing to stop you from creating multiple instances of the same Application Module within the application, all pointing at different connections.  If fact this has been possible for a long time using a custom extension point with code that which extends oracle.jbo.http.HttpSessionCookieFactory. This approach, however, involves writing code and no-one likes to write any more code than they need to, so, is there an easier way? Yes indeed.  It is in fact  a little publicized feature that's available in all versions of 11g, the ELEnvInfoProvider.

What Does it Do? 

The ELEnvInfoProvider  is  a pre-existing class (the full path is  oracle.jbo.client.ELEnvInfoProvider) which you can plug into your ApplicationModule configuration using the jbo.envinfoprovider property. Visuallty you can set this in the editor, or you can also set it directly in the bc4j.xcfg (see below for an example) .
Configuration Editor
Once you have plugged in this envinfoprovider, here's the fun bit, rather than defining the hard-coded name of a datasource instead you can plug in a EL expression for the connection to use.  So what's the benefit of that? Well it allows you to defer the selection of a connection until the point in time that you instantiate the AM.
To define the expression itself you'll need to do a couple of things:
  1. First of all you'll need a managed bean of some sort – e.g. a sessionScoped bean defined in your ViewController project. This will need a getter method that returns the name of the connection. Now this connection itself needs to be defined in your Application Server, and can be managed through Enterprise Manager, WLST or through MBeans. (You may need to read the documentation [] here on how to configure connections at runtime if you're not familiar with this) 
  2.  The EL expression (e.g. ${connectionManager.connection} is then defined in the configuration by editing the bc4j.xcfg file (there is a hyperlink directly to this file on the configuration editing screen in the Application Module editor). You simply replace the hardcoded JDBCName value with the expression.  So your cfg file would end up looking something like this (notice the reference to the ELEnvInfoProvider that I talked about earlier)
<BC4JConfig version="11.1" xmlns="">
  <AppModuleConfigBag ApplicationName="oracle.demo.model.TargetAppModule">
    <AppModuleConfig DeployPlatform="LOCAL" 
      <AM-Pooling jbo.doconnectionpooling="true"/>
      <Database jbo.locking.mode="optimistic">
      <Security AppModuleJndiName="oracle.demo.model.TargetAppModule"/>
      <Custom jbo.envinfoprovider="oracle.jbo.client.ELEnvInfoProvider"/>

Still Don't Quite Get It?

So far you might be thinking, well that's fine but what difference does it make if the connection is resolved "just in time" rather than up front and changed as required through Enterprise Manager?
Well a trivial example would be where you have a single application deployed to your application server, but for different users you want to connect to different databases. Because, the evaluation of the connection is deferred until you first reference the AM you have a decision point that can take the user identity into account.

However, think about it for a second.  Under what circumstances does a new AM get instantiated? Well at the first reference of the AM within the application yes, but also whenever a Task Flow is entered -  if the data control scope for the Task Flow is ISOLATED.  So the reality is, that on a single screen you can embed multiple Task Flows, all of which are pointing at different database connections concurrently.

Hopefully you'll find this feature useful, let me know... 

Wednesday May 22, 2013

UKOUG ADF Mobile Demo

Yesterday I participated in a Special Interest Group meeting organised by the UK Oracle User Group on ADF Mobile. 

As part of my session I concentrated on building an ADF Mobile application from the ground up based on grabbing JSON data from Hudson. This demo shows the core techniques for dealing with URL based data and parsing the same. Several folks at the event had asked for the demo code so I've packaged and uploaded onto the ADF EMG Code Samples Repository:


Friday Apr 19, 2013

Lions and Tigers and RangeSize, Oh My!

One of the most common mistakes I see made in ADF Business Components based applications is a failure to tune the View Objects, and specifically to tune the in Batches of parameter in the VO tuning section. This setting defaults to 1, which does not always meet the needs of the consuming UI or service interface and should generally be changed.  This is a topic that I and others have covered before.

Now certainly the batch fetch size is a crucial tuning parameter as it controls how many times the framework has to hit the database to get the rows needed to service a particular function.  However, in this posting I wanted to turn my attention to another factor which can also have a significant effect - the iterator RangeSize.

The background to this was some recent detective work on an application where the time taken to display one particular screen was suspiciously long. 
The page in question had a tabular display of data, but an inspection of the VO tuning parameters showed that a reasonable Batch size of 51 was being used. What's more the As Needed switch rather than the All at Once option in the VO tuning was being used. So the developer had done totally the right things there.
Running a SQL Trace on the page revealed an interesting thing though.  Because the batch size was pretty high we'd expect that the framework would have to only do one or at most two fetches from the cursor to satisfy the needs of that table.  However The TKProf output showed that in fact over 150 fetches took place retrieving over 8000 rows!

My thought processes in diagnosing this were to look in the following places:
  1. Are there alternative VO Instances defined on the AM where the tuning parameters are different (e.g. ALL_ROWS was specified)? We know the base definition is OK but it could be overridden.  
  2. Any programmatic calls to change the Batch Size or fetch node in the VO?
  3. Any programatic calls to last() on the rowset or iterations through the rowset? 
  4. Check for a RangeSize of -1 on the iterator definition in the pageDef files.

All of these drew a blank.  The last one in particular felt like the problem but a search for the value of -1 in the pageDefs of the UI project only turned up legitimate usages of the -1 value. 

Hold on I don't Understand This RangeSize?

Maybe I should take a quick step back and explain the iterator RangeSize.  So, as we've seen, the tuning options in the view Object will control how often the VO has to go back to the database to get a specific number of rows. The iterator rangeSize is defined in the pageDef file for a particular page, fragment or method activity and it defines how many rows the UI layer should ask the service layer (in this case the VO) for. 
Here's a typical definition that you'll see in the pageDef:
<iterator Binds="EmployeesView1" 

You'll see that the rangeSize here is set to 25 which just happens to be the value that is defaulted in when you drag and drop a binding into the page.  However, it turns out that 25 is not the default value, something which has a bearing later in this investigation as we'll see.
So in this default case when the iterator is asked for data, it in turn will ask the VO for 25 rows, and if the VO does not already have that many rows in the cache it will have to go back to the database as many times, as determined by the batch-size, as it needs to get enough data.

Back to the Problem page 

As it happens the pageDef for the table displaying the problem VO was indeed the defacto default of 25, so, sad to say, it was not the obvious suspect at fault, more investigation was needed.

At this stage the investigation splits into a couple of parallel efforts, manual code inspection, and tracing using the ADF Logging capability to try and work out what interactions were happening with the problem VO.

Welcome to the Internet, Please Tread with Care

What can we trust? Well in the world of ADF Blogs in the wild there are some great bloggers, but that does not mean that you can just copy without thinking.  It turned out that one of the problems with this application was to fall foul of copy-without-thinking syndrome.
The code in question seems innocent enough, it's published out there on the internet as a way of refreshing an iterator:

//Please, Please Don't do this! (My comment)
DCIteratorBinding iterBind= (DCIteratorBinding)dc.get("<your iterator name>");  

Two facts to discuss in relation to this code snippet:
  1. Read the JavaDoc for DCIteratorBinding - the refresh() method is very clearly marked as Internal only, applications should not use. That's what we call "a hint" in the trade, you can choose to ignore it but don't come crying...
  2. Look at that parameter being passed to the refresh method DCIteratorBinding.RANGESIZE_UNLIMITED - can you guess what that does? Yes it does the same as setting the RangeSize to -1 and will cause the VO to be asked for all of the data for that query. You can see how bad that could be if the VO has the potential to return a lot of rows.
So something to put right already. 

But Wait, There's more!

Although the call to refresh was a great catch and the application will be better without it, it turned out not to be the cause - darn. 
However, the parellel effort to run some more tracing found the smoking gun.  The ADF Log trace showed a double execute on the iterator for the VO in question, or to be more precise, executes on two different iterators bound to the same VO from different regions on the page. 
A useful diagnostic here was then to set a breakpoint in the setRangeSize() of oracle.adf.model.binding.DCIteratorBinding.  Doing this we could see that the first iterator execution was actually responsible for setting the RangeSize to -1 and the second to the value we where expecting for that table based on the pageDef. 
All credit to the development team I was working with here who ferreted out the actual problem, it was finally down to one of omission. 

Recall I made the statement earlier about 25 being the defacto default for the RangeSize? Very true, when you create a binding, that's what the IDE puts in for you.  But what's the actual default? Well that turns out to be -1.  So if you omit the RangeSize from the iterator definition by intent, or mistake, you're going to have a potential side effect you may not have expected!  That was exactly the problem in this case  - no RangeSize. 

Specifically the problem was caused by a method binding in one of the bounded task flows in the page. The pageDef for this method activity included and iterator defined for the problem VO but without a RangeSize defined.  

Lessons to Learn

  1. For each peice of UI that is bound to data understand how the user is going to use that screen - will they view just one record, will they scroll through several or a lot, will they only scroll downwards and process one record at a time and so on. You can't effectivly tune a page until you understand how it will be used.
  2. Always tune your VO definitions or instances to the requirements of each endpoint.  If this means having multiple VO definitions or multiple VO instances with different tuning parameters then do it.
  3. If you have consciously set your Batch size in the VO tuning parameters to a small number because that's all you see on the page at once then also tune the pageDef iterator RangeSize. Otherwise that defacto 25 RangeSize could generate a bunch of unnecessary calls back to the database. Think about it, if you have a single record form and you've not tuned the VO Batch size and you've not tuned the iterator RangeSize, you could be doing 25 roundtrips to the database just to see one record.  Great way to please your DBA!
  4. Use a RangeSize of -1 with caution.  It has its place for iterators that serve short lists used for lookups and menus but anything else is an exception.
  5. Don't blindly copy everything you see in the blog-o-sphere. If you don't recognize an API call then look it up.  If something says it's for internal use only, then guess what, don't use it.
  6. Never ever, define an iterator in your pageDef without an explicit rangeSize. If you need to see all rows, say so with the -1 value, otherwise use a positive integer.

We all go home older and wiser...

Monday Feb 18, 2013

MySQL & ADF Business Components - Enum types

A quick guide to effectively mapping and representing MySQL enumeration types through ADF Business Components [Read More]

Friday Jan 18, 2013

Refresh Problems using Adaptive Bindings

In a previous article (Towards Ultra-Reusability for ADF - Adaptive Bindings)  I discussed how ADF Data Binding can be a lot more flexible that you would think due to the neat trick of being able to use expression language within the PageDef file to create bind sources that  can be switched at runtime.

As it happens my good buddy Frank Nimphius picked up the technique to use on a particular  project and hit a slight problem. If you change the results of the EL used in the binding - for example, you switch the base VO from Departments to Employees, things don't get refreshed correctly.  In fact what you see is that any attribute names that happen to match between the old and the new source will be correctly populated with the new data but the actual list of attributes will not be refreshed. The effect is that if you were using one of these bindings to populate a table, the "shape" of the table, in terms of its columns, would not change. 

No worries though, given that Frank is a clever chap he worked out the correct way to address this which is to simply call clearForRecreate() on the iterator binding.

 BindingContext bctx = BindingContext.getCurrent();
 BindingContainer bindings = bctx.getCurrentBindingsEntry();
 DCIteratorBinding iter = (DCIteratorBinding)

Thanks Frank! 

Saturday Nov 17, 2012

Towards Ultra-Reusability for ADF - Adaptive Bindings

The task flow mechanism embodies one of the key value propositions of the ADF Framework, it's primary contribution being the componentization of your applications and implicitly the introduction of a re-use culture, particularly in large applications.

However, what if we could do more? How could we make task flows even more re-usable than they are today? Well one great technique is to take advantage of a feature that is already present in the framework, a feature which I will call, for want of a better name, "adaptive bindings".

What's an adaptive binding? well consider a simple use case.  I have several screens within my application which display tabular data which are all essentially identical, the only difference is that they happen to be based on different data collections (View Objects, Bean collections, whatever) , and have a different set of columns. Apart from that, however, they happen to be identical; same toolbar, same key functions and so on. So wouldn't it be nice if I could have a single parametrized task flow to represent that type of UI and reuse it?

Hold on you say, great idea, however, to do that we'd run into problems. Each different collection that I want to display needs different entries in the pageDef file and:

  1. I want to continue to use the ADF Bindings mechanism rather than dropping back to passing the whole collection into the taskflow  
  2. If I do use bindings, there is no way I want to have to declare iterators and tree bindings for every possible collection that I might want the flow to handle

 Ah, joy! I reply, no need to panic, you can just use adaptive bindings.

Defining an Adaptive Binding 

It's easiest to explain with a simple before and after use case.  Here's a basic pageDef definition for our familiar Departments table. 

  <iterator Binds="DepartmentsView1" 
  <tree IterBinding="DepartmentsView1Iterator" id="DepartmentsView1">
    <nodeDefinition DefName="oracle.demo.model.vo.DepartmentsView" Name="DepartmentsView10">
        <Item Value="DepartmentId"/>
        <Item Value="DepartmentName"/>
        <Item Value="ManagerId"/>
        <Item Value="LocationId"/>

Here's the adaptive version:

  <iterator Binds="${pageFlowScope.voName}" 
  <tree IterBinding="TableSourceIterator" id="GenericView">
      <nodeDefinition Name="GenericViewNode"/>

You'll notice three changes here.  

  1. Most importantly, you'll see that the hard-coded View Object name  that formally populated the iterator Binds attribute is gone and has been replaced by an expression (${pageFlowScope.voName}). This of course, is key, you can see that we can pass a parameter to the task flow, telling it exactly what VO to instantiate to populate this table!
  2. I've changed the IDs of the iterator and the tree binding, simply to reflect that they are now re-usable
  3. The tree binding itself has simplified and the node definition is now empty.  Now what this effectively means is that the #{node} map exposed through the tree binding will expose every attribute of the underlying iterator's collection - neat! (kudos to Eugene Fedorenko at this point who reminded me that this was even possible in his excellent "deep dive" session at OpenWorld  this year)

Using the adaptive binding in the UI

Now we have a parametrized  binding we have to make changes in the UI as well, first of all to reflect the new ID that we've assigned to the binding (of course) but also to change the column list from being a fixed known list to being a generic metadata driven set:

<af:table value="#{bindings.GenericView.collectionModel}"
          emptyText="#{bindings.GenericView.viewable ? 'No data to display.' : 'Access Denied.'}"
          var="row" rowBandingInterval="0" 
          rowSelection="single" id="t1">
  <af:forEach items="#{bindings.GenericView.attributeDefs}" var="def">
    <af:column headerText="#{bindings.GenericView.labels[]}" sortable="true"
               sortProperty="#{}" id="c1">
      <af:outputText value="#{row.bindings[].inputValue}" id="ot1"/>

Of course you are not constrained to a simple read only table here.  It's a normal tree binding and iterator that you are using behind the scenes so you can do all the usual things, but you can see the value of using ADFBC as the back end model as you have the rich pantheon of UI hints to use to derive things like labels (and validators and converters...) 

One Final Twist

 To finish on a high note I wanted to point out that you can take this even further and achieve the ultra-reusability I promised. Here's the new version of the pageDef iterator, see if you can notice the subtle change?

<iterator Binds="{pageFlowScope.voName}" 

Yes, as well as parametrizing the collection (VO) name, we can also parametrize the name of the data control. So your task flow can graduate from being re-usable within an application to being truly generic. So if you have some really common patterns within your app you can wrap them up and reuse then across multiple developments without having to dictate data control names, or connection names. This also demonstrates the importance of interacting with data only via the binding layer APIs. If you keep any code in the task flow generic in that way you can deal with data from multiple types of data controls, not just one flavour. Enjoy!


Read this post as well on overcoming possible refresh problems when changing the source on a single page. 

Further update

Check out this article from Luc Bors on using similar ideas with Query Components / View Criteria.  

Thursday Oct 18, 2012

ADF Logging In Deployed Apps

Harking back to my series on using the ADF logger and the related  ADF Insider Video, I've had a couple of queries this week about using the logger from Enterprise Manager (EM). I've alluded in those previous materials to how EM can be used but it's evident that folks need a little help.  So in this article, I'll quickly look at how you can switch logging on from the EM console for an application and how you can view the output. 

Before we start I'm assuming that you have EM up and running, in my case I have a small test install of Fusion Middleware Patchset 5 with an ADF application deployed to a managed server.

Step 1 - Select your Application

In the EM navigator select the app you're interested in:

At this point you can actually bring up the context ( right mouse click) menu to jump to the logging, but let's do it another way. 

Step 2 - Open the Application Deployment Menu

At the top of the screen, underneath the application name, you'll find a drop down menu which will take you to the options to view log messages and configure logging, thus:

Step 3 - Set your Logging Levels 

Just like the log configuration within JDeveloper, we can set up transient or permanent (not recommended!) loggers here.

In this case I've filtered the class list down to just oracle.demo, and set the log level to config. You can now go away and do stuff in the app to generate log entries.

Step 4 - View the Output 

Again from the Application Deployment menu we can jump to the log viewer screen and, as I have here, start to filter down the logging output to the stuff you're interested in. 

In this case I've filtered by module name. You'll notice here that you can again look at related log messages.

Importantly, you'll also see the name of the log file that holds this message, so it you'd rather analyse the log in more detail offline, through the ODL log analyser in JDeveloper, then you can see which log to download.


Hawaii, Yes! Duncan has been around Oracle technology way too long but occasionally has interesting things to say. He works in the Development Tools Division at Oracle, but you guessed that right? In his spare time he contributes to the Hudson CI Server Project at Eclipse
Follow DuncanMills on Twitter

Note that comments on this blog are moderated so (1) There may be a delay before it gets published (2) I reserve the right to ignore silly questions and comment spam is not tolerated - it gets deleted so don't even bother, we all have better things to do with our lives.
However, don't be put off, I want to hear what you have to say!


« October 2015