If you learned something
today, please
1x

The First Step of a Journey that Began Five Years Ago

March 22nd, 2014
No Gravatar

Note: I will update this article with a link to the application once the customer has done their own announcements in accordance with their external communication policies and procedures.

In the Beginning there was BEA WebLogic Portal

In 2008, Oracle acquired BEA Systems. 19 days after the official merger, Oracle announced that premiere support for WebLogic Portal would end in 2014. The current policy document (latest can be found on http://www.oracle.com/us/support/lifetime-support/index.html) has moved this date out to 2018, though they have been sticking to the “no new feature release” policy since the 10.3.2 release in 2010. 10.3.2 was intended to be 11g, except it came out a year later than originally announced at Open World in 2008 and was released as a “dot” release of 10g despite the fact that it had several major enhancements and new features.

I had been hired by BEA in 2006 as a WebLogic Portal consultant due to my extensive experience with the product as a consultant for netNumina Solutions. In 2009, Oracle released WebCenter 11g and I attended the Masters Training two weeks prior to the GA date where I learned just how very different the two portal products are.

Which Way Do We Go?

I have been unable to find any officially published direction for WebLogic Portal customers who wish to migrate to WebCenter Portal, though I have had numerous conversations with engineers, architects, consultants and product managers about how to go about this. These discussions revealed three general approaches.

One approach is to simply re-build the portal in WebCenter. This is quite viable for very small portals and avoids the pitfall of other approaches, which is the need to maintain two architectures. It is not a very practical approach for medium to large portals as it is a great deal of effort and expense over a long period of time to just to provide the same functionality.

Both the second and third approaches are about transitions. On method is to create the new WebCenter portal and build all new features there and link over to the legacy WebLogic Portal for existing features. This is very quick and easy to deliver but difficult to maintain.

The third approach is staged migration. This approach creates the a new WebCenter portal that is the where users log in and interact, with the legacy functionality being exposed using WSRP. This solution allows for the immediate introduction of the WebCenter architecture and minimizes maintenance cost. By following a policy where any legacy portlet that requires modification be first moved over to WebCenter, Business and Technology stake holders can plan the complete retirement of the WebLogic Portal infrastructure as best suits the Enterprise as a whole.

Every Journey Starts with a Sprint

This month marks the deployment of the third solution to production for my current client. It is a medium-sized, high-complexity portal and it was brought from inception to production in six months using a mixed-Agile approach. It consists of 20 portlets produced by the legacy WebLogic Portal application and two legacy JSF portlets that were migrated in two days because they include file download functionality that made them easier to migrate than to dig through the documentation to fix as WSRP. The portal also includes managed content from WebCenter Content and a shared navigation structure with a legacy Struts 1.1 application.

The Enterprise Portal Architecture for the customer is to migrate all legacy functionality from WebLogic Portal to WebCenter Portal over the next year in staged releases that will also include the introduction of new features and functionality.

Stopping Sticky States in WebLogic Portal Beehive Producers in a WebCenter Portal Consumer

March 19th, 2014
No Gravatar

Recently had an issue where Beehive pageflows would retain their state when the user navigated to another page and returned. The business owners would not accept either the use of a button to start over or the ever-popular “Well, then don’t do that”. Understandable given it is a public site.

Without putting you through the tedium I went through to obtain the solution from Oracle Support (https://support.oracle.com/epmos/faces/DocumentDisplay?id=1419774.1 for those with an account, and thanks to Ming Kwok for providing it), turns out there is a setting accessible from the WebCenter Portal Page Definition that will cure this ill:

portletStateLifetime="ViewScope"

The above is an attribute of a portlet element. Note that in this project, all portlets are placed at design time (not fun with WebCenter, BTW). We did a bulk update of the entire application by doing a find and replace of

retainPortletHeader="false"

with

retainPortletHeader="false" portletStateLifetime="ViewScope"

Additional effort is required for JSF portlets, which a colleague is working on will be posted here when he completes his solution.

Stopping _afrLoop Looping Refresh

February 13th, 2014
No Gravatar

While building out a new environment I found that my WebCenter portal application URL would go into a long cycle of refreshing the page at login when more than one managed server in the cluster was running.

To save many of you the long process of research I went through, the key piece to my puzzle was that SiteMinder is used for perimeter authentication. The fix for this combination (WebCenter and SiteMinder) is to change the WebLogic cookie name from JSESSION to anything else and ALL_CAPS. In my case, there was already a custom cookie name, but it was lower case.

While I did not test each part of the fix, I’ll include the rest and let someone else do so. That is, setting the cookie name as the same in both the Apache plug in and the WebCenter application. For the Apache plug-in, the cookie name is managed by WLCookieName. In the application, is done by setting the cookie name in weblogic.xml:

<session-descriptor>
 <cookie-name>MYWEBCENTERCOOKIE</cookie-name> 
</session-descriptor>

Also, there were many posts suggesting to remove the Trinidad filter to address this. That is the wrong solution in most cases and will lead to new and annoying issues.

Official solution can be found at Oracle Support Document 1491984.1 (ADF Application Redirects Browser Indefinitely) can be found at: https://support.oracle.com/epmos/faces/DocumentDisplay?id=1491984.1. I found the all-capse naming convention on some post, and don’t know if it is necessary but do know that it is working now.

Oracle DB Tip Link for the Non-Oracle DBA – Resetting Passwords

January 28th, 2014
No Gravatar

This blog saved my day: http://sai-surya-talk.blogspot.com/2011/06/resetting-oracle-xe-system-account.html

Finding What is Not There in Eclipse

January 25th, 2014
No Gravatar

In my current project there is a need to add some parameters to portlet definition files. The first pass through we only updated the ones we knew needed the update. As is often the case, what we knew then and what we know now changed, and it became a better approach to simply add the values to all of the portlet definition files. Rather than sorting through one by one to find which had not been updated, I did a search and found a stackoverflow thread about how to do these searches in Eclipse. The thread included the following example of a regular expression for finding files that do not include a particular value:

(?s)\A((?!YourSearchText).)*\Z

For those who like pictures, below is how the search box is used with regex to find files missing the string:

EclipseRegExSearchExample

Three Workflow Approaches with WebLogic Portal

December 30th, 2013
No Gravatar

This is a blast from the past originally published at Developer.com when they were still interested in portal development.  I came across it because I needed a reference to Nested Page Flows and couldn’t find one until I ran across a link to my own article. Deja dude. Anyway, here it is. One day I will clean up the mark up, but for now it is still useful for reference and so long as the link above works you can still see the clean version…

While the disclaimers usually start later, this article merits one up front: These are not the only solutions to creating workflows in WLP. For example, we’re not even going to touch on JSF, or consider the possibility of special considerations in a federated portal architecture. So don’t let yourself be limited by the scope of this article or author’s experiences, and prejudices. What we will examine is some solutions that are known to work and should give you enough of the basics to implement any set of workflow requirements on WLP.

Simple Page Flows

Page flows provide a very straight forward approach to creating a workflow. Using the built-in wizard will quickly generate your page flow controller with the default begin action. This default action is a simple action, which doesn’t do much for flow as all it does is forward to the generated index.jsp.

This is quickly enhanced by right-clicking on the begin action under the Actions folder in the page flow perspective and selecting Convert to a Method.

@Jpf.Action(forwards = { @Jpf.Forward(name = "default", path = "index.jsp") })
public Forward begin()
{
return new Forward("default");
}

Now you can begin adding workflow logic to your page flow. This approach is good for a simple process where the user will enter data in multiple forms and each submit does some level of processing on new data entered. You can even provide branching logic, forwarding to an action based on inputs. In either case, a single form bean in the page flow controller serves well to maintain the values, placing “frozen” values into hidden fields to maintain them from page to page and action to action.

Below is a series of action stubs that follow a simple workflow to create a web site user account:

/**
* Check if existing first last and email
* @param form userDataFormBean
* @return success if new user, error if existing user
*/
@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "creatUserName.jsp"), @Jpf.Forward(name="error", path="index.jsp")
})
public Forward processUserNameAndEmail(userDataFormBean form)
{
Forward forward = new Forward("success");
return forward;
}

