An interesting problem we were working on some time ago is the following: a JHeadstart application – release 9.0.4.5 created with UIX, BC4J and Struts, JDeveloper 9.0.3 – has many Find pages. These pages contain many search-criteria. Our users would like to have their own default values provided for some/many/most of these search criteria. That means: when user A enter a Find page, a number of fields will already have specific values that limit the search results in a certain way. When user B enters the same Find page, again a number of fields – probably different fields – will have a default value – probably a different default. Each user will have a persistent user-profile, stored in the database, that contains these default values. This post describes how we implemented a solution for this request.
Note that we made use of the JHeadstart ALS demo application created by AMIS for these purposes. See Overview of the AMIS Library System Reference Application (ALS) (9.0.4.x) for details and download of this application.
Investigation:
The first step was finding out how the UIX FindPage is generated by JHeadstart and how the fields in the FindPage are defined. The fields in a UIX FindPage are defined
as follows:
messageTextInput name="FindNAME" data:promptAndAccessKey="NAME@jheadstart:nls" data:text="FindNAME@jheadstart:sessionData" isCaseInsensitive="true" queryOperator="like" persistentAttribute="Title" maximumLength="100" columns="30" rows="1">
The interesting piece here: data:text=”FindNAME@jheadstart:sessionData”That means that the value displayed in the UIX page is derived from the element FindNAME in the sessionData. So to set default values for find-fields in the UIX findpage, we need to make sure that SessionData contains attributes with the name of the Find-field. This can easily be done using this Action Class.
Preparation/Setup:
Below you will find a step by step description of what we did to solve this issue:
- Create the table ALS_USER_PROFILE with columns USER_ID, LANGUAGE, PUBLISH_YEAR and COMPLEXITY. USER_ID will identify a user of the ALS Application, the other columns hold the default search value for the FindBookPage.
- Create BC4J Entity Object AlsUserProfile and BC4J View Object AlsUserProfileView. Add AlsUserProfileView to BC4J Application Module AlsAppModule.
- Edit the AlsUserProfileView using the JHeadstart BC4J property editor. Set properties such as Domain, Display in Tables? and Prompt.
- Edit the JHeadstart Application Structure: switch the View from JSP to UIX, create a new Base Group userProfile. This Group is Table Layout only – with insert, delete and update – based on the AlsUserProfileView.
- Generate the ALS application with the JHeadstart Application Generator
- Run the ALS application. Go to the User Profile Tab and create a new User Profile – for USERID=USER1. Set appropriate values for Language, Publish Year and Complexity
CREATE TABLE ALS_USER_PROFILE ( USER_ID VARCHAR2(20), LANGUAGE VARCHAR2(5), PUBLISH_YEAR VARCHAR2(4), COMPLEXITY VARCHAR2(1) );
Addressing the issue
From here on we can no longer generate the ALS-application ‘just like that’ – we would lose part of our work!
- Create class nl.amis.als.jheadstart.controller.struts.action.GetDataObject. This class is a copy of oracle.jheadstart.controller.struts.action.GetDataObject with subtle changes: it will only try to retrieve the DataObject from the Model if it does not already exist in the sessionData. See DefaultFindValuesFromProfile.zip for the source code. Note: JHeadstart 9.0.5.1 contains such functionality in the standard code.
- Create action GetUserProfile in the struts-config.xml. This action uses the class created in the previous step. The action is used to get the UserProfile into the Session, based on a request parameter userId. This action is called from /StartALS and upon success will call the ModuleRouter:
<!-- Start GetUserProfile action --> <action path="GetUserProfile" type="nl.amis.jheadstart.controller.struts.action.GetDataObject" scope="session" name=""> <!-- name of dataObject interface class --> <set-property property="dataObjectInterface" value="nl.amis.als.model.UserProfile"/> <!-- key used to store result DataObjectSet in SessionData --> <set-property property="dataObjectName" value="UserProfile"/> <!-- The name of the SessionData attribute holding the value of the primary key column for the dataObject to be retrieved. --> <set-property property="keyParameterName" value="userId"/> <!--Is Updatable?--> <set-property property="isUpdatable" value="false"/> <forward name="success" path="ModuleRouter"/> <forward name="userError" path="/common/DisplayErrorPage.uix"/> <forward name="dataObjectNotFound" path="/common/DisplayErrorPage.uix"/> </action>
Note: when the UserProfile is changed in the UserProfile tab, the changes will immediately have an effect the next time the Find Books page is entered. If the profile is changed in the database or from another session, that change is not immediately in effect.
- Edit file web/WEB_INF/index.html; Change the link to start the ALS application by adding a parameter that will specify the UserProfile used for running the application:
<a href="StartALS.do?userId=USER1">
- Create class nl.amis.als.jheadstart.controller.struts.action.SetDefaultFindValues. This class can be configured – in the struts-config.xml file – to read values from a DataObject and store those values in attributes in the sessionData – either request or session scope. It is fairly generic: the names of the DataObject, its Attributes and the sessionData attributes to create are all specified in the struts-config.xml file. See DefaultFindValuesFromProfile.zip for the source code.
- Create action SetFindBookDefaults in the struts-config.xml file. This action is based on the SetDefaultFindValues class created in the previous step. It is configured as follows:
o property="dataObjectName" must contain the name of the DataObject from which this values are read; in this case the DataObject is called UserProfile – as specified in the GetUserProfile Action. o property="attributeValueParameter" must contain a comma separated list of attributes on the Dataobject that contain the values to be set in the session attributes; in this example, the attributes PublishYear,Language,Complexity in the UserProfile data object contain the values that we want to use as defaults for the FindBookPage o property="attributeNameParameter" contains the names of the session attributes that should be created by this action; the names of the corresponding fields in the FindBookPage.uix for which the default values must be set are FindBookPublishYear,FindBookLanguage,FindBookComplexity
This action must be invoked prior to showing the FindBookPage.uix. Therefore it is forwarded to from the BookRouter – as initial, instead of GetBookPublisherList. The action itself forwards to GetBookPublisherList, after which FindBookPage.uix is forwarded to.
<!– Start SetDefaultFindValues action –>
<action path=”SetFindBookDefaults” type=”nl.amis.jheadstart.controller.struts.action.SetDefaultFindValues” name=”FindBook”>
<!– comma separated list of Session Attributes that should be set –>
<set-property property=”attributeNameParameter” value=”FindBookPublishYear,FindBookLanguage,FindBookComplexity”/>
<!– comma separated list of attributes on the Dataobject that contain the values to be set in the session attributes –>
<set-property property=”attributeValueParameter” value=”PublishYear,Language,Complexity”/>
<!– key under which the DataObject that provides the values is stored in SessionData –>
<set-property property=”dataObjectName” value=”UserProfile”/>
<forward name=”success” path=”GetBookPublisherList”/>
<forward name=”userError” path=”GetBookPublisherList”/>
<forward name=”dataObjectNotFound” path=”GetBookPublisherList”/>
</action>Now when the Application is started from the index.html file you will find the UserProfile’s default values being applied when you navigate to the Find Books Page.
Added the sources for the classes mentioned in this post: See DefaultFindValuesFromProfile.zip for the source code.