Intermediate Blackboard Building Block Development

Intermediate Blackboard Building
®
Block Development
MVC, JSP and Java
Inside Blackboard Engineering: The Series
Mark O'Neil,
Curricular Systems Engineer,
Dartmouth College
[email protected]
About this webinar
This webinar series will introduce participants
to using MVC in Building Block development.
Continuing with previous sessions in this
series,
this Webinar will cover the value of model view
controllers (MVC) and port the Java Server
Page (JSP) extension to the MVC model.
Who....
ƒ Mark O'Neil, Dartmouth College
ƒ Blackboard client since 1998, Blackboard Academic Suite client
since 2002
ƒ Art historian, Printmaker, Blacksmith, Motocyclist
Everything presented today is covered in more depth in the
Intermediate Developer's Guide
www.tinyurl.com/ysrb4j
Agenda
ƒ Part 1: MVC
ƒ Part 2: MVC Example - Users
ƒ Part 3: Resources
Part 1: MVC JSP/JAVA
Extensions may be written entirely in JSP, a combination of JSP and
Java
• JSP
– Advantages of JSP
• Quick development cycle
– JSP may be edited on the server without reloading the Building Block
– Disadvantages of JSP
• Complex applications are difficult to maintain
• Sharing of code “modules” is possible but not as clear as using Java
• Java
– Advantages of JAVA
• Modularization and reuse of code
– JSP pages easier to read/code when using external JAVA classes
– Disadvantages of Java
• Requires reloading of Building Block on each java code cycle
• Beginning developers may not be as comfortable with Java
Part 1: MVC Model View Controller
Why use MVC?
It solves several problems in software design
notably it provides a clean separation
between the display of your data and the
models which provide that data
It allows for ease of maintenance
It allows for ease of reuse
Part 1: MVC Model View Controller
But it comes with a cost
– Understanding MVC can sometimes be a
hurdle
– Added complexity to the application
instead of a series of JSP pages you have
both JSP and Java code
Part 1: MVC Model View Controller
and it comes with savings
– as you become familiar with the process it
becomes easier to build flexible extensible
applications
– as your model grows you can reuse it in
multiple applications
– adding or making changes to the application
may be as simple as changing the model,
view, or controller
– easier to spread development efforts
Part 1: MVC Model View Controller
• This model sits between MVC1 which uses only JSP and
JavaBeans, and MVC2 which uses servlets for the
Controller.
Part 1: MVC The Controller
calls UserController.jsp
calls CourseController.jsp
• The main index page for our tool is a simple JSP page
which simply calls the correct controller for the action we
wish to perform...
Part 1: MVC The Controller
• In this case the CourseController or UserController; each
of which in turn renders an entry level view – in this case a
Course or a User Search...
Part 1: MVC The Controller
• Entering user search information calls the UserController
which instantiates the User Model (userbean) and Course
Model (coursebean), pulls information from the models based
on the query and displays it using the UserDetails view...
Part 1: MVC The Controller
• Certainly this could all be handled in a series of JSP pages
without using java classes at all but...
– You now have the means to change any single portion
of the extension - Model, View or Controller - without
adversely effecting the other components
– You now have a set of reusable models for your other
extensions
– While you have introduced a light complexity in the
number of files and their interaction, you in the long run
have simplified the application in terms of maintenance
Let's take a look at the project...
Part 1: MVC The Controllers
• We add controllers
based on the target of
the action....
Part 1: MVC The Models
• We add java classes for
the Models to reflect the
Data we will be working
with...
Part 1: MVC The Views
• And we add views which
display results based on
the desired actions...
Part 1: Progress so far....
Based on our requirements, we determined the actions, the results to view, and
constructed an extension consisting of:
• Controllers to load the models, gather data and direct
the user to the correct view
• Views to display the required results
• Models which contain the logic to provide the required
data
Let's take a look at some code...
Part 2: MVC Example Main.jsp
Simple enough – a jsp which just links to the controller specifying the action:
...
String ManageUserPageURL = "tools/users/UserController.jsp";
String ManageCoursesPageURL = "tools/courses/CourseController.jsp";
...
<bbUI:docTemplate title="Blackboard Admin Tools">
<% String iconUrl = "/images/ci/icons/bookopen_u.gif"; %>
<bbUI:breadcrumbBar environment="SYS_ADMIN" handle="bbrd-BBIGBAT-nav-1" >
<bbUI:breadcrumb>User Search</bbUI:breadcrumb>
</bbUI:breadcrumbBar>
<bbUI:titleBar iconUrl="<%=iconUrl%>"><%=title%></bbUI:titleBar>
...
<bbUI:caretList description="Tasks">
<bbUI:caret title="Manage Users" href="<%= ManageUserPageURL %>" description="Use this to List and
Modify a User's properties, Renable a User, and to Create a New User Account. You may also
manage a User's Memberships from the User's details page." />
...
</bbUI:caretList>
Part 2: MVC Example UserController.jsp
UserController is a jsp which conditionally instantiates models and redirects to a
view based on the requested action – none in this case:
...
String requestedAction =
request.getParameter("gsgAction")!=null?request.getParameter("gsgAction"):"NOVALUE";
...
if ( requestedAction.equals( "NOVALUE" ) ) {
// Just display the UserSearch page
%>
<jsp:forward page="UserSearch.jsp">
<jsp:param name="gsgAction" value="NOVALUE"/>
</jsp:forward>
<%
// end up here if no matches - could display an error page instead...
} else {
%>
<jsp:forward page="UserSearch.jsp">
<jsp:param name="gsgAction" value="NOVALUE"/>
</jsp:forward>
Part 2: MVC Example UserController.jsp
Handling specific actions is as simple as adding a conditional:
String requestedAction =
request.getParameter("gsgAction")!=null?request.getParameter("gsgAction"):"NOVALUE";
...
<%
if ( requestedAction.equals( "SEARCH" ) ) {
// search for a user based on form data passed from UserSearch.jsp
//tell the model to do the search and save a list of found users
%>
<jsp:setProperty name="UserManager" property="searchKey” value="
<%=request.getParameter("searchKey") %>"/>
<jsp:setProperty name="UserManager" property="searchOperator"
value="<%=request.getParameter("searchOperator") %>"/>
<jsp:setProperty name="UserManager" property="searchTerm"
value="<%=request.getParameter("searchTerm") %>"/>
<%
UserManager.searchForUsers( request.getParameter("searchKey"),
request.getParameter("searchOperator"), request.getParameter("searchTerm") );
%>
<jsp:forward page="UserSearch.jsp">
<jsp:param name="gsgAction" value="SEARCH"/>
</jsp:forward>
<%
} else if ( requestedAction.equals( "NOVALUE" ) ) {
Part 2: MVC Example UserController.jsp (users)‫‏‬
oops, don't forget the model(s):
String requestedAction =
request.getParameter("gsgAction")!=null?request.getParameter("gsgAction"):"NOVALUE";
...
<jsp:useBean id="UserManager" scope="request" class="org.oscelot.bats.userbean.UserBean"/>
<jsp:useBean id="emailBean" scope="page" class="org.oscelot.utils.Utils"/>
<jsp:useBean id="PropertiesManager" scope="application"
class="org.oscelot.bats.propertiesbean.PropertiesBean"/>
<%
if ( requestedAction.equals( "SEARCH" ) ) {
// search for a user based on form data passed from UserSearch.jsp
//tell the model to do the search and save a list of found users
%>
<jsp:setProperty name="UserManager" property="searchKey” value="
<%=request.getParameter("searchKey") %>"/>
<jsp:setProperty name="UserManager" property="searchOperator"
value="<%=request.getParameter("searchOperator") %>"/>
<jsp:setProperty name="UserManager" property="searchTerm"
value="<%=request.getParameter("searchTerm") %>"/>
<%
UserManager.searchForUsers( request.getParameter("searchKey"),
request.getParameter("searchOperator"), request.getParameter("searchTerm") );
%>
<jsp:forward page="UserSearch.jsp">
<jsp:param name="gsgAction" value="SEARCH"/>
</jsp:forward>
<%
} else if ( requestedAction.equals( "NOVALUE" ) ) {
Part 2: MVC Example View: UserSearch.jsp
The User Search View provides the search form:
<td nowrap><div id="UserInformation">
<table width="100%" border="0" cellpadding="3" cellspacing="0"><tr>
<td nowrap>
<select NAME="searchKey">
<OPTION VALUE="UserName" selected>Username</OPTION>
<OPTION VALUE="GivenName" >First Name</OPTION>
<OPTION VALUE="FamilyName" >Last Name</OPTION>
<OPTION VALUE="Email" >Email</OPTION>
</select>
</td>
<td nowrap>
<select NAME="searchOperator">
<OPTION VALUE="Contains" selected>Contains</OPTION>
<OPTION VALUE="Equals" >Equal to</OPTION>
<OPTION VALUE="StartsWith" >Starts with</OPTION>
</select>
</td>
<td nowrap><INPUT TYPE="TEXT" NAME="searchTerm" VALUE="" size="30" maxlength="50"></td>
<td nowrap><input type="IMAGE" name="FILTER_SEARCH_PARAM" src="/images/ci/misc/go_btn_off.gif"
alt="Go" border=0 ></td>
<td><img src="/images/spacer.gif" height="1" width="1" alt=""></td>
<td align="left" width="2" height="10"><img
src="/images/ci/misc/gb_divider_e8e8e8.gif" height="20" width="2" alt=""></td>
<td width="100%" nowrap><img src="/images/spacer.gif" width="3" height="3"
alt=""></td>
</tr></table>
</div></td>
Part 2: MVC Example View: UserSearch.jsp
The User Search View provides the search form:
<td nowrap><div id="UserInformation">
<table width="100%" border="0" cellpadding="3" cellspacing="0"><tr>
<td nowrap>
<select NAME="searchKey">
<OPTION VALUE="UserName" selected>Username</OPTION>
<OPTION VALUE="GivenName" >First Name</OPTION>
<OPTION VALUE="FamilyName" >Last Name</OPTION>
<OPTION VALUE="Email" >Email</OPTION>
</select>
</td>
<td nowrap>
<select NAME="searchOperator">
<OPTION VALUE="Contains" selected>Contains</OPTION>
<OPTION VALUE="Equals" >Equal to</OPTION>
<OPTION VALUE="StartsWith" >Starts with</OPTION>
</select>
</td>
<td nowrap><INPUT TYPE="TEXT" NAME="searchTerm" VALUE="" size="30" maxlength="50"></td>
<td nowrap><input type="IMAGE" name="FILTER_SEARCH_PARAM" src="/images/ci/misc/go_btn_off.gif"
alt="Go" border=0 ></td>
<td><img src="/images/spacer.gif" height="1" width="1" alt=""></td>
<td align="left" width="2" height="10"><img
src="/images/ci/misc/gb_divider_e8e8e8.gif" height="20" width="2" alt=""></td>
<td width="100%" nowrap><img src="/images/spacer.gif" width="3" height="3"
alt=""></td>
</tr></table>
</div></td>
Part 2: MVC Example View: UserSearch.jsp
and the results:
<% if ( UserManager.isSuccessfulSearch() && requestedAction.equals("SEARCH") ) { %>
Select a User to get more info.<br>
<bbUI:list collection="<%= UserManager.getUserList() %>" collectionLabel="Persons"
objectId="p" className="Person" sortUrl="UserController.jsp?gsgAction=SEARCH">
<%
cnt++;
if ( UserManager.userIsEnabled(p) ) {
status = "Enabled";
tcolor = "#000000";
} else {
status = "Disabled";
tcolor = "#999999";
}%>
<bbUI:listElement width="10%" label="" name="found_user">
<FORM action="UserController.jsp" method=post style="margin:0px">
<bbUI:button type="INLINE" name="select" action="SUBMIT_FORM" alt="SELECT"/>
<input type="hidden" name="gsgAction" value="DETAILS">
<input type="hidden" name="userBatchUID" value="<%=p.getBatchUid()%>">
</FORM>
</bbUI:listElement>
...
Part 2: MVC Example View: UserSearch.jsp
...
<bbUI:listElement width="20%" label="Username" name="Username"
comparator="<%=UserManager.usernameCmp%>">
<FONT COLOR="<%=tcolor%>"><%=p.getUserName()%></FONT>
</bbUI:listElement>
<bbUI:listElement width="25%" label="Name" name="Name"
comparator="<%=UserManager.familynameCmp%>">
<FONT COLOR="<%=tcolor%>"><%=p.getGivenName()%> <%=p.getFamilyName()%></FONT>
</bbUI:listElement>
<bbUI:listElement width="25%" label="Email" name="Email"
comparator="<%=UserManager.emailaddressCmp%>">
<FONT COLOR="<%=tcolor%>"><%=p.getEmailAddress()%></FONT>
</bbUI:listElement>
<bbUI:listElement width="10%" label="Batch UID" name="BatchUID">
<FONT COLOR="<%=tcolor%>"><%=p.getBatchUid()%></FONT>
</bbUI:listElement>
<bbUI:listElement width="10%" label="Status" name="Status">
<FONT COLOR="<%=tcolor%>"><%=status%></FONT>
</bbUI:listElement>
</bbUI:list>
<% } %>
Part 2: MVC Example Model: UserBean.java
UserBean.java provides all the logic for provideing data to the views in this case
the search results and success:
public void searchForUsers( String searchKey, String searchOperator, String searchTerm ) {
String strSearchTerm;
//this.setLogger();
PersonLoader ploader = null;
if ( this.logger != null) {
this.logger.logWarning("------>UserBean performing user search");
}
System.err.println("UserBean performing user search");
BbPersistenceManager bbPm = BbServiceManager.getPersistenceService().getDbPersistenceManager();
try {
ploader = (PersonLoader) bbPm.getLoader( PersonLoader.TYPE );
} catch (PersistenceException pe) {
System.err.println( pe );
}
if ( (searchTerm) != null && (!searchTerm.equals( "" )) ) {
strSearchTerm = searchTerm;
if (searchOperator.equals("Contains") ) {
strSearchTerm = "%" + strSearchTerm + "%";
} else if (searchOperator.equals("StartsWith") ) {
strSearchTerm = strSearchTerm + "%";
} // else it is equals and we leave it alone
Person ptemplate = new Person();
if ( searchKey.equals("Email")){
ptemplate.setEmailAddress(strSearchTerm);
} else if ( searchKey.equals("FamilyName")) {
ptemplate.setFamilyName(strSearchTerm);
Part 2: MVC Example Model: UserBean.java
UserBean.java provides all the logic for provideing data to the views in this case
the search results and success:
} else if ( searchKey.equals("BatchUID")) {
ptemplate.setBatchUid(strSearchTerm);
}
try {
this.userList = ploader.load(ptemplate);
} catch (PersistenceException pe) {
if ( this.logger != null ) {
this.logger.logWarning("------>UserBean error:");
}
pe.printStackTrace();
}
Collections.sort(this.userList, this.familynameCmp);
this.successfulSearch = ( this.userList.size() > 0 )?true:false;
if ( this.logger != null ) {
this.logger.logWarning("------>UserBean completed user search");
}
}
}
Part 2: MVC Example All of the Above Results in
with a successful search (and when it works!)‫‏‬
Part 2: MVC Example Rinse Repeat
•Adding additional actions follows the pattern:
•Determine the data needs
•Add necessary logic to the model
•Determine how you wish to display the data
•Add the necessary view
•Add the action to the controller
Part 2: Some things to watch out for
•JSP only supports specific data types:
• String (the best)‫‏‬
• boolean or Boolean
• byte
• Double
• Float
This means you may have to handle some data conversion before use or
break the bean model and call a method directly
Part 2: Some things to watch out for
• Naming conventions
• Make certain when possible you name your
methods following the getter setter pattern
• Eclipse will do this for you
• Variable name typos may give the “White Screen of
Death”... You begin to pray for a stack trace... ;-)‫‏‬
• Develop incrementally to facilitate tracking errors
Part 3: Developer Resources
Blackboard Developers Network
ƒ The BbDN Team:
ƒ Jan Day/Senior Director, Client Engagement <[email protected]>
ƒ George Kroner/Solutions Engineer <[email protected]>
ƒ Technologies:
ƒ Building Blocks AND PowerLinks
ƒ Benefits:
ƒ Access for up to 25 developers to BbDN website and online forums
Developer license to the Blackboard Learning SystemTM,
Blackboard Community SystemTM, and Blackboard Content
SystemTM
Part 3: Developer Resources
Finding help is easy
Use Behind Blackboard knowledge bases
Use the Bb Open Source email list
Use the Blackboard BbDevNet forum
Participate in OSCELOT - Think Community!
Part 3: Developer Resources
Getting Started Guide
Intermediate Developer's Guide
www.tinyurll.com/hnjq
Bb Open Source
www.tinyurl.com/ysrb4j
Use Playing with Building Blocks
www.bb-opensource.org
www.dur.ac.uk/malcolm.murray/blog
Blackboard Developer Network
www.blackboard.com/extend/dev/BbDN
Behind the Blackboard support site
Building Block JAVA DOCS!
behind.blackboard.com
www.oscelot.org
Thank you!