September 10, 2009

Pre filtering table data

I've recently spent a few rough weeks doing something I would consider rather trivial. Unfortunately, the task of actually doing it was harder than I had anticipated. The documentation on how to accomplish this is somewhat sparse at best so I've decided it was a perfect opportunity for an entry because this seems like a very common scenario.

The scenario is this.

I am a developer and have a requirement to display a table on a JSP page. Easy enough to do if you have a pre-defined DC (Data Control) with a VO (View Object) to drag over an iterator to a jsp page. What if you want that data already filtered? You can drag over a query from the 'Operations' folder under the selected VO. The problem is, this wants to create a query form or some other visual element that THEN filters the table. What if you want the data already filtered by the time the page even renders. This seems like a very common requirment yet is not 'out of the box' behavior. Rarely does one want a SELECT * FROM tableName without some sort of WHERE clause to filter the data. Many times we want to pre filter this data before it reaches the end user without them entering the data themselves.

In my example, I pull the data from a field in an object in pageFlowScope. pageFlowScope is a scope, similiar to session scope. It is only within the lifecycle of a task flow. I wish they had called it taskFlowScope. It took me a little while, and some research, before I realized that pageFlowScope was task flow scope. It sounds too much like pageContext scope to me personally and was a little confusing.

Apparently there was an easier way to do this in previous releases. I am using 11g and always have been. I've never used a previous version. It is a bit more difficult now because they wanted to split up the logic of the task logically into more of an MVC pattern instead of the previous way of doing things, which stuck too much at the View layer.

Here is what we are trying to accomplish;

SELECT ..... FROM tableName WHERE fieldName = ?

We want to set ? to a pageFlowScoped variable BEFORE we even reach our page so the table is pre-filtered.

The first place to accomplish this is in the Model layer. We used ADF BC components. These are the components that become your DataControls. You should have already created a VO for the table in question.

Within the VO we need to add the WHERE clause. To do this, open the VO and you should be under the overview tab. Click the 'Query' link option from the left hand side of the VO. Then click the '+' at the bottom right under the 'View Criteria' section.
vo_view_criteria_choose.png

This is the next screen you'll see. Give your criteria a name and click the 'Add Item' button.
vo_view_criteria_create1.png

Choose the 'Attribute', or field, you wish to add to your WHERE clause. Then choose the 'Operator'. In our case we want the 'Equal to'.
vo_view_criteria_create2.png

Now we need to define a variable that will our our data to be passed into the query. This is the value that will go into the '?' in our SQL above. Click the 'Operand' and choose 'Bind Variable'. Now we have to create our bind variable. To do this, click the '+'.
vo_view_criteria_create3.png

Give your variable a logical name. I also use a literal. When the query is finally called, whatever variable you bound to this bind variable will be passed as a literal. You can use expression, but I'm not sure why. I guess if you want it evaluated the same way every time later. Since I'm using a literal, I give a default value. I also chose to make this NOT required. The reason is, you will get errors if this VO is ever referenced and your bind variable is not set. Click 'Ok'.
vo_view_criteria_create4.png

I left the validation optional, for the same reasons given in the previous paragraph. This yields the following SQL. Notice that it has an OR condition that allows NULLs which removes any errors from just trying to use the VO without the bind variable being set. Click 'Ok' and save your VO.
vo_view_criteria_create5.png

Notice now that you can see your newly created criteria and bind variable.
vo_view_criteria_create6.png

Now open the AM (ApplicationModule) for this VO. We need to set it so that this criteria runs when anyone tries to access this VO. In the 'Overview' tab click the 'Data Model' link on the left hand side. Choose the Data Model with the newly created criteria filter in it. In my case it is called 'Addressee1'. Click the 'Edit' button.
am_map_criteria1.png

Choose your filter criteria and then click the '>' or add button to add it to the list of criteria selected to run on this VO. Notice the parameter added to the 'Bind Parameter Values' section. Click 'Ok'.
am_map_criteria2.png

Now save and build your new AM.

Those were the steps for the Model layer.

Now for the controller layer.

We need to set the variable before we display our VO as a table in the JSP, otherwise, it will show all data, because the bind variable will be set to null, which is acceptable because we set it as optional at the model layer.

The way that was recommended that I do this was to add an activity to a task flow that gets called before our JSP to display the data.

If you don't already have a task flow, create one. You should have your VO as part of a data control listed on JDeveloper's left side (typically) under 'Data Controls'. Click on 'ExecWithParams' Operation and drag it onto your task flow. This is the task that will set the parameter. You may notice the parameter nested within the 'ExecWithParams' operation.
controller_DC_execwithparams.png

You should now see the 'Edit Action Bindings' dialog. Most of it should be filled in correctly for you. Here you may want to change the option, if its mandatory or not. It is within this screen where you finally set the variable that maps to the '?' in our WHERE clause in our SQL for our base requirement.
controller_edit_action_binding.png

Click the down arrow in the 'Value' and choose 'Show EL Expression Builder'. Choose the piece of data you wish to bind to the criteria bind variable. Mine is in a pageFlowScope variable. There is a problem with the latest GA release that does not allow you to browse to the variable even though it is within scope. It is fixed already for the next relase. You'll just havet to enter it by hand. Click 'Ok'.
controller_bind_variable.png

