Looking for a simple portlet for quick search in the catalog by location? Look no further, Saba Guru has created this portlet for you! The portlet is a simplified version of the Catalog Search, offering a list of locations and the next 5 offerings available for the selected location. In this first implementation of the portlet, I'll present the list of locations in a drop-down list. In the next article, locations will be displayed on a map. Because the search in the catalog is specific to offerings available by location, WBT (Web Based Training) and any other type of offerings without a location assigned are automatically excluded by the result.
By selecting a location in the list, the portlet refreshes and then displays the search result, that is a table of the next five offerings available in the selected location.
For each offering, it is possible to register to it by clicking on the Register link under the Actions column.
Step by step, this is the way I have implemented the Location drop-down list in Saba:
1) Any portlet always starts with a manager. I am assigning the name QuickSearchByLocationPortletPageManager to the manager class. The fully qualified name of the manager class, i.e. including also the package name, will be entered in Saba when configuring the portlet on the portal.
A list of Locations
Locations will be displayed in a drop-down list, at least initially, and displayed in the portlet as in the screenshot below.
List of Locations in the portlet
By selecting a location in the list, the portlet refreshes and then displays the search result, that is a table of the next five offerings available in the selected location.
For each offering, it is possible to register to it by clicking on the Register link under the Actions column.
Step by step, this is the way I have implemented the Location drop-down list in Saba:
public class QuickSearchByLocationPortletPageManager
extends AbstractPortletPageManager
implements PortletPageManager
{
@Override
protected void init()
{
registerPage("showDefaultDisplay",
"/custom/portlets/quickSearchByLocation.rdf");
}
}
2) The manager refers to the quickSearchByLocation.rdf page for the layout of the portlet on screen. This is the controller page, we also have the model quickSearchByLocation.xml and the view quickSearchByLocation.xsl.
In the model we define the logic for retrieving the list of locations, which is encapsulated in a portlet command. A portlet command is simply an extension of a regular SabaWebCommand that generates the result (the list of locations) and returns it to the model page as an XML document.
public class QuickSearchByLocationPortletCommand
extends SabaWebCommand
{
public void doExecute(HttpServletRequest request, IXMLVisitor visitor)
{
visitor.beginVisit(null, "Result", null, null, null);
visitLocations(visitor);
visitor.endVisit(null, "Result");
}
QuickSearchByLocationPortletCommand is the portlet command class that builds a model document with the list of the available locations, in alphabetical order. For each location, ID and Name attributes are retrieved and passed to the model page using the following XML format:
<Result>
<Locations>
<Location>
<Id></Id>
<Name></Name>
</Location>
</Locations>
</Result>
The structure of the <Locations> tag is built by the visitLocations() method.
protected void visitLocations(IXMLVisitor visitor)
{
visitor.beginVisit(null, "Locations", null, null, null);
List<ArrayList<String>> locations = getLocations();
for (ArrayList<String> loc : locations) {
visitor.beginVisit(null, "Location", null, null, null);
visitor.visit(null, "Id", loc.get(0));
visitor.visit(null, "Name", loc.get(1));
visitor.endVisit(null, "Location");
}
visitor.endVisit(null, "Locations");
}
The getLocations() method retrieves a list of ArrayList containing Id and Name at position 0 and 1 respectively for each location, and with this information builds the XML tree aforementioned.
3) With the XML model ready, it is now the turn of the model page to map it to a widget for display inside the portlet. A drop-down list control is rendered in Saba using the <wdk:list> widget with type = select. I call this widget locationId, as this will be the name of the parameter passed to the portlet command again when searching for offerings in the indicated location, as we will see later.
<wdk:list name="locationId">
<type>select</type>
<wdktags:attachTo path="Result/Locations"/>
<wdktags:repeat name="options" path="Location">
<option>
<value>
<wdktags:nodeRef source="options" path="Id"/>
</value>
<text>
<wdktags:nodeRef source="options" path="Name"/>
</text>
</option>
</wdktags:repeat>
<event>
<type>action</type>
<action>
<type>submit</type>
<href>
/platform/presentation/portal/portalDriver.rdf
</href>
</action>
</event>
</wdk:list>
The list is "attached to" the Result/Locations path using the <wdktags:attachTo> tag. This means that single locations are listed under this parent node in the XML model, and each location is identified by the Location tag, as defined in the <wdktags:repeat> tag. This tag, as the name implies, repeats each occurrence of the defined path and displays multiple options for the drop-down list. The value of the option is assigned as the content of the Id tag in the XML model, and the text as the Name tag.
When an option is selected, the event defined in the <event> tag is triggered, which basically is a refresh of the portal driver page that contains the portlet.
4) When the portal page is refreshed, the locationId parameter identifying the selected location is passed to the portlet command for performing the search in the catalog.
<xsp:logic>
QuickSearchByLocationPortletCommand command =
new QuickSearchByLocationPortletCommand();
</xsp:logic>
<wdk:model>
<wdktags:execute commandObj="command">
<param name="locationId" expr="locationId" type="String"
mode="in" />
</wdktags:execute>
</wdk:model>
An instance of the QuickSearchByLocationPortletCommand object is created and then used to execute the command as specified in the <wdktags:execute> tag, by passing the locationId parameter.
Performing the search in the catalog by location
Continuing along the step by step implementation, it is now the turn of performing the search in the catalog for offerings in the selected location.
5) We are now back in the portlet command. First of all we need to register the input parameter, and we do so in the constructor of the command class.
public QuickSearchByLocationPortletCommand()
{
addInParam("locationId", String.class, "Id of the Location");
}
6) We then retrieve the value of this parameter in the doExecute() method and then pass it to the Saba API that performs the search in the catalog.
protected void visitOfferings(IXMLVisitor visitor,
String locationId)
{
visitor.beginVisit(null, "Offerings", null, null, null);
Iterator<OfferingResult> offerings = getOfferings(locationId);
while (offerings.hasNext()) {
OfferingResult result = offerings.next();
visitor.beginVisit(null, "Offering", null, null, null);
visitor.visit(null, "Id",
result.getPrimaryKey().toString());
visitor.visit(null, "OfferingId",
result.getPartNo());
visitor.visit(null, "Title",
result.getOffTemp().getDisplayName());
visitor.visit(null, "Delivery",
result.getDelivery().getDisplayName());
visitor.visit(null, "StartDate",
result.getStartDate());
visitor.endVisit(null, "Offering");
}
visitor.endVisit(null, "Offerings");
}
The visitOfferings() method is basically building the XML model with the list of offerings to display in the portlet, for the selected location. The XML model has the following format, with the <Offering> tag repeated for each occurrence. The <Offerings> node is contained within the <Result> root node, as we have seen previously for the <Locations> node.
<Offerings>
<Offering>
<Id></Id>
<OfferingId></OfferingId>
<Title></Title>
<Delivery></Delivery>
<StartDate></StartDate>
</Offering>
</Offerings>
7) The final touch is with displaying the offering list in the portlet. I decided to use the <wdk:table> widget for displaying items in a table format. The full description of the syntax of this widget can be found in the Saba Application Developer Guide, so for now I will describe only the significant parts that concern this portlet.
<wdk:table name="finderResults">
<wdktags:attachTo path="Result/Offerings"/>
<head>
<column>Title</column>
<column>Offering ID</column>
<column>Delivery Type</column>
<column>Start Date</column>
<column>Actions</column>
</head>
<row path="Offering">
<column><wdktags:nodeRef path="Title"/></column>
<column><wdktags:nodeRef path="OfferingId"/></column>
<column><wdktags:nodeRef path="Delivery"/></column>
<column><wdktags:nodeRef path="StartDate"/></column>
<column>
<wdk:link name="register"></wdk:link>
</column>
</row>
</wdk:table>
The widget is attached to the Result/Offerings path in the XML model, where all the offerings can be found. For each row identified by the Offering node, the following columns are displayed:
- Title
- Offering ID
- Delivery Type
- Start Date
The Actions column contains a link to the registration page for the offering (link not detailed in the code above). For simplicity of visualization of the code snipped above, I hard-coded the name of the columns in the <column> tag within <head>. In a real scenario, no hard-coded labels should be used, but a reference to the label bundle should be used instead. This will facilitate internationalization of the portlet as well.
The value of the each column, as in the model, is retrieved from the XML node using the <wdktags:nodeRef> tag for each <column> within <row>.
Wrap up
Lot of Java and XML code in this post, but hope it's been useful to figure out the necessary steps for creating a fully functional portlet that interacts with the database. I saved you the use of the Saba API for actually retrieving information (locations and offerings) from the database, as this is not specific to a portlet implementation. Feel free to contact me if you want to discuss these details further.
In the next article, I will expand the functionality of this portlet by introducing a visualization of locations based on Google Maps rather than in a drop-down list. The opportunity is good to show how to integrate Saba resources (locations in this case) with external web sites and display everything within a portlet!
Happy search!


No comments:
Post a Comment