MoodleWebServiceImpl.java
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.userdirectory.moodle;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Implementation of the Moodle web service client.
*/
public class MoodleWebServiceImpl implements MoodleWebService {
/**
* The logger.
*/
private static final Logger logger = LoggerFactory.getLogger(MoodleUserProviderInstance.class);
/**
* HTTP user agent when performing requests.
*/
private static final String OC_USERAGENT = "Opencast";
/**
* The URL of the Moodle instance.
*/
private URI url;
/**
* The token used to call Moodle REST webservices.
*/
private String token;
/**
* Constructs a new Moodle web service client.
*
* @param url URL of the Moodle instance
* @param token Web service token
*/
public MoodleWebServiceImpl(URI url, String token) {
this.url = url;
this.token = token;
}
/**
* {@inheritDoc}
*/
@Override
public List<MoodleUser> coreUserGetUsersByField(CoreUserGetUserByFieldFilters filter, List<String> values)
throws URISyntaxException, IOException, MoodleWebServiceException, ParseException {
logger.debug("coreUserGetUsersByField(({}, {}))", filter, values);
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("field", filter.toString()));
for (int i = 0; i < values.size(); ++i) {
params.add(new BasicNameValuePair("values[" + i + "]", values.get(i)));
}
Object resp = executeMoodleRequest(MOODLE_FUNCTION_CORE_USER_GET_USERS_BY_FIELD, params);
// Parse response
if (resp == null || !(resp instanceof JSONArray)) {
throw new MoodleWebServiceException("Moodle responded in unexpected format");
}
JSONArray respArray = (JSONArray) resp;
List<MoodleUser> users = new ArrayList<>(respArray.size());
for (Object userObj : respArray) {
if (!(userObj instanceof JSONObject)) {
throw new MoodleWebServiceException("Moodle responded in unexpected format");
}
JSONObject userJsonObj = (JSONObject) userObj;
MoodleUser user = new MoodleUser();
if (userJsonObj.containsKey("id")) {
user.setId(userJsonObj.get("id").toString());
}
if (userJsonObj.containsKey("username")) {
user.setUsername(userJsonObj.get("username").toString());
}
if (userJsonObj.containsKey("fullname")) {
user.setFullname(userJsonObj.get("fullname").toString());
}
if (userJsonObj.containsKey("idnumber")) {
user.setIdnumber(userJsonObj.get("idnumber").toString());
}
if (userJsonObj.containsKey("email")) {
user.setEmail(userJsonObj.get("email").toString());
}
if (userJsonObj.containsKey("auth")) {
user.setAuth(userJsonObj.get("auth").toString());
}
users.add(user);
}
return users;
}
/**
* {@inheritDoc}
*
* @see org.opencastproject.userdirectory.moodle.MoodleWebService#toolOpencastGetCoursesForInstructor(String)
*/
@Override
public List<String> toolOpencastGetCoursesForInstructor(String username)
throws URISyntaxException, IOException, MoodleWebServiceException, ParseException {
logger.debug("toolOpencastGetCoursesForInstructor({})", username);
List<NameValuePair> params = Collections
.singletonList((NameValuePair) new BasicNameValuePair("username", username));
return parseIdList(executeMoodleRequest(MOODLE_FUNCTION_TOOL_OPENCAST_GET_COURSES_FOR_INSTRUCTOR, params));
}
/**
* {@inheritDoc}
*
* @see org.opencastproject.userdirectory.moodle.MoodleWebService#toolOpencastGetCoursesForLearner(String)
*/
@Override
public List<String> toolOpencastGetCoursesForLearner(String username)
throws URISyntaxException, IOException, MoodleWebServiceException, ParseException {
logger.debug("toolOpencastGetCoursesForLearner({})", username);
List<NameValuePair> params = Collections
.singletonList((NameValuePair) new BasicNameValuePair("username", username));
return parseIdList(executeMoodleRequest(MOODLE_FUNCTION_TOOL_OPENCAST_GET_COURSES_FOR_LEARNER, params));
}
@Override
public List<String> toolOpencastGetGroupsForLearner(String username)
throws URISyntaxException, IOException, MoodleWebServiceException, ParseException {
logger.debug("toolOpencastGetGroupsForLearner({})", username);
List<NameValuePair> params = Collections
.singletonList((NameValuePair) new BasicNameValuePair("username", username));
return parseIdList(executeMoodleRequest(MOODLE_FUNCTION_TOOL_OPENCAST_GET_GROUPS_FOR_LEARNER, params));
}
/**
* {@inheritDoc}
*
* @see org.opencastproject.userdirectory.moodle.MoodleWebService#getURL()
*/
@Override
public String getURL() {
return url.toString();
}
/**
* Parses the returned Moodle response for a list of IDs.
*
* @param resp The Moodle response. It should be of type {@link JSONArray}.
* @return A list of Moodle IDs.
* @throws MoodleWebServiceException If the parsing failed because the response format was unexpected.
*/
private List<String> parseIdList(Object resp) throws MoodleWebServiceException {
if (resp == null) {
return new LinkedList<>();
}
if (!(resp instanceof JSONArray)) {
throw new MoodleWebServiceException("Moodle responded in unexpected format");
}
JSONArray respArray = (JSONArray) resp;
List<String> ids = new ArrayList<>(respArray.size());
for (Object courseObj : respArray) {
if (!(courseObj instanceof JSONObject) || ((JSONObject) courseObj).get("id") == null) {
throw new MoodleWebServiceException("Moodle responded in unexpected format");
}
ids.add(((JSONObject) courseObj).get("id").toString());
}
return ids;
}
/**
* Executes a Moodle webservice request.
*
* @param function The function to execute.
* @param params Additional parameters to pass.
* @return A JSON object, array, String, Number, Boolean, or null.
* @throws URISyntaxException In case the URL cannot be constructed.
* @throws IOException In case of an IO error.
* @throws MoodleWebServiceException In case Moodle returns an error.
* @throws ParseException In case the Moodle response cannot be parsed.
*/
private Object executeMoodleRequest(String function, List<NameValuePair> params)
throws URISyntaxException, IOException, MoodleWebServiceException, ParseException {
// Build URL
URIBuilder url = new URIBuilder(this.url);
url.addParameters(params);
url.addParameter("wstoken", token);
url.addParameter("wsfunction", function);
url.addParameter("moodlewsrestformat", "json");
// Execute request
HttpGet get = new HttpGet(url.build());
get.setHeader("User-Agent", OC_USERAGENT);
try (CloseableHttpClient client = HttpClients.createDefault()) {
try (CloseableHttpResponse resp = client.execute(get)) {
// Parse response
BufferedReader reader = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
JSONParser parser = new JSONParser();
Object obj = parser.parse(reader);
// Check for errors
if (obj instanceof JSONObject) {
JSONObject jObj = (JSONObject) obj;
if (jObj.containsKey("exception") || jObj.containsKey("errorcode")) {
throw new MoodleWebServiceException("Moodle returned an error: " + jObj.toJSONString());
}
}
return obj;
}
}
}
}