From the 'Edit ActionBindings' screen click 'Ok'. You should now see the action available on your task flow. It will also create a data binding page for your task flow/activity if one was not already created. To view the bindings file, just right click on your 'ExecWithParams' activity and choose 'Go to Page Definition'. There you will see, under structure on JDeveloper's lower left side, the ExecuteWithParams action along with the bind variable as a NamedData node under it.

Now just connect this activity however you want in your task flow. The key thing is, of course, it has to occur BEFORE you get to your JSP page with the filtered table data. Here you can see an initialization action that occurs first in my task flow. This sets the variable in my page flow scoped object that is passed into my VO bind variable. The next is the activity we just generated and performs the filtering. Notice it has a warning. It says 'ExecuteWithParams' not found even though it created it. You can see in the bindings file it is there. Just ignore this warning. The next page is a JSP page. The page after that, the second one in the train, is the JSP page that displays the newly filtered data.
controller_task_flow.png

The JSP page is nothing special. I just drug the VO over to the page and said make table from the options it gave me.

That's it. Wshew.

August 4, 2009

Creating a Spring ADF Library

I've worked to be able to create a reusable spring library that can be exported from JDev as an ADF Library jar. There were a couple of key points.

First create a general java project in your application.

Add all jars you need to the project classpath. This is in the project properties. Make sure the library jars are exported to the project on deployment! It is an option on deployment. This is often what causes most Spring enabled ADF applications to fail.

The spring module exits only as a a spring enabled, java interface. I then created a deployment profile to export my spring project as a jar. It helps to make sure that jar contains all necessary resources.

If you want DataControls you can just right click on any of your Spring beans and say 'Create Data Control'. To do this I specifically created an ADF project to put ADF DataControls in front of my spring objects. That way, I can deploy an ADF Spring enabled library jar with spring facaded behind DataControls. This project would be different than my main project with my Spring code. The reason is someone may want to just work with the spring enabled code without ADF. I do this to ease command line and unit testing.

If you are having problems with a web deployment, such as ClassNotFound, then you may need to add a weblogic.xml to your war, inside the WEB-INF directory. It will look like this;

  <weblogic-web-app>
    <container-descriptor>
      <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
  </weblogic-web-app>


This makes sure that weblogic loads your classes before it's own.

Check your final war in the WEB-INF/lib directory. Make sure it contains all the necessary jars. If you are loading your applicationContext.xml via the class loader, then the framework loads the same way it would in any other Spring enabled J2EE application. Either include it in the WEB-INF/classes directory or in the classpath itself, modified in one of the startWeblogic.cmd type files, or use the WebApplicationContext. I use Facaded DataControls that reference these Spring beans using my own static Spring Factory which loads everything via the XML Class loader.

June 5, 2009

How to add an image to a column header

We have a requirement to use an image as a column header instead of text.
This is documented that it can be done but I couldn't see how to actually
do it. The solution is to use the tag 'facet'. With a facet you can stick
just about anything you want, anywhere you want. I removed the column
header text, added a facet and then put an image tag in the facet. All
this goes above the component, 'selectBooleanCheckbox', of course. Here is
the code.

<af:column sortProperty="Attachments" sortable="false"width="25" align="center">
  <f:facet name="header">
    <af:image source="/images/attachment.png"/>
  </f:facet>
  <af:selectBooleanCheckbox value="#{row.Attachments}"/>
</af:column>

June 4, 2009

ADF Noob

Hello to anyone who may be an ADF noob. You are in good company. I am relatively new to Oracle. My team was part of an aquisition and are currently in the process of migrating some of our technologies over to the ADF stack. We had a rather typical J2EE/Java hodge-podge of technologies (JSP, Dojo, etc) before but have decided to try to consolidate these into a unified ADF platform. We have a variety of customers using a variety of technologies.

This scenario, from what I can read on the forums and email lists, makes me a somewhat typical ADF Noob. I have already realized that many of the questions and problems I've run into are quite typical. I would like to use this blog as a sort of non-ADF expert who can help post solutions, and ask questions, from a perspective one can only have as a non-expert. I will post any time I've found a solution to something I was struggling with, in the hopes that it will help other's strugling with the same issues.

I have been working with ADF for a few months now and actually just got back from training so many of my confusions have been answered but the questions are still fresh enough in my memory so I can post their solutions here.

Also, if anyone is interested in training, I would highly recommend it. It was VERY helpful and packs in a LOT in a week...and I mean....a LOT!

Here are some areas I've had to address in my work and will blog about in future posts. Most of these have been addressed in other Oracle documentation or blogs but this is just my own experience, or clarification that I needed on the topic.

* Integrating ADF and spring to create a reusable ADF/Spring library.

* Running ADF on different application servers; ie: Tomcat, Websphere and Weblogic not bundled in JDeveloper.

* Some big 'ah ha!' moments.

* Running ADF with multiple databases; ie: Oracle XE, MySQL, hsqldb

* Creating tables with non-standard components

* Using an image as a column header.

* Deploying and debugging magic.

* How to create a table linked to a detail form (row selection updates form detail).

* Some common errors, why they happened and how to fix them. ie: Out of PermGen space, ADFBinding not found, etc.

And who knows what else. These are just some of the issues I've ran into and solved (some of them!). If you are in the same boat then we can grow with ADF together and you can feel free to send me any email regarding a pain point and solution you may have come across and I may throw it up here as well.

Who is this guy?

pigletandme2.jpg p>

ADF Noob tries to help you through similar trouble areas by posting my confusions and solutions.

Categories

Powered by
Movable Type and Oracle