View
220
Download
0
Tags:
Embed Size (px)
Citation preview
Mobile Applications at NOCCCD
Brad RippeNOCCCD
Goal
Provide insight into developing and deploying mobile applications with
Sungard’s Mobile Connection.
Brad RippeIT Project Leader
North Orange County Community College District
Smartphone StatisticsTypes of Smartphones
iPhone 40%Blackberry 36%Android 22%Other 2%
Source: University Colorado Boulder
Source: Google Analytics
Mobile Connection 1.0
• 1.0 Release• Support multiple mobile platforms • Built on Open Source Software• Integrates with LDAP and Banner Data• Quick Start
• m-Apps (Feeds, Grades, Schedule, Restaurant)
What features?
22 College/University iPhone appsNews - 21Directory - 18Maps - 18Events - 13Videos - 9Courses - 6Sports - 6Photos - 5Library - 5Twitter - 4
8 vendor solutionsUniversity Texas at Austin; Stanford; Harvard; Boston College; Saddleback; Irvine Valley College; Mt. Hood College; Rice University; more
1.0 Planned Features
• m-Apps• Student’s Daily Schedule• Grades• Restaurants• News Feed• Staff Directory• Class Schedule• Campus Map
Mobile Connection 1.0.1
• Java Development Kit (JDK) 1.6.21+• Grails 1.3.6 - http://www.grails.org
• Spring• Hibernate • Groovy
• Rhodes Framework 2.2.5 - http://rhomobile.com/projects/rhodes
• Ruby/Rails• Android SDK and NDK • Blackberry JDE• iOS SDK/Xcode
Android Requirements
• Android SDK Android 2.2, API 8http://developer.android.com/sdk/index.html
• Android NDK r4bWindows - http://dl.google.com/android/ndk/android-ndk-r4b-windows.zipMac - http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zipLinux - http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip
API
MC Architecture
request
Luminis IV LDAP
response
Banner
Mobile Server
NOCCCD Basic Configuration
“The Plan”
3 institutions3 platforms~ 4 months
Setting up the “Team”
District/SCE
Cypress
Fullerton
TEST
Collaborating
Collaborating
Repository Structure
MC Directory Structure
Android Emulator
# Android config - android doesn't respond to localhostsecurity_service_url =
'http://10.0.2.2:8001/mobileserver/rest/security'grade_service_url = 'http://10.0.2.2:8001/mobileserver/rest/grade'schedule_service_url = 'http://10.0.2.2:8001/mobileserver/rest/schedule'feed_service_url = 'http://10.0.2.2:8001/mobileserver/rest/feed/'
http://bit.ly/psZ8G7
News Feeds
Updated Feed
Feed Client
2.
Feed – show.erb<form action="<%= url_for :action => :index %>"> <select name="id" onchange="submit()"> <% if ::Rho.get_app.feedId && ::Rho.get_app.feedId == 'cypress'%> <option selected value="cypress">Cypress College News</option> <% else %> <option value="cypress">Cypress College News</option> <%end%> <% if ::Rho.get_app.feedId && ::Rho.get_app.feedId == 'fullerton'%> <option selected value="fullerton">Fullerton College News</option> <% else %> <option value="fullerton">Fullerton College News</option> <%end%></select></form><hr />… More …
Feed – application.rbrequire 'rho/rhoapplication'
class AppApplication < Rho::RhoApplication attr_accessor :feedId
# more code in here def initialize super endend
Feed – feed_controller.rbdef index ::Rho.get_app.feedId = @params['id'] url = "#{@serviceUrl}" url << "/#{::Rho.get_app.feedId}.json"
#More code result = Rho::AsyncHttp.get( :url => url,
:callback => (url_for :action => :feed_callback))
redirect :action => :wait end
Feed – Config.groovyfeed.location = [ cypress:"http://cypresscollege.edu/rss.xml", fullerton:"http://www.fullcoll.edu/rss.xml",sce:"http://sce.edu/rss.xml]sghe { plugins { banner { jdbc { … } } }}
Back Issue
Back Issue – feed_controller.rbdef index ::Rho.get_app.feedId = @params['id'] url = "#{@serviceUrl}" url << "/#{::Rho.get_app.feedId}.json"
#More code
result = Rho::AsyncHttp.get(:url => url, :callback => (url_for :action => :feed_callback))
redirect :action => :wait end
Back Issue – feed_controller.rb# Original Methoddef feed_callback app_info "feed_callback: #{@params}“ # log feedId # parse json response
# send browser to show view but still have wait in history?? WebView.navigate(url_for :action => :show)end
Fix Back Issuedef feed_callback app_info "feed_callback: #{@params}“ # parse json response
# send browser to show_feed method WebView.navigate(url_for :action => :show_feed)end
def show_feed render :action => :show, :back => '/app/Mshell'end
http://bit.ly/p44ghq
MC 1.1.1 – Back Issue
def index feedId = @params['id‘] Rho::AsyncHttp.get( :url => url, :callback => (url_for :action => :feed_callback)) @response["headers"]["Wait-Page"] = "true" redirect :action => :wait end
app_info or app_error
• Android• rake emulator:android:getlog
• BlackBerry• C:\Users\<username>\net\rim\fledge-2\3.0.0.118\
sdcard\Rho\<application_name>\RhoLog.txt
• iPhone• /Users/<username>/Library/Application
Support/iPhone Simulator/4.3/Applications/<GUID>/Documents/RhoLog.txt
Server Side Of Things
Class Schedule Plugin
ClassScheduleUrlMappings
class ClassScheduleUrlMappings {static mappings = {"/rest/getCampuses"(controller:"search",
action:"getCampuses")"/rest/getAllTerms"(controller:"search", action:"getAllTerms")// continued…}
}
SearchControllerclass SearchController { def classScheduleService def getCampuses = { if ( classScheduleService == null ) { // code here, handle null classScheduleService } else { def camps = classScheduleService.getCampuses() if (camps != null && camps.size() > 0) { response.setContentType("text/json") render camps as JSON } else { // send no information 404 error } } } …
ClassScheduleServiceclass ClassScheduleService { def dataSourceBanner //defined in the server’s Config.groovy file def getCampuses() { def sql = Sql.newInstance (dataSourceBanner) def query = " " "select stvcamp_code, stvcamp_desc from stvcamp where stvcamp_code in ('1', '2', '3') order by stvcamp_desc" " " def campuses = [] // list of Campus objects try { sql.eachRow(query) { def campus = new Campus() campus.campusCode = it.stvcamp_code campus.campusDesc = it.stvcamp_desc campuses.add(campus) } } catch(Exception e) { log.error "Exception ${query} - ${e}“ } return campuses } // end getCampuses
ClassSchedule Request
GrailsDispatcherServlet
/service/rest/getCampuses
SearchController
Campus
ClassScheduleServiceresponse
request
Automatic Marshallingimport grails.converters.*class SearchController { def getCampuses = { if ( classScheduleService == null ) { // code here, handle null classScheduleService } else { def camps = classScheduleService.getCampuses() if (camps != null && camps.size() > 0) { response.setContentType("text/json") render camps as JSON } else { // send no information 404 error } } } …
1
2
JSON output?
[{"class":"edu.nocccd.Campus","id":null,"campusCode":"1","campusDesc":"Cypress College"},
{"class":"edu.nocccd.Campus","id":null,"campusCode":"2","campusDesc":"Fullerton College"},
{"class":"edu.nocccd.Campus","id":null,"campusCode":"3","campusDesc":"School of Continuing Education"}]
Server BootStrap.groovyimport grails.converters.JSONimport org.codehaus.groovy.grails.plugins.GrailsPluginUtilsimport edu.nocccd.Campusclass BootStrap {
def init = { } def destroy = { }}
Init – Override Convertersclass BootStrap { def init = { servletContext -> JSON.registerObjectMarshaller(Campus) { def returnArray = [:] returnArray['campusCode'] = it.campusCode returnArray['campusDesc'] = it.campusDesc return returnArray } // continued for each domain object } …}
Result JSON
[{"campusCode":"1","campusDesc":"Cypress College"},{"campusCode":"2","campusDesc":"Fullerton College"},{"campusCode":"3","campusDesc":"School of Continuing Education"}]
Objects with in Objects
• Sections• Multiple buildings• Multiple meeting times
• Default converters • Skip internal data
render sections as JSON
MATH 030 F Bldg 1
Bldg 2
Meet 2
Meet 1
MATH 100 F
SearchControllerdef sections = classScheduleService.getSections(cCode, tCode, subCode, courNum)if (sections != null && sections.size() > 0) { def sectionList = new ArrayList() sections.each { section -> def sectionMap = new HashMap() sectionMap.put "crn", section.crn def bldgs = new ArrayList() // Done for meetings too! section.buildings.each { bldg -> def bldgMap = new HashMap() bldgMap.put "bldgCode", bldg.bldgCode bldgMap.put "bldgDesc", bldg.bldgDesc bldgMap.put "roomCode", bldg.roomCode bldgs.add bldgMap } sectionMap.put "bldgs", bldgs } sectionList.add sectionMap
JSON Response[{"instructor":"Danufsky, Joshua","wDropDate":"11/20/2011","waitAvailable":10,"bldgs":[{"roomCode":"624","bldgDesc":"Math/Comp Science - FC","bldgCode":"600"}] ,"meetings":[{"startDate":"08/15/2011","wednesday":null,"thursday":null,"monday":null,"sunday":null,"beginTime":null,"saturday":null,"endDate":"12/16/2011","friday":null,"tuesday":null,"endTime":null,"arrangedHrs":"Plus arranged hours"},{"startDate":"08/15/2011","wednesday":" Wed ","thursday":null,"monday":" Mon ","sunday":null,"beginTime":"1:00","saturday":null,"endDate":"12/16/2011","friday":null,"tuesday":null,"endTime":"2:50 PM","arrangedHrs":null}]]
Render Results
Mobile Server
•Apache Tomcat 6.0.32• Run Non-Root User• Apache JMeter• JVM Options• VisualVM
http://visualvm.java.net/
PSI-Probe
http://code.google.com/p/psi-probe/
Tips - Build for Devices
• Rhoconfig.txt• MaxLogFileSize=0 to 50• MinSeverity=1 to 3• local_server_port=8080
• build.yml • version: 1.0 to 1.0.0
rake device:android:production
version: 1.0AndroidManifest.xml
<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.north_orange_county_community_college_district.cypresscollege' android:installLocation='auto' android:versionCode='26' android:versionName='2.2.5'>…</manifest>
version: 1.0.0AndroidManifest.xml
<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.north_orange_county_community_college_district.cypresscollege' android:installLocation='auto' android:versionCode='10000' android:versionName='1.0.0'>…</manifest>
Demo
Mobile Connection
• Version 1.1.1• mApps
• Campus Directory• Event Calendar• Campus Map
• iPad Support• JQuery Mobile• Active Directory Support
1.1 Release Notes - http://bit.ly/oq90m6
Things to Take Away
• Collaborative Environment• Team Commitment• Developer Environment• JQuery Mobile• Steering Committee• Limited Feature Set
Questions
ResourcesGrails Tutorialhttp://www.ibm.com/developerworks/java/library/j-grails02128/Ruby Tutorialhttp://www.ruby-lang.org/en/documentation/quickstart/RhoMobile Docshttp://docs.rhomobile.com/JMeterhttp://jakarta.apache.org/jmeter/PSI-Probehttp://code.google.com/p/psi-probe/VisualVMhttp://visualvm.java.net/NOCCCD Mobile Appshttp://www.nocccd.edu/mobile