/**
* create user name and request address information
* @param form userDataFormBean
*/
@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "getAddress.jsp")
})
public Forward createUserName(userDataFormBean form)
{
Forward forward = new Forward("success");
return forward;
}

/**
* Save the snail mail address and offer to subscribe
* @param form userDataFormBean
*/
@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "subscribeNewsletter.jsp")
})
public Forward storeAddressInfo(userDataFormBean form)
{
Forward forward = new Forward("success");
return forward;
}

/**
* Save the subsription choice and send to summary page
* @param form userDataFormBean
*/
@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "summaryPage.jsp")
})
public Forward offerSubscription(userDataFormBean form)
{
Forward forward = new Forward("success");
return forward;
}

What makes this simple is that each JSP uses the same form bean, with the action set to the next action. In a more robust implementation each action would also have an error page to forward to, which could easily be the JSP that submitted the information (such as processUserNameAndEmail does) with error messages. This example could be expanded with some simple branching; such as if the user already exists in the database the page flow action could forward to a password reminder page instead of simply going back to the index page.

Nested Page Flows

Nested page flows take planning a coordination between the originating and nested controllers.This makes them very useful when the work flow is predetermined and not expected to change much or often. In other words, the nested page flow approach is best suited to Waterfall projects where most (if not all) requirements are known prior to development.

