Index: lams_build/common.properties =================================================================== diff -u -r9737423f5e8e1d83315339bc0fe8330946845759 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_build/common.properties (.../common.properties) (revision 9737423f5e8e1d83315339bc0fe8330946845759) +++ lams_build/common.properties (.../common.properties) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -18,7 +18,7 @@ # http://www.gnu.org/licenses/gpl.txt # put into EAR MANIFEST.MF file -project.version=3.0 +project.version=3.1 # is HTTPS in use? if so, set it to true, so JSESSIONID cookie is secured secure.cookie=false Index: lams_build/lib/lams/lams-gradebook.jar =================================================================== diff -u -rc3db10fe6622ab0bb74375275547f75608241c65 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 Binary files differ Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r5bcac6182758458fcd994b9bda8c6620a9493265 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 Binary files differ Index: lams_build/unix.properties =================================================================== diff -u -r9737423f5e8e1d83315339bc0fe8330946845759 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_build/unix.properties (.../unix.properties) (revision 9737423f5e8e1d83315339bc0fe8330946845759) +++ lams_build/unix.properties (.../unix.properties) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -33,7 +33,7 @@ contentrepository.base=/var/opt/lams #JBoss deploy directory (Unix) -server.home=/usr/local/wildfly-8.2/ +server.home=/usr/local/wildfly-10.1/ #Sass executable. sass_exec_file=/usr/local/bin/sass Index: lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java =================================================================== diff -u -r5bcac6182758458fcd994b9bda8c6620a9493265 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 5bcac6182758458fcd994b9bda8c6620a9493265) +++ lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -37,9 +37,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.index.IndexLinkBean; import org.lamsfoundation.lams.integration.service.IIntegrationService; import org.lamsfoundation.lams.integration.service.IntegrationService; @@ -59,6 +56,10 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Fei Yang @@ -77,7 +78,7 @@ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - setHeaderLinks(request); + IndexAction.setHeaderLinks(request); setAdminLinks(request); // check if this is user's first login; some action (like displaying a dialog for disabling tutorials) can be @@ -114,7 +115,7 @@ return mapping.findForward("editprofile"); } else if (StringUtils.equals(method, "password")) { return mapping.findForward("password"); - } else if (StringUtils.equals(method, "portrait")) { + } else if (StringUtils.equals(method, "portrait")) { return mapping.findForward("portrait"); } else if (StringUtils.equals(method, "lessons")) { return mapping.findForward("lessons"); @@ -135,23 +136,24 @@ return null; } } - + // only show the growl warning the first time after a user has logged in & if turned on in configuration Boolean tzWarning = Configuration.getAsBoolean(ConfigurationKeys.SHOW_TIMEZONE_WARNING); request.setAttribute("showTimezoneWarning", tzWarning); request.setAttribute("showTimezoneWarningPopup", false); - if ( tzWarning ) { + if (tzWarning) { Boolean ssWarningShown = (Boolean) ss.getAttribute("timezoneWarningShown"); - if ( ! Boolean.TRUE.equals(ssWarningShown) ) { + if (!Boolean.TRUE.equals(ssWarningShown)) { ss.setAttribute("timezoneWarningShown", Boolean.TRUE); request.setAttribute("showTimezoneWarningPopup", true); } } - - List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userDTO.getUserID()); + + List favoriteOrganisations = userManagementService + .getFavoriteOrganisationsByUser(userDTO.getUserID()); request.setAttribute("favoriteOrganisations", favoriteOrganisations); request.setAttribute("activeOrgId", user.getLastVisitedOrganisationId()); - + boolean isSysadmin = request.isUserInRole(Role.SYSADMIN); int userCoursesCount = userManagementService.getCountActiveCoursesByUser(userDTO.getUserID(), isSysadmin, null); request.setAttribute("isCourseSearchOn", userCoursesCount > 10); @@ -160,9 +162,9 @@ } private static void setHeaderLinks(HttpServletRequest request) { - List headerLinks = new ArrayList(); + List headerLinks = new ArrayList<>(); if (request.isUserInRole(Role.AUTHOR)) { - if (isPedagogicalPlannerAvailable()) { + if (IndexAction.isPedagogicalPlannerAvailable()) { headerLinks.add(new IndexLinkBean("index.planner", "javascript:openPedagogicalPlanner()")); } headerLinks.add(new IndexLinkBean("index.author", "javascript:showAuthoringDialog()")); @@ -178,7 +180,7 @@ } private void setAdminLinks(HttpServletRequest request) { - List adminLinks = new ArrayList(); + List adminLinks = new ArrayList<>(); if (request.isUserInRole(Role.SYSADMIN) || request.isUserInRole(Role.GROUP_ADMIN) || request.isUserInRole(Role.GROUP_MANAGER)) { adminLinks.add(new IndexLinkBean("index.courseman", "javascript:openOrgManagement(" @@ -194,10 +196,10 @@ * Returns list of organisations for user. Used by offcanvas tablesorter on main.jsp. */ public ActionForward getOrgs(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); User loggedInUser = getUserManagementService().getUserByLogin(request.getRemoteUser()); - + Integer userId = loggedInUser.getUserId(); boolean isSysadmin = request.isUserInRole(Role.SYSADMIN); String searchString = WebUtil.readStrParam(request, "fcol[1]", true); @@ -218,27 +220,28 @@ // // } - List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, searchString); + List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, + searchString); - JSONObject responcedata = new JSONObject(); - responcedata.put("total_rows", userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total_rows", + userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); for (OrganisationDTO orgDto : orgDtos) { - - JSONObject responseRow = new JSONObject(); + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); responseRow.put("id", orgDto.getOrganisationID()); String orgName = orgDto.getName() == null ? "" : orgDto.getName(); responseRow.put("name", HtmlUtils.htmlEscape(orgName)); - rows.put(responseRow); + rows.add(responseRow); } - responcedata.put("rows", rows); + responcedata.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responcedata.toString())); return null; } - + /** * Toggles whether organisation is marked as favorite. */ @@ -254,18 +257,18 @@ List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userId); request.setAttribute("favoriteOrganisations", favoriteOrganisations); - + String activeOrgId = request.getParameter("activeOrgId"); request.setAttribute("activeOrgId", activeOrgId); return mapping.findForward("favoriteOrganisations"); } - + /** * Saves to DB last visited organisation. It's required for displaying some org on main.jsp next time user logs in. */ - public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException { + public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, + HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); Integer lastVisitedOrganisationId = WebUtil.readIntParam(request, "orgId", false); @@ -278,13 +281,13 @@ return null; } - + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO learner = (UserDTO) ss.getAttribute(AttributeNames.USER); return learner != null ? learner.getUserID() : null; } - + private IIntegrationService getIntegrationService() { if (integrationService == null) { integrationService = (IntegrationService) WebApplicationContextUtils Index: lams_central/src/java/org/lamsfoundation/lams/web/RatingServlet.java =================================================================== diff -u -r7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_central/src/java/org/lamsfoundation/lams/web/RatingServlet.java (.../RatingServlet.java) (revision 7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778) +++ lams_central/src/java/org/lamsfoundation/lams/web/RatingServlet.java (.../RatingServlet.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -20,7 +20,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.web; import java.io.IOException; @@ -37,8 +36,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.rating.dto.ItemRatingCriteriaDTO; import org.lamsfoundation.lams.rating.model.LearnerItemRatingCriteria; import org.lamsfoundation.lams.rating.model.RatingCriteria; @@ -51,6 +48,9 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * Stores rating. * @@ -67,7 +67,7 @@ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - JSONObject JSONObject = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); getRatingService(); String objectId = WebUtil.readStrParam(request, "idBox"); @@ -78,83 +78,82 @@ UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER); Integer userId = user.getUserID(); - + // get rating value as either float or comment String - try { - boolean doSave = true; - boolean ratingLimitsByCriteria = WebUtil.readBooleanParam(request, "ratingLimitsByCriteria", false); + boolean doSave = true; + boolean ratingLimitsByCriteria = WebUtil.readBooleanParam(request, "ratingLimitsByCriteria", false); - Long maxRatingsForItem = WebUtil.readLongParam(request, "maxRatingsForItem", true); + Long maxRatingsForItem = WebUtil.readLongParam(request, "maxRatingsForItem", true); // log.debug("RatingServlet: Check Max rates for an item reached. Item " + itemId + " criteria id " // + criteria.getRatingCriteriaId() + " maxRatingsForItem " + maxRatingsForItem); - if (maxRatingsForItem != null && maxRatingsForItem > 0) { - if (!ToolActivityRatingCriteria.class.isInstance(criteria)) { - log.error( - "Unable to enforce max ratings on a non ToolActivityRatingCritera class. Need tool content id to do the db lookup!"); - } else { - ToolActivityRatingCriteria toolCriteria = (ToolActivityRatingCriteria) criteria; - List itemIds = new LinkedList(); - itemIds.add(itemId); - Map itemIdToRatedUsersCountMap = ratingLimitsByCriteria ? - ratingService.countUsersRatedEachItemByCriteria(ratingCriteriaId, toolSessionId, itemIds, userId) : - ratingService.countUsersRatedEachItem(toolCriteria.getToolContentId(), toolSessionId, itemIds, userId); + if (maxRatingsForItem != null && maxRatingsForItem > 0) { + if (!ToolActivityRatingCriteria.class.isInstance(criteria)) { + log.error( + "Unable to enforce max ratings on a non ToolActivityRatingCritera class. Need tool content id to do the db lookup!"); + } else { + ToolActivityRatingCriteria toolCriteria = (ToolActivityRatingCriteria) criteria; + List itemIds = new LinkedList<>(); + itemIds.add(itemId); + Map itemIdToRatedUsersCountMap = ratingLimitsByCriteria + ? ratingService.countUsersRatedEachItemByCriteria(ratingCriteriaId, toolSessionId, itemIds, + userId) + : ratingService.countUsersRatedEachItem(toolCriteria.getToolContentId(), toolSessionId, itemIds, + userId); - Long currentRatings = itemIdToRatedUsersCountMap.get(itemId); - if (currentRatings != null && maxRatingsForItem.compareTo(currentRatings) <= 0) { - JSONObject.put("error", true); - JSONObject.put("message", - "Maximum number of ratings for this item has been reached. No more may be saved."); + Long currentRatings = itemIdToRatedUsersCountMap.get(itemId); + if (currentRatings != null && maxRatingsForItem.compareTo(currentRatings) <= 0) { + responseJSON.put("error", true); + responseJSON.put("message", + "Maximum number of ratings for this item has been reached. No more may be saved."); // log.debug("RatingServlet: Max rates for an item reached. Item " + itemId + " criteria id " // + criteria.getRatingCriteriaId() + " count " + currentRatings); - doSave = false; - } + doSave = false; } } + } - if (doSave) { - if (criteria.isCommentsEnabled()) { - // can have but do not have to have comment - String comment = WebUtil.readStrParam(request, "comment", true); - if ( comment != null ) { - ratingService.commentItem(criteria, toolSessionId, userId, itemId, comment); - JSONObject.put("comment", StringEscapeUtils.escapeCsv(comment)); - } - } - - String floatString = request.getParameter("rate"); - if ( floatString != null && floatString.length() > 0 ) { - float rating = Float.parseFloat(request.getParameter("rate")); + if (doSave) { + if (criteria.isCommentsEnabled()) { + // can have but do not have to have comment + String comment = WebUtil.readStrParam(request, "comment", true); + if (comment != null) { + ratingService.commentItem(criteria, toolSessionId, userId, itemId, comment); + responseJSON.put("comment", StringEscapeUtils.escapeCsv(comment)); + } + } - ItemRatingCriteriaDTO averageRatingDTO = ratingService.rateItem(criteria, toolSessionId, userId, itemId, rating); + String floatString = request.getParameter("rate"); + if (floatString != null && floatString.length() > 0) { + float rating = Float.parseFloat(request.getParameter("rate")); - NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); - numberFormat.setMaximumFractionDigits(1); - JSONObject.put("userRating", averageRatingDTO.getUserRating()); - JSONObject.put("averageRating", averageRatingDTO.getAverageRating()); - JSONObject.put("numberOfVotes", averageRatingDTO.getNumberOfVotes()); - } + ItemRatingCriteriaDTO averageRatingDTO = ratingService.rateItem(criteria, toolSessionId, userId, itemId, + rating); - boolean hasRatingLimits = WebUtil.readBooleanParam(request, "hasRatingLimits", false); + NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); + numberFormat.setMaximumFractionDigits(1); + responseJSON.put("userRating", averageRatingDTO.getUserRating()); + responseJSON.put("averageRating", averageRatingDTO.getAverageRating()); + responseJSON.put("numberOfVotes", averageRatingDTO.getNumberOfVotes()); + } - // refresh countRatedItems in case there is rating limit set - // Preview tool counts rated items on a criteria basis, other tools on a set of criteria basis! - if (hasRatingLimits) { - // as long as this can be requested only for LEARNER_ITEM_CRITERIA_TYPE type, cast Criteria - LearnerItemRatingCriteria learnerItemRatingCriteria = (LearnerItemRatingCriteria) criteria; - Long toolContentId = learnerItemRatingCriteria.getToolContentId(); + boolean hasRatingLimits = WebUtil.readBooleanParam(request, "hasRatingLimits", false); - int countRatedItems = ratingLimitsByCriteria ? - ratingService.getCountItemsRatedByUserByCriteria(ratingCriteriaId, userId) : - ratingService.getCountItemsRatedByUser(toolContentId, userId); - JSONObject.put("countRatedItems", countRatedItems); - } + // refresh countRatedItems in case there is rating limit set + // Preview tool counts rated items on a criteria basis, other tools on a set of criteria basis! + if (hasRatingLimits) { + // as long as this can be requested only for LEARNER_ITEM_CRITERIA_TYPE type, cast Criteria + LearnerItemRatingCriteria learnerItemRatingCriteria = (LearnerItemRatingCriteria) criteria; + Long toolContentId = learnerItemRatingCriteria.getToolContentId(); + + int countRatedItems = ratingLimitsByCriteria + ? ratingService.getCountItemsRatedByUserByCriteria(ratingCriteriaId, userId) + : ratingService.getCountItemsRatedByUser(toolContentId, userId); + responseJSON.put("countRatedItems", countRatedItems); } - } catch (JSONException e) { - throw new ServletException(e); } response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(JSONObject); + response.getWriter().print(responseJSON); } @Override Index: lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java =================================================================== diff -u -r7d42c3a0d64c5e7a30a7fd895ab73aa4ad109074 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision 7d42c3a0d64c5e7a30a7fd895ab73aa4ad109074) +++ lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -22,8 +22,6 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionRedirect; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.imsglobal.lti.BasicLTIConstants; import org.imsglobal.lti.BasicLTIUtil; import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; @@ -58,11 +56,14 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + import net.oauth.OAuth; /** * Shows either addLesson.jsp or learnerMonitor.jsp pages. - * + * * @author Andrey Balan */ public class LtiAction extends LamsDispatchAction { @@ -80,15 +81,16 @@ * Single entry point to LAMS LTI processing mechanism. It determines here whether to show author or learnerMonitor * pages */ + @Override public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, - RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, + UserInfoFetchException, UserInfoValidationException { initServices(); String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); String tcGradebookId = request.getParameter(BasicLTIConstants.LIS_RESULT_SOURCEDID); String extUserId = request.getParameter(BasicLTIConstants.USER_ID); - + ExtServerLessonMap lesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); //support for ContentItemSelectionRequest. If lesson was created during such request, update its ExtServerLesson's resourceLinkId for the first time boolean isContentItemSelection = WebUtil.readBooleanParam(request, "custom_isContentItemSelection", false); @@ -98,7 +100,7 @@ lesson.setResourceLinkId(resourceLinkId); userManagementService.save(lesson); } - + //update lessonFinishCallbackUrl. We store it one time during the very first call to LAMS and it stays the same all the time afterwards String lessonFinishCallbackUrl = request.getParameter(BasicLTIConstants.LIS_OUTCOME_SERVICE_URL); ExtServer extServer = integrationService.getExtServer(consumerKey); @@ -118,13 +120,13 @@ return mapping.findForward("error"); } - //determine whether to show author or learnerMonitor pages + //determine whether to show author or learnerMonitor pages if (lesson == null) { return addLesson(mapping, form, request, response); - + } else { - //as per LTI spec we need to update tool consumer's gradebook id on every LTI call + //as per LTI spec we need to update tool consumer's gradebook id on every LTI call ExtUserUseridMap extUserMap = integrationService.getExistingExtUserUseridMap(extServer, extUserId); extUserMap.setTcGradebookId(tcGradebookId); userManagementService.save(extUserMap); @@ -139,8 +141,8 @@ * design and start a lesson. */ private ActionForward addLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, - RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, + UserInfoFetchException, UserInfoValidationException { initServices(); Integer userId = getUser().getUserID(); String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); @@ -167,7 +169,7 @@ request.setAttribute(BasicLTIConstants.CONTEXT_ID, contextId); request.setAttribute(CentralConstants.PARAM_TITLE, resourceLinkTitle); request.setAttribute(CentralConstants.PARAM_DESC, resourceLinkDescription); - + //support for ContentItemSelectionRequest String ltiMessageType = request.getParameter(BasicLTIConstants.LTI_MESSAGE_TYPE); if (LtiUtils.LTI_MESSAGE_TYPE_CONTENTITEMSELECTIONREQUEST.equals(ltiMessageType)) { @@ -177,11 +179,11 @@ "ContentItemSelectionRequest is missing content_item_return_url parameter"); return null; } - + request.setAttribute(BasicLTIConstants.LTI_MESSAGE_TYPE, ltiMessageType); request.setAttribute(LtiUtils.CONTENT_ITEM_RETURN_URL, contentItemReturnUrl); request.setAttribute("title", request.getParameter("title")); - request.setAttribute("desc", request.getParameter("text").replaceAll("\\<[^>]*>","")); + request.setAttribute("desc", request.getParameter("text").replaceAll("\\<[^>]*>", "")); request.setAttribute("data", request.getParameter("data")); } @@ -192,8 +194,8 @@ * Starts a lesson. Then prompts to learnerMonitor page or autosubmitForm (in case of ContentItemSelectionRequest). */ public ActionForward startLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, - RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, + UserInfoValidationException, UserInfoFetchException { initServices(); Integer userId = getUser().getUserID(); User user = getRealUser(getUser()); @@ -206,7 +208,7 @@ String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); Integer organisationId = new Integer(WebUtil.readIntParam(request, CentralConstants.ATTR_COURSE_ID)); boolean enableLessonIntro = WebUtil.readBooleanParam(request, "enableLessonIntro", false); - + //only monitors are allowed to create lesson if (!securityService.isGroupMonitor(organisationId, userId, "add lesson", false)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); @@ -218,8 +220,8 @@ // 1. init lesson Lesson lesson = monitoringService.initializeLesson(title, desc, new Long(ldIdStr), - organisation.getOrganisationId(), user.getUserId(), null, false, enableLessonIntro, false, false, - true, true, false, false, true, null, null); + organisation.getOrganisationId(), user.getUserId(), null, false, enableLessonIntro, false, false, true, + true, false, false, true, null, null); // 2. create lessonClass for lesson List staffList = new LinkedList(); staffList.add(user); @@ -234,13 +236,13 @@ monitoringService.startLesson(lesson.getLessonId(), user.getUserId()); // store information which extServer has started the lesson integrationService.createExtServerLessonMap(lesson.getLessonId(), resourceLinkId, extServer); - + //support for ContentItemSelectionRequest String ltiMessageType = request.getParameter(BasicLTIConstants.LTI_MESSAGE_TYPE); String contentItemReturnUrl = request.getParameter(LtiUtils.CONTENT_ITEM_RETURN_URL); if (LtiUtils.LTI_MESSAGE_TYPE_CONTENTITEMSELECTIONREQUEST.equals(ltiMessageType)) { String opaqueTCData = request.getParameter("data"); - + // Get the post data for the placement String returnValues = postLaunchHTML(extServer, lesson, contentItemReturnUrl, opaqueTCData); @@ -262,8 +264,8 @@ out.println("\n"); return null; - - //regular BasicLTI request + + //regular BasicLTI request } else { //set roles to contain monitor so that the user can see monitor link ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learnerMonitorRedirect")); @@ -273,18 +275,19 @@ return redirect; } } - + /** - * Return HTML form to be posted to TC + * Return HTML form to be posted to TC */ - private String postLaunchHTML(ExtServer extServer, Lesson lesson, String contentItemReturnUrl, String opaqueTCData) throws JSONException, UnsupportedEncodingException { + private String postLaunchHTML(ExtServer extServer, Lesson lesson, String contentItemReturnUrl, String opaqueTCData) + throws UnsupportedEncodingException { String key = extServer.getServerid(); String secret = extServer.getServerkey(); - + //required parameters // // -// +// // // // @@ -300,16 +303,16 @@ if (StringUtils.isNotBlank(opaqueTCData)) { properties.put("data", opaqueTCData); } - + properties.put("lti_msg", "Information about LAMS lesson has been imported successfully."); properties.put(OAuth.OAUTH_VERSION, OAuth.VERSION_1_0); properties.put("oauth_callback", "about:blank"); properties.put(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.HMAC_SHA1); - + //contentItem Json // { -// "@context" : "http://purl.imsglobal.org/ctx/lti/v1/ContentItem", -// "@graph" : [ +// "@context" : "http://purl.imsglobal.org/ctx/lti/v1/ContentItem", +// "@graph" : [ // { // "@type" : "LtiLinkItem", // "mediaType" : "application/vnd.ims.lti.v1.ltilink", @@ -327,18 +330,18 @@ // } // ] // } - JSONObject contentItemJSON = new JSONObject(); + ObjectNode contentItemJSON = JsonNodeFactory.instance.objectNode(); contentItemJSON.put("@type", "LtiLinkItem"); contentItemJSON.put("mediaType", "application/vnd.ims.lti.v1.ltilink"); contentItemJSON.put("title", lesson.getLessonName()); contentItemJSON.put("text", lesson.getLessonDescription()); - JSONObject customJSON = new JSONObject(); + ObjectNode customJSON = JsonNodeFactory.instance.objectNode(); customJSON.put("lessonId", lesson.getLessonId().toString()); customJSON.put("isContentItemSelection", "true"); - contentItemJSON.put("custom", customJSON); + contentItemJSON.set("custom", customJSON); - JSONObject responseJSON = new JSONObject(); - responseJSON.append("@graph", contentItemJSON); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.set("@graph", contentItemJSON); responseJSON.put("@context", "http://purl.imsglobal.org/ctx/lti/v1/ContentItem"); String content_items = URLEncoder.encode(responseJSON.toString(), "UTF-8"); @@ -356,14 +359,14 @@ /** * Once lesson was created, start showing learnerMonitor page to everybody regardless of his role. */ - public ActionForward learnerMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, - RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { + public ActionForward learnerMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, + UserInfoValidationException, UserInfoFetchException { initServices(); Integer userId = getUser().getUserID(); String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); - + //get orgId // String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); // ExtServer extServer = integrationService.getExtServer(consumerKey); @@ -390,7 +393,7 @@ LearnerProgressDTO learnerProgress = learnProg.getLearnerProgressData(); request.setAttribute("learnerProgressDto", learnerProgress); } - + // check if we need to create svg, png files on the server // if (lesson.isDisplayDesignImage() && lesson.getLearnerProgresses().isEmpty()) { // Long learningDesignId = lesson.getLearningDesign().getLearningDesignId(); @@ -426,7 +429,7 @@ .getRequiredWebApplicationContext(getServlet().getServletContext()) .getBean("userManagementService"); } - + if (learningDesignService == null) { learningDesignService = (ILearningDesignService) WebApplicationContextUtils .getRequiredWebApplicationContext(getServlet().getServletContext()) Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java =================================================================== diff -u -r3751037e76fe181b7413af52566405168d36f5e1 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 3751037e76fe181b7413af52566405168d36f5e1) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -43,8 +43,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONObject; import org.imsglobal.pox.IMSPOXRequest; import org.lamsfoundation.lams.gradebook.GradebookUserLesson; import org.lamsfoundation.lams.gradebook.service.IGradebookService; @@ -73,10 +71,14 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CSVUtil; import org.lamsfoundation.lams.util.HashUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.LanguageUtil; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + import oauth.signpost.exception.OAuthException; /** @@ -780,25 +782,22 @@ BufferedReader isReader = new BufferedReader(new InputStreamReader(is)); String str = isReader.readLine(); - JSONArray jsonGroups = new JSONArray(str); + ArrayNode jsonGroups = JsonUtil.readArray(str); List extGroups = new ArrayList<>(); - for (int i = 0; i < jsonGroups.length(); i++) { - JSONObject jsonGroup = jsonGroups.getJSONObject(i); + for (JsonNode jsonGroup : jsonGroups) { ExtGroupDTO group = new ExtGroupDTO(); - group.setGroupName(jsonGroup.getString("groupName")); - group.setGroupId(jsonGroup.getString("groupId")); + group.setGroupName(JsonUtil.optString(jsonGroup, "groupName")); + group.setGroupId(JsonUtil.optString(jsonGroup, "groupId")); extGroups.add(group); // in case group info is also requested - provide selected groups' ids if (extGroupIds != null && extGroupIds.length > 0) { ArrayList users = new ArrayList<>(); - JSONArray jsonUsers = jsonGroup.getJSONArray("users"); - for (int j = 0; j < jsonUsers.length(); j++) { - JSONObject jsonUser = jsonUsers.getJSONObject(j); + ArrayNode jsonUsers = JsonUtil.optArray(jsonGroup, "users"); + for (JsonNode jsonUser : jsonUsers) { + String extUsername = JsonUtil.optString(jsonUser, "userName"); - String extUsername = jsonUser.getString("userName"); - ExtUserUseridMap extUserUseridMap = getExistingExtUserUseridMap(extServer, extUsername); //create extUserUseridMap if it's not available @@ -808,7 +807,7 @@ // language>, String[] userData = new String[14]; for (int k = 1; k <= 14; k++) { - String userProperty = jsonUser.getString("" + k); + String userProperty = JsonUtil.optString(jsonUser, "" + k); userData[k - 1] = userProperty; } String salt = HashUtil.salt(); @@ -832,7 +831,7 @@ group.setUsers(users); } else { - group.setNumberUsers(jsonGroup.getInt("groupSize")); + group.setNumberUsers(JsonUtil.optInt(jsonGroup, "groupSize")); } } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r0f3e85c522449f8f4741f4bae61bd07ec57fde16 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 0f3e85c522449f8f4741f4bae61bd07ec57fde16) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -145,9 +145,10 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; -import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; + import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.security.AnyTypePermission; /** @@ -481,7 +482,7 @@ } // exporting XML - XStream designXml = new XStream(new SunUnsafeReflectionProvider()); + XStream designXml = new XStream(new StaxDriver()); designXml.addPermission(AnyTypePermission.ANY); designXml.toXML(ldDto, ldFile); ldFile.close(); @@ -554,7 +555,7 @@ Writer toolFile = new OutputStreamWriter(new FileOutputStream(toolFileName), "UTF-8"); // serialize tool xml into local file. - XStream toolXml = new XStream(new SunUnsafeReflectionProvider()); + XStream toolXml = new XStream(new StaxDriver()); toolXml.addPermission(AnyTypePermission.ANY); FileConverter fileConverter = null; if (!fileHandleClassList.isEmpty()) { @@ -923,7 +924,7 @@ String toVersion) throws ImportToolContentException { Object toolPOJO = null; // change xml to Tool POJO - XStream toolXml = new XStream(new SunUnsafeReflectionProvider()); + XStream toolXml = new XStream(new StaxDriver()); toolXml.addPermission(AnyTypePermission.ANY); FileConverter fileConverter = null; if (!fileHandleClassList.isEmpty()) { Index: lams_common/src/java/org/lamsfoundation/lams/rating/service/RatingService.java =================================================================== diff -u -r7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_common/src/java/org/lamsfoundation/lams/rating/service/RatingService.java (.../RatingService.java) (revision 7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778) +++ lams_common/src/java/org/lamsfoundation/lams/rating/service/RatingService.java (.../RatingService.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -21,8 +21,6 @@ * **************************************************************** */ - - package org.lamsfoundation.lams.rating.service; import java.math.BigInteger; @@ -39,9 +37,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.rating.RatingException; import org.lamsfoundation.lams.rating.dao.IRatingCommentDAO; import org.lamsfoundation.lams.rating.dao.IRatingCriteriaDAO; @@ -57,9 +52,15 @@ import org.lamsfoundation.lams.rating.model.RatingCriteria; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.WebUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + public class RatingService implements IRatingService { private static Logger log = Logger.getLogger(RatingService.class); @@ -93,29 +94,29 @@ public int getCountItemsRatedByUserByCriteria(final Long criteriaId, final Integer userId) { return ratingDAO.getCountItemsRatedByUserByCriteria(criteriaId, userId); } - + @Override public void removeUserCommitsByContent(final Long contentId, final Integer userId) { List ratings = ratingDAO.getRatingsByUser(contentId, userId); for (Rating rating : ratings) { ratingDAO.delete(rating); } - + List comments = ratingCommentDAO.getCommentsByContentAndUser(contentId, userId); for (RatingComment comment : comments) { ratingDAO.delete(comment); } } - + @Override - public Map countUsersRatedEachItem(final Long contentId, final Long toolSessionId, final Collection itemIds, - Integer excludeUserId) { + public Map countUsersRatedEachItem(final Long contentId, final Long toolSessionId, + final Collection itemIds, Integer excludeUserId) { return ratingDAO.countUsersRatedEachItem(contentId, toolSessionId, itemIds, excludeUserId); } @Override - public Map countUsersRatedEachItemByCriteria(final Long criteriaId, final Long toolSessionId, final Collection itemIds, - Integer excludeUserId) { + public Map countUsersRatedEachItemByCriteria(final Long criteriaId, final Long toolSessionId, + final Collection itemIds, Integer excludeUserId) { return ratingDAO.countUsersRatedEachItemByCriteria(criteriaId, toolSessionId, itemIds, excludeUserId); } @@ -125,8 +126,8 @@ } @Override - public ItemRatingCriteriaDTO rateItem(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, Long itemId, - float ratingFloat) { + public ItemRatingCriteriaDTO rateItem(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, + Long itemId, float ratingFloat) { Long ratingCriteriaId = ratingCriteria.getRatingCriteriaId(); Rating rating = ratingDAO.getRating(ratingCriteriaId, userId, itemId); @@ -159,25 +160,26 @@ } @Override - public int rateItems(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, Map newRatings) { + public int rateItems(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, + Map newRatings) { User learner = (User) userManagementService.findById(User.class, userId); int numRatings = 0; - + List dbRatings = ratingDAO.getRatingsByUserCriteria(ratingCriteria.getRatingCriteriaId(), userId); - for ( Rating rating: dbRatings ) { + for (Rating rating : dbRatings) { Long itemId = rating.getItemId(); Float newRating = newRatings.get(itemId); - if ( newRating != null ) { + if (newRating != null) { rating.setRating(newRating); newRatings.remove(itemId); numRatings++; ratingDAO.saveOrUpdate(rating); } else { - rating.setRating((Float)null); + rating.setRating((Float) null); } } - for ( Map.Entry entry : newRatings.entrySet() ) { + for (Map.Entry entry : newRatings.entrySet()) { Rating rating = new Rating(); rating.setItemId(entry.getKey()); rating.setLearner(learner); @@ -195,12 +197,13 @@ ratingDAO.saveOrUpdate(rating); numRatings++; } - + return numRatings; } - + @Override - public void commentItem(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, Long itemId, String comment) { + public void commentItem(RatingCriteria ratingCriteria, Long toolSessionId, Integer userId, Long itemId, + String comment) { RatingComment ratingComment = ratingCommentDAO.getComment(ratingCriteria.getRatingCriteriaId(), userId, itemId); // persist MessageRating changes in DB @@ -224,8 +227,8 @@ boolean isCommentsByOtherUsersRequired, Long userId) { // fail safe - if there are no items, don't try to look anything up! LDEV-4094 - if ( itemIds == null || itemIds.isEmpty() ) { - return new LinkedList(); + if (itemIds == null || itemIds.isEmpty()) { + return new LinkedList<>(); } //initial preparations @@ -236,8 +239,8 @@ Long singleItemId = isSingleItem ? itemIds.iterator().next() : null; //handle comments criteria - List itemDtos = handleCommentsCriteria(criterias, toolSessionId, itemIds, isCommentsByOtherUsersRequired, - userId); + List itemDtos = handleCommentsCriteria(criterias, toolSessionId, itemIds, + isCommentsByOtherUsersRequired, userId); //get all data from DB List userRatings = ratingDAO.getRatingsByUser(contentId, userId.intValue()); @@ -253,7 +256,7 @@ //handle all criterias except for comments' one for (ItemRatingDTO itemDto : itemDtos) { Long itemId = itemDto.getItemId(); - List criteriaDtos = new LinkedList(); + List criteriaDtos = new LinkedList<>(); itemDto.setCriteriaDtos(criteriaDtos); for (RatingCriteria criteria : criterias) { @@ -289,7 +292,7 @@ } } - if ( itemStatistics != null ) { + if (itemStatistics != null) { Number averageRating = (Number) itemStatistics[2]; criteriaDto.setAverageRating(numberFormat.format(averageRating)); criteriaDto.setAverageRatingAsNumber(averageRating); @@ -312,8 +315,8 @@ /* * Fetches all required comments from the DB. */ - private List handleCommentsCriteria(List criterias, Long toolSessionId, Collection itemIds, - boolean isCommentsByOtherUsersRequired, Long userId) { + private List handleCommentsCriteria(List criterias, Long toolSessionId, + Collection itemIds, boolean isCommentsByOtherUsersRequired, Long userId) { boolean isSingleItem = itemIds.size() == 1; Long singleItemId = isSingleItem ? itemIds.iterator().next() : null; @@ -327,11 +330,13 @@ List commentDtos; if (isSingleItem) { - commentDtos = ratingCommentDAO.getCommentsByCriteriaAndItem(commentCriteriaId, toolSessionId, singleItemId); + commentDtos = ratingCommentDAO.getCommentsByCriteriaAndItem(commentCriteriaId, toolSessionId, + singleItemId); //query DB using itemIds } else if (isCommentsByOtherUsersRequired) { - commentDtos = ratingCommentDAO.getCommentsByCriteriaAndItems(commentCriteriaId, toolSessionId, itemIds); + commentDtos = ratingCommentDAO.getCommentsByCriteriaAndItems(commentCriteriaId, toolSessionId, + itemIds); // get only comments done by the specified user } else { @@ -345,7 +350,7 @@ itemDto.setCommentsMinWordsLimit(criteria.getCommentsMinWordsLimit()); //assign commentDtos by the appropriate items - List commentDtosPerItem = new LinkedList(); + List commentDtosPerItem = new LinkedList<>(); for (RatingCommentDTO commentDto : commentDtos) { if (commentDto.getItemId().equals(itemDto.getItemId())) { commentDtosPerItem.add(commentDto); @@ -369,7 +374,7 @@ private List initializeItemDtos(Collection itemIds) { // initialize itemDtos - List itemDtos = new LinkedList(); + List itemDtos = new LinkedList<>(); for (Long itemId : itemIds) { ItemRatingDTO itemDto = new ItemRatingDTO(); itemDto.setItemId(itemId); @@ -395,9 +400,10 @@ return ratingCriteriaDAO.getByRatingCriteriaId(ratingCriteriaId, clasz); } - - private LearnerItemRatingCriteria updateLearnerItemRatingCriteria(LearnerItemRatingCriteria oldCriteria, Long toolContentId, String title, Integer orderId, int ratingStyle, boolean withComments, int minWordsInComment){ - + private LearnerItemRatingCriteria updateLearnerItemRatingCriteria(LearnerItemRatingCriteria oldCriteria, + Long toolContentId, String title, Integer orderId, int ratingStyle, boolean withComments, + int minWordsInComment) { + LearnerItemRatingCriteria criteria = oldCriteria != null ? oldCriteria : new LearnerItemRatingCriteria(); criteria.setRatingCriteriaTypeId(RatingCriteria.LEARNER_ITEM_CRITERIA_TYPE); criteria.setToolContentId(toolContentId); @@ -411,29 +417,30 @@ criteria.setMaxRating(RatingCriteria.getDefaultMaxRating(ratingStyle)); return criteria; } - + @Override - public LearnerItemRatingCriteria saveLearnerItemRatingCriteria(Long toolContentId, String title, Integer orderId, int ratingStyle, boolean withComments, int minWordsInComment) throws RatingException { + public LearnerItemRatingCriteria saveLearnerItemRatingCriteria(Long toolContentId, String title, Integer orderId, + int ratingStyle, boolean withComments, int minWordsInComment) throws RatingException { List criterias = ratingCriteriaDAO.getByToolContentId(toolContentId); LearnerItemRatingCriteria criteria = null; - if ( criterias.size() > 0 ) { - for ( RatingCriteria c : criterias ) { - if ( c.getOrderId().equals(orderId) ) { - if ( ! c.isLearnerItemRatingCriteria() ) { - String msg = new StringBuilder("Wrong type of criteria found - needs to be a AuthoredItemRatingCriteria for toolContentId ") - .append(toolContentId) - .append("criteriaId ") - .append(c.getRatingCriteriaId()) + if (criterias.size() > 0) { + for (RatingCriteria c : criterias) { + if (c.getOrderId().equals(orderId)) { + if (!c.isLearnerItemRatingCriteria()) { + String msg = new StringBuilder( + "Wrong type of criteria found - needs to be a AuthoredItemRatingCriteria for toolContentId ") + .append(toolContentId).append("criteriaId ").append(c.getRatingCriteriaId()) .toString(); log.error(msg); throw new RatingException(msg); } - criteria = (LearnerItemRatingCriteria)c; - break; + criteria = (LearnerItemRatingCriteria) c; + break; } } - } - criteria = updateLearnerItemRatingCriteria(criteria, toolContentId, title, orderId, ratingStyle, withComments, minWordsInComment); + } + criteria = updateLearnerItemRatingCriteria(criteria, toolContentId, title, orderId, ratingStyle, withComments, + minWordsInComment); ratingCriteriaDAO.saveOrUpdate(criteria); return criteria; } @@ -442,7 +449,7 @@ public int deleteAllRatingCriterias(Long toolContentId) { List criterias = ratingCriteriaDAO.getByToolContentId(toolContentId); int count = 0; - for ( RatingCriteria criteria : criterias ) { + for (RatingCriteria criteria : criterias) { ratingCriteriaDAO.deleteRatingCriteria(criteria.getRatingCriteriaId()); count++; } @@ -452,51 +459,54 @@ @Override public void saveRatingCriterias(HttpServletRequest request, Collection oldCriterias, Long toolContentId) { - + // different handling for comments - simple tag sets the isCommentsEnabled flag, // the complex tag sends explicit comment type entry. boolean explicitCommentTypeFound = false; - + // create orderId to RatingCriteria map - Map mapOrderIdToRatingCriteria = new HashMap(); + Map mapOrderIdToRatingCriteria = new HashMap<>(); for (RatingCriteria ratingCriteriaIter : oldCriterias) { mapOrderIdToRatingCriteria.put(ratingCriteriaIter.getOrderId(), ratingCriteriaIter); } - + // for ( Map.Entry entry : request.getParameterMap().entrySet()) { // log.debug("entry: "+entry.getKey()+" "+entry.getValue()); // } - + int criteriaMaxOrderId = WebUtil.readIntParam(request, "criteriaMaxOrderId"); // i is equal to an old orderId for (int i = 1; i <= criteriaMaxOrderId; i++) { String criteriaTitle = WebUtil.readStrParam(request, "criteriaTitle" + i, true); - Integer ratingStyle = WebUtil.readIntParam(request, "ratingStyle" + i, true); - if ( ratingStyle == null ) + Integer ratingStyle = WebUtil.readIntParam(request, "ratingStyle" + i, true); + if (ratingStyle == null) { ratingStyle = RatingCriteria.RATING_STYLE_STAR; - + } + Integer maxRating = WebUtil.readIntParam(request, "maxRating" + i, true); if (maxRating == null) { maxRating = RatingCriteria.getDefaultMaxRating(ratingStyle); } Integer minRatings = 0; Integer maxRatings = 0; - if ( ratingStyle == RatingCriteria.RATING_STYLE_STAR || ratingStyle == RatingCriteria.RATING_STYLE_COMMENT ) { + if (ratingStyle == RatingCriteria.RATING_STYLE_STAR || ratingStyle == RatingCriteria.RATING_STYLE_COMMENT) { minRatings = WebUtil.readIntParam(request, "minimumRates" + i, true); maxRatings = WebUtil.readIntParam(request, "maximumRates" + i, true); - } - + } - boolean commentsEnabled = ( ratingStyle != RatingCriteria.RATING_STYLE_COMMENT ? WebUtil.readBooleanParam(request, "enableComments" + i, false) : true ); - + boolean commentsEnabled = (ratingStyle != RatingCriteria.RATING_STYLE_COMMENT + ? WebUtil.readBooleanParam(request, "enableComments" + i, false) + : true); + RatingCriteria ratingCriteria = mapOrderIdToRatingCriteria.get(i); - if ( ratingStyle == RatingCriteria.RATING_STYLE_COMMENT || (ratingCriteria != null && ratingCriteria.isCommentRating()) ) { + if (ratingStyle == RatingCriteria.RATING_STYLE_COMMENT + || (ratingCriteria != null && ratingCriteria.isCommentRating())) { explicitCommentTypeFound = true; } - + if (StringUtils.isNotBlank(criteriaTitle)) { int newCriteriaOrderId = WebUtil.readIntParam(request, "criteriaOrderId" + i); @@ -512,17 +522,17 @@ ratingCriteria.setRatingStyle(ratingStyle); ratingCriteria.setMaxRating(maxRating); ratingCriteria.setCommentsEnabled(commentsEnabled); - if ( commentsEnabled ) { + if (commentsEnabled) { Integer commentsMinWordsLimit = WebUtil.readIntParam(request, "commentsMinWordsLimit" + i, true); ratingCriteria.setCommentsMinWordsLimit(commentsMinWordsLimit != null ? commentsMinWordsLimit : 0); } else { ratingCriteria.setCommentsMinWordsLimit(0); } - ratingCriteria.setMinimumRates( minRatings ); - ratingCriteria.setMaximumRates( maxRatings ); - - ratingCriteriaDAO.saveOrUpdate(ratingCriteria); + ratingCriteria.setMinimumRates(minRatings); + ratingCriteria.setMaximumRates(maxRatings); + + ratingCriteriaDAO.saveOrUpdate(ratingCriteria); // !!updatedCriterias.add(ratingCriteria); // delete @@ -533,7 +543,7 @@ } // ==== handle comments criteria - simple tag support ==== - if ( ! explicitCommentTypeFound ) { + if (!explicitCommentTypeFound) { boolean isCommentsEnabled = WebUtil.readBooleanParam(request, "isCommentsEnabled", false); // find comments' responsible RatingCriteria @@ -573,76 +583,79 @@ * Convert the raw data from the database to StyledCriteriaRatingDTO and StyleRatingDTO. The rating service expects * the potential itemId followed by rating.* (its own fields) and the last item in the array to be an item * description (eg formatted user's name) Will go back to the database for the justification comment that would - * apply to hedging. - * + * apply to hedging. + * * If includeCurrentUser == true will include the current users' records (used for SelfReview and Monitoring) * otherwise skips the current user, so they do not rate themselves! - * - * Entries in Object array for comment style: - * tool item id (usually user id), rating.item_id, rating_comment.comment, (tool fields)+ - * Entries in Object array for other styles: - * tool item id (usually user id), rating.item_id, rating_comment.comment, - * rating.rating, calculated.average_rating, calculated.count_vote, (tool fields)+ + * + * Entries in Object array for comment style: + * tool item id (usually user id), rating.item_id, rating_comment.comment, (tool fields)+ + * Entries in Object array for other styles: + * tool item id (usually user id), rating.item_id, rating_comment.comment, + * rating.rating, calculated.average_rating, calculated.count_vote, (tool fields)+ */ @Override - public StyledCriteriaRatingDTO convertToStyledDTO(RatingCriteria ratingCriteria, Long currentUserId, boolean includeCurrentUser, - List rawDataRows) { + public StyledCriteriaRatingDTO convertToStyledDTO(RatingCriteria ratingCriteria, Long currentUserId, + boolean includeCurrentUser, List rawDataRows) { StyledCriteriaRatingDTO criteriaDto = new StyledCriteriaRatingDTO(); criteriaDto.setRatingCriteria(ratingCriteria); - if (ratingCriteria.isHedgeStyleRating() && ratingCriteria.isCommentsEnabled() ) { + if (ratingCriteria.isHedgeStyleRating() && ratingCriteria.isCommentsEnabled()) { RatingComment justification = ratingCommentDAO.getComment(ratingCriteria.getRatingCriteriaId(), currentUserId.intValue(), ratingCriteria.getRatingCriteriaId()); - if (justification != null) + if (justification != null) { criteriaDto.setJustificationComment(justification.getComment()); - } else if ( ratingCriteria.isStarStyleRating() ) { - int ratedCount = getCountItemsRatedByUserByCriteria(ratingCriteria.getRatingCriteriaId(), currentUserId.intValue()); + } + } else if (ratingCriteria.isStarStyleRating()) { + int ratedCount = getCountItemsRatedByUserByCriteria(ratingCriteria.getRatingCriteriaId(), + currentUserId.intValue()); criteriaDto.setCountRatedItems(ratedCount); } boolean isComment = ratingCriteria.isCommentRating(); - if ( rawDataRows != null ) { + if (rawDataRows != null) { - List ratingDtos = new ArrayList(); + List ratingDtos = new ArrayList<>(); criteriaDto.setRatingDtos(ratingDtos); - NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); numberFormat.setMaximumFractionDigits(1); for (Object[] row : rawDataRows) { int numColumns = row.length; - if ( ( isComment && numColumns < 4 ) || ( !isComment && numColumns < 7) ) { + if ((isComment && numColumns < 4) || (!isComment && numColumns < 7)) { StringBuffer buf = new StringBuffer("convertToStyledDTO: ratingCriteria") .append(ratingCriteria.getRatingCriteriaId()).append(" UserId: ").append(currentUserId) .append(" Skipping data row as there are not enough columns. Only ").append(numColumns) .append(" columns. numColumns: ").append(numColumns); - if (numColumns > 0) + if (numColumns > 0) { buf.append(" Data: 0:").append(row[0]); - if (numColumns > 1) + } + if (numColumns > 1) { buf.append(" 1:").append(row[1]); + } log.error(buf.toString()); break; } long itemId = ((BigInteger) row[0]).longValue(); - if ( includeCurrentUser || itemId != currentUserId) { + if (includeCurrentUser || itemId != currentUserId) { - if (row[1] != null && itemId != ((BigInteger) row[0]).longValue() ) { - log.error("convertToStyledDTO: ratingCriteria" + ratingCriteria.getRatingCriteriaId() + " UserId: " - + currentUserId + " Potential issue: expected item id " + row[0] + " does match real item id " - + row[1] + ". Data: 0:" + row[0] + " 1:" + row[1]); + if (row[1] != null && itemId != ((BigInteger) row[0]).longValue()) { + log.error("convertToStyledDTO: ratingCriteria" + ratingCriteria.getRatingCriteriaId() + + " UserId: " + currentUserId + " Potential issue: expected item id " + row[0] + + " does match real item id " + row[1] + ". Data: 0:" + row[0] + " 1:" + row[1]); } - + StyledRatingDTO dto = new StyledRatingDTO(((BigInteger) row[0]).longValue()); dto.setComment((String) row[2]); - dto.setItemDescription( row[numColumns - 2] != null ? row[numColumns - 2].toString() : null); - dto.setItemDescription2( row[numColumns - 1] != null ? row[numColumns - 1].toString() : null); - if ( ! isComment ) { - dto.setUserRating(row[3] == null ? "" : numberFormat.format((Double) row[3])); - dto.setAverageRating(row[4] == null ? "" : numberFormat.format((Double) row[4])); - dto.setNumberOfVotes(row[5] == null ? "" : numberFormat.format((BigInteger) row[5])); + dto.setItemDescription(row[numColumns - 2] != null ? row[numColumns - 2].toString() : null); + dto.setItemDescription2(row[numColumns - 1] != null ? row[numColumns - 1].toString() : null); + if (!isComment) { + dto.setUserRating(row[3] == null ? "" : numberFormat.format(row[3])); + dto.setAverageRating(row[4] == null ? "" : numberFormat.format(row[4])); + dto.setNumberOfVotes(row[5] == null ? "" : numberFormat.format(row[5])); } ratingDtos.add(dto); } @@ -653,96 +666,100 @@ } /** - * Convert the raw data from the database to JSON, similar on StyledCriteriaRatingDTO and StyleRatingDTO. - * The rating service expects the potential itemId followed by rating.* (its own fields) and the last two items - * in the array will be two item descriptions fields (eg formatted user's name, portrait id). Will go back to - * the database for the justification comment that would apply to hedging. - * + * Convert the raw data from the database to JSON, similar on StyledCriteriaRatingDTO and StyleRatingDTO. + * The rating service expects the potential itemId followed by rating.* (its own fields) and the last two items + * in the array will be two item descriptions fields (eg formatted user's name, portrait id). Will go back to + * the database for the justification comment that would apply to hedging. + * * If includeCurrentUser == true will include the current users' records (used for SelfReview and Monitoring) * otherwise skips the current user, so they do not rate themselves! - * + * * toolSessionId is only used to calculate the number of users who have rated an item, so it may be null * if the tool doesn't need to seperate session (Peer Review doesn't need to separate by sessions). - * + * * In JSON for use with tablesorter. - * Entries in Object array for comment style: - * tool item id (usually user id), rating.item_id, rating_comment.comment, (tool fields)+ - * Entries in Object array for other styles: - * tool item id (usually user id), rating.item_id, rating_comment.comment, - * rating.rating, calculated.average_rating, calculated.count_vote, (tool fields)+ - * @throws JSONException + * Entries in Object array for comment style: + * tool item id (usually user id), rating.item_id, rating_comment.comment, (tool fields)+ + * Entries in Object array for other styles: + * tool item id (usually user id), rating.item_id, rating_comment.comment, + * rating.rating, calculated.average_rating, calculated.count_vote, (tool fields)+ + * + * @throws JSONException */ @Override - public JSONArray convertToStyledJSON(RatingCriteria ratingCriteria, Long toolSessionId, Long currentUserId, boolean includeCurrentUser, - List rawDataRows, boolean needRatesPerUser) throws JSONException { + public ArrayNode convertToStyledJSON(RatingCriteria ratingCriteria, Long toolSessionId, Long currentUserId, + boolean includeCurrentUser, List rawDataRows, boolean needRatesPerUser) { - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); boolean isComment = ratingCriteria.isCommentRating(); - if ( rawDataRows != null ) { + if (rawDataRows != null) { - List itemIds = needRatesPerUser ? new ArrayList(rawDataRows.size()) : null; + List itemIds = needRatesPerUser ? new ArrayList<>(rawDataRows.size()) : null; NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); numberFormat.setMaximumFractionDigits(1); for (Object[] row : rawDataRows) { int numColumns = row.length; - if ( ( isComment && numColumns < 4 ) || ( !isComment && numColumns < 7) ) { + if ((isComment && numColumns < 4) || (!isComment && numColumns < 7)) { StringBuffer buf = new StringBuffer("convertToStyledJSON: ratingCriteria") .append(ratingCriteria.getRatingCriteriaId()).append(" UserId: ").append(currentUserId) .append(" Skipping data row as there are not enough columns. Only ").append(numColumns) .append(" columns. numColumns: ").append(numColumns); - if (numColumns > 0) + if (numColumns > 0) { buf.append(" Data: 0:").append(row[0]); - if (numColumns > 1) + } + if (numColumns > 1) { buf.append(" 1:").append(row[1]); + } log.error(buf.toString()); break; } - + Long itemId = ((BigInteger) row[0]).longValue(); - if ( includeCurrentUser || itemId != currentUserId) { + if (includeCurrentUser || itemId != currentUserId) { - if (row[1] != null && itemId.longValue() != ((BigInteger) row[0]).longValue() ) { - log.error("convertToStyledJSON: ratingCriteria" + ratingCriteria.getRatingCriteriaId() + " UserId: " - + currentUserId + " Potential issue: expected item id " + row[0] + " does match real item id " - + row[1] + ". Data: 0:" + row[0] + " 1:" + row[1]); + if (row[1] != null && itemId.longValue() != ((BigInteger) row[0]).longValue()) { + log.error("convertToStyledJSON: ratingCriteria" + ratingCriteria.getRatingCriteriaId() + + " UserId: " + currentUserId + " Potential issue: expected item id " + row[0] + + " does match real item id " + row[1] + ". Data: 0:" + row[0] + " 1:" + row[1]); } - - JSONObject userRow = new JSONObject(); + + ObjectNode userRow = JsonNodeFactory.instance.objectNode(); userRow.put("itemId", itemId); userRow.put("comment", row[2] == null ? "" : (String) row[2]); - userRow.put("itemDescription", row[numColumns - 2] == null ? "" : row[numColumns - 2].toString()); - userRow.put("itemDescription2", row[numColumns - 1] == null ? "" : row[numColumns - 1].toString()); - if ( ! isComment ) { - userRow.put("userRating", row[3] == null ? "" : numberFormat.format((Double) row[3])); - userRow.put("averageRating", row[4] == null ? "" : numberFormat.format((Double) row[4])); - userRow.put("numberOfVotes", row[5] == null ? "" : numberFormat.format((BigInteger) row[5])); + userRow.put("itemDescription", row[numColumns - 2] == null ? "" : row[numColumns - 2].toString()); + userRow.put("itemDescription2", row[numColumns - 1] == null ? "" : row[numColumns - 1].toString()); + if (!isComment) { + userRow.put("userRating", row[3] == null ? "" : numberFormat.format(row[3])); + userRow.put("averageRating", row[4] == null ? "" : numberFormat.format(row[4])); + userRow.put("numberOfVotes", row[5] == null ? "" : numberFormat.format(row[5])); } else { // don't have missing entries in JSON or an exception can occur if you try to access them - userRow.put("userRating", ""); - userRow.put("averageRating", ""); - userRow.put("numberOfVotes", ""); + userRow.put("userRating", ""); + userRow.put("averageRating", ""); + userRow.put("numberOfVotes", ""); } - rows.put(userRow); - - if ( needRatesPerUser ) + rows.add(userRow); + + if (needRatesPerUser) { itemIds.add(itemId); + } } } - - if ( needRatesPerUser ) { - Map countUsersRatedEachItemMap = ratingDAO.countUsersRatedEachItemByCriteria(ratingCriteria.getRatingCriteriaId(), toolSessionId, itemIds, -1); - for ( int i=0; i < rows.length(); i++ ) { - JSONObject row = rows.getJSONObject(i); - Long count = countUsersRatedEachItemMap.get(row.get("itemId")); - row.put("ratesPerUser", count != null ? count : 0); + + if (needRatesPerUser) { + Map countUsersRatedEachItemMap = ratingDAO.countUsersRatedEachItemByCriteria( + ratingCriteria.getRatingCriteriaId(), toolSessionId, itemIds, -1); + for (JsonNode row : rows) { + Long count = countUsersRatedEachItemMap.get(JsonUtil.optLong(row, "itemId")); + ((ObjectNode) row).put("ratesPerUser", count == null ? 0 : count); } } } - + return rows; } @@ -761,8 +778,8 @@ public String getRatingSelectJoinSQL(Integer ratingStyle, boolean getByUser) { return ratingDAO.getRatingSelectJoinSQL(ratingStyle, getByUser); } - - /** + + /** * Get all the raw ratings for a combination of criteria and item ids. Used by Peer Review to do SPA analysis. */ @Override Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -ra4002ee13a835e74c08e3d657494f1c97b531013 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision a4002ee13a835e74c08e3d657494f1c97b531013) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -51,9 +51,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.authoring.ObjectExtractor; import org.lamsfoundation.lams.authoring.service.IAuthoringService; import org.lamsfoundation.lams.learning.service.ILearnerService; @@ -91,6 +88,7 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CentralConstants; import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; @@ -101,8 +99,9 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * The action servlet that provide all the monitoring functionalities. It interact with the teacher via JSP monitoring @@ -324,7 +323,7 @@ // either all users participate in a lesson, or we split them among instances List lessonInstanceLearners = splitNumberLessons == null ? learners - : new ArrayList((learners.size() / splitNumberLessons) + 1); + : new ArrayList<>((learners.size() / splitNumberLessons) + 1); for (int lessonIndex = 1; lessonIndex <= (splitNumberLessons == null ? 1 : splitNumberLessons); lessonIndex++) { String lessonInstanceName = lessonName; String learnerGroupInstanceName = learnerGroupName; @@ -479,11 +478,12 @@ long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); String dateStr = WebUtil.readStrParam(request, MonitoringConstants.PARAM_LESSON_END_DATE, true); try { - if (dateStr == null || dateStr.length() == 0) + if (dateStr == null || dateStr.length() == 0) { getMonitoringService().suspendLesson(lessonId, getUserId(), true); - else + } else { getMonitoringService().finishLessonOnSchedule(lessonId, MonitoringAction.LESSON_SCHEDULING_DATETIME_FORMAT.parse(dateStr), getUserId()); + } } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -526,7 +526,7 @@ * @throws ServletException */ public ActionForward removeLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException, ServletException { + HttpServletResponse response) throws IOException, ServletException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); Integer userId = getUserId(); boolean permanently = WebUtil.readBooleanParam(request, "permanently", false); @@ -538,7 +538,7 @@ return null; } - JSONObject jsonObject = new JSONObject(); + ObjectNode jsonObject = JsonNodeFactory.instance.objectNode(); try { // if this method throws an Exception, there will be no removeLesson=true in the JSON reply @@ -572,7 +572,7 @@ * @throws JSONException */ public ActionForward forceComplete(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException, JSONException { + HttpServletResponse response) throws IOException, ServletException { // get parameters Long activityId = null; @@ -591,7 +591,7 @@ boolean removeLearnerContent = WebUtil.readBooleanParam(request, MonitoringConstants.PARAM_REMOVE_LEARNER_CONTENT, false); - JSONObject jsonCommand = new JSONObject(); + ObjectNode jsonCommand = JsonNodeFactory.instance.objectNode(); jsonCommand.put("message", getMessageService().getMessage("force.complete.learner.command.message")); jsonCommand.put("redirectURL", "/lams/learning/learner.do?method=joinLesson&lessonID=" + lessonId); String command = jsonCommand.toString(); @@ -649,7 +649,7 @@ * Get learners who are part of the lesson class. */ public ActionForward getLessonLearners(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); if (!getSecurityService().isLessonMonitor(lessonId, getUserId(), "get lesson learners", false)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -665,15 +665,15 @@ List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); - JSONArray learnersJSON = new JSONArray(); + ArrayNode learnersJSON = JsonNodeFactory.instance.arrayNode(); for (User learner : learners) { - learnersJSON.put(WebUtil.userToJSON(learner)); + learnersJSON.add(WebUtil.userToJSON(learner)); } Integer learnerCount = getLessonService().getCountLessonLearners(lessonId, searchPhrase); - JSONObject responseJSON = new JSONObject(); - responseJSON.put("learners", learnersJSON); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.set("learners", learnersJSON); responseJSON.put("learnerCount", learnerCount); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -684,7 +684,7 @@ * Gets learners or monitors of the lesson and organisation containing it. */ public ActionForward getClassMembers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); if (!getSecurityService().isLessonMonitor(lessonId, getUserId(), "get class members", false)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -702,7 +702,7 @@ pageNumber = 1; } boolean orderAscending = WebUtil.readBooleanParam(request, "orderAscending", true); - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); // find organisation users and whether they participate in the current lesson Map users = getLessonService().getUsersWithLessonParticipation(lessonId, role, searchPhrase, @@ -715,18 +715,18 @@ responseJSON.put("userCount", userCount); - JSONArray usersJSON = new JSONArray(); + ArrayNode usersJSON = JsonNodeFactory.instance.arrayNode(); for (Entry userEntry : users.entrySet()) { User user = userEntry.getKey(); - JSONObject userJSON = WebUtil.userToJSON(user); + ObjectNode userJSON = WebUtil.userToJSON(user); userJSON.put("classMember", userEntry.getValue()); // teacher can't remove lesson creator and himself from the lesson staff if (isMonitor && (creator.getUserId().equals(user.getUserId()) || currentUserId.equals(user.getUserId()))) { userJSON.put("readonly", true); } - usersJSON.put(userJSON); + usersJSON.add(userJSON); } - responseJSON.put("users", usersJSON); + responseJSON.set("users", usersJSON); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -737,8 +737,8 @@ * Gets users in JSON format who are at the given activity at the moment or finished the given lesson. */ public ActionForward getCurrentLearners(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { - JSONArray learnersJSON = new JSONArray(); + HttpServletResponse response) throws IOException { + ArrayNode learnersJSON = JsonNodeFactory.instance.arrayNode(); Integer learnerCount = null; Integer pageNumber = WebUtil.readIntParam(request, "pageNumber", true); @@ -759,7 +759,7 @@ MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); for (User learner : learners) { - learnersJSON.put(WebUtil.userToJSON(learner)); + learnersJSON.add(WebUtil.userToJSON(learner)); } learnerCount = getMonitoringService().getCountLearnersCompletedLesson(lessonId); @@ -772,21 +772,21 @@ return null; } - Set activities = new TreeSet(); + Set activities = new TreeSet<>(); activities.add(activityId); List learners = getMonitoringService().getLearnersByActivities(activities.toArray(new Long[] {}), MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); for (User learner : learners) { - learnersJSON.put(WebUtil.userToJSON(learner)); + learnersJSON.add(WebUtil.userToJSON(learner)); } learnerCount = getMonitoringService().getCountLearnersCurrentActivities(new Long[] { activityId }) .get(activityId); } - JSONObject responseJSON = new JSONObject(); - responseJSON.put("learners", learnersJSON); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.set("learners", learnersJSON); responseJSON.put("learnerCount", learnerCount); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -797,7 +797,7 @@ * Adds/removes learners and monitors to/from lesson class. */ public ActionForward updateLessonClass(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); if (!getSecurityService().isLessonMonitor(lessonId, getUserId(), "update lesson class", false)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -842,7 +842,7 @@ String module = WebUtil.readStrParam(request, "module", false); - ArrayList languageCollection = new ArrayList(); + ArrayList languageCollection = new ArrayList<>(); if (module.equals("timechart")) { languageCollection.add(new String("sys.error")); @@ -967,45 +967,47 @@ return mapping.findForward("monitorLesson"); } - + /** * If learning design contains the following activities Grouping->(MCQ or Assessment)->Leader Selection->Scratchie * (potentially with some other gates or activities in the middle), there is a good chance this is a TBL sequence * and all activities must be grouped. */ private boolean isTBLSequence(Long lessonId) { - + Lesson lesson = getLessonService().getLesson(lessonId); Long firstActivityId = lesson.getLearningDesign().getFirstActivity().getActivityId(); //Hibernate CGLIB is failing to load the first activity in the sequence as a ToolActivity Activity firstActivity = getMonitoringService().getActivityById(firstActivityId); - + return verifyNextActivityFitsTbl(firstActivity, "Grouping"); } - + /** * Traverses the learning design verifying it follows typical TBL structure - * + * * @param activity - * @param anticipatedActivity could be either "Grouping", "MCQ or Assessment", "Leaderselection" or "Scratchie" + * @param anticipatedActivity + * could be either "Grouping", "MCQ or Assessment", "Leaderselection" or "Scratchie" */ private boolean verifyNextActivityFitsTbl(Activity activity, String anticipatedActivity) { - + Transition transitionFromActivity = activity.getTransitionFrom(); //TBL can finish with the Scratchie if (transitionFromActivity == null && !"Scratchie".equals(anticipatedActivity)) { return false; } // query activity from DB as transition holds only proxied activity object - Long nextActivityId = transitionFromActivity == null ? null : transitionFromActivity.getToActivity().getActivityId(); + Long nextActivityId = transitionFromActivity == null ? null + : transitionFromActivity.getToActivity().getActivityId(); Activity nextActivity = nextActivityId == null ? null : monitoringService.getActivityById(nextActivityId); - + switch (anticipatedActivity) { case "Grouping": //the first activity should be a grouping if (activity instanceof GroupingActivity) { return verifyNextActivityFitsTbl(nextActivity, "MCQ or Assessment"); - + } else { return verifyNextActivityFitsTbl(nextActivity, "Grouping"); } @@ -1017,7 +1019,7 @@ || CentralConstants.TOOL_SIGNATURE_MCQ .equals(((ToolActivity) activity).getTool().getToolSignature()))) { return verifyNextActivityFitsTbl(nextActivity, "Leaderselection"); - + } else { return verifyNextActivityFitsTbl(nextActivity, "MCQ or Assessment"); } @@ -1027,20 +1029,20 @@ if (activity.isToolActivity() && CentralConstants.TOOL_SIGNATURE_LEADERSELECTION .equals(((ToolActivity) activity).getTool().getToolSignature())) { return verifyNextActivityFitsTbl(nextActivity, "Scratchie"); - + } else { return verifyNextActivityFitsTbl(nextActivity, "Leaderselection"); } - + case "Scratchie": //the fourth activity shall be Scratchie if (activity.isToolActivity() && CentralConstants.TOOL_SIGNATURE_SCRATCHIE .equals(((ToolActivity) activity).getTool().getToolSignature())) { return true; - + } else if (nextActivity == null) { return false; - + } else { return verifyNextActivityFitsTbl(nextActivity, "Scratchie"); } @@ -1054,7 +1056,7 @@ * Gets users whose progress bars will be displayed in Learner tab in Monitor. */ public ActionForward getLearnerProgressPage(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); if (!getSecurityService().isLessonMonitor(lessonId, getUserId(), "get learner progress page", false)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -1073,9 +1075,9 @@ List learners = isProgressSorted ? getMonitoringService().getLearnersByMostProgress(lessonId, searchPhrase, 10, (pageNumber - 1) * 10) : getLessonService().getLessonLearners(lessonId, searchPhrase, 10, (pageNumber - 1) * 10, true); - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); for (User learner : learners) { - responseJSON.append("learners", WebUtil.userToJSON(learner)); + responseJSON.withArray("learners").add(WebUtil.userToJSON(learner)); } // get all possible learners matching the given phrase, if any; used for max page number @@ -1089,7 +1091,7 @@ * Produces data to update Lesson tab in Monitor. */ public ActionForward getLessonDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); @@ -1099,7 +1101,7 @@ return null; } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); Lesson lesson = getLessonService().getLesson(lessonId); LearningDesign learningDesign = lesson.getLearningDesign(); @@ -1117,25 +1119,25 @@ Date finishDate = lesson.getScheduleEndDate(); DateFormat indfm = null; - if ( startOrScheduleDate != null || finishDate != null ) + if (startOrScheduleDate != null || finishDate != null) { indfm = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", userLocale); - + } + if (startOrScheduleDate != null) { Date tzStartDate = DateUtil.convertToTimeZoneFromDefault(user.getTimeZone(), startOrScheduleDate); responseJSON.put("startDate", indfm.format(tzStartDate) + " " + user.getTimeZone().getDisplayName(userLocale)); } - if ( finishDate != null ) { + if (finishDate != null) { Date tzFinishDate = DateUtil.convertToTimeZoneFromDefault(user.getTimeZone(), finishDate); responseJSON.put("finishDate", - indfm.format(tzFinishDate) + " " + user.getTimeZone().getDisplayName(userLocale)); + indfm.format(tzFinishDate) + " " + user.getTimeZone().getDisplayName(userLocale)); } - + List contributeActivities = getContributeActivities(lessonId, false); if (contributeActivities != null) { - Gson gson = new GsonBuilder().create(); - responseJSON.put("contributeActivities", new JSONArray(gson.toJson(contributeActivities))); + responseJSON.set("contributeActivities", JsonUtil.readArray(contributeActivities)); } response.setContentType("application/json;charset=utf-8"); @@ -1144,7 +1146,7 @@ } public ActionForward getLessonChartData(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); Integer possibleLearnersCount = getLessonService().getCountLessonLearners(lessonId, null); @@ -1153,21 +1155,21 @@ - completedLearnersCount; Integer notCompletedLearnersCount = possibleLearnersCount - completedLearnersCount - startedLearnersCount; - JSONObject responseJSON = new JSONObject(); - JSONObject notStartedJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + ObjectNode notStartedJSON = JsonNodeFactory.instance.objectNode(); notStartedJSON.put("name", getMessageService().getMessage("lesson.chart.not.completed")); notStartedJSON.put("value", Math.round(notCompletedLearnersCount.doubleValue() / possibleLearnersCount * 100)); - responseJSON.append("data", notStartedJSON); + responseJSON.withArray("data").add(notStartedJSON); - JSONObject startedJSON = new JSONObject(); + ObjectNode startedJSON = JsonNodeFactory.instance.objectNode(); startedJSON.put("name", getMessageService().getMessage("lesson.chart.started")); startedJSON.put("value", Math.round((startedLearnersCount.doubleValue()) / possibleLearnersCount * 100)); - responseJSON.append("data", startedJSON); + responseJSON.withArray("data").add(startedJSON); - JSONObject completedJSON = new JSONObject(); + ObjectNode completedJSON = JsonNodeFactory.instance.objectNode(); completedJSON.put("name", getMessageService().getMessage("lesson.chart.completed")); completedJSON.put("value", Math.round(completedLearnersCount.doubleValue() / possibleLearnersCount * 100)); - responseJSON.append("data", completedJSON); + responseJSON.withArray("data").add(completedJSON); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -1179,7 +1181,7 @@ */ @SuppressWarnings("unchecked") public ActionForward getLessonProgress(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); Integer monitorUserId = getUserId(); if (!getSecurityService().isLessonMonitor(lessonId, monitorUserId, "get lesson progress", false)) { @@ -1192,7 +1194,7 @@ LearningDesign learningDesign = lesson.getLearningDesign(); String contentFolderId = learningDesign.getContentFolderID(); - Set activities = new HashSet(); + Set activities = new HashSet<>(); // filter activities that are interesting for further processing for (Activity activity : (Set) learningDesign.getActivities()) { if (activity.isSequenceActivity()) { @@ -1203,11 +1205,10 @@ activities.add(getMonitoringService().getActivityById(activity.getActivityId())); } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); List contributeActivities = getContributeActivities(lessonId, true); if (contributeActivities != null) { - Gson gson = new GsonBuilder().create(); - responseJSON.put("contributeActivities", new JSONArray(gson.toJson(contributeActivities))); + responseJSON.set("contributeActivities", JsonUtil.readArray(contributeActivities)); } // check if the searched learner has started the lesson @@ -1218,8 +1219,8 @@ } // Fetch number of learners at each activity - ArrayList activityIds = new ArrayList(); - Set leaders = new TreeSet(); + ArrayList activityIds = new ArrayList<>(); + Set leaders = new TreeSet<>(); for (Activity activity : activities) { activityIds.add(activity.getActivityId()); // find leaders from Leader Selection Tool @@ -1235,10 +1236,10 @@ Map learnerCounts = getMonitoringService() .getCountLearnersCurrentActivities(activityIds.toArray(new Long[activityIds.size()])); - JSONArray activitiesJSON = new JSONArray(); + ArrayNode activitiesJSON = JsonNodeFactory.instance.arrayNode(); for (Activity activity : activities) { Long activityId = activity.getActivityId(); - JSONObject activityJSON = new JSONObject(); + ObjectNode activityJSON = JsonNodeFactory.instance.objectNode(); activityJSON.put("id", activityId); activityJSON.put("uiid", activity.getActivityUIID()); activityJSON.put("title", activity.getTitle()); @@ -1301,23 +1302,23 @@ // parse learners into JSON format if (!latestLearners.isEmpty()) { - JSONArray learnersJSON = new JSONArray(); + ArrayNode learnersJSON = JsonNodeFactory.instance.arrayNode(); for (User learner : latestLearners) { - JSONObject userJSON = WebUtil.userToJSON(learner); + ObjectNode userJSON = WebUtil.userToJSON(learner); if (leaders.contains(learner.getUserId().longValue())) { userJSON.put("leader", true); } - learnersJSON.put(userJSON); + learnersJSON.add(userJSON); } - activityJSON.put("learners", learnersJSON); + activityJSON.set("learners", learnersJSON); } } activityJSON.put("learnerCount", learnerCount); - activitiesJSON.put(activityJSON); + activitiesJSON.add(activityJSON); } - responseJSON.put("activities", activitiesJSON); + responseJSON.set("activities", activitiesJSON); // find learners who completed the lesson List completedLearners = getMonitoringService().getLearnersLatestCompleted(lessonId, @@ -1336,25 +1337,25 @@ completedLearners, MonitoringAction.LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT); } for (User learner : completedLearners) { - JSONObject learnerJSON = WebUtil.userToJSON(learner); + ObjectNode learnerJSON = WebUtil.userToJSON(learner); // no more details are needed for learners who completed the lesson - responseJSON.append("completedLearners", learnerJSON); + responseJSON.withArray("completedLearners").add(learnerJSON); } responseJSON.put("numberPossibleLearners", getLessonService().getCountLessonLearners(lessonId, null)); // on first fetch get transitions metadata so Monitoring can set their SVG elems IDs if (WebUtil.readBooleanParam(request, "getTransitions", false)) { - JSONArray transitions = new JSONArray(); + ArrayNode transitions = JsonNodeFactory.instance.arrayNode(); for (Transition transition : (Set) learningDesign.getTransitions()) { - JSONObject transitionJSON = new JSONObject(); + ObjectNode transitionJSON = JsonNodeFactory.instance.objectNode(); transitionJSON.put("uiid", transition.getTransitionUIID()); transitionJSON.put("fromID", transition.getFromActivity().getActivityId()); transitionJSON.put("toID", transition.getToActivity().getActivityId()); - transitions.put(transitionJSON); + transitions.add(transitionJSON); } - responseJSON.put("transitions", transitions); + responseJSON.set("transitions", transitions); } response.setContentType("application/json;charset=utf-8"); @@ -1389,13 +1390,13 @@ true); } - JSONArray responseJSON = new JSONArray(); + ArrayNode responseJSON = JsonNodeFactory.instance.arrayNode(); for (User user : users) { - JSONObject userJSON = new JSONObject(); + ObjectNode userJSON = JsonNodeFactory.instance.objectNode(); userJSON.put("label", user.getFirstName() + " " + user.getLastName() + " " + user.getLogin()); userJSON.put("value", user.getUserId()); - responseJSON.put(userJSON); + responseJSON.add(userJSON); } response.setContentType("application/json;charset=utf-8"); @@ -1625,9 +1626,9 @@ } return null; } - + /** - * Set whether or not the activity scores / gradebook values are shown to the learner at the end of the lesson. + * Set whether or not the activity scores / gradebook values are shown to the learner at the end of the lesson. * Expects parameters lessonID and presenceAvailable. */ public ActionForward gradebookOnComplete(ActionMapping mapping, ActionForm form, HttpServletRequest request, @@ -1677,7 +1678,7 @@ private List parseUserList(HttpServletRequest request, String paramName, Collection users) { String userIdList = request.getParameter(paramName); String[] userIdArray = userIdList.split(","); - List result = new ArrayList(userIdArray.length); + List result = new ArrayList<>(userIdArray.length); for (User user : users) { Integer userId = user.getUserId(); @@ -1698,7 +1699,7 @@ Lesson lesson = getLessonService().getLesson(lessonId); if (contributeActivities != null) { - List resultContributeActivities = new ArrayList(); + List resultContributeActivities = new ArrayList<>(); for (ContributeActivityDTO contributeActivity : contributeActivities) { if (contributeActivity.getContributeEntries() != null) { Iterator entryIterator = contributeActivity @@ -1709,7 +1710,7 @@ // extra filtering for chosen branching: do not show in Sequence tab if all users were assigned if (skipCompletedBranching && ContributionTypes.CHOSEN_BRANCHING.equals(contributeEntry.getContributionType())) { - Set learners = new HashSet(lesson.getLessonClass().getLearners()); + Set learners = new HashSet<>(lesson.getLessonClass().getLearners()); ChosenBranchingActivity branching = (ChosenBranchingActivity) getMonitoringService() .getActivityById(contributeActivity.getActivityID()); for (SequenceActivity branch : (Set) branching.getActivities()) { @@ -1745,7 +1746,7 @@ */ private static List insertHighlightedLearner(User searchedLearner, List latestLearners, int limit) { latestLearners.remove(searchedLearner); - LinkedList updatedLatestLearners = new LinkedList(latestLearners); + LinkedList updatedLatestLearners = new LinkedList<>(latestLearners); updatedLatestLearners.addFirst(searchedLearner); if (updatedLatestLearners.size() > limit) { updatedLatestLearners.removeLast(); Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java =================================================================== diff -u -r2485ce33e55a921bdcde94e4f242da5da3cf1fc4 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 2485ce33e55a921bdcde94e4f242da5da3cf1fc4) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -45,9 +45,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.gradebook.util.GradebookConstants; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; @@ -70,6 +67,7 @@ import org.lamsfoundation.lams.util.DateUtil; import org.lamsfoundation.lams.util.ExcelCell; import org.lamsfoundation.lams.util.ExcelUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; @@ -78,14 +76,18 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + public class MonitoringAction extends Action { public static Logger log = Logger.getLogger(MonitoringAction.class); private IAssessmentService service; @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException, JSONException { + HttpServletResponse response) throws IOException, ServletException { request.setAttribute("initialTabId", WebUtil.readLongParam(request, AttributeNames.PARAM_CURRENT_TAB, true)); String param = mapping.getParameter(); @@ -140,7 +142,7 @@ initAssessmentService(); // initialize Session Map - SessionMap sessionMap = new SessionMap(); + SessionMap sessionMap = new SessionMap<>(); request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); @@ -171,7 +173,7 @@ } //prepare list of the questions to display in question drop down menu, filtering out questions that aren't supposed to be answered - Set questionList = new TreeSet(); + Set questionList = new TreeSet<>(); //in case there is at least one random question - we need to show all questions in a drop down select if (assessment.hasRandomQuestion()) { questionList.addAll(assessment.getQuestions()); @@ -184,7 +186,7 @@ } //prepare toolOutputDefinitions and activityEvaluation - List toolOutputDefinitions = new ArrayList(); + List toolOutputDefinitions = new ArrayList<>(); toolOutputDefinitions.add(AssessmentConstants.OUTPUT_NAME_LEARNER_TOTAL_SCORE); toolOutputDefinitions.add(AssessmentConstants.OUTPUT_NAME_BEST_SCORE); toolOutputDefinitions.add(AssessmentConstants.OUTPUT_NAME_FIRST_SCORE); @@ -317,7 +319,7 @@ * @throws IOException */ private ActionForward setActivityEvaluation(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { initAssessmentService(); String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); @@ -332,7 +334,7 @@ // causes the old value to be redisplayed sessionMap.put(AssessmentConstants.ATTR_ACTIVITY_EVALUATION, activityEvaluation); - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); responseJSON.put("success", "true"); response.setContentType("application/json;charset=utf-8"); response.getWriter().print(new String(responseJSON.toString())); @@ -343,7 +345,7 @@ * Refreshes user list. */ public ActionForward getUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { initAssessmentService(); String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = (SessionMap) request.getSession() @@ -362,7 +364,7 @@ } String searchString = WebUtil.readStrParam(request, "userName", true); - List userDtos = new ArrayList(); + List userDtos = new ArrayList<>(); int countSessionUsers = 0; //in case of UseSelectLeaderToolOuput - display only one user if (assessment.isUseSelectLeaderToolOuput()) { @@ -395,32 +397,32 @@ Math.ceil(new Integer(countSessionUsers).doubleValue() / new Integer(rowLimit).doubleValue())) .intValue(); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); int i = 1; for (AssessmentUserDTO userDto : userDtos) { - JSONArray userData = new JSONArray(); - userData.put(userDto.getUserId()); - userData.put(sessionId); + ArrayNode userData = JsonNodeFactory.instance.arrayNode(); + userData.add(userDto.getUserId()); + userData.add(sessionId); String fullName = HtmlUtils.htmlEscape(userDto.getFirstName() + " " + userDto.getLastName()); - userData.put(fullName); - userData.put(userDto.getGrade()); + userData.add(fullName); + userData.add(userDto.getGrade()); if (userDto.getPortraitId() != null) { - userData.put(userDto.getPortraitId()); + userData.add(userDto.getPortraitId()); } - JSONObject userRow = new JSONObject(); + ObjectNode userRow = JsonNodeFactory.instance.objectNode(); userRow.put("id", i++); - userRow.put("cell", userData); + userRow.set("cell", userData); - rows.put(userRow); + rows.add(userRow); } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); responseJSON.put("total", totalPages); responseJSON.put("page", page); responseJSON.put("records", countSessionUsers); - responseJSON.put("rows", rows); + responseJSON.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responseJSON.toString())); @@ -431,7 +433,7 @@ * Refreshes user list. */ public ActionForward getUsersByQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { initAssessmentService(); String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = (SessionMap) request.getSession() @@ -451,7 +453,7 @@ } String searchString = WebUtil.readStrParam(request, "userName", true); - List userDtos = new ArrayList(); + List userDtos = new ArrayList<>(); int countSessionUsers = 0; //in case of UseSelectLeaderToolOuput - display only one user if (assessment.isUseSelectLeaderToolOuput()) { @@ -492,54 +494,55 @@ Math.ceil(new Integer(countSessionUsers).doubleValue() / new Integer(rowLimit).doubleValue())) .intValue(); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); int i = 1; for (AssessmentUserDTO userDto : userDtos) { Long questionResultUid = userDto.getQuestionResultUid(); String fullName = HtmlUtils.htmlEscape(userDto.getFirstName() + " " + userDto.getLastName()); - JSONArray userData = new JSONArray(); + ArrayNode userData = JsonNodeFactory.instance.arrayNode(); if (questionResultUid != null) { AssessmentQuestionResult questionResult = service.getAssessmentQuestionResultByUid(questionResultUid); - userData.put(questionResultUid); - userData.put(questionResult.getMaxMark()); - userData.put(fullName); + userData.add(questionResultUid); + userData.add(questionResult.getMaxMark()); + userData.add(fullName); //LDEV_NTU-11 Swapping Mark and Response columns in Assessment Monitor - userData.put(questionResult.getMark()); + userData.add(questionResult.getMark()); // show confidence levels if this feature is turned ON if (assessment.isEnableConfidenceLevels()) { - userData.put(questionResult.getConfidenceLevel()); + userData.add(questionResult.getConfidenceLevel()); } - userData.put(AssessmentEscapeUtils.printResponsesForJqgrid(questionResult)); + + userData.add(AssessmentEscapeUtils.printResponsesForJqgrid(questionResult)); if (userDto.getPortraitId() != null) { - userData.put(userDto.getPortraitId()); + userData.add(userDto.getPortraitId()); } } else { - userData.put(""); - userData.put(""); - userData.put(fullName); - userData.put("-"); + userData.add(""); + userData.add(""); + userData.add(fullName); + userData.add("-"); if (assessment.isEnableConfidenceLevels()) { - userData.put(-1); + userData.add(-1); } - userData.put("-"); + userData.add("-"); } - JSONObject userRow = new JSONObject(); + ObjectNode userRow = JsonNodeFactory.instance.objectNode(); userRow.put("id", i++); - userRow.put("cell", userData); + userRow.set("cell", userData); - rows.put(userRow); + rows.add(userRow); } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); responseJSON.put("total", totalPages); responseJSON.put("page", page); responseJSON.put("records", countSessionUsers); - responseJSON.put("rows", rows); + responseJSON.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responseJSON.toString())); @@ -550,7 +553,7 @@ * Get the mark summary with data arranged in bands. Can be displayed graphically or in a table. */ private ActionForward getMarkChartData(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { initAssessmentService(); @@ -572,11 +575,11 @@ } } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); if (results != null) { - responseJSON.put("data", results); + responseJSON.set("data", JsonUtil.readArray(results)); } else { - responseJSON.put("data", new Float[0]); + responseJSON.set("data", JsonUtil.readArray(new Float[0])); } res.setContentType("application/json;charset=utf-8"); @@ -675,7 +678,7 @@ * Allows displaying correct answers to learners */ private ActionForward discloseCorrectAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException { + HttpServletResponse response) { Long questionUid = WebUtil.readLongParam(request, "questionUid"); Long toolContentId = WebUtil.readLongParam(request, AssessmentConstants.PARAM_TOOL_CONTENT_ID); @@ -698,7 +701,7 @@ * Allows displaying other groups' answers to learners */ private ActionForward discloseGroupsAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException { + HttpServletResponse response) { Long questionUid = WebUtil.readLongParam(request, "questionUid"); Long toolContentId = WebUtil.readLongParam(request, AssessmentConstants.PARAM_TOOL_CONTENT_ID); Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java =================================================================== diff -u -r7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision 7665ade66b927eb4b1fa6cb20ad55f3c1d7c2778) +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -42,9 +42,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; @@ -116,6 +113,9 @@ import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Steve.Ni @@ -1530,50 +1530,49 @@ /** * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions, topics. - * Topics must contain a JSONArray of JSONObject objects, which have the following mandatory fields: subject, body + * Topics must contain a ArrayNode of ObjectNode objects, which have the following mandatory fields: subject, body * There will usually be at least one topic object in the Topics array but the array may be of zero length. */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { Forum forum = new Forum(); Date updateDate = new Date(); forum.setCreated(updateDate); forum.setUpdated(updateDate); forum.setContentId(toolContentID); - forum.setTitle(toolContentJSON.getString(RestTags.TITLE)); - forum.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + forum.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + forum.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); - forum.setAllowAnonym(JsonUtil.opt(toolContentJSON, "allowAnonym", Boolean.FALSE)); - forum.setAllowEdit(JsonUtil.opt(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default - // entry in the db - forum.setAllowNewTopic(JsonUtil.opt(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the - // default entry in the db - forum.setAllowRateMessages(JsonUtil.opt(toolContentJSON, "allowRateMessages", Boolean.FALSE)); - forum.setAllowRichEditor(JsonUtil.opt(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - forum.setAllowUpload(JsonUtil.opt(toolContentJSON, "allowUpload", Boolean.FALSE)); + forum.setAllowAnonym(JsonUtil.optBoolean(toolContentJSON, "allowAnonym", Boolean.FALSE)); + forum.setAllowEdit(JsonUtil.optBoolean(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default + // entry in the db + forum.setAllowNewTopic(JsonUtil.optBoolean(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the + // default entry in the db + forum.setAllowRateMessages(JsonUtil.optBoolean(toolContentJSON, "allowRateMessages", Boolean.FALSE)); + forum.setAllowRichEditor(JsonUtil.optBoolean(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + forum.setAllowUpload(JsonUtil.optBoolean(toolContentJSON, "allowUpload", Boolean.FALSE)); forum.setContentInUse(false); forum.setDefineLater(false); - forum.setLimitedMaxCharacters(JsonUtil.opt(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); - forum.setLimitedMinCharacters(JsonUtil.opt(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); - forum.setLockWhenFinished(JsonUtil.opt(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); - forum.setMaxCharacters(JsonUtil.opt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the - // default entry in the db. - forum.setMaximumRate(JsonUtil.opt(toolContentJSON, "maximumRate", 0)); - forum.setMaximumReply(JsonUtil.opt(toolContentJSON, "maximumReply", 0)); - forum.setMinCharacters(JsonUtil.opt(toolContentJSON, "minCharacters", 0)); - forum.setMinimumRate(JsonUtil.opt(toolContentJSON, "minimumRate", 0)); - forum.setMinimumReply(JsonUtil.opt(toolContentJSON, "minimumReply", 0)); + forum.setLimitedMaxCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); + forum.setLimitedMinCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); + forum.setLockWhenFinished(JsonUtil.optBoolean(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); + forum.setMaxCharacters(JsonUtil.optInt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the + // default entry in the db. + forum.setMaximumRate(JsonUtil.optInt(toolContentJSON, "maximumRate", 0)); + forum.setMaximumReply(JsonUtil.optInt(toolContentJSON, "maximumReply", 0)); + forum.setMinCharacters(JsonUtil.optInt(toolContentJSON, "minCharacters", 0)); + forum.setMinimumRate(JsonUtil.optInt(toolContentJSON, "minimumRate", 0)); + forum.setMinimumReply(JsonUtil.optInt(toolContentJSON, "minimumReply", 0)); forum.setNotifyLearnersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); forum.setNotifyLearnersOnMarkRelease( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); forum.setNotifyTeachersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); - forum.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - forum.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); + forum.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + forum.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); // submissionDeadline is set in monitoring // *******************************Handle user******************* @@ -1587,27 +1586,27 @@ // UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); ForumUser forumUser = getUserByID(userID.longValue()); if (forumUser == null) { - forumUser = new ForumUser(userID.longValue(), toolContentJSON.getString("firstName"), - toolContentJSON.getString("lastName"), toolContentJSON.getString("loginName")); + forumUser = new ForumUser(userID.longValue(), JsonUtil.optString(toolContentJSON, "firstName"), + JsonUtil.optString(toolContentJSON, "lastName"), JsonUtil.optString(toolContentJSON, "loginName")); getForumUserDao().save(forumUser); } forum.setCreatedBy(forumUser); updateForum(forum); // **************************** Handle topic ********************* - JSONArray topics = toolContentJSON.getJSONArray("topics"); - for (int i = 0; i < topics.length(); i++) { - JSONObject msgData = (JSONObject) topics.get(i); + ArrayNode topics = JsonUtil.optArray(toolContentJSON, "topics"); + for (int i = 0; i < topics.size(); i++) { + ObjectNode msgData = (ObjectNode) topics.get(i); Message newMsg = new Message(); // newMsg.setAttachments(attachments); TODO newMsg.setCreatedBy(forumUser); newMsg.setCreated(updateDate); newMsg.setModifiedBy(null); newMsg.setUpdated(updateDate); - newMsg.setSubject(msgData.getString("subject")); - newMsg.setBody(msgData.getString("body")); + newMsg.setSubject(JsonUtil.optString(msgData, "subject")); + newMsg.setBody(JsonUtil.optString(msgData, "body")); newMsg.setForum(forum); newMsg.setHideFlag(false); // newMsg.setIsAnonymous(false); Does not appear on authoring interface Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java =================================================================== diff -u -rc2ad516e6b1fa68cf9828f1b6664344c99b980fc -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java (.../McLearningAction.java) (revision c2ad516e6b1fa68cf9828f1b6664344c99b980fc) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java (.../McLearningAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -40,8 +40,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; @@ -68,6 +66,9 @@ import org.lamsfoundation.lams.web.util.AttributeNames; import org.lamsfoundation.lams.web.util.SessionMap; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Ozgur Demirtas */ @@ -260,13 +261,14 @@ String httpSessionID = mcLearningForm.getHttpSessionID(); SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID); request.getSession().setAttribute(httpSessionID, sessionMap); - + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); McSession session = mcService.getMcSessionById(new Long(toolSessionID)); String toolContentId = session.getMcContent().getMcContentId().toString(); McContent mcContent = mcService.getMcContent(new Long(toolContentId)); - List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, mcContent.isQuestionsSequenced()); + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); if (mcContent.isQuestionsSequenced()) { sessionMap.put(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY, answers); } @@ -283,7 +285,7 @@ /* process the answers */ List answerDtos = buildAnswerDtos(answers, mcContent, request); mcService.saveUserAttempt(user, answerDtos); - + //calculate total learner mark int learnerMark = 0; for (AnswerDTO answerDto : answerDtos) { @@ -330,13 +332,14 @@ } //parse learner input - List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, mcContent.isQuestionsSequenced()); + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); sessionMap.put(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY, answers); //save user attempt List answerDtos = buildAnswerDtos(answers, mcContent, request); mcService.saveUserAttempt(user, answerDtos); - + List learnerAnswersDTOList = mcService.getAnswersFromDatabase(mcContent, user); request.setAttribute(McAppConstants.LEARNER_ANSWERS_DTO_LIST, learnerAnswersDTOList); @@ -389,7 +392,7 @@ String toolContentId = mcSession.getMcContent().getMcContentId().toString(); McContent mcContent = mcService.getMcContent(new Long(toolContentId)); - + String sessionMapID = mcLearningForm.getHttpSessionID(); request.setAttribute("sessionMapID", sessionMapID); @@ -493,15 +496,17 @@ mcGeneralLearnerFlowDTO.setDisplayAnswers(new Boolean(mcContent.isDisplayAnswers()).toString()); mcGeneralLearnerFlowDTO.setDisplayFeedbackOnly(((Boolean)mcContent.isDisplayFeedbackOnly()).toString()); mcGeneralLearnerFlowDTO.setLearnerMark(user.getLastAttemptTotalMark()); - + Object[] markStatistics = null; if (mcContent.isShowMarks()) { markStatistics = mcService.getMarkStatistics(mcSession); } if (markStatistics != null) { - mcGeneralLearnerFlowDTO.setLowestMark(markStatistics[0] != null ? ((Float)markStatistics[0]).intValue() : 0); - mcGeneralLearnerFlowDTO.setAverageMark(markStatistics[1] != null ? ((Float)markStatistics[1]).intValue() : 0); - mcGeneralLearnerFlowDTO.setTopMark(markStatistics[2] != null ? ((Float)markStatistics[2]).intValue() : 0); + mcGeneralLearnerFlowDTO + .setLowestMark(markStatistics[0] != null ? ((Float) markStatistics[0]).intValue() : 0); + mcGeneralLearnerFlowDTO + .setAverageMark(markStatistics[1] != null ? ((Float) markStatistics[1]).intValue() : 0); + mcGeneralLearnerFlowDTO.setTopMark(markStatistics[2] != null ? ((Float) markStatistics[2]).intValue() : 0); } else { mcGeneralLearnerFlowDTO.setLowestMark(0); mcGeneralLearnerFlowDTO.setAverageMark(0); @@ -574,7 +579,7 @@ * checks Leader Progress */ public ActionForward checkLeaderProgress(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { if (mcService == null) { mcService = McServiceProxy.getMcService(getServlet().getServletContext()); @@ -586,10 +591,10 @@ boolean isLeaderResponseFinalized = leader.isResponseFinalised(); - JSONObject JSONObject = new JSONObject(); - JSONObject.put("isLeaderResponseFinalized", isLeaderResponseFinalized); + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); response.setContentType("application/x-json;charset=utf-8"); - response.getWriter().print(JSONObject); + response.getWriter().print(ObjectNode); return null; } @@ -708,15 +713,17 @@ return null; } - List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, mcContent.isQuestionsSequenced()); + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); List answerDtos = buildAnswerDtos(answers, mcContent, request); mcService.saveUserAttempt(user, answerDtos); return null; } - private static List parseLearnerAnswers(McLearningForm mcLearningForm, HttpServletRequest request, boolean isQuestionsSequenced) { + private static List parseLearnerAnswers(McLearningForm mcLearningForm, HttpServletRequest request, + boolean isQuestionsSequenced) { String httpSessionID = mcLearningForm.getHttpSessionID(); SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID); Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java =================================================================== diff -u -r2485ce33e55a921bdcde94e4f242da5da3cf1fc4 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java (.../McMonitoringAction.java) (revision 2485ce33e55a921bdcde94e4f242da5da3cf1fc4) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java (.../McMonitoringAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -37,14 +37,10 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionRedirect; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; import org.lamsfoundation.lams.tool.exception.ToolException; @@ -62,19 +58,22 @@ import org.lamsfoundation.lams.tool.mc.service.IMcService; import org.lamsfoundation.lams.tool.mc.service.McServiceProxy; import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.action.LamsDispatchAction; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Ozgur Demirtas */ public class McMonitoringAction extends LamsDispatchAction { - private static Logger logger = Logger.getLogger(McMonitoringAction.class.getName()); - /** * Turn on displayAnswers */ @@ -88,7 +87,7 @@ mcContent.setDisplayAnswers(new Boolean(true)); mcContent.setDisplayFeedbackOnly(new Boolean(false)); mcService.updateMc(mcContent); - + // use redirect to prevent resubmition of the same request ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("monitoringStarterRedirect")); redirect.addParameter(McAppConstants.TOOL_CONTENT_ID, strToolContentID); @@ -104,7 +103,7 @@ IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); String strToolContentID = request.getParameter(AttributeNames.PARAM_TOOL_CONTENT_ID); String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID); - + McContent mcContent = mcService.getMcContent(new Long(strToolContentID)); mcContent.setDisplayFeedbackOnly(new Boolean(true)); mcService.updateMc(mcContent); @@ -195,7 +194,7 @@ /** * Set Submission Deadline - * + * * @throws IOException */ public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request, @@ -237,14 +236,14 @@ * @throws IOException */ public ActionForward setActivityEvaluation(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { IMcService service = McServiceProxy.getMcService(getServlet().getServletContext()); Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); - String activityEvaluation = WebUtil.readStrParam(request, McAppConstants.ATTR_ACTIVITY_EVALUATION, true); + String activityEvaluation = WebUtil.readStrParam(request, McAppConstants.ATTR_ACTIVITY_EVALUATION); service.setActivityEvaluation(contentID, activityEvaluation); - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); responseJSON.put("success", "true"); response.setContentType("application/json;charset=utf-8"); response.getWriter().print(new String(responseJSON.toString())); @@ -294,7 +293,7 @@ * Return paged users for jqGrid. */ public ActionForward getPagedUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); @@ -316,19 +315,19 @@ int countVisitLogs = 0; //in case of UseSelectLeaderToolOuput - display only one user if (groupLeader != null) { + + Integer totalMark = groupLeader.getLastAttemptTotalMark(); + Long portraitId = mcService.getPortraitId(groupLeader.getQueUsrId()); + + McUserMarkDTO userDto = new McUserMarkDTO(); + userDto.setQueUsrId(groupLeader.getUid().toString()); + userDto.setUserId(groupLeader.getQueUsrId().toString()); + userDto.setFullName(groupLeader.getFullname()); + userDto.setTotalMark(totalMark != null ? totalMark.longValue() : null); + userDto.setPortraitId(portraitId==null ? null : portraitId.toString()); + userDtos.add(userDto); + countVisitLogs = 1; - Integer totalMark = groupLeader.getLastAttemptTotalMark(); - Long portraitId = mcService.getPortraitId(groupLeader.getQueUsrId()); - - McUserMarkDTO userDto = new McUserMarkDTO(); - userDto.setQueUsrId(groupLeader.getUid().toString()); - userDto.setUserId(groupLeader.getQueUsrId().toString()); - userDto.setFullName(groupLeader.getFullname()); - userDto.setTotalMark(totalMark != null ? totalMark.longValue() : null); - userDto.setPortraitId(portraitId == null ? null : portraitId.toString()); - userDtos.add(userDto); - countVisitLogs = 1; - } else { userDtos = mcService.getPagedUsersBySession(sessionId, page - 1, rowLimit, sortBy, sortOrder, searchString); countVisitLogs = mcService.getCountPagedUsersBySession(sessionId, searchString); @@ -337,38 +336,38 @@ int totalPages = new Double( Math.ceil(new Integer(countVisitLogs).doubleValue() / new Integer(rowLimit).doubleValue())).intValue(); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); int i = 1; for (McUserMarkDTO userDto : userDtos) { - JSONArray visitLogData = new JSONArray(); + ArrayNode visitLogData = JsonNodeFactory.instance.arrayNode(); Long userUid = Long.parseLong(userDto.getQueUsrId()); - visitLogData.put(userUid); - visitLogData.put(userDto.getUserId()); + visitLogData.add(userUid); + visitLogData.add(userDto.getUserId()); String fullName = HtmlUtils.htmlEscape(userDto.getFullName()); if (groupLeader != null && groupLeader.getUid().equals(userUid)) { fullName += " (" + mcService.getLocalizedMessage("label.monitoring.group.leader") + ")"; } - visitLogData.put(fullName); + visitLogData.add(fullName); Long totalMark = (userDto.getTotalMark() == null) ? 0 : userDto.getTotalMark(); - visitLogData.put(totalMark); + visitLogData.add(totalMark); + + visitLogData.add(userDto.getPortraitId()); - visitLogData.put(userDto.getPortraitId()); - - JSONObject userRow = new JSONObject(); + ObjectNode userRow = JsonNodeFactory.instance.objectNode(); userRow.put("id", i++); - userRow.put("cell", visitLogData); + userRow.set("cell", visitLogData); - rows.put(userRow); + rows.add(userRow); } - JSONObject responseJSON = new JSONObject(); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); responseJSON.put("total", totalPages); responseJSON.put("page", page); responseJSON.put("records", countVisitLogs); - responseJSON.put("rows", rows); + responseJSON.set("rows", rows); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -394,7 +393,7 @@ * Get the mark summary with data arranged in bands. Can be displayed graphically or in a table. */ public ActionForward getMarkChartData(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); @@ -410,11 +409,12 @@ } } - JSONObject responseJSON = new JSONObject(); - if (results != null) - responseJSON.put("data", results); - else - responseJSON.put("data", new Float[0]); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + if (results != null) { + responseJSON.set("data", JsonUtil.readArray(results)); + } else { + responseJSON.set("data", JsonUtil.readArray(new Float[0])); + } res.setContentType("application/json;charset=utf-8"); res.getWriter().write(responseJSON.toString()); Index: lams_tool_mindmap/.classpath =================================================================== diff -u -r0e594c4a472245d5f4fc8b4978d20a1e7c99867b -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_mindmap/.classpath (.../.classpath) (revision 0e594c4a472245d5f4fc8b4978d20a1e7c99867b) +++ lams_tool_mindmap/.classpath (.../.classpath) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -12,17 +12,20 @@ - + - + - + + + + - + Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/IdeaJSON.java =================================================================== diff -u --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/IdeaJSON.java (revision 0) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/IdeaJSON.java (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -0,0 +1,151 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.mindmap.dto; + +import java.util.Iterator; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeConceptModel; +import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeModel; +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * A JSONObject in the MapJs v3 format as per https://github.com/mindmup/mapjs/wiki/Data-Format. + * Converts from our existing XML Model to JSON and back again. + */ + +// invididual ideas +// +// { +// id: _idea id_, /*alphanumeric */ +// title: _idea title_, /* string */ +// attr : { /* key-value map of idea attributes, optional */ +// style: { }, /* key-value map of style properties, optional */ +// collapsed: true/false /* optional */ +// attachment: { contentType: _content type_, content: _content_ }, +// icon: { url: _icon url_, position: _icon position_, width: _icon width_, height: _icon height_ } +// } + +public class IdeaJSON extends ObjectNode { + + private static Logger logger = Logger.getLogger(IdeaJSON.class); + + public static final String MAPJS_JSON_ID_KEY = "id"; + public static final String MAPJS_JSON_TITLE_KEY = "title"; + public static final String MAPJS_JSON_IDEAS_KEY = "ideas"; + public static final String MAPJS_JSON_STYLE_KEY = "style"; + public static final String MAPJS_JSON_ATTRIBUTES_KEY = "attr"; + public static final String MAPJS_JSON_BACKGROUND_COLOR_KEY = "background"; + public static final String MAPJS_JSON_WIDTH_KEY = "width"; + public static final String MAPJS_JSON_ATTRIBUTES_CONTENTLOCKED = "contentLocked"; + + public static final String DEFAULT_COLOR = "#ffffff"; + + // TODO support more than one main node. mindmup does it, our database code does not + /** Create JSON objects from the database model */ + public IdeaJSON(NodeModel node, int level, boolean includeCreator) { + super(JsonNodeFactory.instance); + + this.put(MAPJS_JSON_ID_KEY, node.getConcept().getId()); + this.put(MAPJS_JSON_TITLE_KEY, node.getConcept().getText()); + + if (includeCreator) { + // only needed for multi user maps + this.put("creator", node.getConcept().getCreator()); // LAMS custom value + } + + ObjectNode attr = JsonNodeFactory.instance.objectNode(); + if (node.getConcept().isEdit() == 0) { + attr.put(MAPJS_JSON_ATTRIBUTES_CONTENTLOCKED, true); + } + ObjectNode style = JsonNodeFactory.instance.objectNode(); + + int nextLevel = level + 1; + if (!node.getBranch().isEmpty()) { + ObjectNode ideasList = JsonNodeFactory.instance.objectNode(); + if (level == 0) { + int rank = 1; + for (NodeModel childNode : node.getBranch()) { + ideasList.set(String.valueOf(rank), new IdeaJSON(childNode, nextLevel, includeCreator)); + rank = -rank; + if (rank > 0) { + rank++; + } + } + } else { + int rank = 1; + for (NodeModel childNode : node.getBranch()) { + ideasList.set(String.valueOf(rank++), new IdeaJSON(childNode, nextLevel, includeCreator)); + } + } + this.set(MAPJS_JSON_IDEAS_KEY, ideasList); + } + + String color = node.getConcept().getColor(); + if (color == null || color.length() == 0) { + color = DEFAULT_COLOR; + } else if (color != null && color.length() > 0 && !color.startsWith("#")) { + color = "#" + color; + } + style.put(MAPJS_JSON_BACKGROUND_COLOR_KEY, color); + attr.set(MAPJS_JSON_STYLE_KEY, style); + this.set(MAPJS_JSON_ATTRIBUTES_KEY, attr); + } + + public static NodeModel toNodeModel(ObjectNode idea) { + + // Pull out the style attributes + String color = null; + if (idea.has(MAPJS_JSON_ATTRIBUTES_KEY)) { + ObjectNode attributes = JsonUtil.optObject(idea, MAPJS_JSON_ATTRIBUTES_KEY); + if (attributes.has(MAPJS_JSON_STYLE_KEY)) { + ObjectNode styles = JsonUtil.optObject(attributes, MAPJS_JSON_STYLE_KEY); + color = JsonUtil.optString(styles, MAPJS_JSON_BACKGROUND_COLOR_KEY); + } + } + if (color == null || color.length() == 0) { + color = DEFAULT_COLOR; + } + + String creator = JsonUtil.optString(idea, "creator"); + NodeConceptModel nodeConceptModel = new NodeConceptModel(JsonUtil.optLong(idea, MAPJS_JSON_ID_KEY), + JsonUtil.optString(idea, MAPJS_JSON_TITLE_KEY), color, creator); + NodeModel nodeModel = new NodeModel(nodeConceptModel); + + if (idea.has(MAPJS_JSON_IDEAS_KEY)) { + ObjectNode ideas = JsonUtil.optObject(idea, MAPJS_JSON_IDEAS_KEY); + Iterator keys = ideas.fieldNames(); + while (keys.hasNext()) { + String key = keys.next(); + nodeModel.addNode(IdeaJSON.toNodeModel(JsonUtil.optObject(ideas, key))); + } + } + + return nodeModel; + } + +} Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyActionJSON.java =================================================================== diff -u --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyActionJSON.java (revision 0) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyActionJSON.java (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -0,0 +1,55 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.mindmap.dto; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * JSON Class for returning update actions to the client for multiuser mode + */ +public class NotifyActionJSON extends ObjectNode { + + // Poll server response + public static final String REQUEST_ID_KEY = "actionId"; // Global ID from request table. + public static final String NODE_ID_KEY = "nodeId"; // Node ID + public static final String TYPE_KEY = "type"; // 0 - delete; 1 - create node; 2 - change color; 3 - change text + public static final String CHILD_NODE_ID_KEY = "childNodeId"; // Child Node ID // 1 - create node + public static final String TITLE_KEY = "title"; // Text (if type is 3, 1) + public static final String BACKGROUND_COLOR = "color"; // Color (if type is 2, maybe 1) + public static final String CREATOR = "creator"; // Creator description (type 1) - not used at present + + public NotifyActionJSON(Long requestId, Long nodeId, int type, Long childNodeId, String text, String color, + String creator) { + super(JsonNodeFactory.instance); + this.put(REQUEST_ID_KEY, requestId); + this.put(NODE_ID_KEY, nodeId); + this.put(TYPE_KEY, type); + this.put(CHILD_NODE_ID_KEY, childNodeId); + this.put(TITLE_KEY, text); + this.put(BACKGROUND_COLOR, color); + this.put(CREATOR, creator); + } + +} Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyResponseJSON.java =================================================================== diff -u --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyResponseJSON.java (revision 0) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/NotifyResponseJSON.java (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -0,0 +1,46 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.mindmap.dto; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * JSON Class for returning responding to a multi user change sent from the client. + */ +public class NotifyResponseJSON extends ObjectNode { + + // Poll server response + public static final String REQUEST_ID_KEY = "requestId"; // Request ID + public static final String NODE_ID_KEY = "nodeId"; // Node ID + public static final String OK = "ok"; + + public NotifyResponseJSON(int ok, Long requestId, Long nodeId) { + super(JsonNodeFactory.instance); + this.put(OK, ok); + this.put(REQUEST_ID_KEY, requestId); + this.put(NODE_ID_KEY, nodeId); + } + +} Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/RootJSON.java =================================================================== diff -u --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/RootJSON.java (revision 0) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/dto/RootJSON.java (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -0,0 +1,110 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.mindmap.dto; + +import java.io.IOException; +import java.util.Iterator; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeModel; +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * A JSONObject in the MapJs v3 format as per https://github.com/mindmup/mapjs/wiki/Data-Format. + * Converts from our existing XML Model to JSON and back again. + * + * If matchUserId is not null then check if this user can edit. If it is null, any user can edit. + */ + +// aggregate root +// +// { +// formatVersion:3, /*numeric, only applicable to root idea*/ +// id: _aggregate idea id_, /* alphanumeric */ +// attr: {}, /* aggregate attributes, such as the map theme */ +// ideas: { _rank_: {_root idea_}, _rank2_: {_root idea 2_} ... }, /* key-value map of root nodes */ +// } +// + +public class RootJSON extends ObjectNode { + + public static final String MAPJS_JSON_ROOT_ID_VALUE = "root"; + + private static Logger logger = Logger.getLogger(RootJSON.class); + + // TODO support more than one main node. mindmup does it, our database code does not + /** Create JSON objects from the database model */ + public RootJSON(NodeModel node, boolean includeCreator) { + super(JsonNodeFactory.instance); + + // create special root level JSON object + this.put(IdeaJSON.MAPJS_JSON_ID_KEY, MAPJS_JSON_ROOT_ID_VALUE); + this.put("formatVersion", "3"); + + if (node != null) { + this.put(IdeaJSON.MAPJS_JSON_TITLE_KEY, node.getConcept().getText()); + } + + // start the recursion to create the ideas objects + ObjectNode ideas = JsonNodeFactory.instance.objectNode(); + ideas.set("1", new IdeaJSON(node, 0, includeCreator)); + this.set(IdeaJSON.MAPJS_JSON_IDEAS_KEY, ideas); + } + + /** + * Deserialise the JSON from the client + * + * @throws IOException + * @throws JsonProcessingException + */ + public static NodeModel toNodeModel(String jsonContent) throws JsonProcessingException, IOException { + ObjectNode rootModel = JsonUtil.readObject(jsonContent); + if (!MAPJS_JSON_ROOT_ID_VALUE.equals(rootModel.get(IdeaJSON.MAPJS_JSON_ID_KEY))) { + throw new IOException("Root idea missing. Unable to parse mindmap. " + jsonContent); + } + + ObjectNode ideasObject = JsonUtil.optObject(rootModel, IdeaJSON.MAPJS_JSON_IDEAS_KEY); + + if (ideasObject.size() == 0) { + logger.error("No ideas to save!!!!!"); + return null; + } + + if (ideasObject.size() > 1) { + logger.warn("More than node found at top level. Saving random node and children only." + jsonContent); + } + + Iterator keys = ideasObject.fieldNames(); + while (keys.hasNext()) { + String key = keys.next(); + return IdeaJSON.toNodeModel(JsonUtil.optObject(ideasObject, key)); + } + return null; + } + +} Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java =================================================================== diff -u -r0e594c4a472245d5f4fc8b4978d20a1e7c99867b -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java (.../MindmapService.java) (revision 0e594c4a472245d5f4fc8b4978d20a1e7c99867b) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java (.../MindmapService.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.tool.mindmap.service; import java.util.ArrayList; @@ -33,8 +32,6 @@ import java.util.SortedMap; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; import org.lamsfoundation.lams.learning.service.ILearnerService; @@ -79,8 +76,9 @@ import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; +import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.security.AnyTypePermission; /** @@ -91,7 +89,7 @@ private static Logger logger = Logger.getLogger(MindmapService.class.getName()); - private final XStream xstream = new XStream(new SunUnsafeReflectionProvider()); + private final XStream xstream = new XStream(new StaxDriver()); private IMindmapDAO mindmapDAO = null; private IMindmapSessionDAO mindmapSessionDAO = null; @@ -168,12 +166,12 @@ public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { return getMindmapOutputFactory().getToolOutput(name, this, toolSessionId, learnerId); } - + @Override public List getToolOutputs(String name, Long toolContentId) { - return new ArrayList(); + return new ArrayList<>(); } - + @Override public List getConfidenceLevels(Long toolSessionId) { return null; @@ -334,12 +332,12 @@ int edit; if ( isAuthor ){ - edit = 1; + edit = 1; } else if ( isMonitor || isUserLocked || mindmapUser == null) { edit = 0; - } else { + } else { edit = mindmapUser.equals(mindmapNode.getUser()) ? 1 : 0; - } + } NodeModel nodeModel = new NodeModel(new NodeConceptModel(mindmapNode.getUniqueId(), mindmapNode.getText(), mindmapNode.getColor(), mindmapUserName, edit)); @@ -428,13 +426,13 @@ return; } - List nodesToDelete = new LinkedList(); + List nodesToDelete = new LinkedList<>(); for (MindmapSession session : (Set) mindmap.getMindmapSessions()) { List nodes = mindmapNodeDAO.getMindmapNodesBySessionIdAndUserId(session.getSessionId(), userId.longValue()); for (MindmapNode node : nodes) { - List descendants = new LinkedList(); + List descendants = new LinkedList<>(); if ((node.getUser() != null) && node.getUser().getUserId().equals(userId.longValue()) && !nodesToDelete.contains(node) && userOwnsChildrenNodes(node, userId.longValue(), descendants)) { @@ -839,10 +837,10 @@ public boolean isGroupedActivity(long toolContentID) { return toolService.isGroupedActivity(toolContentID); } - + @Override public void auditLogStartEditingActivityInMonitor(long toolContentID) { - toolService.auditLogStartEditingActivityInMonitor(toolContentID); + toolService.auditLogStartEditingActivityInMonitor(toolContentID); } public void setMindmapNodeDAO(IMindmapNodeDAO mindmapNodeDAO) { @@ -901,7 +899,6 @@ @Override public MindmapNode getMindmapNodeByUniqueIdSessionId(Long uniqueId, Long mindmapId, Long sessionId) { return mindmapNodeDAO.getMindmapNodeByUniqueIdSessionId(uniqueId, mindmapId, sessionId); - } @Override @@ -990,22 +987,21 @@ * (default false), reflectOnActivity (default false), reflectInstructions */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { Mindmap content = new Mindmap(); Date updateDate = new Date(); content.setToolContentId(toolContentID); content.setCreateDate(updateDate); content.setUpdateDate(updateDate); - content.setTitle(toolContentJSON.getString(RestTags.TITLE)); - content.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + content.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + content.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); content.setContentInUse(false); content.setDefineLater(false); - content.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - content.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - content.setLockOnFinished(JsonUtil.opt(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); - content.setMultiUserMode(JsonUtil.opt(toolContentJSON, "multiUserMode", Boolean.FALSE)); + content.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + content.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + content.setLockOnFinished(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + content.setMultiUserMode(JsonUtil.optBoolean(toolContentJSON, "multiUserMode", Boolean.FALSE)); // createdBy and submissionDeadline are null in the database using the standard authoring module // submissionDeadline is set in monitoring Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/AuthoringAction.java =================================================================== diff -u -r6cfcb91c5526d4bbb22cd98dbd9d04c175cba1eb -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/AuthoringAction.java (.../AuthoringAction.java) (revision 6cfcb91c5526d4bbb22cd98dbd9d04c175cba1eb) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/AuthoringAction.java (.../AuthoringAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.tool.mindmap.web.actions; import java.io.IOException; @@ -31,13 +30,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.lamsfoundation.lams.authoring.web.AuthoringConstants; import org.lamsfoundation.lams.tool.ToolAccessMode; +import org.lamsfoundation.lams.tool.mindmap.dto.RootJSON; import org.lamsfoundation.lams.tool.mindmap.model.Mindmap; import org.lamsfoundation.lams.tool.mindmap.model.MindmapNode; import org.lamsfoundation.lams.tool.mindmap.model.MindmapUser; @@ -47,13 +46,14 @@ import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeConceptModel; import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeModel; import org.lamsfoundation.lams.tool.mindmap.web.forms.AuthoringForm; -import org.lamsfoundation.lams.util.Configuration; -import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.action.LamsDispatchAction; import org.lamsfoundation.lams.web.util.AttributeNames; import org.lamsfoundation.lams.web.util.SessionMap; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Ruslan Kazakov * @version 1.0.1 @@ -104,46 +104,32 @@ String childNodeName1 = mindmapService.getMindmapMessageService().getMessage("node.child1.defaultName"); String childNodeName2 = mindmapService.getMindmapMessageService().getMessage("node.child2.defaultName"); - MindmapNode rootMindmapNode = mindmapService.saveMindmapNode(null, null, 1l, rootNodeName, "ffffff", null, + MindmapNode rootMindmapNode = mindmapService.saveMindmapNode(null, null, 1l, rootNodeName, "#ffffff", null, mindmap, null); mindmapService.saveOrUpdateMindmapNode(rootMindmapNode); - mindmapService.saveMindmapNode(null, rootMindmapNode, 2l, childNodeName1, "ffffff", null, mindmap, null); - mindmapService.saveMindmapNode(null, rootMindmapNode, 3l, childNodeName2, "ffffff", null, mindmap, null); + mindmapService.saveMindmapNode(null, rootMindmapNode, 2l, childNodeName1, "#ffffff", null, mindmap, null); + mindmapService.saveMindmapNode(null, rootMindmapNode, 3l, childNodeName2, "#ffffff", null, mindmap, null); } if (mode.isTeacher()) { // Set the defineLater flag so that learners cannot use content // while we are editing. This flag is released when updateContent is called. mindmap.setDefineLater(true); mindmapService.saveOrUpdateMindmap(mindmap); - + //audit log the teacher has started editing activity in monitor mindmapService.auditLogStartEditingActivityInMonitor(toolContentID); } /* Mindmap Attributes */ + request.setAttribute("mindmapId", mindmap.getUid()); - String mindmapContentPath = Configuration.get(ConfigurationKeys.SERVER_URL) - + "tool/lamind10/authoring.do?dispatch=setMindmapContent%26mindmapId=" + mindmap.getUid(); - request.setAttribute("mindmapContentPath", mindmapContentPath); - - String localizationPath = Configuration.get(ConfigurationKeys.SERVER_URL) - + "tool/lamind10/authoring.do?dispatch=setLocale"; - request.setAttribute("localizationPath", localizationPath); - - String currentMindmapUser = mindmapService.getMindmapMessageService().getMessage("node.instructor.label"); - request.setAttribute("currentMindmapUser", currentMindmapUser); - - String mindmapType = "images/mindmap_singleuser.swf"; - request.setAttribute("mindmapType", mindmapType); - // Set up the authForm. AuthoringForm authForm = (AuthoringForm) form; updateAuthForm(authForm, mindmap); // Set up sessionMap - SessionMap map = createSessionMap(mindmap, mode, contentFolderID, - toolContentID); + SessionMap map = createSessionMap(mindmap, mode, contentFolderID, toolContentID); authForm.setSessionMapID(map.getSessionID()); // add the sessionMap to HTTPSession. @@ -155,18 +141,16 @@ /** * Returns the serialized XML of the Mindmap Nodes from Database - * - * @param mapping - * @param form - * @param request - * @param response - * @return null */ - public ActionForward setMindmapContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + public ActionForward setMindmapContentJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { - Long mindmapId = WebUtil.readLongParam(request, "mindmapId", false); + // set up mindmapService + if (mindmapService == null) { + mindmapService = MindmapServiceProxy.getMindmapService(this.getServlet().getServletContext()); + } + Long mindmapId = WebUtil.readLongParam(request, "mindmapId", false); List mindmapNodeList = mindmapService.getAuthorRootNodeByMindmapId(mindmapId); if (mindmapNodeList != null && mindmapNodeList.size() > 0) { @@ -177,56 +161,26 @@ NodeModel rootNodeModel = new NodeModel(new NodeConceptModel(rootMindmapNode.getUniqueId(), rootMindmapNode.getText(), rootMindmapNode.getColor(), rootMindmapUser, 1)); NodeModel currentNodeModel = mindmapService.getMindmapXMLFromDatabase(rootMindmapNode.getNodeId(), - mindmapId, rootNodeModel, null); + mindmapId, rootNodeModel, null, false, true, false); - String mindmapContent = mindmapService.getXStream().toXML(currentNodeModel); + ObjectNode jsonObject = JsonNodeFactory.instance.objectNode(); + jsonObject.set("mindmap", new RootJSON(currentNodeModel, false)); - try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(mindmapContent); - } catch (IOException e) { - e.printStackTrace(); - } + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(jsonObject.toString()); + return null; } return null; } /** - * Returns the serialized XML of the Mindmap Nodes from Database - * - * @param mapping - * @param form - * @param request - * @param response - * @return null - */ - public ActionForward setLocale(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - - try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(mindmapService.getLanguageXML()); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - - /** * Saves Mindmap Nodes to Database * - * @param mapping - * @param form - * @param request - * @param response - * @return null + * @throws IOException */ public ActionForward updateContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws IOException { // get authForm and session map. AuthoringForm authForm = (AuthoringForm) form; SessionMap map = getSessionMap(request, authForm); @@ -253,13 +207,17 @@ request.setAttribute(MindmapConstants.ATTR_SESSION_MAP, map); /* Saving Minmdap Nodes */ - - // getting xml data from SWF - String mindmapContent = authForm.getMindmapContent(); MindmapUser mindmapUser = mindmapService.getUserByUID(mindmap.getCreateBy()); + String mindmapContent = authForm.getMindmapContent(); - // Saving Mindmap data to XML - NodeModel rootNodeModel = (NodeModel) mindmapService.getXStream().fromXML(mindmapContent); + NodeModel rootNodeModel = RootJSON.toNodeModel(mindmapContent); + if (rootNodeModel == null) { + String error = new StringBuilder("Unable to save mindmap for authoring. User:") + .append(mindmapUser.getLoginName()).append("(" + mindmapUser.getUserId()) + .append("). No root node. JSON: ").append(mindmapContent).toString(); + throw new IOException(error); + } + NodeConceptModel nodeConceptModel = rootNodeModel.getConcept(); List branches = rootNodeModel.getBranch(); Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningAction.java =================================================================== diff -u -rc460c4454266a5b356af92096468e48613939da9 -r1b036cb2e23c7358b8b44b47c4a131853d2075d1 --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningAction.java (.../LearningAction.java) (revision c460c4454266a5b356af92096468e48613939da9) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningAction.java (.../LearningAction.java) (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -45,7 +45,10 @@ import org.lamsfoundation.lams.tool.ToolSessionManager; import org.lamsfoundation.lams.tool.exception.DataMissingException; import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.mindmap.dto.IdeaJSON; import org.lamsfoundation.lams.tool.mindmap.dto.MindmapDTO; +import org.lamsfoundation.lams.tool.mindmap.dto.NotifyResponseJSON; +import org.lamsfoundation.lams.tool.mindmap.dto.RootJSON; import org.lamsfoundation.lams.tool.mindmap.model.Mindmap; import org.lamsfoundation.lams.tool.mindmap.model.MindmapNode; import org.lamsfoundation.lams.tool.mindmap.model.MindmapRequest; @@ -57,19 +60,21 @@ import org.lamsfoundation.lams.tool.mindmap.util.MindmapException; import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeConceptModel; import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NodeModel; -import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NotifyRequestModel; -import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.NotifyResponseModel; -import org.lamsfoundation.lams.tool.mindmap.util.xmlmodel.PollResponseModel; import org.lamsfoundation.lams.tool.mindmap.web.forms.LearningForm; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.action.LamsDispatchAction; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Ruslan Kazakov * @version 1.0.1 @@ -86,6 +91,10 @@ private static final boolean MODE_OPTIONAL = false; private IMindmapService mindmapService; + private static final String REQUEST_JSON_TYPE = "type"; // Expected to be int: 0 - delete; 1 - create node; 2 - change color; 3 - change text + private static final String REQUEST_JSON_REQUEST_ID = "requestId"; // Expected to be long + private static final String REQUEST_JSON_PARENT_NODE_ID = "parentId"; // Expected to be long + /** * Default action on page load. Clones Mindmap Nodes for each Learner in single-user mode. Uses shared (runtime * created in CopyToolContent method) Mindmap Nodes in multi-user mode. @@ -97,6 +106,7 @@ * @return null */ @Override + @SuppressWarnings("rawtypes") public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { @@ -149,15 +159,15 @@ LearningWebUtil.putActivityPositionInRequestByToolSessionId(toolSessionID, request, getServlet().getServletContext()); + HttpSession ss = SessionManager.getSession(); + UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + // check if there is submission deadline Date submissionDeadline = mindmap.getSubmissionDeadline(); if (submissionDeadline != null) { // store submission deadline to sessionMap request.setAttribute(MindmapConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); - - HttpSession ss = SessionManager.getSession(); - UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); - TimeZone learnerTimeZone = learnerDto.getTimeZone(); + TimeZone learnerTimeZone = userDto.getTimeZone(); Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); @@ -169,8 +179,7 @@ MindmapUser mindmapUser; if (mode.equals(ToolAccessMode.TEACHER)) { - Long userID = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID, false); - mindmapUser = mindmapService.getUserByUserIdAndSessionId(userID, toolSessionID); + mindmapUser = mindmapService.getUserByUserIdAndSessionId(userDto.getUserID().longValue(), toolSessionID); } else { mindmapUser = getCurrentUser(toolSessionID); } @@ -193,35 +202,6 @@ String currentMindmapUser = mindmapUser.getFirstName() + " " + mindmapUser.getLastName(); request.setAttribute("currentMindmapUser", currentMindmapUser); - // mindmapType Parameter - String mindmapType = null; - if (mindmap.isLockOnFinished() && mindmapUser.isFinishedActivity()) { - mindmapType = "images/mindmap_locked.swf"; - } else { - if (mindmap.isMultiUserMode() == true) { - mindmapType = "images/mindmap_multiuser.swf"; - } else { - mindmapType = "images/mindmap_singleuser.swf"; - } - } - request.setAttribute("mindmapType", mindmapType); - - // pollServer Parameter - String pollServerParam = Configuration.get(ConfigurationKeys.SERVER_URL) - + "tool/lamind10/learning.do?dispatch=pollServerAction%26mindmapId=" + mindmap.getUid() + "%26userId=" - + mindmapUser.getUid() + "%26sessionId=" + mindmapSession.getSessionId(); - request.setAttribute("pollServerParam", pollServerParam); - - // notifyServer Parameter - String notifyServerParam = Configuration.get(ConfigurationKeys.SERVER_URL) - + "tool/lamind10/learning.do?dispatch=notifyServerAction%26mindmapId=" + mindmap.getUid() + "%26userId=" - + mindmapUser.getUid() + "%26sessionId=" + mindmapSession.getSessionId(); - request.setAttribute("notifyServerParam", notifyServerParam); - - String localizationPath = Configuration.get(ConfigurationKeys.SERVER_URL) - + "tool/lamind10/learning.do?dispatch=setLocale"; - request.setAttribute("localizationPath", localizationPath); - // setting userId for reflection request.setAttribute("userIdParam", mindmapUser.getUid()); request.setAttribute("toolContentIdParam", mindmap.getUid()); @@ -272,6 +252,7 @@ * @param toContent * @param user */ + @SuppressWarnings("rawtypes") public void cloneMindmapNodesForRuntime(MindmapNode fromMindmapNode, MindmapNode toMindmapNode, Mindmap fromContent, Mindmap toContent, MindmapUser user, MindmapSession session) { toMindmapNode = mindmapService.saveMindmapNode(null, toMindmapNode, fromMindmapNode.getUniqueId(), @@ -296,126 +277,140 @@ * @param request * @param response * @return null + * @throws IOException + * @throws JsonProcessingException + * @throws JSONException */ - public ActionForward notifyServerAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - + @SuppressWarnings("rawtypes") + public ActionForward notifyServerActionJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws JsonProcessingException, IOException { Long userId = WebUtil.readLongParam(request, "userId", false); Long mindmapId = WebUtil.readLongParam(request, "mindmapId", false); Long toolSessionId = WebUtil.readLongParam(request, "sessionId", false); - String requestAction = WebUtil.readStrParam(request, "actionXML", false); + String requestAction = WebUtil.readStrParam(request, "actionJSON", false); MindmapSession mindmapSession = mindmapService.getSessionBySessionId(toolSessionId); - NotifyRequestModel notifyRequestModel = (NotifyRequestModel) mindmapService.getXStream().fromXML(requestAction); - int requestType = notifyRequestModel.getType(); + ObjectNode notifyRequest = JsonUtil.readObject(requestAction); + int requestType = JsonUtil.optInt(notifyRequest, REQUEST_JSON_TYPE); - // if request was previously created - Long lastActionId = WebUtil.readLongParam(request, "lastActionId", false); + MindmapRequest mindmapRequest = null; + if (notifyRequest.has(REQUEST_JSON_REQUEST_ID)) { + Long lastActionId = WebUtil.readLongParam(request, "lastActionId", false); + mindmapRequest = mindmapService.getRequestByUniqueId( + JsonUtil.optLong(notifyRequest, REQUEST_JSON_REQUEST_ID), userId, mindmapId, lastActionId); + } - MindmapRequest mindmapRequest = mindmapService.getRequestByUniqueId(notifyRequestModel.getID(), userId, - mindmapId, lastActionId); + NotifyResponseJSON notifyResponse = null; - String notifyResponse = null; + MindmapUser currentUser = mindmapService.getUserByUID(userId); + if (currentUser == null + || (mindmapSession.getMindmap().isLockOnFinished() && currentUser.isFinishedActivity())) { + notifyResponse = new NotifyResponseJSON(0, null, null); + } // if request wasn't created before, create it - if (mindmapRequest == null) { + else if (mindmapRequest == null) { // getting node to which changes will be applied MindmapNode mindmapNode = null; - List mindmapNodeList = mindmapService.getMindmapNodeByUniqueIdSessionId(notifyRequestModel.getNodeID(), - mindmapId, toolSessionId); - if ((mindmapNodeList != null) && (mindmapNodeList.size() > 0)) { - mindmapNode = (MindmapNode) mindmapNodeList.get(0); - } else { - LearningAction.log.error("notifyServerAction(): Error finding node!"); - return null; + if (notifyRequest.has(IdeaJSON.MAPJS_JSON_ID_KEY) && requestType != 1) { + mindmapNode = mindmapService.getMindmapNodeByUniqueIdSessionId( + JsonUtil.optLong(notifyRequest, IdeaJSON.MAPJS_JSON_ID_KEY), mindmapId, toolSessionId); + if (mindmapNode == null) { + LearningAction.log.error("notifyServerAction(): Error finding node!"); + return null; + } } // delete node if (requestType == 0) { // if node is created not by author or by other user... cannot delete if (mindmapNode.getUser() == mindmapService.getUserByUID(userId)) { - List nodes = mindmapService.getMindmapNodeByUniqueIdSessionId(notifyRequestModel.getNodeID(), + List childNodes = mindmapService.getMindmapNodeByParentIdMindmapIdSessionId(mindmapNode.getNodeId(), mindmapId, toolSessionId); - //if (nodes != null && nodes.size() > 0) // check if node exists - //{ - MindmapNode curNode = (MindmapNode) nodes.get(0); - List childNodes = mindmapService.getMindmapNodeByParentIdMindmapIdSessionId(curNode.getNodeId(), - mindmapId, toolSessionId); - if ((childNodes == null) || (childNodes.size() == 0)) // check if node has any children { - mindmapService.deleteNodeByUniqueMindmapUser(notifyRequestModel.getNodeID(), mindmapId, userId, - toolSessionId); - mindmapRequest = saveMindmapRequest(mindmapRequest, requestType, notifyRequestModel, userId, - mindmapId, null, toolSessionId); - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), null); + mindmapService.deleteNodeByUniqueMindmapUser(mindmapNode.getUniqueId(), mindmapId, userId, + mindmapSession.getUid()); + mindmapRequest = saveMindmapRequestJSON(mindmapRequest, requestType, null, + mindmapNode.getUniqueId(), userId, mindmapId, null, toolSessionId); + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), null); } else { - notifyResponse = generateNotifyResponse(0, null, null); + notifyResponse = new NotifyResponseJSON(0, null, null); } - //} else - // notifyResponse = generateNotifyResponse(0, null, null); } else { - notifyResponse = generateNotifyResponse(0, null, null); + notifyResponse = new NotifyResponseJSON(0, null, null); } } // create node else if (requestType == 1) { - // no checking... users can create nodes everywhere - NodeConceptModel nodeConceptModel = notifyRequestModel.getConcept(); + // no checking... users can create nodes everywhere. - Long uniqueId = // node unique ID - mindmapService.getNodeLastUniqueIdByMindmapUidSessionId(mindmapId, toolSessionId) + 1; + // node unique ID - keep the biggest out of (next database value, client node). this ensures + // that deletions don't go back and fill holes with nodes that may conflict with something on a client. + Long uniqueId = mindmapService.getNodeLastUniqueIdByMindmapUidSessionId(mindmapId, toolSessionId) + 1; + Long childIdFromRequest = JsonUtil.optLong(notifyRequest, IdeaJSON.MAPJS_JSON_ID_KEY); + if (childIdFromRequest.longValue() > uniqueId.longValue()) { + uniqueId = childIdFromRequest; + } - mindmapService.saveMindmapNode(null, mindmapNode, uniqueId, nodeConceptModel.getText(), - nodeConceptModel.getColor(), mindmapService.getUserByUID(userId), - mindmapService.getMindmapByUid(mindmapId), mindmapSession); + Long parentNodeId = JsonUtil.optLong(notifyRequest, REQUEST_JSON_PARENT_NODE_ID); + MindmapNode parentNode = mindmapService.getMindmapNodeByUniqueIdSessionId(parentNodeId, mindmapId, + toolSessionId); + if (parentNode == null) { + LearningAction.log.error("notifyServerAction(): Unable to find parent node: " + parentNodeId + + " toolSessionId " + toolSessionId); + } - mindmapRequest = saveMindmapRequest(mindmapRequest, requestType, notifyRequestModel, userId, mindmapId, - uniqueId, toolSessionId); - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), uniqueId); + mindmapService.saveMindmapNode(null, parentNode, uniqueId, + JsonUtil.optString(notifyRequest, IdeaJSON.MAPJS_JSON_TITLE_KEY), + JsonUtil.optString(notifyRequest, IdeaJSON.MAPJS_JSON_BACKGROUND_COLOR_KEY), + mindmapService.getUserByUID(userId), mindmapService.getMindmapByUid(mindmapId), mindmapSession); + + mindmapRequest = saveMindmapRequestJSON(mindmapRequest, requestType, null, parentNodeId, userId, + mindmapId, uniqueId, toolSessionId); + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), uniqueId); } // change color else if (requestType == 2) { if (mindmapNode.getUser() == mindmapService.getUserByUID(userId)) { - mindmapNode.setColor(notifyRequestModel.getColor()); + mindmapNode.setColor(JsonUtil.optString(notifyRequest, IdeaJSON.MAPJS_JSON_BACKGROUND_COLOR_KEY)); mindmapNode.setUser(mindmapService.getUserByUID(userId)); mindmapService.saveOrUpdateMindmapNode(mindmapNode); - mindmapRequest = saveMindmapRequest(mindmapRequest, requestType, notifyRequestModel, userId, - mindmapId, null, toolSessionId); - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), null); + mindmapRequest = saveMindmapRequestJSON(mindmapRequest, requestType, null, + mindmapNode.getUniqueId(), userId, mindmapId, null, toolSessionId); + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), null); } else { - notifyResponse = generateNotifyResponse(0, null, null); + notifyResponse = new NotifyResponseJSON(0, null, null); } } // change text else if (requestType == 3) { if (mindmapNode.getUser() == mindmapService.getUserByUID(userId)) { - mindmapNode.setText(notifyRequestModel.getText()); + mindmapNode.setText(JsonUtil.optString(notifyRequest, IdeaJSON.MAPJS_JSON_TITLE_KEY)); mindmapNode.setUser(mindmapService.getUserByUID(userId)); mindmapService.saveOrUpdateMindmapNode(mindmapNode); - mindmapRequest = saveMindmapRequest(mindmapRequest, requestType, notifyRequestModel, userId, - mindmapId, null, toolSessionId); - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), null); + mindmapRequest = saveMindmapRequestJSON(mindmapRequest, requestType, null, + mindmapNode.getUniqueId(), userId, mindmapId, null, toolSessionId); + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), null); } else { - notifyResponse = generateNotifyResponse(0, null, null); + notifyResponse = new NotifyResponseJSON(0, null, null); } } } else { if (requestType == 1) { - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), mindmapRequest.getNodeChildId()); } else { - notifyResponse = generateNotifyResponse(1, mindmapRequest.getGlobalId(), null); + notifyResponse = new NotifyResponseJSON(1, mindmapRequest.getGlobalId(), null); } } try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(notifyResponse); + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().write(notifyResponse.toString()); } catch (IOException e) { e.printStackTrace(); } @@ -433,159 +428,62 @@ * @param mindmapId * @param nodeChildId */ - private MindmapRequest saveMindmapRequest(MindmapRequest mindmapRequest, int requestType, - NotifyRequestModel notifyRequestModel, Long userId, Long mindmapId, Long nodeChildId, Long sessionId) { + private MindmapRequest saveMindmapRequestJSON(MindmapRequest mindmapRequest, int requestType, Long requestId, + Long nodeId, Long userId, Long mindmapId, Long nodeChildId, Long sessionId) { mindmapRequest = new MindmapRequest(); mindmapRequest.setType(requestType); - mindmapRequest.setUniqueId(notifyRequestModel.getID()); + mindmapRequest.setUniqueId(requestId); // incrementing lastRequestId mindmapRequest.setGlobalId(mindmapService.getLastGlobalIdByMindmapId(mindmapId, sessionId) + 1); mindmapRequest.setUser(mindmapService.getUserByUID(userId)); mindmapRequest.setMindmap(mindmapService.getMindmapByUid(mindmapId)); - mindmapRequest.setNodeId(notifyRequestModel.getNodeID()); + mindmapRequest.setNodeId(nodeId); mindmapRequest.setNodeChildId(nodeChildId); // nodeChildId mindmapService.saveOrUpdateMindmapRequest(mindmapRequest); return mindmapRequest; } /** - * Generated Notify Responses + * Returns the serialized JSON of the Mindmap Nodes from Database * - * @param ok - * @param id - * @param data - */ - private String generateNotifyResponse(int ok, Long id, Long data) { - NotifyResponseModel nodeResponseModel = new NotifyResponseModel(); - nodeResponseModel.setOk(ok); - nodeResponseModel.setId(id); - if (data != null) { - nodeResponseModel.setData(data); - } - - return mindmapService.getXStream().toXML(nodeResponseModel); - } - - /** - * Returns lists of Poll Requests (Actions) on Mindmap Nodes made by other learners - * * @param mapping * @param form * @param request * @param response * @return null + * @throws JSONException + * @throws IOException */ - public ActionForward pollServerAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + @SuppressWarnings("rawtypes") + public ActionForward setMindmapContentJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + // set up mindmapService + if (mindmapService == null) { + mindmapService = MindmapServiceProxy.getMindmapService(this.getServlet().getServletContext()); + } + Long mindmapId = WebUtil.readLongParam(request, "mindmapId", false); - Long userId = WebUtil.readLongParam(request, "userId", false); - Long toolSessionId = WebUtil.readLongParam(request, "sessionId", false); - Long lastActionId = WebUtil.readLongParam(request, "lastActionID", false); + Long toolSessionId = WebUtil.readLongParam(request, "sessionId", true); + Mindmap mindmap = mindmapService.getMindmapByUid(mindmapId); - PollResponseModel pollResponseModel = new PollResponseModel(); + ToolAccessMode mode = WebUtil.readToolAccessModeParam(request, AttributeNames.PARAM_MODE, + LearningAction.MODE_OPTIONAL); + boolean monitoring = mode.equals(ToolAccessMode.TEACHER); - List requestsList = mindmapService.getLastRequestsAfterGlobalId(lastActionId, mindmapId, userId, toolSessionId); - for (Iterator iterator = requestsList.iterator(); iterator.hasNext();) { - MindmapRequest mindmapRequest = (MindmapRequest) iterator.next(); - int requestType = mindmapRequest.getType(); - - NotifyRequestModel notifyRequestModel = null; - NodeConceptModel nodeConceptModel = null; - - MindmapNode rootMindmapNode = null; - if ((requestType != 0) && (requestType != 1)) { - //List nodesList = mindmapService.getMindmapNodeByUniqueId(mindmapRequest.getNodeId(), mindmapId); - List nodesList = mindmapService.getMindmapNodeByUniqueIdSessionId(mindmapRequest.getNodeId(), mindmapId, - toolSessionId); - - if ((nodesList != null) && (nodesList.size() > 0)) { - rootMindmapNode = (MindmapNode) nodesList.get(0); - } else { - LearningAction.log.error("pollServerAction(): Error finding node while changing text or color!"); - } - } - - MindmapNode mindmapNode = null; - if (requestType == 1) { - //List nodesList = mindmapService.getMindmapNodeByUniqueId(mindmapRequest.getNodeChildId(), mindmapId); - List nodesList = mindmapService.getMindmapNodeByUniqueIdSessionId(mindmapRequest.getNodeChildId(), - mindmapId, toolSessionId); - - if ((nodesList != null) && (nodesList.size() > 0)) { - mindmapNode = (MindmapNode) nodesList.get(0); - } else { - LearningAction.log.error("pollServerAction(): Error finding node while creating a node!"); - } - } - - // delete node - if (requestType == 0) { - notifyRequestModel = new NotifyRequestModel(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), - mindmapRequest.getType(), null, null, null); - } - // create node - else if (requestType == 1) { - nodeConceptModel = new NodeConceptModel(); - nodeConceptModel.setId(mindmapNode.getUniqueId()); - nodeConceptModel.setText(mindmapNode.getText()); - nodeConceptModel.setColor(mindmapNode.getColor()); - - MindmapUser mindmapUser = mindmapNode.getUser(); - if (mindmapUser != null) { - nodeConceptModel.setCreator(mindmapUser.getFirstName() + " " + mindmapUser.getLastName()); - } else { - nodeConceptModel.setCreator("Student"); - } - - notifyRequestModel = new NotifyRequestModel(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), - mindmapRequest.getType(), null, null, nodeConceptModel); - } - // change color - else if (requestType == 2) { - notifyRequestModel = new NotifyRequestModel(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), - mindmapRequest.getType(), null, rootMindmapNode.getColor(), null); - } - // change text - else if (requestType == 3) { - notifyRequestModel = new NotifyRequestModel(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), - mindmapRequest.getType(), rootMindmapNode.getText(), null, null); - } - - pollResponseModel.addNotifyRequest(notifyRequestModel); + // In monitoring we do not need the user when accessing multi mode mindmap + Long userId = WebUtil.readLongParam(request, "userId", true); + if (userId == null && !(monitoring && mindmap.isMultiUserMode())) { + log.error( + "Unable to display mindmap as no user id is supplied. Can only skip user id if this is monitoring and multiuser mode."); + return null; } - String pollResponse = mindmapService.getXStream().toXML(pollResponseModel); - - try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(pollResponse); - } catch (IOException e) { - e.printStackTrace(); + MindmapUser mindmapUser = null; + if (userId != null) { + mindmapUser = mindmapService.getUserByUID(userId); } - return null; - } - - /** - * Returns the serialized XML of the Mindmap Nodes from Database - * - * @param mapping - * @param form - * @param request - * @param response - * @return null - */ - public ActionForward setMindmapContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - - Long mindmapId = WebUtil.readLongParam(request, "mindmapId", false); - Long userId = WebUtil.readLongParam(request, "userId", false); - Long toolSessionId = WebUtil.readLongParam(request, "sessionId", true); - Mindmap mindmap = mindmapService.getMindmapByUid(mindmapId); - MindmapUser mindmapUser = mindmapService.getUserByUID(userId); - List mindmapNodeList = null; if (mindmap.isMultiUserMode()) { mindmapNodeList = mindmapService.getAuthorRootNodeByMindmapSession(mindmapId, toolSessionId); @@ -604,74 +502,66 @@ + rootMindmapNode.getUser().getLastName(); } - int edit = 1; - if (rootMindmapNode.getUser() == mindmapUser) { - edit = 1; - } else { - edit = 0; - } - NodeModel rootNodeModel = new NodeModel(new NodeConceptModel(rootMindmapNode.getUniqueId(), - rootMindmapNode.getText(), rootMindmapNode.getColor(), mindmapUserName, edit)); + rootMindmapNode.getText(), rootMindmapNode.getColor(), mindmapUserName, 0)); NodeModel currentNodeModel = mindmapService.getMindmapXMLFromDatabase(rootMindmapNode.getNodeId(), - mindmapId, rootNodeModel, mindmapUser); + mindmapId, rootNodeModel, mindmapUser, monitoring, false, + mindmap.isLockOnFinished() && mindmapUser.isFinishedActivity()); - String mindmapContent = mindmapService.getXStream().toXML(currentNodeModel); - - // Saving lastActionID - Long lastActionId = mindmapService.getLastGlobalIdByMindmapId(mindmap.getUid(), toolSessionId); - //mindmap.setLastActionId(lastActionId); - + ObjectNode jsonObject = JsonNodeFactory.instance.objectNode(); + jsonObject.set("mindmap", new RootJSON(currentNodeModel, mindmap.isMultiUserMode())); // adding lastActionId if (mindmap.isMultiUserMode()) { - if (mindmap.isLockOnFinished() && !mindmapUser.isFinishedActivity()) { - mindmapContent = "\n" + mindmapContent + "\n" + lastActionId - + "\n"; - } else if (!mindmap.isLockOnFinished()) { - mindmapContent = "\n" + mindmapContent + "\n" + lastActionId - + "\n"; - } + Long lastActionId = mindmapService.getLastGlobalIdByMindmapId(mindmap.getUid(), toolSessionId); + jsonObject.put("lastActionId", lastActionId); } - try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(mindmapContent); - } catch (IOException e) { - e.printStackTrace(); - } - + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(jsonObject.toString()); + return null; } return null; } public ActionForward saveLastMindmapChanges(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws IOException { Long userId = WebUtil.readLongParam(request, "userId", false); Long toolContentId = WebUtil.readLongParam(request, "mindmapId", false); - Long toolSessionId = WebUtil.readLongParam(request, "sessionId", true); + Long toolSessionId = WebUtil.readLongParam(request, "toolSessionID", true); MindmapUser mindmapUser = mindmapService.getUserByUID(userId); Mindmap mindmap = mindmapService.getMindmapByUid(toolContentId); MindmapSession mindmapSession = mindmapService.getSessionBySessionId(toolSessionId); + NotifyResponseJSON responseJSON = null; // Saving Mindmap Nodes if (!mindmap.isMultiUserMode()) { - // getting xml data from SWF + // getting JSON from Mindmup String mindmapContent = WebUtil.readStrParam(request, "content", false); - // learningForm.getMindmapContent(); - - saveMindmapXML(mindmap, mindmapUser, mindmapContent, mindmapSession); + Long rootNodeId = saveMapJsJSON(mindmap, mindmapUser, mindmapContent, mindmapSession); + responseJSON = new NotifyResponseJSON(rootNodeId != null ? 1 : 0, null, rootNodeId); + } else { + responseJSON = new NotifyResponseJSON(0, null, 0L); } + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(responseJSON.toString()); return null; } - public void saveMindmapXML(Mindmap mindmap, MindmapUser mindmapUser, String mindmapContent, - MindmapSession mindmapSession) { - // Saving Mindmap data to XML - NodeModel rootNodeModel = (NodeModel) mindmapService.getXStream().fromXML(mindmapContent); + private Long saveMapJsJSON(Mindmap mindmap, MindmapUser mindmapUser, String mindmapContent, + MindmapSession mindmapSession) throws IOException { + + NodeModel rootNodeModel = RootJSON.toNodeModel(mindmapContent); + if (rootNodeModel == null) { + String error = new StringBuilder("Unable to save mindmap for session:") + .append(mindmapSession.getSessionName()).append("(").append(mindmapSession.getSessionId()) + .append(") user:").append(mindmapUser.getLoginName()).append("(" + mindmapUser.getUserId()) + .append("). No root node. JSON: ").append(mindmapContent).toString(); + throw new IOException(error); + } + NodeConceptModel nodeConceptModel = rootNodeModel.getConcept(); List branches = rootNodeModel.getBranch(); @@ -693,29 +583,8 @@ nodesToDeleteCondition += mindmapService.getNodesToDeleteCondition() + " and mindmap_id = " + mindmap.getUid() + " and user_id = " + mindmapUser.getUid(); mindmapService.deleteNodes(nodesToDeleteCondition); - } - /** - * Returns the serialized XML of the Mindmap Nodes from Database - * - * @param mapping - * @param form - * @param request - * @param response - * @return null - */ - public ActionForward setLocale(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - - try { - response.setContentType("text/xml"); - response.setCharacterEncoding("utf-8"); - response.getWriter().write(mindmapService.getLanguageXML()); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; + return rootMindmapNode.getNodeId(); } /** @@ -747,9 +616,11 @@ * @param request * @param response * @return + * @throws IOException + * @throws JSONException */ public ActionForward reflect(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws IOException { LearningForm learningForm = (LearningForm) form; @@ -771,7 +642,7 @@ // Saving Mindmap Nodes if (!mindmap.isMultiUserMode() && !StringUtils.isBlank(learningForm.getMindmapContent())) { - saveMindmapXML(mindmap, mindmapUser, learningForm.getMindmapContent(), mindmapSession); + saveMapJsJSON(mindmap, mindmapUser, learningForm.getMindmapContent(), mindmapSession); } // Reflection @@ -794,48 +665,54 @@ * @param request * @param response * @return null + * @throws IOException + * @throws JSONException */ public ActionForward finishActivity(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws IOException { Long toolSessionID = WebUtil.readLongParam(request, "toolSessionID"); MindmapUser mindmapUser = getCurrentUser(toolSessionID); - if (mindmapUser != null) { - LearningForm learningForm = (LearningForm) form; + // Retrieve the session and content + MindmapSession mindmapSession = mindmapService.getSessionBySessionId(toolSessionID); + if (mindmapSession == null) { + throw new MindmapException("Cannot retrieve session with toolSessionID" + toolSessionID); + } + Mindmap mindmap = mindmapSession.getMindmap(); - mindmapUser.setFinishedActivity(true); - mindmapService.saveOrUpdateMindmapUser(mindmapUser); + // if locked do not update anything - do not want to risk having accidently changed the mindmap + boolean contentLocked = mindmap.isLockOnFinished() && mindmapUser.isFinishedActivity(); - // Retrieve the session and content - MindmapSession mindmapSession = mindmapService.getSessionBySessionId(toolSessionID); - if (mindmapSession == null) { - throw new MindmapException("Cannot retrieve session with toolSessionID" + toolSessionID); - } + if (mindmapUser != null) { + if (!contentLocked) { + LearningForm learningForm = (LearningForm) form; - Mindmap mindmap = mindmapSession.getMindmap(); + mindmapUser.setFinishedActivity(true); + mindmapService.saveOrUpdateMindmapUser(mindmapUser); - // save the reflection entry and call the notebook. - if (mindmap.isReflectOnActivity()) { - // check for existing notebook entry - NotebookEntry entry = mindmapService.getEntry(mindmapUser.getEntryUID()); - if (entry == null) { - // create new entry - Long entryUID = mindmapService.createNotebookEntry(toolSessionID, - CoreNotebookConstants.NOTEBOOK_TOOL, MindmapConstants.TOOL_SIGNATURE, - mindmapUser.getUserId().intValue(), learningForm.getEntryText()); - mindmapUser.setEntryUID(entryUID); - mindmapService.saveOrUpdateMindmapUser(mindmapUser); + // save the reflection entry and call the notebook. + if (mindmap.isReflectOnActivity()) { + // check for existing notebook entry + NotebookEntry entry = mindmapService.getEntry(mindmapUser.getEntryUID()); + if (entry == null) { + // create new entry + Long entryUID = mindmapService.createNotebookEntry(toolSessionID, + CoreNotebookConstants.NOTEBOOK_TOOL, MindmapConstants.TOOL_SIGNATURE, + mindmapUser.getUserId().intValue(), learningForm.getEntryText()); + mindmapUser.setEntryUID(entryUID); + mindmapService.saveOrUpdateMindmapUser(mindmapUser); + } else { + // update existing entry + entry.setEntry(learningForm.getEntryText()); + entry.setLastModified(new Date()); + mindmapService.updateEntry(entry); + } } else { - // update existing entry - entry.setEntry(learningForm.getEntryText()); - entry.setLastModified(new Date()); - mindmapService.updateEntry(entry); + if (!mindmap.isMultiUserMode() && !StringUtils.isBlank(learningForm.getMindmapContent())) { + saveMapJsJSON(mindmap, mindmapUser, learningForm.getMindmapContent(), mindmapSession); + } } - } else { - if (!mindmap.isMultiUserMode() && !StringUtils.isBlank(learningForm.getMindmapContent())) { - saveMindmapXML(mindmap, mindmapUser, learningForm.getMindmapContent(), mindmapSession); - } } } else { Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningWebsocketServer.java =================================================================== diff -u --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningWebsocketServer.java (revision 0) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/web/actions/LearningWebsocketServer.java (revision 1b036cb2e23c7358b8b44b47c4a131853d2075d1) @@ -0,0 +1,291 @@ +package org.lamsfoundation.lams.tool.mindmap.web.actions; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.websocket.CloseReason; +import javax.websocket.CloseReason.CloseCodes; +import javax.websocket.OnClose; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.tool.mindmap.dto.NotifyActionJSON; +import org.lamsfoundation.lams.tool.mindmap.model.MindmapNode; +import org.lamsfoundation.lams.tool.mindmap.model.MindmapRequest; +import org.lamsfoundation.lams.tool.mindmap.model.MindmapSession; +import org.lamsfoundation.lams.tool.mindmap.model.MindmapUser; +import org.lamsfoundation.lams.tool.mindmap.service.IMindmapService; +import org.lamsfoundation.lams.tool.mindmap.service.MindmapServiceProxy; +import org.lamsfoundation.lams.util.hibernate.HibernateSessionManager; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Sends Node changes to Learners. + * + * @author Fiona Malikoff, based on code from Marcin Cieslak + */ +@ServerEndpoint("/learningWebsocket") +public class LearningWebsocketServer { + + /** + * A singleton which updates Learners with node changes. + */ + private static class SendWorker extends Thread { + private boolean stopFlag = false; + // how ofter the thread runs + private static final long CHECK_INTERVAL = 3000; + + @Override + public void run() { + while (!stopFlag) { + try { + // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually + HibernateSessionManager.openSession(); + Iterator>> entryIterator = LearningWebsocketServer.websockets.entrySet() + .iterator(); + // go through activities and update registered learners with reports and vote count + while (entryIterator.hasNext()) { + Entry> entry = entryIterator.next(); + Long toolSessionId = entry.getKey(); + // if all learners left the activity, remove the obsolete mapping + Set sessionWebsockets = entry.getValue(); + if (sessionWebsockets.isEmpty()) { + entryIterator.remove(); + LearningWebsocketServer.globalIdCache.remove(toolSessionId); + continue; + } + SendWorker.send(toolSessionId, null, null); + } + } catch (Exception e) { + // error caught, but carry on + LearningWebsocketServer.log.error("Error in Mindmap worker thread", e); + } finally { + HibernateSessionManager.closeSession(); + try { + Thread.sleep(SendWorker.CHECK_INTERVAL); + } catch (InterruptedException e) { + LearningWebsocketServer.log.warn("Stopping Mindmap worker thread"); + stopFlag = true; + } + } + } + } + + /** + * Feeds websockets with reports and votes. + */ + private static void send(Long toolSessionId, Session newWebsocket, Long userLastGlobalId) throws IOException { + Long previousGlobalId = LearningWebsocketServer.globalIdCache.get(toolSessionId); + if (previousGlobalId == null) { + // first time run, create the cache + previousGlobalId = 0L; + LearningWebsocketServer.globalIdCache.put(toolSessionId, previousGlobalId); + } + + MindmapSession mindmapSession = LearningWebsocketServer.getMindmapService() + .getSessionBySessionId(toolSessionId); + + ObjectNode responseJSON = null; + // new user joined. Send everything from their initial globalId sent when the websocket was created + if (newWebsocket != null) { + responseJSON = SendWorker.getServerActionJSON(mindmapSession.getMindmap().getUid(), + mindmapSession.getSessionId(), userLastGlobalId); + newWebsocket.getBasicRemote().sendText(responseJSON.toString()); + + // send all requests since previousGlobalId + } else { + Long currentMaxGlobalId = LearningWebsocketServer.getMindmapService().getLastGlobalIdByMindmapId( + mindmapSession.getMindmap().getUid(), mindmapSession.getSessionId()); + if (currentMaxGlobalId > previousGlobalId) { + responseJSON = SendWorker.getServerActionJSON(mindmapSession.getMindmap().getUid(), + mindmapSession.getSessionId(), previousGlobalId); + LearningWebsocketServer.globalIdCache.put(toolSessionId, currentMaxGlobalId); + Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); + for (Session websocket : sessionWebsockets) { + websocket.getBasicRemote().sendText(responseJSON.toString()); + } + } + } + } + + private static final String RESPONSE_JSON_ACTIONS = "actions"; + + private static ObjectNode getServerActionJSON(Long mindmapId, Long toolSessionId, Long lastActionId) { + + ObjectNode sendObjectNode = JsonNodeFactory.instance.objectNode(); + ArrayNode actions = JsonNodeFactory.instance.arrayNode(); + sendObjectNode.set(RESPONSE_JSON_ACTIONS, actions); + + List requestsList = mindmapService.getLastRequestsAfterGlobalId(lastActionId, mindmapId, + toolSessionId); + for (Iterator iterator = requestsList.iterator(); iterator.hasNext();) { + MindmapRequest mindmapRequest = iterator.next(); + int requestType = mindmapRequest.getType(); + + ObjectNode notifyRequestModel = null; + MindmapNode mindmapNode = null; + MindmapNode childMindmapNode = null; + if ((requestType != 0)) { + + mindmapNode = mindmapService.getMindmapNodeByUniqueIdSessionId(mindmapRequest.getNodeId(), + mindmapId, toolSessionId); + if (mindmapNode == null) { + LearningWebsocketServer.log.error( + "getServerActionJSON(): Error finding node while sending data about adding child, changing text or color. Cannot send request to clients. Request details:" + + mindmapRequest); + continue; + } + + if (requestType == 1) { + childMindmapNode = mindmapService.getMindmapNodeByUniqueIdSessionId( + mindmapRequest.getNodeChildId(), mindmapId, toolSessionId); + if (childMindmapNode == null) { + LearningWebsocketServer.log.error( + "pollServerAction(): Error finding node while sending data about creating a child node. Cannot send request to clients. Cannot send request to clients. Request details:" + + mindmapRequest); + continue; + } + } + } + + // delete node + if (requestType == 0) { + notifyRequestModel = new NotifyActionJSON(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), + mindmapRequest.getType(), null, null, null, null); + } + // create node + else if (requestType == 1) { + String creator = null; + MindmapUser mindmapUser = childMindmapNode.getUser(); + if (mindmapUser != null) { + creator = mindmapUser.getFirstName() + " " + mindmapUser.getLastName(); + } else { + creator = "Student"; + } + notifyRequestModel = new NotifyActionJSON(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), + mindmapRequest.getType(), mindmapRequest.getNodeChildId(), childMindmapNode.getText(), + childMindmapNode.getColor(), creator); + } + // change color + else if (requestType == 2) { + notifyRequestModel = new NotifyActionJSON(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), + mindmapRequest.getType(), null, null, mindmapNode.getColor(), null); + } + // change text + else if (requestType == 3) { + notifyRequestModel = new NotifyActionJSON(mindmapRequest.getGlobalId(), mindmapRequest.getNodeId(), + mindmapRequest.getType(), null, mindmapNode.getText(), null, null); + } + + actions.add(notifyRequestModel); + } + + return sendObjectNode; + } + } + + private static Logger log = Logger.getLogger(LearningWebsocketServer.class); + + private static IMindmapService mindmapService; + + private static final SendWorker sendWorker = new SendWorker(); + // maps toolSessionId -> cached session data + private static final Map globalIdCache = new ConcurrentHashMap<>(); + private static final Map> websockets = new ConcurrentHashMap<>(); + + static { + // run the singleton thread + LearningWebsocketServer.sendWorker.start(); + } + + /** + * Registeres the Learner for processing by SendWorker. + */ + @OnOpen + public void registerUser(Session websocket) throws IOException { + Long toolSessionId = Long + .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); + Long lastActionId = Long.valueOf(websocket.getRequestParameterMap().get("lastActionId").get(0)); + Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); + if (sessionWebsockets == null) { + sessionWebsockets = ConcurrentHashMap.newKeySet(); + LearningWebsocketServer.websockets.put(toolSessionId, sessionWebsockets); + } + sessionWebsockets.add(websocket); + + if (LearningWebsocketServer.log.isDebugEnabled()) { + LearningWebsocketServer.log.debug("User " + websocket.getUserPrincipal().getName() + + " entered Mindmap with toolSessionId: " + toolSessionId + " lastActionId: " + lastActionId); + } + + new Thread(() -> { + try { + HibernateSessionManager.openSession(); + SendWorker.send(toolSessionId, websocket, lastActionId); + } catch (Exception e) { + log.error("Error while sending messages", e); + } finally { + HibernateSessionManager.closeSession(); + } + }).start(); + } + + /** + * When user leaves the activity. + */ + @OnClose + public void unregisterUser(Session websocket, CloseReason reason) { + Long toolSessionId = Long + .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); + LearningWebsocketServer.websockets.get(toolSessionId).remove(websocket); + + if (LearningWebsocketServer.log.isDebugEnabled()) { + // If there was something wrong with the connection, put it into logs. + LearningWebsocketServer.log.debug("User " + websocket.getUserPrincipal().getName() + + " left Mindmap with Tool Session ID: " + toolSessionId + + (!(reason.getCloseCode().equals(CloseCodes.GOING_AWAY) + || reason.getCloseCode().equals(CloseCodes.NORMAL_CLOSURE)) + ? ". Abnormal close. Code: " + reason.getCloseCode() + ". Reason: " + + reason.getReasonPhrase() + : "")); + } + } + + /** + * Receives a message sent by Learner via a websocket. + */ + @OnMessage + public void receiveRequest(String input, Session websocket) { + if (StringUtils.isBlank(input)) { + return; + } + if (input.equalsIgnoreCase("ping")) { + // just a ping every few minutes + return; + } + log.warn("Unexpected request received by Mindmap websocket. Message is being ignored. Message was: " + input); + } + + private static IMindmapService getMindmapService() { + if (LearningWebsocketServer.mindmapService == null) { + LearningWebsocketServer.mindmapService = MindmapServiceProxy + .getMindmapService(SessionManager.getServletContext()); + } + return LearningWebsocketServer.mindmapService; + } + +} \ No newline at end of file