diff --git a/courses-portlet-api/pom.xml b/courses-portlet-api/pom.xml index 453c820..2237fbc 100644 --- a/courses-portlet-api/pom.xml +++ b/courses-portlet-api/pom.xml @@ -16,6 +16,10 @@ org.jvnet.jaxb2_commons jaxb2-basics-runtime + + commons-lang + commons-lang + diff --git a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/CachingDegreeProgressDao.java b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/CachingDegreeProgressDao.java new file mode 100644 index 0000000..b642331 --- /dev/null +++ b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/CachingDegreeProgressDao.java @@ -0,0 +1,93 @@ +/** + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.portlet.degreeprogress.dao; + +import javax.portlet.PortletRequest; +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jasig.portlet.degreeprogress.model.xml.DegreeProgressReport; + +/** + * This {@link org.jasig.portlet.degreeprogress.dao.IDegreeProgressDao} implementation decorates one or more other DAOs and + * adds caching features to them. Whatever data the underlying DAOs provide + * will be stored in cache according to parameters specified in ehcache.xml. + * All caching is per-user. + * + * @author Chris Waymire, chris@waymire.net + */ +public class CachingDegreeProgressDao implements IDegreeProgressDao { + private final Log log = LogFactory.getLog(getClass()); + + /* + * Spring-wired dependencies + */ + + private IDegreeProgressDao enclosedDegreeProgressDao; + + public void setEnclosedDegreeProgressDao(IDegreeProgressDao enclosedDegreeProgressDao) { + this.enclosedDegreeProgressDao = enclosedDegreeProgressDao; + } + + private Cache progressReportCache; + + public void setProgressReportCache(Cache progressReportCache) { + this.progressReportCache = progressReportCache; + } + + @Override + public DegreeProgressReport getProgressReport(PortletRequest request) { + DegreeProgressReport rslt = null; + String cacheKey = getDegreeProgressCacheKey(request); + Element m = progressReportCache.get(cacheKey); + + if (m != null) { + rslt = (DegreeProgressReport) m.getValue(); + } else { + if (log.isDebugEnabled()) { + log.debug("Fetching new DegreeProgressReport from enclosedDegreeProgressDao for user '" + request.getRemoteUser() + "'"); + } + rslt = enclosedDegreeProgressDao.getProgressReport(request); + m = new Element(cacheKey, rslt); + progressReportCache.put(m); + } + return rslt; + } + + @Override + public Boolean getWebEnabled(PortletRequest request) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public WhatIfRequest createWhatIfRequest(PortletRequest request) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public DegreeProgressReport getWhatIfReport(WhatIfRequest whatIfRequest) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + private String getDegreeProgressCacheKey(PortletRequest request) { + return CachingDegreeProgressDao.class.getName() + "." + request.getRemoteUser(); + + } +} diff --git a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgramDaoImpl.java b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgramDaoImpl.java index aa0bb96..9c83d79 100644 --- a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgramDaoImpl.java +++ b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgramDaoImpl.java @@ -8,7 +8,6 @@ import org.jasig.portlet.degreeprogress.dao.ProgramInformation; import org.springframework.stereotype.Service; -@Service public class MockDegreeProgramDaoImpl implements IDegreeProgramDao { public DegreeProgramSummary getProgramSummary(PortletRequest request) { diff --git a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgressDaoImpl.java b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgressDaoImpl.java index b5c77ea..cf9101d 100644 --- a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgressDaoImpl.java +++ b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/mock/MockDegreeProgressDaoImpl.java @@ -23,7 +23,6 @@ import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; -@Service public class MockDegreeProgressDaoImpl implements IDegreeProgressDao, InitializingBean { protected final Log log = LogFactory.getLog(getClass()); diff --git a/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/xml/HttpDegreeProgressDaoImpl.java b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/xml/HttpDegreeProgressDaoImpl.java new file mode 100644 index 0000000..5515fd2 --- /dev/null +++ b/courses-portlet-dao/src/main/java/org/jasig/portlet/degreeprogress/dao/xml/HttpDegreeProgressDaoImpl.java @@ -0,0 +1,167 @@ +/** + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.portlet.degreeprogress.dao.xml; + +import java.util.HashMap; +import java.util.Map; +import javax.portlet.PortletRequest; +import javax.xml.bind.JAXBElement; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jasig.portlet.courses.util.IParameterEvaluator; +import org.jasig.portlet.degreeprogress.dao.IDegreeProgressDao; +import org.jasig.portlet.degreeprogress.dao.WhatIfRequest; +import org.jasig.portlet.degreeprogress.model.StudentCourseRegistration; +import org.jasig.portlet.degreeprogress.model.xml.Course; +import org.jasig.portlet.degreeprogress.model.xml.CourseRequirement; +import org.jasig.portlet.degreeprogress.model.xml.DegreeProgressReport; +import org.jasig.portlet.degreeprogress.model.xml.DegreeRequirementSection; +import org.jasig.portlet.degreeprogress.model.xml.GeneralRequirementType; +import org.jasig.portlet.degreeprogress.model.xml.GpaRequirement; +import org.jasig.portlet.degreeprogress.model.xml.Grade; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.web.client.RestTemplate; + +/** + * HttpDegreeProgressDaoImpl retrieves degree progress from a Basic Authentication + * protected XML feed. + * + * @author Chris Waymire, chris@waymire.net + */ +public class HttpDegreeProgressDaoImpl implements IDegreeProgressDao { + private final Log log = LogFactory.getLog(getClass()); + + private IParameterEvaluator usernameEvaluator; + + public void setUsernameEvaluator(IParameterEvaluator usernameEvaluator) { + this.usernameEvaluator = usernameEvaluator; + } + + private IParameterEvaluator passwordEvaluator; + + private Map urlParams = new HashMap(); + + public void setUrlParams(Map params) { + this.urlParams = params; + } + + public void setPasswordEvaluator(IParameterEvaluator passwordEvaluator) { + this.passwordEvaluator = passwordEvaluator; + } + + private RestTemplate restTemplate; + + public void setRestTemplate(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + private String degreeProgressUrlFormat = null; + + public void setDegreeProgressUrlFormat(String urlFormat) { + this.degreeProgressUrlFormat = urlFormat; + } + + @Override + public DegreeProgressReport getProgressReport(PortletRequest request) { + Map params = createParameters(request, urlParams); + if (log.isDebugEnabled()) { + log.debug("Invoking uri '" + degreeProgressUrlFormat + "' with the following parameters: " + params.toString()); + } + + HttpEntity requestEntity = getRequestEntity(request); + HttpEntity response = restTemplate.exchange( + degreeProgressUrlFormat, HttpMethod.GET, requestEntity, + DegreeProgressReport.class, params); + + DegreeProgressReport report = response.getBody(); + for (DegreeRequirementSection section : report.getDegreeRequirementSections()) { + for (JAXBElement requirement : section.getGeneralRequirements()) { + GeneralRequirementType req = requirement.getValue(); + if (req instanceof GpaRequirement) { + section.setRequiredGpa(((GpaRequirement) req).getRequiredGpa()); + } + } + for (CourseRequirement req : section.getCourseRequirements()) { + for (Course course : req.getCourses()) { + StudentCourseRegistration registration = new StudentCourseRegistration(); + registration.setCredits(course.getCredits()); + registration.setSource(course.getSource()); + registration.setSemester(course.getSemester()); + registration.setCourse(course); + Grade grade = new Grade(); + grade.setCode(course.getGrade().getCode()); + registration.setGrade(grade); + req.getRegistrations().add(registration); + } + } + report.addSection(section); + } + return report; + } + + @Override + public Boolean getWebEnabled(PortletRequest request) { + return Boolean.TRUE; + } + + @Override + public WhatIfRequest createWhatIfRequest(PortletRequest request) { + return null; + } + + @Override + public DegreeProgressReport getWhatIfReport(WhatIfRequest whatIfRequest) { + return null; + } + + /** + * Get a request entity prepared for basic authentication. + */ + protected HttpEntity getRequestEntity(PortletRequest request) { + + String username = usernameEvaluator.evaluate(request); + String password = passwordEvaluator.evaluate(request); + + if (log.isDebugEnabled()) { + boolean hasPassword = password != null; + log.debug("Preparing HttpEntity for user '" + username + "' (password provided = " + hasPassword + ")"); + } + + HttpHeaders requestHeaders = new HttpHeaders(); + String authString = username.concat(":").concat(password); + String encodedAuthString = new Base64().encodeToString(authString.getBytes()); + requestHeaders.set("Authorization", "Basic ".concat(encodedAuthString)); + + HttpEntity rslt = new HttpEntity(requestHeaders); + return rslt; + + } + + protected Map createParameters(PortletRequest request,Map params) { + Map result = new HashMap(); + + for(String key : params.keySet()) { + result.put(key,params.get(key).evaluate(request)); + } + return result; + } +} diff --git a/courses-portlet-webapp/src/main/java/org/jasig/portlet/degreeprogress/mvc/portlet/DegreeProgressController.java b/courses-portlet-webapp/src/main/java/org/jasig/portlet/degreeprogress/mvc/portlet/DegreeProgressController.java index 16483a3..02364cf 100644 --- a/courses-portlet-webapp/src/main/java/org/jasig/portlet/degreeprogress/mvc/portlet/DegreeProgressController.java +++ b/courses-portlet-webapp/src/main/java/org/jasig/portlet/degreeprogress/mvc/portlet/DegreeProgressController.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import org.apache.commons.lang.StringUtils; import org.jasig.portlet.courses.dao.ICoursesDao; @@ -27,7 +28,9 @@ @Controller @RequestMapping("VIEW") public class DegreeProgressController { - + public static final String PREFERENCE_INFORMATION_LINK = "DegreeProgress.INFORMATION_LINK"; + public static final String PREFERENCE_INFORMATION_LINK_DEFAULT = "#;"; + private IDegreeProgressDao degreeProgressDao; @Autowired(required = true) @@ -52,7 +55,11 @@ public void setCoursesDao(ICoursesDao coursesDao) { @RequestMapping public ModelAndView getMainView(PortletRequest request) { Map model = new HashMap(); + PortletPreferences preferences = request.getPreferences(); model.put("terms", degreeProgramDao.getEntryTerms()); + model.put("infoLink",preferences.getValue(PREFERENCE_INFORMATION_LINK,PREFERENCE_INFORMATION_LINK_DEFAULT)); + return new ModelAndView("selectReport",model); + /* Boolean webEnabled = degreeProgressDao.getWebEnabled(request); if (webEnabled == null) { return new ModelAndView("error", model); @@ -62,7 +69,7 @@ public ModelAndView getMainView(PortletRequest request) { } else { return new ModelAndView("selectWhatIf", model); } - + */ } @RequestMapping(params = "action=getScenario") diff --git a/courses-portlet-webapp/src/main/resources/ehcache.xml b/courses-portlet-webapp/src/main/resources/ehcache.xml index 2688e8d..5af3950 100644 --- a/courses-portlet-webapp/src/main/resources/ehcache.xml +++ b/courses-portlet-webapp/src/main/resources/ehcache.xml @@ -37,4 +37,8 @@ overflowToDisk="false" diskPersistent="false" timeToLiveSeconds="900" memoryStoreEvictionPolicy="LRU" statistics="true" /> + + \ No newline at end of file diff --git a/courses-portlet-webapp/src/main/webapp/WEB-INF/context/applicationContext.xml b/courses-portlet-webapp/src/main/webapp/WEB-INF/context/applicationContext.xml index 8bb91dc..37bcd17 100644 --- a/courses-portlet-webapp/src/main/webapp/WEB-INF/context/applicationContext.xml +++ b/courses-portlet-webapp/src/main/webapp/WEB-INF/context/applicationContext.xml @@ -91,6 +91,31 @@ --> + + + + + + + + + + + + diff --git a/courses-portlet-webapp/src/main/webapp/WEB-INF/context/portlet/degree-progress.xml b/courses-portlet-webapp/src/main/webapp/WEB-INF/context/portlet/degree-progress.xml index 761136a..2fcba58 100644 --- a/courses-portlet-webapp/src/main/webapp/WEB-INF/context/portlet/degree-progress.xml +++ b/courses-portlet-webapp/src/main/webapp/WEB-INF/context/portlet/degree-progress.xml @@ -25,9 +25,10 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> - + + diff --git a/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/degreeProgress.jsp b/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/degreeProgress.jsp index cec3ace..938018b 100644 --- a/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/degreeProgress.jsp +++ b/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/degreeProgress.jsp @@ -1,9 +1,7 @@ -"> - + + @@ -11,6 +9,7 @@
+ +

Credits and GPA

Overall GPA
@@ -160,4 +160,8 @@
-
+ + + + +
\ No newline at end of file diff --git a/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/selectReport.jsp b/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/selectReport.jsp index 2098aef..d833156 100644 --- a/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/selectReport.jsp +++ b/courses-portlet-webapp/src/main/webapp/WEB-INF/jsp/degreeprogress/selectReport.jsp @@ -12,12 +12,13 @@

Degree Progress Report

-

Welcome to the degree progress reporting tool. You may either view progress - towards your current degree or create - a what-if analysis report for a new degree.

+

+ Welcome to the degree progress reporting tool. Here you can view the progress + towards your current degree. +

This evaluation is not meant to replace your adviser or the University Catalog, but it serves as a great reference tool to plan for graduation by tracking your progress towards degree completion. - Undergraduate students can find out more information here.

+ Undergraduate students can find out more information here.

\ No newline at end of file diff --git a/courses-portlet-webapp/src/main/webapp/icons/arrow_left.png b/courses-portlet-webapp/src/main/webapp/icons/arrow_left.png new file mode 100644 index 0000000..5dc6967 Binary files /dev/null and b/courses-portlet-webapp/src/main/webapp/icons/arrow_left.png differ diff --git a/pom.xml b/pom.xml index 7893f0f..7b71756 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ commons-lang commons-lang - 2.3 + 2.6 javax.portlet