JSP
Page Contents
If you read the documentation of the Taglibrary you might have noticed that we only covered the render and action tags very briefly. The reason for this is that when you are only using the build in tags then the options made available to you in those tags are of little use – actually the action tag is of no use at all.
Another thing that might make your life easier when starting to work with the features mentioned here is to read the Tools documentation, here you will get advice on which tools to use, how to debug etc.
The description in this section will be at a slightly higher abstraction layer that it was for the Taglib this is simply because the number of possibilites are so great – this is especially true for the APIs. So instead you will get an overview of what is available and how you can use it. If you have a particular case that you need to get resolved you are always welcome to contact Agillic Support. The following is covered in this section:
- Flow: Documentation of the flow interface
- Render and action attributes: A more thourough run through of the attributes made available by the action and render tag
- Interfaces: High level description of the different apis that are available
- Annotated examples: A number of annotated examples where we use some of the features described in the different sections
Flow
All instances of the applications have a corresponding flow instance. This is simply a place where all the entered values are kept. The map you get is a copy so removing or adding values to it will have no impact. See the addEnteredValue for way of updating it.
java.util.Map<java.lang.String,java.lang.String> getEnteredValues
Returns a map of all the entered values for all the pages in the application.
void addEnteredValue(java.lang.String name, java.lang.String value, boolean personData)
Way to programmatically add a value to the list of values. This is an easy way to add an auto-generated internal id without using hidden fields.
int getEnteredValueAsInt(java.lang.String s) throws java.lang.NumberFormatException
Convenience method to transform an entered value to an integer – saving you the problem of doing this yourself. Obviously this method is best used with input that have been validated as digits.
boolean getEnteredValueAsBoolean(java.lang.Strings)
Convenience method to transform an entered value to a boolean. It works by returning "true".equals(<value>)
.
java.util.Date getEnteredValueAsDate(java.lang.String s) throws java.text.ParseException
Convenience method to transform an entered value to a date. Obviously this method is best used with input that have been validated as a date.
java.util.Map<java.lang.String,java.lang.String> getEnteredClmAttributes()
Same as getEnteredValues but only returns the fields where the clmAttribute is set (or added using the addEnteredValue with true in the personData parameter).
java.lang.String getKeyFieldValue()
Returns the value in the field that has the clmAttribute which is unique id. null if that field is not part of the application (or no value is set on it).
Example: If EMAIL is the unique id then the value of this field <inp:text clmAttribute="EMAIL"/>
Render and action attributes
The render and action tags make a number of attributes available to you. Below we go through all of them, first the ones they have in common and then the ones specific to the two tags.
common tags
jsplog
The jsplog attribute exposes the log4j logger that you can use to log messages on you page. For full details on how to use the logger please read the Logging documentation.
api
The API attribute exposes the CLMUserApi interface, this is the interface that contains most of the logic related to updating users.
web
The web attribute exposes the WebHelper interface, this is the interface that contains most of the logic related to web based functionality (setting/reading cookies etc).
advisorApi
The advisorApi attribute exposes the AdvisorApi interface, this interface contains a few advisor related functions.
attrs
The attrs attribute contains a map of all the person data for the known user (empty map is no user is known). Since this map is always exposed there are many situations where you do not have to use the API to get the data for logged in people but can just grab it for this map. The map will also contain Global Data (including parametrized value with the correct value set), so you can also find values for these here.
userid
Contains the internal id of the active user. The value is set if you are logged in, or if you have made a call to storeIdInSession on the webHelper. This value is not read by any of our internal code, and is only made available to make it easy to get the id. If you you know you are logged in and want to call the API it is better to use null as the id parameter than this variable.
userkey
As with userid but here it is the value of the Person Data defined as user_id.
flow
The flow attribute exposes the Flow interface. This interface is the representation of your jsp pages, and will allow you to both read the inputted data as well as add extra data. For full details read the Flow documentation.
settings
Agillic allows you to create editors for you application, the settings object exposes the settings the configurator have set for this particular application (the Standard Apps applications uses this a lot). The variable exposed is a json object. Actually it is a slightly extended version of that interface, in our version the JSONObject implements java.util.Map and JSONArray implements java.util.List which makes it easier to interact with and allow you to use jstl to read it.
spring
Mainly interesting if you are adding your own spring services (Extending further with Java). This variable contains the Spring Application context. This allows you to easily lookup any bean you have registered yourself.
action tags
portletRequest
The current Action request, this is required in a few methods in the WebHelper, but in other cases we suggest you use the standard HttpServletRequest, which is available as request.
portletResponse
The current Action response, this is required in a few methods in the WebHelper, but in other cases we suggest you use the standard HttpServletResponse, which is available as response.
render tags
renderRequest The current Render request, this is required in a few methods in the WebHelper, but in other cases we suggest you use the standard HttpServletRequest, which is available as request.
renderResponse
The current Render response, this is required in a few methods in the WebHelper, but in other cases we suggest you use the standard HttpServletResponse, which is available as response.
preview
When you view pages in the Content module we will call application on the page to create as realistic a preview of the page as possible, but since it might be that certain applications to more logic on their first page it is possible to detect that this is a call from preview and therefore return some simpler content, or disable some of the logic. It is a string and if it has the value true the call came from the Content module.
Interfaces
All Agillic interfaces have javadoc documentation (see Developer tools for details on how to get it). Therefore we will not go through all the methods for all the interfaces, but only discuss overall themes, and document special areas of interest.
The interfaces are:
- CLMUserApi – the interface for all user related functionality
- WebHelper – the interface for web oriented functionality
- AdvisorApi – the interface for special functionality related to the advisor portal
CLMUserApi
This is the interface that will give you all the functionality for actually creating, reading, updating or deleting users as well as a number of more Agillic specific functionalities (such as evaluating a promotion, achieving events etc).
Common for all methods that are user centered is that should specify the internal id of that user – if you are logged in you can simple give null in which case the system will use the id of the logged in person. If the application is running on an anonyomous page (or is not related to the logged in person) you can get the id using one of the available finders.
Basic user functionality
There are methods for creating users, deleting users, getting and setting person data (both a single and a map of them). There are also methods for achieving events, reading achieved events for a user, reading the target groups a user is member of, changing username and password.
The method impersonateUser is very useful if you are creating advisor functionality (support center functions or similar) – this allows you to tell the system that is should act as if the specified user was logged in. This has the effect that promotion portlets are evaluated as that user, and that all replacement parameters on the page are replaced using the specified persons Person Data. Calling it with null will reset it to check for the actually logged in person again.
Global Data
There are methods for reading and writing Global Data, including parameterized. The finders can be a bit tricky, please note there are four different finders for Global Data.
Promotion evaluation
You can evaluate Promotions for a particular user and both simply get the name(s) of the matched Propositions back or get the content for the given Proposition back. There are also an option of bypassing the rules and get the content/names back for all Propositions in a Promotion.
Finding users
There are a number of ways to find users ranging from the very basic of getting the internal id given the user_id to creating more advanced Conditions. There are both ways of getting all Person Data for the searched for user or simply counting if such a user exists (the latter is quite often more effective for uniqueness checks or similar).
The condition based search functions are the most advanced, and does allow you to create Condtions with the same possibilites as you have inside Agillic when creating Target Groups or similar. Using these Conditions can be a bit tricky, you can read the documentation of the Condition types available in the javadoc documentation – it’s primarily the documentation of com.agillic.portletsdk.condition.APIConditionFactory which should help you on your way. In the examples sections you will also see a few examples of how to create such Conditions.
Statistics
You can get a list of emails, sms and logins performed by a specific user. This can be useful on advisor pages if you want to show an interaction log.
Various
A few interesting methods that can be of use in some cases:
- sendEmail: sends some specified content to a specified address. Please note that it’s the full content (not the name of an email in the Content Designer) you specify – similarly it’s the email address and not a user you specify
- isPublishingRunning: checks if a publish is currently in progress – this is mainly interesting if you have created your own jobs and want to prevent them from running at the same time as the publish is under way.
WebHelper
This interface provides a number of method that can be quite useful when working with web applications.
Logging in
This interface provides methods for logging a user in. They can both take an internal id (good if you authenticate a user by looking them up by Person Data) or by the built-in username/password technology.
If you want to use the Remember me cookie you can tell the login to use this.
Before you create your own login application it might be a good idea to have a look at the built-in one: Login application
Another method which is slightly related to at least authentication is storeIdInSession – this does not log you in or even influences the different API – but they will make the internal id and user id of the specified user available for later use.
Encoding and decoding
The identification parameter and identification cookies are all encoded by Agillic (simple md5 of the value and a secret salt for the system). IF you want to have use same type of security for something specific to your system you have access to method to both encode and decode your own values.
Production and staging system have different secret salts
Cookies
Agillic uses a number of cookie to identify the user – the interface provides a number of method to read/write these cookies, or to read/write your own cookies.
Another somewhat cookie related method is getIdentifiedUserId which returns the internal id of the user based on the full set of authentication means available (parameters, cookies, login, etc.)
Roles
When logging in we resolve the persons Target groups and store them as roles on the user, you can then query these later. The value here are the same through the whole session.
Promotion & Propositions
If you use Promotion links (a link with a specific Promotion and Proposition as parameter) there are methods to retrieve or to write these parameters.
AdvisorApi
This interface is an extra helper interface for the advisor part (it is available for all portals, but the methods only return meaningful data when used in the advisor portal).
It has methods for getting the name of the logged in administrator and which group that administrator belongs to. This can be useful for creating a sort of audit log for advisor interactions, or to control which menu item a particular administrator has access to.
Annotated examples
Advisor
Creating an advisor application.
Actually we will show you a number of small applications:
- A search functionality, that will allow you to select a user
- A statistics functionality which will allow you to see the users interactions with the system
- A small update function which will add an “audit log” on the user noting who changed the settings.
1. Searching for recipient
We start by building a simple form where you can search for a user by email, msisdn or account number:
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:render>
<inp:form next="index">
<label for="email">Email</label>
<inp:text name="email"/>
<label for="msisdn">Phone</label>
<inp:text name="msisdn"/>
<label for="accountno">Account number</label>
<inp:text name="accountno"/>
<input type="submit" value="Search">
</inp:form>
</sdk:render>
2. Doing the searching
We will to prefix searching on the input data – with or between them. If we match only one user we will accept that user right away, otherwise we will list the users in the render phase. In this particular setup we have not setup any way of clicking in the list – but that can be done of course.
From a jsp point of view this is a very basic page and from the code and the comments in the code it should be fairly obvious what we do.
Inside the render:
<%
List<Map<String,String>> foundUsers = (List<Map<String,String>>) request.getAttribute("foundUsers");
//Checking if we have some matches and if so list them
if(foundUsers!=null && foundUsers.size()>0) {
%>
<table>
<thead>
<tr>
<th>Email</th>
<th>Phone</th>
<th>Account number</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<%
for (Iterator<Map<String, String>> iterator = foundUsers.iterator(); iterator.hasNext();) {
Map<String, String> map = iterator.next();
%>
<tr>
<td><%=map.get("EMAIL")%></td>
<td><%=map.get("MSISDN")%></td>
<td><%=map.get("ACCOUNT_NO")%></td>
<td><%=map.get("FIRSTNAME")+" "+map.get("LASTNAME")%></td>
</tr>
<%
}
%>
</tbody>
</table>
<%
}
%>
3. Adding an update with audit log
On the page we go to we want to add a few applications. One for listing user statistics and one for updating a few settings on the user. We are going to start with the update with audit log:
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:action>
<%
flow.addEnteredValue("ADVISOR_UPDATE_USER",advisorApi.getUserName(),true);
flow.addEnteredValue("ADVISOR_UPDATE_GROUP",advisorApi.getGroupName(),true);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
flow.addEnteredValue("ADVISOR_UPDATE_DATE",simpleDateFormat.format(new Date()),true);
%>
</sdk:action>
<sdk:render>
<inp:form next="index" function="update">
<label for="email">Email</label>
<inp:text clmAttribute="EMAIL"/>
<label for="msisdn">MSISDN</label>
<inp:text clmAttribute="MSISDN"/>
<input type="submit" value="Update">
</inp:form>
</sdk:render>
Here we notice the combination of function and action. The action phase is run first so there we add some extra values to the list of Person Data, remembering to mark that they are Person Data. Now when the function is execution and it asks for all entered values it will both get the ones the user submitted and the extra ones we added programatically. Notice that we also set a date, all Person Data regardless of their type must be set as string in the interface so we must remember to format the date to the correct format (by default it is dd.MM.yyyy
but can be configured in Agillic).
4. User statistics
We also create a small application capable of showing all emails sent to the user within the last 10 days.
<%@ page import="com.agillic.portletsdk.UserEmailStatistics" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Calendar" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.List" %>
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:render>
<%
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DAY_OF_YEAR, -10);
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");
List<UserEmailStatistics> userEmailStatisticsList = api.getEmails(null, instance.getTime(), new Date());
if (userEmailStatisticsList == null || userEmailStatisticsList.isEmpty()) {
%>
<p>No emails send within the last ten days</p>
<%
} else {
%>
<table>
<thead>
<tr>
<th>Email name</th>
<th>Sent on</th>
<th>Opened on</th>
</tr>
</thead>
<tbody>
<%
for (Iterator<UserEmailStatistics> iterator = userEmailStatisticsList.iterator(); iterator.hasNext();) {
UserEmailStatistics emailStatistics = iterator.next();
%>
<tr>
<td><%=emailStatistics.getTemplateName()%></td>
<td><%=emailStatistics.getSentDate() != null ? format.format(emailStatistics.getSentDate()) : ""%></td>
<td><%=emailStatistics.getOpenedDate() != null ? format.format(emailStatistics.getOpenedDate()) : ""%></td>
</tr>
<%
}
%>
</tbody>
</table>
<%
}
%>
</sdk:render>
Advisor code examples
index.jsp
– The search page
audit.jsp
– The page with update and audit log
statistics.jsp
– Statistics page
One to Many data 1
Since there is no way to use One-To-Many data in the questionnaire, this is one of two small examples of how to build an app that can collect and maintain One-To-Many data. The example covers both a signup situation where data is collected and an update where the current data is read and then later updated.
This example covers a situation where each line represents a selection of something from a static list, this can be used for collecting preferences etc., the other example covers a situation where the list is dynamic.
These are advanced examples so I will assume you know the basic way that jsp apps in Agillic work and focus on more technical details in solving this problem.
These examples are not designed to show how to build a nice looking webform, absolutely no time has been spent on the html, nor is it an example of the right way to use One-To-Many tables, the only purpose of this example is to show how to collect and store One-To-Many data from a form. The examples has been tested and work.
As always the jsp pages are attached to the page, since there are in fact two index.jsp pages here, I’ve prefix the pages with which app they belong to, if you want to use them remove the prefix before you upload them.
Context
In your signup app you want to collect some basic data (email, first and lastname) and then which colors the person likes among a set of available colors, and you want to store the colors as One-To-Many lines.
Slightly off-topic, actually using One-To-Many for this setup is generally not recommended, Agillic would in a case like this with relative few options recommend using Boolean Person Data to represent the choices, but let’s pretend that is not possible here.
So we have our One-To-Many table called COLORS, and that contains three fields:
- COLOR – the name of the color and also primary key in the table
- SELECTED_DATE – the date the color was selected
- REMOVED_DATE – the date the color was removed from the selection (blank for lines that are selected)
Sign up
1. The basics
If we didn’t want to collect One-To-Many data but just the person data this would be what we needed. This is actually stolen directly from one of the basic examples from the taglib section.
In this setup we send the user to a receipt page where the action phase creates the user, if this was all we wanted we could simply use a function instead.
The index.jsp
page:
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:render>
<inp:form next="receipt" method="post">
<!-- Just a few basic fields to gather. Completely standard -->
<label>Email</label>
<inp:text clmAttribute="EMAIL" class="required email unique textinput" transformer="trim,lower"/>
<label>Firstname</label>
<inp:text clmAttribute="FIRSTNAME" class="textinput"/>
<label>Surname</label>
<inp:text clmAttribute="LASTNAME" class="textinput"/>
<input type="submit" value="Signup">
</inp:form>
</sdk:render>
The receipt.jsp
page:
2. Adding One-To-Many to the form
In this example we’re using a checkbox for each color and have it hardcoded in a very basic way, there would be smarter ways of doing that of course. Notice that we just doing normal html form tags no use of the taglib, you could have used the taglib but in this setup it really wouldn’t have given you much advantage over this simple setup.
So what we do is to add this html to the form.
3. Saving the data
Most of the relevant information is in the comments in the code. In a few words what we do is that we build a list of the lines we want to save. Each line is represented as a map of the columns to the values that we want to set for each column, you don’t have to supply all columns in the One-To-Many table, any column not present will simply be blank in case of adding lines. You do have to provide a value for the column defines as the primary key for the table.
We add this code after creating the user, but before achieving the Event, the placement is a bit random, but would mean that in case the event triggers an email which uses the colors, then we know they are saved.
Update
Update is slightly more difficult than create when it comes to One-To-Many, the main reason for this is that there are different methods for adding and updating lines. In this particular example we do not delete lines but rather set a removed_date on lines that are no longer relevant, the other example shows how to delete lines. For update we keep everything in a single page, so that you simply see the form again.
1. The basics
As before we start with the part related to Person Data.
2. Adding One-To-Many to the rendering
We want to show the same checkboxes as for signup, but now we need to make sure that the ones the user already selected are checked. To do this we get the lines for the user and build a set of the colors those lines hold. The comments in the code should make it pretty clear what is going on.
So we add this:
3. Updating the One-To-Many table
So this is the most complex part of the code. In this setup there are four possible situations we must handle
- A color was chosen before and is still chosen (no nothing)
- A color was chosen before but is no longer chosen (set a removed date on the line)
- A color that was once chosen, but have been removed was chosen again (remove the removed date from the line and update the selected date)
- A color that has never been chosen was now chosen (add a line with the color and selected date)
We already know how to add lines from the signup case, but update is a bit more tricky. The reason it’s tricky is that to make it possible to update the primary id of a line, the update call does not take the primary id of the line as a parameter, but rather a special rowId which uniquely identifies both the user and the row. This is nice for the update call itself, but means that the update code becomes a bit more complex.
The comments should make it pretty clear what is going on, but it’s probably a good idea to read it through a couple of times.
One to Many 1 – code examples
The file names here are a bit misleading, and should actually all be index.jsp files placed in different folders, as separate applications.
signup-index.jsp
– The first page of the signup
signup-receipt.jsp
– The action page as well as the receipt
update-index.jsp
– The update page
One to Many data 2
Since there is no way to use One-To-Many data in the questionnaire, this is one of two small examples of how to build an app that can collect and maintain One-To-Many data. The example covers both a signup situation where data is collected and an update where the current data is read and then later updated.
This example covers a situation where the user can add a dynamic amount of lines, for an example where the options are static have a look at example one.
These are advanced examples so I will assume you know the basic way that jsp apps in Agillic work and focus on more technical details in solving this problem.
These examples are not designed to show how to build a nice looking webform, absolutely no time has been spent on the html, nor is it an example of the right way to use One-To-Many tables, the only purpose of this example is to show how to collect and store One-To-Many data from a form. The examples has been tested and work.
As always the jsp pages are attached to the page, since there are in fact two index.jsp pages here, I’ve prefix the pages with which app they belong to, if you want to use them remove the prefix before you upload them.
Context
In your signup app you want to collect some basic data (email, first and lastname) and then collection information about your children, their name, age, gender and which sport they play and store this as One To Many lines, the design is slightly stupid since if a child attend more than one sport, then a line for each sport is created and all the data about the childs name, gender and age is repeated.
So we have our One-To-Many table called CHILDREN, and that contains a number of fields:
ID
– a unique id representing this particular line, needed because One-To-Many tables must have a unique identifier.NAME
– the name of the childGENDER
– the gender of the childBIRTHDAY
– the birthday and year of the childSPORT
– the sport the child plays
Sign up
1. The basics
If we didn’t want to collect One-To-Many data but just the person data this would be what we needed. This is actually stolen directly from one of the basic examples from the taglib section.
In this setup we send the user to a receipt page where the action phase creates the user, if this was all we wanted we could simply use a function instead.
The index.jsp
page:
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:render>
<inp:form next="receipt" method="post">
<!-- Just a few basic fields to gather. Completely standard -->
<label>Email</label>
<inp:text clmAttribute="EMAIL" class="required email unique textinput" transformer="trim,lower"/>
<label>Firstname</label>
<inp:text clmAttribute="FIRSTNAME" class="textinput"/>
<label>Surname</label>
<inp:text clmAttribute="LASTNAME" class="textinput"/>
<input type="submit" value="Signup">
</inp:form>
</sdk:render>
The receipt.jsp
page:
<%@ page import="java.util.*" %>
<%@ taglib prefix="sdk" uri="http://agillic.com/jsp/sdk/1.0" %>
<%@ taglib prefix="inp" uri="http://agillic.com/jsp/sdkinput/1.0" %>
<sdk:render>
<!-- Basic text, you probably want something more advanced here :) -->
Thank you for signing up
</sdk:render>
<sdk:action>
<%
//First we start by creating the user - we get the fields from the form came from our tags and were tied to a Person Data
Map<String, String> map = flow.getEnteredClmAttributes();
//Now we create a user based on this data - the returned value is the internal user id that we'll use from then on
String userId = api.createBasePerson(map);
//Finally we achieve an event to signal that the user was created - of course the event should be created in the system for this to have any meaning
api.achieveEvent(userId, "Signup", "web", "signup");
%>
</sdk:action>
2. Adding One-To-Many to the form
We use some basic html form elements, nothing Agillic related as all – to allow the user to add a dynamic amount of lines we simply use jQuery to update the form, the fact that we are using jQuery to add elements to the form is also part of the reason we’re not using the Agillic tags, had we used those we would not be able to add more lines since the form items were tied to backend objects. It should be pretty clear how to add a limit to the amount of lines that could be created.
So basically what you have here standard html code and standard JS code with no ties to Agillic at all.
So what we do is to add this html to the form.
And this JS code, after the form.
<script type="text/javascript">
var c = 1;
//Basic method that simply clones the code sets up some names and add it to the dom
function clone() {
var template = $(".linetemplate").clone().removeClass("linetemplate");
template.insertBefore(".linetemplate");
$("[name=cname]",template).attr("name","cname-" + c);
$("[name=cbday]",template).attr("name","cbday-" + c);
$("[name=cgen]",template).attr("name","cgen-" + c);
$("[name=csport]",template).attr("name","csport-" + c);
$("input[name=ids]",template).val(c);
$(".addline",template).click(function(e) {
e.preventDefault();
e.stopPropagation();
clone();
});
$(".removeline",template).click(function(e) {
e.preventDefault();
e.stopPropagation();
$(this).parent().remove();
});
c++;
template.show();
}
clone();
</script>
3. Saving the data
Most of the relevant information is in the comments in the code. In a few words what we do is that we build a list of the lines we want to save. Each line is represented as a map of the columns to the values that we want to set for each column, you don’t have to supply all columns in the One-To-Many table, any column not present will simply be blank in case of adding lines. You do have to provide a value for the column defines as the primary key for the table.
As with the rendering part, much of the code has more to do with simple jsp logic of getting data submitted in a form out of the request on another page, and little to do with Agillic.
We add this code after creating the user, but before achieving the Event, the placement is a bit random, but would mean that in case the event triggers an email which uses the children, then we know they are saved.
Update
Update is slightly more difficult than create when it comes to One-To-Many, the main reason for this is that there are different methods for adding, updating and deleting lines. It should be possible to remove lines since it could be that a child looses interest in a sport and therefore the line with that sport is no longer relevant.
For update we keep everything in a single page, so that you simply see the form again.
1. The basics
As before we start with the part related to Person Data.
2. Adding One-To-Many to the rendering
We have the same code as in create for being able to add new lines, we will not show that again here. On the update page all the current lines should be shown, and that is done by getting the One-To-Many lines from the database and then iterate over them and show them, the code for doing that part is shown below, for the full example look at the attached jsp page.
Please note that the lines are not being sorted in the code that is shown that is to make the code simpler, you cannot be certain the ordering that lines were inserted in will be the same that they are returned, so if ordering is important you should consider doing some ordering yourself.
So we add this:
3. Updating the One-To-Many table
So this is the most complex part of the code.
The design is a little bit lazy, we will not compare a line with what is already in the database but simply always do an update, this makes the code a bit easier to read and will in all but the most extreme cases not make any difference to the performance of the app or the server.
So what the code should do is to:
- Update any line already in the system
- Insert any new line that was not already in the system
- Remove any lines removed by the user
We already know how to add lines from the signup case, but update is a bit more tricky. The reason it’s tricky is that to make it possible to update the primary id of a line, the update call does not take the primary id of the line as a parameter, but rather a special rowId which uniquely identifies both the user and the row. This is nice for the update call itself, but means that the update code becomes a bit more complex. The remove all also uses the rowId to indentify which line should be removed.
The comments should make it pretty clear what is going on, but it’s probably a good idea to read it through a couple of times.
One to Many 2 – code examples
The file names here are a bit misleading, and should actually all be index.jsp files placed in different folders, as separate applications.
signup-index.jsp
– The first page of the signup
signup-receipt.jsp
– The action page as well as the receipt
update-index.jsp
– The update page
Search and Email/SMS History
This examples consists of three different application:
search.jsp
emailHistory.jsp
smsHistory.jsp
Search
The search.jsp
allows you to perform simple searches for a match across all recipients. To make the search form easy to customize, four different Global Data values are used to control the Title and available search fields.
The “title” of the application (shown above the available search fields) gets its value from the Global Data field “ADVISOR_TITLE”.
Additionally you have the options to define 1-3 Person Data fields to search and display. If Global Data field has no value, it will not be shown as a search input/column in search results.
Excerpt:
(...)
<sdk:render>
<c:set var="advisorTitle" value='<%=api.getValueForGlobalData("ADVISOR_TITLE")%>'/>
<c:set var="advisorSearch1" value='<%=api.getValueForGlobalData("ADVISOR_SEARCH_1")%>'/>
<c:set var="advisorSearch2" value='<%=api.getValueForGlobalData("ADVISOR_SEARCH_2")%>'/>
<c:set var="advisorSearch3" value='<%=api.getValueForGlobalData("ADVISOR_SEARCH_3")%>'/>
<inp:form next="index">
<header>
<h2>${advisorTitle}</h2>
</header>
<c:if test="${advisorSearch1 != null}">
<label for="search1">${advisorSearch1}</label>
<inp:text type="text" id="search1" name="${advisorSearch1}" size="20"/>
</c:if>
<c:if test="${advisorSearch2 != null}">
<label for="search2">${advisorSearch2}</label>
<inp:text type="text" id="search2" name="${advisorSearch2}" size="20"/>
</c:if>
<c:if test="${advisorSearch3 != null}">
<ljspabel for="search3">${advisorSearch3}</label>
<inp:text type="text" id="search3" name="${advisorSearch3}" size="20"/>
</c:if>
<button type="submit">Search</button>
</inp:form>
(...)
Email History
This example app displays emails Sent, Opened/Clicked for the currently logged in recipient. In addition to this, an example implementation of the “generateContentUrl
” and “resendEmail
‘ apis are included, allowing you to see and resend a stored copy of an Email already sent to the recipient.
SMS History
This example app displays outbound and inbound SMS messages for the currently logged in recipient. In addition to this, an example implementation of the “generateContentUrl
” api is included, allowing you to see a stored copy of the SMS message.
search.jsp
– The search page
emailhistory.jsp
– The email history page
smsHistory.jsp
– The SMS history page