Nested page flows allow passing control off to another controller while maintaining the state of the originating controller. This can be useful for branching logic or if you are creating multiple workflows that have the same set of steps as part of the flow. You can develop a page flow control that does the common steps, then call it from the controllers that deal with the parts of the workflow that vary. For instance, in our earlier simple page flow we could add a survey in the work flow before the subscription page to determine what types of subscriptions to offer. This survey workflow could also be presented to existing users at log in if their responses were out of date or when there was a new survey. In both the account creation scenario and the login scenario, the survey comes in at the middle of the process, so we want to be able to reuse the survey code without losing the state of either the enrollment or login workflow, so we call the survey flow as a nested flow.

If you know you are going to be calling a page flow as a nested flow at the beginning you can get the necessary annotations and action methods generated by checking the “Make this a nested page flow” option at the start of the page flow creation wizard. The two key ingredients to making a pageflow nested is in the controller annotation at the class declaration:

@Jpf.Controller(nested = true)
public class NestedPageFlowAController extends PageFlowController{

And the necessity to have an action with a forward that includes a return action:

@Jpf.Action(forwards = { @Jpf.Forward(name = "done", returnAction = "portlets_nestedPageFlowADone")})
protected Forward done() {return new Forward("done");}

The return action must be an action method that exists in the controller that called the nested controller. Calling the nested controller is simply a matter of having an action with a forward that resolves to the nested controller (or a method within the controller) like this:

@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "subscribeNewsletter.jsp")})
public Forward portlets_nestedPageFlowADone(userDataFormBean form)
{return new Forward("success");}

As noted, this takes a good deal of planning up front. For a more Agile approach, let’s look at a new approach.

Event Flows

As far as the author knows, this is the first description of using events for this particular purpose. This is probably because the author doesn’t have as much time to read articles as write them, because it is a fairly intuitive leap to go from inter-portlet communication (a common use of portal events), to passing control back and forth between specialized controllers as well as loading hidden pages used only for special purposes in a workflow.

Events are a handy way of decoupling your controllers and actions. They allow you to move from one controller to another and back again with the only explicit relationship being to the event rather than the action. If you come up with a better way of handling an event or your workflow rules change, you can simply change how the event is handled rather changing all parts of the workflow.

Let’s say we are looking at a login workflow. When the user logs in, the first step would always be to check their credentials. From that point, there are many tasks we may want the user to do. It may be time for them to change their password, or there may be a message we want to show them based on some demographic information. None of these activities are mutually exclusive and could occur in any combination. We could use simple page flows or nested page flows to achieve this, but that would require tight coupling between the actions and/or controllers. Instead, we can fire an event based on an evaluation and send the user off to take a survey (for example). When they have completed the survey we may want them to see a bulletin or not. So rather than having the logic in the survey action as to where to send them to next, we can send them back to the initial action which will then evaluate whether they should just go to the landing page or somewhere else (such as our bulletin) first. The bulletin could either send them back to the same action after the user acknowledges receipt or forward them on to the landing page itself.

Accomplishing is fairly straight forward. For each page where you want to handle an event, create a .portlet file. While the portlet configuration must have some class defined where it would presumably start, once you add event handling to the configuration you have ultimate control over how to respond to that event. Let’s look at a simple example of how this works.

public Forward begin(userFromBean form)
{
PortletBackingContext pbc = PortletBackingContext.getPortletBackingContext(getRequest());;
int status = getStatus(form.getUserId());

switch(status)
{
case 0:
pbc.fireCustomEvent("callDisplayBulletin", form);
break;
case 1:
pbc.fireCustomEvent("callChangePassword", form);
break;
case 2:
pbc.fireCustomEvent("callPresentSurvey", form);
break;
}
return new Forward("default");
}

Our logic can go in any action, but for simplicity we will put it in the begin action:Since this action method always evaluates the users’ status, we can continue to send them back here and determine where to go next. If value of the status doesn’t have a case, we simply send them to the forward destination.

