Pages

Showing posts with label JDeveloper. Show all posts
Showing posts with label JDeveloper. Show all posts

The Struggles of Personalization in ADF

A Mike Heeren & Richard Olrichs co-production

ADF comes with the out-of-the-box features of personalization. This means that whenever you configure personalisation, users can persist changes they make to the application across sessions and personalize their experience with the application. We have seen that this feature can also confuse some of our users, so it is not always wise to use this. It depends on the use case you have. However, when recently implementing personalization on an ADF 12.2.1.2 application, we had a couple of issues regarding persisting these personalizations to the MDS.

We felt that most of the blogs we came across while implementing these features, share the joyful out-of-the-box configuration. Just select some of the checkboxes in the properties and you are done, ready to enjoy your beer and have your designers and product owners cheer for you.
Sometimes however, real life applications at customers do not match the out-of-the-box configuration and things can become a little bit more tricky than you might expect.

Let's start at the top, and go through some of the steps you will always need within your application for personalization to work. You need to have authentication and authorization set up. If you also want to follow our struggles, we have posted a sample application at the end of this blog to show both the problems as well as the solutions.

Getting started with customizations

The basic configuration of customization in ADF is pretty simple. We start with a simple ADF application (with authentication already configured), and select the Project Properties > ADF View. Here we check Enable user customization and Across sessions using MDS, as seen below:



When enabling user customizations, the following files are edited:
In the adf-config.xml file the following lines are added:

 
  oracle.adf.view.rich.change.MDSDocumentChangeManager
 


In the web.xml file the javax.faces.FACELETS_RESOURCE_RESOLVER context-param is changed from oracle.adfinternal.view.faces.facelets.rich.AdfFaceletsResourceResolver to oracle.adfinternal.view.faces.facelets.rich.MDSFaceletsResourceResolver, and the following blocks are added:

 adflibResources
 oracle.adf.library.webapp.ResourceServlet

