Intermediate Blackboard Building Block Development
Transcription
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 mark.a.oneil@dartmouth.edu 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 <jday@blackboard.com> George Kroner/Solutions Engineer <gkroner@blackboard.com> 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!