/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo 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 the following location:
*
* 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.courses.dao.xml;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.PortletRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portlet.courses.dao.ICacheableCoursesDao;
import org.jasig.portlet.courses.dao.xml.HttpClientCoursesDaoImpl.CoursesCacheKey;
import org.jasig.portlet.courses.model.xml.TermList;
import org.jasig.portlet.courses.model.xml.personal.CoursesByTerm;
import org.jasig.portlet.courses.model.xml.personal.TermsAndCourses;
import org.jasig.portlet.courses.util.IParameterEvaluator;
import org.jasig.portlet.courses.util.TermCodeParameterEvaluator;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestOperations;
/**
* HttpClientCoursesDaoImpl retrieves courses from a Basic Authentication
* protected XML feed.
*
* @author Jen Bourey, jennifer.bourey@gmail.com
* @version $Revision$
*/
public class HttpClientCoursesDaoImpl implements ICacheableCoursesDao<CoursesCacheKey, CoursesCacheKey> {
public static final String PROPERTY_KEY_TERMCODE = "#TERMCODE#";
private final Log log = LogFactory.getLog(getClass());
private String termsUrlFormat = null;
private String coursesUrlFormat = null;
private Map<String,IParameterEvaluator> urlParamEvaluators = new HashMap<String,IParameterEvaluator>();
private IParameterEvaluator usernameEvaluator;
private IParameterEvaluator passwordEvaluator;
private RestOperations restTemplate;
public void setTermsUrlFormat(String urlFormat) {
this.termsUrlFormat = urlFormat;
}
public void setCoursesUrlFormat(String urlFormat) {
this.coursesUrlFormat = urlFormat;
}
public void setUrlParams(Map<String,IParameterEvaluator> params) {
this.urlParamEvaluators = params;
}
public void setUsernameEvaluator(IParameterEvaluator usernameEvaluator) {
this.usernameEvaluator = usernameEvaluator;
}
public void setPasswordEvaluator(IParameterEvaluator passwordEvaluator) {
this.passwordEvaluator = passwordEvaluator;
}
public void setRestTemplate(RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public CoursesCacheKey getTermListKey(PortletRequest request) {
final String username = usernameEvaluator.evaluate(request);
final String password = passwordEvaluator.evaluate(request);
final Map<String, String> params = createParameters(request, urlParamEvaluators);
return new CoursesCacheKey(username, password.toCharArray(), params);
}
@Override
public TermList getTermList(CoursesCacheKey key) {
final TermsAndCourses termsAndCourses = getTermsAndCourses(key, termsUrlFormat);
return termsAndCourses.getTermList();
}
@Override
public CoursesCacheKey getCoursesByTermKey(PortletRequest request, String termCode, TermList termList) {
final String username = usernameEvaluator.evaluate(request);
final String password = passwordEvaluator.evaluate(request);
final Map<String, String> params = createParameters(request, urlParamEvaluators);
return new CoursesCacheKey(username, password.toCharArray(), params, termCode);
}
@Override
public CoursesByTerm getCoursesByTerm(CoursesCacheKey key) {
final TermsAndCourses termsAndCourses = getTermsAndCourses(key, coursesUrlFormat);
return termsAndCourses.getCoursesByTerm(key.getTermCode());
}
protected TermsAndCourses getTermsAndCourses(CoursesCacheKey key, String url) {
Map<String,String> params = key.getParams();
if (log.isDebugEnabled()) {
log.debug("Invoking uri '" + url
+ "' with the following parameters: "
+ params.toString());
}
HttpEntity<?> requestEntity = getRequestEntity(key);
HttpEntity<TermsAndCourses> response = restTemplate.exchange(
url, HttpMethod.GET, requestEntity,
TermsAndCourses.class, params);
final TermsAndCourses termsAndCourses = response.getBody();
return termsAndCourses;
}
/**
* Get a request entity prepared for basic authentication.
*/
protected HttpEntity<?> getRequestEntity(CoursesCacheKey credentials) {
final String username = credentials.getUsername();
final char[] password = credentials.getPassword();
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(new String(password));
String encodedAuthString = new Base64().encodeToString(authString.getBytes());
requestHeaders.set("Authorization", "Basic ".concat(encodedAuthString));
HttpEntity<?> rslt = new HttpEntity<Object>(requestHeaders);
return rslt;
}
protected void setTermCodeRequestAttribute(PortletRequest request, String termCode) {
for(IParameterEvaluator evaluator : urlParamEvaluators.values()) {
if(evaluator instanceof TermCodeParameterEvaluator) {
request.setAttribute(((TermCodeParameterEvaluator)evaluator).getAttributeKey(),termCode);
return;
}
}
}
protected Map<String,String> createParameters(PortletRequest request, Map<String,IParameterEvaluator> params) {
Map<String,String> result = new HashMap<String,String>();
for(String key : params.keySet()) {
result.put(key,params.get(key).evaluate(request));
}
return result;
}
public static final class CoursesCacheKey implements Serializable {
private static final long serialVersionUID = 1L;
private final SecureRequestCredentials credentials;
private final Map<String, String> params;
private final String termCode;
private CoursesCacheKey(String username, char[] password, Map<String, String> params) {
this(username, password, params, null);
}
private CoursesCacheKey(String username, char[] password, Map<String, String> params, String termCode) {
this.credentials = new SecureRequestCredentials(username, password);
this.params = params;
this.termCode = termCode;
}
private String getUsername() {
return credentials.getUsername();
}
private char[] getPassword() {
return credentials.getPassword();
}
private Map<String, String> getParams() {
return params;
}
public String getTermCode() {
return termCode;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
result = prime * result + ((params == null) ? 0 : params.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CoursesCacheKey other = (CoursesCacheKey) obj;
if (credentials == null) {
if (other.credentials != null)
return false;
}
else if (!credentials.equals(other.credentials))
return false;
if (params == null) {
if (other.params != null)
return false;
}
else if (!params.equals(other.params))
return false;
return true;
}
@Override
public String toString() {
return "CoursesCacheKey [credentials=" + credentials + ", params=" + params + "]";
}
}
}