...

 adflibResources
 /adflib/*

...

 ADFLibraryFilter
 oracle.adf.library.webapp.LibraryFilter

...

 ADFLibraryFilter
 /*
 FORWARD
 REQUEST

...

 oracle.adf.jsp.provider.0
 oracle.mds.jsp.MDSJSPProviderHelper


 org.apache.myfaces.trinidad.CHANGE_PERSISTENCE
 oracle.adf.view.rich.change.FilteredPersistenceChangeManager


Finally, the following block will be added to the project .jpr file:

 
 


After this we need to configure the adf-config.xml file and add the oracle.adf.share.config.UserCC Customization Class on the MDS tab. This is a default customization class that is shipped with ADF. You can also write your own, but that is more of a use case for customization than it is for personalization. In our case we’ll just configure the application using the UserCC:



Now you need to configure the components that you want the end user to be able to personalize. This can be done in the View tab. Select the ADF Faces Components Tag Library, because we want to personalize the table and column components, these are default component from ADF Faces. By default all attributes will be persisted, you can uncheck them if you do not wish to persist these:



After the above steps are configured, you can give a fancy demo on your demo application, and everybody is happy. However, in our production application, there were still a few issues to tackle, we struggled with some of these.

Struggle 1: Task flows from libraries combined with a file based MDS on a Windows machine.


Our application was not a simple MVC application, but like many application out there, we used ADF libraries to include taskflows from library projects and included them in a bigger main application. When we turned on personalisation on components from task flows which come from libraries instead of directly from the application, they were not correctly persisted to the file based MDS on Windows machines.

When running the application via JDeveloper (in our example application by right clicking default.jsf in the ViewController project, and selecting Run), we see that the task flow that comes directly from the ViewController project (the table on the left of the screen), behaves as expected. However, when personalizing the table from the task flow that comes from the imported library (so from the ViewControllerLibrary project), we see the following warning in the log files.

    

We can verify that the preferences were persisted to the MDS for the left table, but not for the right table, by opening the application (with the same user) in another browser:



Unfortunately, this issue occurs when using task flows from libraries in combination with using a file based MDS on a Windows machine. Weblogic is not able to create a file path, which contains !/ (which is used to indicate that the resource is part of a library).

Luckily, in our case all other DTAP environments don’t use a file based MDS, but a database MDS. In the database MDS, we don’t have the file path issues, so there we won’t see this issue. So on all environments except the (local) Integrated WLS, we don’t see these warning logs, and we will see both table personalizations being persisted. It might take you some time to realise this, if you do not want to deploy to Dev or Test without having the Personalization working on your local machine.

Struggle 2: Deploying the application as EAR instead of via JDeveloper


Deploying both from JDeveloper as well as creating an EAR file seems to work. However, there was still some struggle there as well. The personalisation was working when deploying via JDeveloper, but when we would build in EAR from the application via JDeveloper, and deploy it manually to the Integrated WLS via the console, none of the settings were persisted to the MDS, and we saw the following warning in the log files:

     

By opening the application in different browsers again, we can also confirm that neither of customizations the tables is persisted in the MDS now:



When Personalization across sessions with the MDS is configured, JDeveloper always creates a metadata store usages in the adf-config file at deployment time. This configuration is named MAR_TargetRepos.

It does not matter that we have configured a different metadata store usages within the adf-config. If the MAR_TargetRepos is not present while creating the EAR file, it will be added to the adf-config file. The only solution that we found to this, is by naming our metadata store usages to match the expected default, then it will not override or add anything.


      
            
      
 
  
   
    
    
   
  
 


Note that we did not set deploy-target to true, because if we do this, our custom MAR_TargetRepos will be overridden with the default implementation again, when building the EAR file. This default implementation does not contain the FileMetadataStore implementation:



Because we want to override the default MAR_TargetRepos, so the personalization will also work when deploying the EAR instead of deploying via JDeveloper, we do not set the deploy-target to true so the default (false) will be used. In this case the FileMetadataStore configuration will be preserved in the EAR file.

If we deploy the new EAR file, we see the same behaviour as we did when deploying it via JDeveloper. Also, when we use the personalization functions on the screen, we will see files being created within the PersDef folder within the %TEMP% environment variable.

This FileMetadataStore configuration is changed (back) to a DBMetaDataStore configuration by an ANT build script, before deploying on the different DTAP environments instead of the Integrated WLS environment. An example of such ANT script can be found below.


  
  
  
  
 
  
  
  
  
  
 
 
   
   
 
 
  


Be sure that the WLS_HOME environment variable is set in the system environment variables, and the ear.location property is replaced in the ANT file when you want to use the above example.

Struggle 3: Suddenly our application does persisting during the session.


We have configured the adf-config to persist only certain components and attributes across the session. This works very nice and clear, however, suddenly all the other components also persist their state, just not across the session, but during the session.

It is possible that this is not what you want, it certainly was not what we expected or had in mind for our application, but there is nothing much we can do about it. It would have made more sense to turn this off for all the components and only persist those that were configured to be persisted.

Luckily the ADF components have an attribute persist and dontPersist on them. When reading the documentation on these attributes, it sounds exactly like what we need for our application! Before adding the dontPersist attribute to the hundreds of components we have in the application, we decide to test it on a couple. What we found out was very unpleasing, basically these attributes could be used for documentation purpose or for fun, but it certainly did nothing concerning persistence.

We decided to create our own custom class to adjust the framework and get this working. To achieve this, the context-param org.apache.myfaces.trinidad.CHANGE_PERSISTENCE can be adjusted to a custom class.

At first we tried to extend the oracle.adf.view.rich.change.FilteredPersistenceChangeManager class, which is the class ADF uses by default. However, unfortunately this class is declared final. We decided to create a class that extends the org.apache.myfaces.trinidad.change.SessionChangeManager class, and use the FilteredPersistenceChangeManager as an instance variable. This may not be the prettiest solution, but it serves our purpose:
package nl.whitehorses.personalization.changemanager;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import oracle.adf.view.rich.change.FilteredPersistenceChangeManager;

import org.apache.myfaces.trinidad.change.AttributeComponentChange;
import org.apache.myfaces.trinidad.change.ChangeManager;
import org.apache.myfaces.trinidad.change.ComponentChange;
import org.apache.myfaces.trinidad.change.DocumentChange;
import org.apache.myfaces.trinidad.change.SessionChangeManager;

public class CustomChangeManager extends SessionChangeManager {
 private final FilteredPersistenceChangeManager fpcmInstance = new FilteredPersistenceChangeManager();

 @Override
 public void addComponentChange(final FacesContext context, final UIComponent component, final ComponentChange change) {
     if (component == null || component.getAttributes() == null) {
         return;
     }
     final String[] persistArray = (String[]) component.getAttributes().get("persist");
     if (persistArray == null) {
         return;
     }
     for (final String persistVal : persistArray) {
         if (persistVal != null && change instanceof AttributeComponentChange && ("ALL".equals(persistVal) || ((AttributeComponentChange) change).getAttributeName().equals(persistVal))) {
             fpcmInstance.addComponentChange(context, component, change);
         }
     }     
 }

 @Override
 public void addDocumentChange(final FacesContext context, final UIComponent component, final DocumentChange change) {
     fpcmInstance.addDocumentChange(context, component, change);
 }

 @Override
 public boolean supportsDocumentPersistence(final FacesContext context) {
     return fpcmInstance.supportsDocumentPersistence(context);
 }

 @Override
 public ChangeManager.ChangeOutcome addDocumentChangeWithOutcome(final FacesContext context, final UIComponent component, final DocumentChange change) {
     return fpcmInstance.addDocumentChangeWithOutcome(context, component, change);
 }
}

As you can see, the logic for the persist attribute has been implemented in the addComponentChange method. The addComponentChange method from the FilteredPersistenceChangeManager instance, will only be called when the component contains the persist attribute which is set to ALL. Besides the addComponentChange method, all other (public) methods from the FilteredPersistenceChangeManager have been implemented to use the instance variable as well.
Conclusion

After some struggles and adjustments to the implementation and configuration of the application, we got personalization to work in our real world application used by customers. We overcame the struggles, but this was not as easy as the blogs on the internet made us believe beforehand. We hope that sharing this experience, might save you for some of the troubles we had.

To give you some more insight in the code and the struggles, we have created a (simple) demo application AdfPersonalization, to reproduce the issues we had, and which we used to solve them.

This application consists of the default Model and ViewController projects. Also, we added a ViewControllerLibrary project. This ViewControllerLibrary project is imported as a library by the ViewController project.

The AdfPersonalization application can be deployed to Weblogic in multiple ways:

  • Using the ‘Run’ button in JDeveloper.
  • Using Application > Deploy > … to IntegratedWebLogicServer in JDeveloper. This can be done to verify that struggle 2 is no longer an issue.
  • Using Application > Deploy > … to EAR, followed by running the replace-persdef-repo ANT target from the build.xml file. Afterwards the EAR can be deployed to a Weblogic servers, which is capable using a database based MDS. This can be done to verify struggle 1 is no longer an issue.
  • The source of this project can be downloaded via AdfPersonalization.zip.

Resources




Put Component References in the correct memory scope

Memory scopes itself can be confusing enough, therefor I always advise my fellow developers to use the ADF scopes as much as possible and avoid the JSF scopes if they can.

When using taskflows, a lot of times, we want to store values in a pageFlowScope bean, for example to use during the lifecycle of the taskflow on several pages. Now a common mistakes is to have the UI components bind to the same bean as the values.
Usually this happens, because there is an actionListener that refreshes the component in the pageFlowScope bean, that also sets values in that same bean.

I am always a fan of splitting up beans in smaller logical blocks of code, but in this case it is necessary as well. There is a good blog by the a-team on the best practises for bindings in ADF. Next to that, there is also a Code Guideline on the ADF Architecture Square:

• [ADFcg1-03009] – Store UI components in requestScope and backingBeanScope beans - only store references to UI components in requestScope and backingBeanScope beans. Never store references to UI components in applicationScope, sessionScope, viewScope or pageFlowScope beans.

Not doing this, can cause problems on a HA clustered environment, but the main and best reason in my eyes for this is because the UI component tree might not be released correctly. This has two side effects, mostly a significantly increasing of memory load of your application, but I have also seen some strange behaviour of the UI component, leading to inconsistent state of the component in the browser.

The tricks is to split the beans in separated concerns, one that manages the UI components, holding the component references, as well as the actionlisteners. In the taskflow we inject the pageFlowScope bean holding the values in this backingBeanScoped bean that manages the UI state.
Because we have access to the values through the injected bean, we can use the getters and setters to read or modify the value in the pageFlowScope bean, while making sure our UI component references never exceed the backingBeanScope.

My next blogpost will show an example of how to set up this beans including code examples.

Resources:


JDeveloper Shortcut Keys: Reformat All Files in your Project

When writing Java code, it is a good practice to reformat your code before committing it to a source control system. In JDeveloper, you can put this in your save actions, however, JDeveloper will then also reformat all your XML code, this is not always what you want, plus it is a lot slower than reformatting only the Java code.

When in your Java file, you can use the right mouse menu, or the shortcut keys to reformat the java file you are currently working on, this is 'Ctrl' + 'Alt' + 'L' on windows or '⌘' + '⇧' + 'L' on mac.

However, when you change something in your code style, you probably do not want to go by every file individually to reformat the code. Good thing is that JDeveloper can also reformat a whole project at once.
This is not really well documented and it is not in the right mouse window either, but when you select a project in your Application Window and press the shorcut key for reformat, JDeveloper will reformat the whole selected project for you.


JDeveloper Shortcut Keys: Select in Application Window

In more complex projects with a lot of files, you can sometimes lose track of where the files are located. This can be helpful if you have your files saved in a logical package structure. After looking up a file, for example by using the Go to File shortcut key, it might be helpful to know where this file is located.

Well, in JDeveloper there is a shortcut key to find the file in your Application Window. This is 'Alt' + 'Home' on windows or '⌘' + 'Home' on mac. 

As you can see the file is selected and displayed in the Application Window.


JDeveloper Shortcut Keys: Go To File

I have been noticing that a lot of developers are either struggling with finding files in JDeveloper or taking a long time to open all the packages and browsing to the files. However, JDeveloper has a lot of shortcut keys that come in handy.

First of, a shortcut key to 'Go To Java Type', I think most developers know this one. It is the 'ctrl' + '-' on windows or '⌘' + 'J' on mac, you will get this window:

However, did you also know the search is CamelCaseSensitive? It is a very neat trick, imagine you have connected your ADF sources and want to look up the PageFlowScopeMap in the 'org.apache.myfaces.trinidadinternal.context' package.
You can open the 'Go to Java Type' screen and start typing page, but a lot of java classes will come up:

As said the search box understands CamelCase, so if you instead start typing the fist capital of each CamelCase word, in this case 'PFSM' (PageFlowScopeMap) JDeveloper will understand:

How cool is that?

Now this is not where it ends, instead of only searching for Java Types, you can search over all your files in JDeveloper, using the shortcut key: 'ctrl' + 'alt' + '-' on windows or '⌥' + '⌘' + '-' on mac. The following window will popup:

In here you can search for any file, but again you can also search CamelCase, for example, in case I want to search my ViewControllerBundle.properties file:

Now, in both windows you can also use wildcards (*), however the CamelCase will not work in combination with a wild card anymore.


Switch the Audit Level to Development mode

With JDeveloper 12c it is now possible to run your SOA Suite against the Integrated WLS. However, by default the Audit Level of this server is Production mode which means you do not get to see details when looking at the flow trace of your service.
If you do not change your running mode, the flow trace window will look like this:


We will switch the Audit Level of your local SOA domain to Development mode, to get more info in the flow trace. Right click on your soa-infra, go to the SOA Administration and select the Common Properties:



Change the Audit Level to Development and click Apply:



You do not need to restart your server after this. However, you do need to test your service again. Test your service and again go to the flow trace, the result should now look like this:



You can now press the ‘View Payload’ to see the payload of your transformation:




Run ADF & SOA on the IntegratedWLS in separated domains

In JDeveloper 12c, it is possible to run SOA Suite on the InternalWLS, which is a great feature. However, once you have done this, your domain will be filled with SOA extensions. Meaning the server start up time will increase drastically.
When you do both ADF & SOA development, this can be annoying when you just want to run your ADF application and the IntegratedWLS is busy starting up the SOA domain. One way to avoid this is to run two different JDeveloper instances with two different Jdev Homes configure.
In this blog I will describe you how to set this up.

First of all, I got my ‘normal’ JDeveloper for ADF development, this is installed on my C drive, under: C:\oracle\JDev1213, if you navigating to the Oracle_Home\jdeveloper\jdev\bin folder and open the jdev.boot file, you will see the variable ‘ide.user.dir.var’:


Now I recently installed a second JDeveloper 12c in a different directory, this JDeveloper is installed with the SOA extensions, I installed this on the C drive as well, but in the folder C:\oracle\JDevHomeSOA. Within this JDeveloper folder, there is also a jdev.boot file under the folder ‘\jdeveloper\jdev\bin’, however, I changed the ‘ide.user.dir.var’ to a specific _SOA variable:


Now all that is left to do is to create two new Environment Variables, pointing to different JDevHome directories:


This will create two different domains for each JDeveloper, keeping your environment clean and tidy!

Stretch your table to full page

In a previous blog I mentioned dynamic stretching table height with the autoHeightRows property. However, I have noticed people are having more troubles with stretching the height of the table.

This time I will focus on stretching your table to fill the total page height. We start with a simple ADF table on the employee table, showing all employees. Although I have seen more complex questions, including regions and more components in the structure, it all comes down to the same principle. I created a pretty straight forward jsf file with the following structure:



On the panelCollection I have set the styleClass AFStretchWidth to stretch the table to the full width of the page, however, by default it will not stretch the full height, but it will look like this:

Especially when you have a more complex structure, with more layout components in your page, it is easy to think you configured something wrong, however, this is the default behavior even when you use the panelStretchLayout.
In the documentation of the panelStretchLayout you can read up on the Geometry Management, it is important to focus on the section about the ‘dimensionsFrom’ property. The default value is read from the web.xml context-param ‘oracle.adf.view.rich.geometry.DEFAULT_DIMENSIONS’ which results in ‘auto’.
However, for our page we want the table to take the dimensions from parent. You can set the dimensionsFrom="parent" on the panelStretchLayout on your page, or you can override the default in the web.xml parameter.
The result will be the same, a table shown over the full page:





Using Code Snippets in JDeveloper

In JDeveloper, it can be helpful to set up code snippets to be of easy use later. Personally I use this mainly to set up code snippets for demo purposes and this is rather easy to set up.
First of all, if not already open, open your Components Window in JDeveloper: 

Now open the file that you want to create the code snippet from, this can be any file in JDeveloper as example I opened a Java file with a main method in it. After you have opened the file, you should see a choice list in your Component Pane in JDeveloper.
In this choice list select the option ‘My Components’ and open the ‘Code Snippets’ area:

In the file you opened, select the part of the file that you want to save as a snippet and drag and drop this to the Code Snippets area:

After this a pop up should appear to enter a name for the snippet, enter a name and press OK:

The result should be a saved code snippet on the Code Snippets area when My Components is selected:

You can now drag and drop this code snippet into any other file to create the exact same code as you have saved.


JDeveloper Debugging Tips (Watchpoints & Beep)

In a previous blog post I talked about scoping breakpoints for debugging purposes, next to scoping breakpoints JDeveloper has more interesting debugging features to offer.

I created a simple example to show both the watchpoint as well as the beep functionality. To illustrate this, I created a page with an inputText and a button, both bound to a backingBean. 

This  is the jsf code:
 
      
      
 
The code from the bean is also pretty straight forward:
   private String value = "value";

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void changeValue(ActionEvent actionEvent) {
        value += "!";
    }

Now imagine that I want to halt execution everytime the bean field value changes. I can simply right-click the field and choose ‘Toggle Watchpoint’:

This will show a nice sunglass instead of a breakpoint in the line gutter:


I also want to be informed when the getter of the value is called, however, I do not have the need to be redirected to JDeveloper and press F9 again to continue. I just want a signal that we have been inside the getValue() method, in this case a beeping sound.
To do this, you place a breakpoint in the getter, right-click on it and go to ‘Edit Breakpoint’.

Go to the Actions tab, in here unselect the ‘Halt Execution’ option and select the ‘Beep’ option. You will hear a beep when the breakpoint is reached, but it will not force you into JDeveloper.


If you run the page, you will hear a Beep whenever the getter is called, so you recieve a signal of this action. Whenever the field value is changed, it will take me into JDeveloper and halt the execution, this means it will halt execution in the method when I press the button on the screen, while there is no explicit breakpoint at this point in the code:

You can also see the old and new value in the log window:


ADF EMG XML Data Control version 1.0.0

Today at Oracle Open World, we (Wilfred and myself) officially announced the 1.0.0 version of the ADF EMG XML Data Control. Check out the presentation on slideshare if you missed it.

You can get this extension through the JDeveloper Help -> Check for Updates menu. Make sure you select the 'Open Source and Partner Extensions' checkbox:


There you should see the 'ADF EMG Data Control' extension:


A brief description for those who were not at our OOW Sunday Session:
The XML Data Control is an ADF Data Control that is used by developers to create data bindings in ADF Faces pages, just like the ADF BC Data Control and the POJO Data Control. The data exposed through this data control can be any XML source – from a BPM Human Task, from a SOAP or REST WebService, from a static XML document or a custom Java Class that produces an XML document from anywhere.

Read more on this project on our public wiki.

If you’re interested in following or contributing to this open source project, make sure you bookmark the following links:


The ADF EMG XML Data Control Extension is available for both JDeveloper 11gR1 and JDeverloper 12c.


ADF EMG Audit Rules available on JDeveloper 12.1.3

I got a few questions from people why the ADF EMG Audit Rules are not available in JDeveloper 12.1.3. So there has been a new release of the ADF EMG Audit Rules. No new functionality is implemented this time, but the extension is now available for JDeveloper 12.1.3.

If you go to Help -> Check for Updates, tick the Open source and Partner Extensions checkbox and press Next: 

Select the ADF EMG Audit Rules and click Next:

The extension ADF EMG Audit Rules should be installed correctly, click finish and restart JDeveloper 12.1.3:

Now if you go to your Tools -> Preferences, there is a button ‘Manage Profles’ on top of the Audit tab, you will find your profiles under that submenu. Press the button to open the Profiles menu:

Within the Audit Profile, you should see the ADF EMG Audit Rules appear:

Disabling and Enabling the Auto Map for XSL

When working with more complex XSL files, it can sometimes be useful to disable the Auto Map option. This can easily be achieved in the Auto Map Preferences popup you get when drawing lines in the design view of an XSL Map.


However, once disabled, you will not get this popup anymore to re-enable the Auto Map option. You need to do this through the Tools -> Preferences menu in JDeveloper. On the bottom of the list you see the XSL Maps menu with a submenu for Auto Map properties.


Here you can re-enable the Auto Map option for you XSL maps.

Share your source between projects

Normally we pack functionality into libraries and use this library to share the functionality. However, during development of several JDeveloper Extensions our goal was to have one shared java source between our JDeveloper 11g and JDeveloper 12c extension.
Off course we wanted the ability to easily develop, test, debug and run the extension, but we also want to share the java code to introduce reusability.

We accomplished this, by creating a separated ‘coresrc’ folder and add this folder as a Java source path both in JDeveloper 11g and JDeveloper 12c. To illustrate two screenshots of the open source project ADF EMG Audit Rules.

JDeveloper 11g:


JDeveloper 12c:

A great trick to share your Java source between several projects, where you can still keep project specific source in the regular project src directory.

New release of the ADF EMG Audit Rules

There is a new release of the ADF EMG Audit Rules extension. With this release there is now support for both JDeveloper11R1 and JDeveloper12c. However, remember that JDeverlop11g does not support the suppression of violations, so this may lead to a lot of violation on existing projects.
Remember that you can define a custom profile in the Audit tab under preferences to unselect certain rules, but off course it is better to look at the warnings and see if you can fix them.


In this new release we also improved the stability of the extension, but if you see unexpected behavior in JDeveloper and you suspect it comes from the ADF EMG Audit Rules extension, you can file an issue in Jira. The amount of rules went up from 18 in version 1.0 to 35 audit rules in version 2.0.


Next to Wilfred I would also like to thanks Rohan Walia for his time and commitment to this project!


If you would like to help out and get involved in this project, check out the Index page with various links to documentation, blogs and the open source project on java.net.