Each of the events has a portlet event handler registered to listen for it. The handlers can be in as many different portlet definitions as we want, allowing for reusing the methods in the same controller on different pages or be able to have several different controllers interact with each other through the event framework. Keeping our example simple, we will have the methods in one controller in a single portlet:

<netuix:portlet definitionLabel="eventBasedPageFlow" title="Event Based Page Flow">
<netuix:handleCustomEvent event="callDisplayBulletin" eventLabel="callDisplayBulletin"
fromSelfInstanceOnly="false" onlyIfDisplayed="false" sourceDefinitionWildcard="any">
<netuix:activatePage/>
<netuix:invokePageFlowAction action="callDisplayBulletin"/>
</netuix:handleCustomEvent>
<netuix:handleCustomEvent event="callChangePassword" eventLabel="callChangePassword"
fromSelfInstanceOnly="false" onlyIfDisplayed="false" sourceDefinitionWildcard="any">
<netuix:invokePageFlowAction action="changePassword"/>
</netuix:handleCustomEvent>
<netuix:handleCustomEvent event="callPresentSurvey" eventLabel="callPresentSurvey"
fromSelfInstanceOnly="false" onlyIfDisplayed="true" sourceDefinitionWildcard="any">
<netuix:activatePage/>
<netuix:invokePageFlowAction action="presentSurvey"/>
</netuix:handleCustomEvent>
<netuix:titlebar/>
<netuix:content>
<netuix:pageflowContent contentUri="/portlets/eventBasePageFlow/EventBasePageFlowController.jpf"/>
</netuix:content>
</netuix:portlet>

The above example is for the sake or brevity. It is far more likely that these events would be handled by multiple portlets either due to presentation considerations (such as going from a page full of portlets to a page with a single portlet) or logical separation of functionality (such as a survey controller, bulletin controller, etc.).

In addition to custom events, page flow actions are events that can also be listened for, allowing for the possibility of completely changing the functionality of action by listening for it and adding additional or new behaviors. The combinations are endless and can often be changed with only a minor configuration update or a single line of code. This simplicity is key to agile methodologies and provides developers with a rapid way to add functionality on an as needed basis.
Conclusion
Workflows are a common requirement for portals. While the examples in this article revolved around a simple registration and login process, they were chosen for their commonality. Employment applications, freight logistics, legal document creation, supply requisitioning, and financial transactions are other common workflows that are often required within a portal. Those that are straight-forward with little or no deviation are easily implemented with a simple page flow. Nested page flows provide a solution to complex workflows that need to interact and provide an opportunity for the reuse of common sub-flows when a project has well defined requirements. For a more agile approach, listening for and calling events provides a flexible, loosely-coupled way to call portlet methods within and between controllers without having to know all of the specifics what future requirements may be.

Refreshing View of JDeveloper and Source Control

November 5th, 2013
No Gravatar

I was adding WSRP portlets to a WebCenter Portal application and seeing files updated when running a diff with WinMerge that did not show up as Pending Changes in SVN. I tried refreshing the Pending Changes view, restarting the JDeveloper and repeating, but nothing. Then, just for fun, I ran refresh on the application and boom, there they were.

Problem and Solution with telnet on Oracle Linux

September 29th, 2013
No Gravatar
[root@oraclelinux6 /]# telnet 192.168.56.1 1521
-bash: telnet: command not found
[root@oraclelinux6 /]# yum install telnet
...[TRUNCATED FOR READABILITY]
Installed:
  telnet.x86_64 1:0.17-47.el6_3.1

Complete!
[root@oraclelinux6 /]# telnet 192.168.56.1 1521
Trying 192.168.56.1...
Connected to 192.168.56.1.

Deploying Projects with JQuery with Eclipse to WebLogic Server

August 29th, 2013
No Gravatar

Seems Eclipse determines that there is something wrong with JQuery and refuses to deploy a web application containing it. The work-around is to give up validation of JavaScript, specifically with two steps:

  1. Turn off automatic build, go to Navigator view for your project, open the .project file and remove the following line: <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
  2. In project properties go to Builders and de-select the JavaScript Validator

Remove JavaScript Builder

 

(Click image to enlarge)

It’s Just a Phrase I’m Going Through

August 22nd, 2013
No Gravatar

I’m always delighted when I hear one of my sarcastic word-plays repeated by someone else. Today I heard someone attribute me with:

Water Crash Methodology

which I had come up with when discussing the merits of SDLC approaches in light of the resulting deliverables.