Java tutorial
/********************************************************************************** * $URL: https://source.sakaiproject.org/contrib/assignment2/trunk/impl/src/java/org/sakaiproject/assignment2/logic/impl/AssignmentLogicImpl.java $ * $Id: AssignmentLogicImpl.java 86722 2014-07-11 04:59:45Z wagnermr@iupui.edu $ *********************************************************************************** * * Copyright (c) 2007 The Sakai Foundation. * * Licensed under the Educational Community License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl1.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.assignment2.logic.impl; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.assignment2.dao.AssignmentDao; import org.sakaiproject.assignment2.exception.AnnouncementPermissionException; import org.sakaiproject.assignment2.exception.AssignmentNotFoundException; import org.sakaiproject.assignment2.exception.CalendarPermissionException; import org.sakaiproject.assignment2.exception.ContentReviewException; import org.sakaiproject.assignment2.exception.InvalidGradebookItemAssociationException; import org.sakaiproject.assignment2.exception.NoGradebookItemForGradedAssignmentException; import org.sakaiproject.assignment2.exception.StaleObjectModificationException; import org.sakaiproject.assignment2.logic.AssignmentBundleLogic; import org.sakaiproject.assignment2.logic.AssignmentLogic; import org.sakaiproject.assignment2.logic.AssignmentPermissionLogic; import org.sakaiproject.assignment2.logic.ExternalAnnouncementLogic; import org.sakaiproject.assignment2.logic.ExternalCalendarLogic; import org.sakaiproject.assignment2.logic.ExternalContentReviewLogic; import org.sakaiproject.assignment2.logic.ExternalEventLogic; import org.sakaiproject.assignment2.logic.ExternalGradebookLogic; import org.sakaiproject.assignment2.logic.ExternalLogic; import org.sakaiproject.assignment2.logic.GradebookItem; import org.sakaiproject.assignment2.logic.utils.Assignment2Utils; import org.sakaiproject.assignment2.logic.utils.ComparatorsUtils; import org.sakaiproject.assignment2.model.Assignment2; import org.sakaiproject.assignment2.model.AssignmentAttachment; import org.sakaiproject.assignment2.model.AssignmentAttachmentBase; import org.sakaiproject.assignment2.model.AssignmentGroup; import org.sakaiproject.assignment2.model.ModelAnswerAttachment; import org.sakaiproject.assignment2.model.constants.AssignmentConstants; import org.sakaiproject.assignment2.service.model.AssignmentDefinition; import org.sakaiproject.assignment2.taggable.api.AssignmentActivityProducer; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.entitybroker.entityprovider.EntityProviderManager; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.genericdao.api.search.Search; import org.sakaiproject.taggable.api.TaggingManager; import org.sakaiproject.taggable.api.TaggingProvider; import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException; /** * This is the interface for the Assignment object * * @author <a href="mailto:wagnermr@iupui.edu">michelle wagner</a> */ public class AssignmentLogicImpl implements AssignmentLogic { private static Log log = LogFactory.getLog(AssignmentLogicImpl.class); private ExternalLogic externalLogic; public void setExternalLogic(ExternalLogic externalLogic) { this.externalLogic = externalLogic; } private ExternalGradebookLogic gradebookLogic; public void setExternalGradebookLogic(ExternalGradebookLogic gradebookLogic) { this.gradebookLogic = gradebookLogic; } private ExternalAnnouncementLogic announcementLogic; public void setExternalAnnouncementLogic(ExternalAnnouncementLogic announcementLogic) { this.announcementLogic = announcementLogic; } private ExternalCalendarLogic calendarLogic; public void setExternalCalendarLogic(ExternalCalendarLogic calendarLogic) { this.calendarLogic = calendarLogic; } private AssignmentPermissionLogic permissionLogic; public void setPermissionLogic(AssignmentPermissionLogic permissionLogic) { this.permissionLogic = permissionLogic; } private AssignmentDao dao; public void setDao(AssignmentDao dao) { this.dao = dao; } private AssignmentBundleLogic bundleLogic; public void setAssignmentBundleLogic(AssignmentBundleLogic bundleLogic) { this.bundleLogic = bundleLogic; } private TaggingManager taggingManager; public void setTaggingManager(TaggingManager taggingManager) { this.taggingManager = taggingManager; } private AssignmentActivityProducer assignmentActivityProducer; public void setAssignmentActivityProducer(AssignmentActivityProducer assignmentActivityProducer) { this.assignmentActivityProducer = assignmentActivityProducer; } private EntityProviderManager entityProviderManager; public void setEntityProviderManager(EntityProviderManager entityProviderManager) { this.entityProviderManager = entityProviderManager; } private ExternalContentReviewLogic externalContentReviewLogic; public void setExternalContentReviewLogic(ExternalContentReviewLogic externalContentReviewLogic) { this.externalContentReviewLogic = externalContentReviewLogic; } private ExternalEventLogic externalEventLogic; public void setExternalEventLogic(ExternalEventLogic externalEventLogic) { this.externalEventLogic = externalEventLogic; } // Move to an external API private ServerConfigurationService serverConfigurationService; public void setServerConfigurationService(ServerConfigurationService serverConfigurationService) { this.serverConfigurationService = serverConfigurationService; } private boolean allowGradebookSync; public void init() { if (log.isDebugEnabled()) log.debug("init"); allowGradebookSync = serverConfigurationService.getBoolean(AssignmentConstants.CONFIG_ALLOW_GB_SYNC, true); } public Assignment2 getAssignmentByIdWithAssociatedData(Long assignmentId) { if (assignmentId == null) { throw new IllegalArgumentException("Null assignmentId passed to getAssignmentByIdWithAssociatedData"); } return getAssignmentByIdWithAssociatedData(assignmentId, null); } public Assignment2 getAssignmentByIdWithAssociatedData(Long assignmentId, Map<String, Object> optionalParameters) { if (assignmentId == null) { throw new IllegalArgumentException("Null assignmentId passed to getAssignmentByIdWithAssociatedData"); } // retrieve Assignment2 object Assignment2 assign = (Assignment2) dao.getAssignmentByIdWithGroupsAndAttachments(assignmentId); if (assign == null) { throw new AssignmentNotFoundException("No assignment found with id: " + assignmentId); } // make sure the user can access the assignment object if (!permissionLogic.isUserAllowedToViewAssignment(null, assign, optionalParameters)) { throw new SecurityException( "User attempted to access assignment with id " + assignmentId + " without permission"); } // TODO ASNN-516 Check for ContentReview and populate // check for null entityProviderManager so we don't have to mock it for the unit tests //if (entityProviderManager != null) { // EntityProvider turnitinAsnnProvider = entityProviderManager.getProviderByPrefix("turnitin-assignment"); // if (turnitinAsnnProvider != null && turnitinAsnnProvider instanceof CRUDable) { // CRUDable crudable = (CRUDable) turnitinAsnnProvider; // Map tiiopts = (Map) crudable.getEntity(new EntityReference("turnitin-assignment", externalContentReviewLogic.getTaskId(assign))); // assign.setProperties(tiiopts); // TODO this should be a map merge and not a complete replacement // } //} if (externalContentReviewLogic.isContentReviewAvailable(assign.getContextId())) { externalContentReviewLogic.populateAssignmentPropertiesFromAssignment(assign); } return assign; } public Assignment2 getAssignmentById(Long assignmentId) { if (assignmentId == null) { throw new IllegalArgumentException( "Null assignmentId passed to getAssignmentByIdWithGroupsAndAttachments"); } // make sure the user can access the assignment object if (!permissionLogic.isUserAllowedToViewAssignmentId(null, assignmentId, null)) { throw new SecurityException( "User attempted to access assignment with id " + assignmentId + " without permission"); } Assignment2 assign = (Assignment2) dao.getAssignmentByIdWithGroupsAndAttachments(assignmentId); if (assign == null) { throw new AssignmentNotFoundException("No assignment found with id: " + assignmentId); } return assign; } public void saveAssignment(Assignment2 assignment) throws SecurityException, NoGradebookItemForGradedAssignmentException { saveAssignment(assignment, true); } public void saveAssignment(Assignment2 assignment, boolean syncGradebook) throws SecurityException, NoGradebookItemForGradedAssignmentException { if (assignment == null || assignment.getContextId() == null) { throw new IllegalArgumentException("Null assignment or assignment.contextId passed to saveAssignment"); } // now let's double check the non-null properties have been set if (assignment.getTitle() == null || "".equals(assignment.getTitle().trim()) || assignment.getOpenDate() == null) { throw new IllegalArgumentException("A non-null property of the assignment was null. title:" + assignment.getTitle() + " open date:" + assignment.getOpenDate()); } String currentUserId = externalLogic.getCurrentUserId(); if (assignment.isGraded() && assignment.getGradebookItemId() == null) { throw new NoGradebookItemForGradedAssignmentException( "The assignment to save " + "was defined as graded but it had a null getGradebookItemId"); } boolean isNewAssignment = true; Assignment2 existingAssignment = null; // determine if this is a new assignment if (assignment.getId() != null) { // check to see if assignment exists existingAssignment = (Assignment2) dao.getAssignmentByIdWithGroupsAndAttachments(assignment.getId()); if (existingAssignment != null) { isNewAssignment = false; } else { throw new AssignmentNotFoundException( "No assignment exists with id: " + assignment.getId() + " Assignment update failure."); } } // if it is a new assignment, check to see if user is allowed to add assignments // in this context. otherwise, ensure the user may edit this assignment if (isNewAssignment && !permissionLogic.isUserAllowedToAddAssignment(currentUserId, assignment)) { throw new SecurityException("Current user may not save assignment " + assignment.getTitle() + " because they do not have add permission"); } else if (!isNewAssignment && !permissionLogic.isUserAllowedToEditAssignment(currentUserId, assignment)) { throw new SecurityException("Current user may not edit assignment " + assignment.getTitle() + " because they do not have edit permission"); } // check to see if the gradebook item association is valid if (assignment.isGraded() && !gradebookLogic.isGradebookItemAssociationValid(assignment.getContextId(), assignment.getGradebookItemId())) { throw new InvalidGradebookItemAssociationException( "The gradebook item " + assignment.getGradebookItemId() + " is not a valid gradebook item to associate with this assignment"); } // trim trailing spaces on title assignment.setTitle(assignment.getTitle().trim()); // clean up the html string for the instructions assignment.setInstructions(externalLogic.cleanupUserStrings(assignment.getInstructions(), true)); // double check that content review is available for this assignment if (assignment.isContentReviewEnabled()) { if (!externalContentReviewLogic.isContentReviewAvailable(assignment.getContextId())) { if (log.isDebugEnabled()) log.debug("Content review turned off b/c not available in this site"); assignment.setContentReviewEnabled(false); assignment.setContentReviewStudentViewReport(false); } } Set<AssignmentAttachment> attachToDelete = new HashSet<AssignmentAttachment>(); Set<ModelAnswerAttachment> modelAnswerAttachToDelete = new HashSet<ModelAnswerAttachment>(); Set<AssignmentGroup> groupsToDelete = new HashSet<AssignmentGroup>(); if (isNewAssignment) { // identify the next sort index to be used Integer highestIndex = dao.getHighestSortIndexInSite(assignment.getContextId()); if (highestIndex != null) { assignment.setSortIndex(highestIndex + 1); } else { assignment.setSortIndex(0); } assignment.setRemoved(false); assignment.setCreateDate(new Date()); assignment.setCreator(currentUserId); } else { assignment.setRemoved(false); assignment.setModifiedBy(currentUserId); assignment.setModifiedDate(new Date()); attachToDelete = identifyAttachmentsToDelete(existingAssignment.getAttachmentSet(), assignment.getAttachmentSet()); modelAnswerAttachToDelete = identifyAttachmentsToDelete( existingAssignment.getModelAnswerAttachmentSet(), assignment.getModelAnswerAttachmentSet()); groupsToDelete = identifyGroupsToDelete(existingAssignment, assignment); } try { Set<AssignmentGroup> groupSet = new HashSet<AssignmentGroup>(); if (assignment.getAssignmentGroupSet() != null) { groupSet = assignment.getAssignmentGroupSet(); } Set<AssignmentAttachment> attachToCreate = identifyAttachmentsToCreate( existingAssignment == null ? null : existingAssignment.getAttachmentSet(), assignment == null ? null : assignment.getAttachmentSet()); Set<ModelAnswerAttachment> modelAnswerAttachToCreate = identifyAttachmentsToCreate( existingAssignment == null ? null : existingAssignment.getModelAnswerAttachmentSet(), assignment == null ? null : assignment.getModelAnswerAttachmentSet()); // make sure the assignment has been set for the attachments and groups populateAssignmentForAttachmentAndGroupSets(modelAnswerAttachToCreate, attachToCreate, groupSet, assignment); // ensure that these objects are ready for saving validateAttachmentsAndGroups(modelAnswerAttachToCreate, attachToCreate, groupSet); // TODO ASNN-530 Where is this really happening and why doesn't the null // error occur with regular attachments? /* if (assignment.getModelAnswerAttachmentSet() == null) { assignment.setModelAnswerAttachmentSet(new HashSet<ModelAnswerAttachment>()); } if (assignment.getAttachmentSet() == null) { assignment.setAttachmentSet(new HashSet<AssignmentAttachment>()); } if (assignment.getAssignmentGroupSet() == null) { assignment.setAssignmentGroupSet(new HashSet<AssignmentGroup>()); } */ Set<Assignment2> assignSet = new HashSet<Assignment2>(); assignSet.add(assignment); // to avoid the WARN: Nothing to update messages... List<Set> setsToSave = new ArrayList<Set>(); if (!attachToCreate.isEmpty()) { setsToSave.add(attachToCreate); } if (!groupSet.isEmpty()) { setsToSave.add(groupSet); } if (!modelAnswerAttachToCreate.isEmpty()) { setsToSave.add(modelAnswerAttachToCreate); } if (setsToSave.size() > 0) { Set[] toSave = new Set[setsToSave.size() + 1]; toSave[0] = assignSet; for (int i = 1; i <= setsToSave.size(); i++) { toSave[i] = setsToSave.get(i - 1); } dao.saveMixedSet(toSave); } else { dao.save(assignment); } /* if (!attachToCreate.isEmpty() && !groupSet.isEmpty()) { dao.saveMixedSet(new Set[] {assignSet, attachToCreate, groupSet}); } else if (!attachToCreate.isEmpty()) { dao.saveMixedSet(new Set[] {assignSet, attachToCreate}); } else if (!groupSet.isEmpty()) { dao.saveMixedSet(new Set[] {assignSet, groupSet}); } else { dao.save(assignment); } */ if (log.isDebugEnabled()) { if (isNewAssignment) { log.debug("Created assignment: " + assignment.getTitle()); } else { log.debug("Updated assignment: " + assignment.getTitle() + "with id: " + assignment.getId()); } } if (!isNewAssignment) { if ((attachToDelete != null && !attachToDelete.isEmpty()) || (groupsToDelete != null && !groupsToDelete.isEmpty()) || (modelAnswerAttachToDelete != null && !modelAnswerAttachToDelete.isEmpty())) { dao.deleteMixedSet(new Set[] { attachToDelete, groupsToDelete, modelAnswerAttachToDelete }); if (log.isDebugEnabled()) log.debug("Attachments and/or groups removed for updated assignment " + assignment.getId()); } } if (isNewAssignment) { // ASNN-29 externalEventLogic.postEvent(AssignmentConstants.EVENT_ASSIGN_CREATE, assignment.getReference()); } else { externalEventLogic.postEvent(AssignmentConstants.EVENT_ASSIGN_UPDATE, assignment.getReference()); } } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update assignment with id: " + assignment.getId()); throw new StaleObjectModificationException( "An optimistic locking failure occurred while attempting to update assignment with id: " + assignment.getId(), holfe); } // now let's handle the impact on announcements if (externalLogic.siteHasTool(assignment.getContextId(), ExternalLogic.TOOL_ID_ANNC)) { try { saveAssignmentAnnouncement(existingAssignment, assignment); } catch (AnnouncementPermissionException ape) { log.warn("The current user is not " + "authorized to update announcements in the announcements " + "tool. Any related announcements were NOT updated", ape); } } // now let's handle the impact on the Schedule if (externalLogic.siteHasTool(assignment.getContextId(), ExternalLogic.TOOL_ID_SCHEDULE)) { try { handleDueDateEvent(existingAssignment, assignment); } catch (CalendarPermissionException cpe) { log.warn("The current user is not " + "authorized to update events in the Schedule " + "tool. Any related events were NOT updated", cpe); } } // TODO ASNN-516 Content Review / Turnitin Integration if (assignment.isContentReviewEnabled()) { boolean newIntegration = assignment.getContentReviewRef() == null; String tiiAsnnTitle = externalContentReviewLogic.getTaskId(assignment); assignment.setContentReviewRef(tiiAsnnTitle); log.debug("Going to Create/Update TII Asnn with title: " + tiiAsnnTitle); try { externalContentReviewLogic.createAssignment(assignment); dao.update(assignment); } catch (ContentReviewException cre) { // if we were attempting to integrate for the first time, // we don't want TII enabled to be left as true if (newIntegration) { assignment.setContentReviewEnabled(false); assignment.setContentReviewStudentViewReport(false); assignment.setContentReviewRef(null); dao.update(assignment); } throw new ContentReviewException( "The assignment was saved, " + "but Turnitin information was unable to be updated", cre); } } if (assignment.isGraded()) { GradebookItem gbItem = gradebookLogic.getGradebookItemById(assignment.getContextId(), assignment.getGradebookItemId()); boolean updateGradebook = false; if (allowGradebookSync && syncGradebook) { // ONC-3115 (refactored) List<Assignment2> linkedAsnns = getAssignmentsWithLinkedGradebookItemId( assignment.getGradebookItemId()); if (linkedAsnns != null && linkedAsnns.size() == 1) { gbItem.setTitle(assignment.getTitle()); gbItem.setDueDate(assignment.getDueDate()); updateGradebook = true; } } if (assignment.getGradebookPointsPossible() != null && // this needs to be checked because if this is called // by updateEntity() during an JS inline title rename // PointsPossible will be null gbItem.getPointsPossible() != assignment.getGradebookPointsPossibleDouble()) { gbItem.setPointsPossible(assignment.getGradebookPointsPossibleDouble()); updateGradebook = true; } if (updateGradebook) { gradebookLogic.updateGbItemInGradebook(assignment.getContextId(), gbItem); } } // end if isGraded() } public void deleteAssignment(Assignment2 assignment) throws SecurityException, AnnouncementPermissionException { if (assignment == null) { throw new IllegalArgumentException("Null assignment passed to deleteAssignment"); } if (assignment.getId() == null) { throw new IllegalArgumentException( "The passed assignment does not have an id. Can only delete persisted assignments"); } if (assignment.getContextId() == null) { throw new IllegalArgumentException("The passed assignment does not have an " + "associated contextId. You may not delete an assignment without a contextId"); } if (!permissionLogic.isUserAllowedToDeleteAssignment(null, assignment)) { throw new SecurityException("Current user may not delete assignment " + assignment.getTitle() + " because they do not have delete permission"); } // we remove the tags first because it will check for "delete" permission // while removing the tags, and users can't delete items that have already // been deleted. // only process if taggingManager != null --> this is for the unit // tests to run without mocking up all the tagging stuff if (taggingManager != null) { try { if (taggingManager.isTaggable()) { for (TaggingProvider provider : taggingManager.getProviders()) { provider.removeTags(assignmentActivityProducer.getActivity(assignment)); } } } catch (PermissionException pe) { log.warn("The current user is not authorized to remove tags in the assignment tool, " + "but the associated assignment was deleted", pe); } } assignment.setRemoved(true); assignment.setModifiedBy(externalLogic.getCurrentUserId()); assignment.setModifiedDate(new Date()); // remove associated announcements, if appropriate String announcementIdToDelete = null; if (assignment.getAnnouncementId() != null) { announcementIdToDelete = assignment.getAnnouncementId(); assignment.setAnnouncementId(null); assignment.setHasAnnouncement(false); } // remove associated Schedule/Calendar events, if appropriate String eventIdToDelete = null; if (assignment.getEventId() != null) { eventIdToDelete = assignment.getEventId(); assignment.setEventId(null); assignment.setAddedToSchedule(false); } try { dao.update(assignment); if (log.isDebugEnabled()) log.debug("Deleted assignment: " + assignment.getTitle() + " with id " + assignment.getId()); // ASNN-29 externalEventLogic.postEvent(AssignmentConstants.EVENT_ASSIGN_DELETE, assignment.getReference()); // now remove the announcement, if applicable if (announcementIdToDelete != null) { try { announcementLogic.deleteOpenDateAnnouncement(announcementIdToDelete, assignment.getContextId()); if (log.isDebugEnabled()) log.debug("Deleted announcement with id " + announcementIdToDelete + " for assignment " + assignment.getId()); } catch (AnnouncementPermissionException ape) { log.warn("The current user is not authorized to remove announcements in the annc tool, " + "but the linked assignment was deleted"); } } // now remove the event, if applicable if (eventIdToDelete != null) { try { calendarLogic.deleteDueDateEvent(eventIdToDelete, assignment.getContextId()); if (log.isDebugEnabled()) log.debug("Deleted event with id " + eventIdToDelete + " for assignment " + assignment.getId()); } catch (CalendarPermissionException cpe) { log.warn("The current user is not authorized to remove events in the Schedule tool, " + "but the associated assignment was deleted"); } } } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred " + "while attempting to update an assignment"); throw new StaleObjectModificationException( "Locking failure occurred " + "while removing assignment with id: " + assignment.getId(), holfe); } } public List<Assignment2> getViewableAssignments(String contextId) { if (contextId == null) { throw new IllegalArgumentException("null contextId passed to " + this); } List<Assignment2> viewableAssignments = new ArrayList<Assignment2>(); // include the removed assignments in case the user is auth to view it List<Assignment2> allAssignments = dao.getAllAssignmentsWithGroupsAndAttachments(contextId); if (allAssignments != null && !allAssignments.isEmpty()) { viewableAssignments = permissionLogic.filterViewableAssignments(contextId, allAssignments); } Collections.sort(viewableAssignments, new ComparatorsUtils.Assignment2SortIndexComparator()); return viewableAssignments; } public void reorderAssignments(List<Long> assignmentIds, String contextId) { if (assignmentIds == null) { throw new IllegalArgumentException("Null list of assignmentIds passed to reorder."); } if (contextId == null) { throw new IllegalArgumentException("Null contextId passed to " + this); } if (!permissionLogic.isUserAllowedToEditAllAssignments(null, contextId)) { throw new SecurityException("Unauthorized user attempted to reorder assignments!"); } List<Assignment2> allAssigns = dao.findByProperties(Assignment2.class, new String[] { "contextId", "removed" }, new Object[] { contextId, false }); Map<Long, Assignment2> assignIdAssignMap = new HashMap<Long, Assignment2>(); if (allAssigns != null) { for (Assignment2 assign : allAssigns) { assignIdAssignMap.put(assign.getId(), assign); } } // throw the passed ids into a set to remove duplicates Set<Long> assignIdSet = new HashSet<Long>(); for (Long assignId : assignmentIds) { assignIdSet.add(assignId); } // check that there are an equal number in the passed list as there are // assignments in this site if (assignIdSet.size() != assignIdAssignMap.size()) { throw new IllegalArgumentException( "The number of unique assignment ids passed does not match the num assignments in the site"); } // now make sure all of the passed ids actually exist for (Long assignId : assignmentIds) { if (!assignIdAssignMap.containsKey(assignId)) { throw new IllegalArgumentException( "The assignment id " + assignId + " does not exist in site " + contextId); } } String userId = externalLogic.getCurrentUserId(); //Assume array of longs is in correct order now //so that the index of the array is the new //sort index Set<Assignment2> assignSet = new HashSet<Assignment2>(); for (int i = 0; i < assignmentIds.size(); i++) { //get Assignment Long assignId = assignmentIds.get(i); Assignment2 assignment = assignIdAssignMap.get(assignId); if (assignment != null) { //check if we need to update if (assignment.getSortIndex() != i) { //update and save assignment.setSortIndex(i); assignment.setModifiedBy(userId); assignment.setModifiedDate(new Date()); assignSet.add(assignment); if (log.isDebugEnabled()) log.debug("Assignment " + assignment.getId() + " sort index changed to " + i); } } } try { dao.saveMixedSet(new Set[] { assignSet }); if (log.isDebugEnabled()) log.debug("Reordered assignments saved. " + assignSet.size() + " assigns were updated"); } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to reorder the assignments"); throw new StaleObjectModificationException( "An optimistic locking failure occurred while attempting to reorder the assignments", holfe); } } public int getStatusForAssignment(Assignment2 assignment) { if (assignment == null) { throw new IllegalArgumentException("Null assignment passed to getStatusForAssignment"); } if (assignment.isDraft()) return AssignmentConstants.STATUS_DRAFT; Date currDate = new Date(); if (currDate.before(assignment.getOpenDate())) return AssignmentConstants.STATUS_NOT_OPEN; if (!assignment.isSubmissionOpen()) { return AssignmentConstants.STATUS_CLOSED; } if (assignment.getDueDate() != null) { if (currDate.after(assignment.getDueDate())) return AssignmentConstants.STATUS_DUE; } return AssignmentConstants.STATUS_OPEN; } private void populateAssignmentForAttachmentAndGroupSets(Set<ModelAnswerAttachment> modelAnswerAttachmentSet, Set<AssignmentAttachment> attachSet, Set<AssignmentGroup> groupSet, Assignment2 assign) { if (modelAnswerAttachmentSet != null && !modelAnswerAttachmentSet.isEmpty()) { for (ModelAnswerAttachment attach : modelAnswerAttachmentSet) { if (attach != null) { attach.setAssignment(assign); } } } if (attachSet != null && !attachSet.isEmpty()) { for (AssignmentAttachment attach : attachSet) { if (attach != null) { attach.setAssignment(assign); } } } if (groupSet != null && !groupSet.isEmpty()) { for (AssignmentGroup group : groupSet) { if (group != null) { group.setAssignment(assign); } } } } private Set identifyAttachmentsToDelete(Set existingAttachments, Set updatedAttachments) { Set attachToRemove = new HashSet(); // make a set of attachment references in case the id wasn't populated // properly Set<String> updatedAttachSetRefs = new HashSet<String>(); if (updatedAttachments != null) { for (Object next : updatedAttachments) { AssignmentAttachmentBase attach = (AssignmentAttachmentBase) next; updatedAttachSetRefs.add(attach.getAttachmentReference()); } } if (updatedAttachments != null && existingAttachments != null) { for (Object next : existingAttachments) { //for (AssignmentAttachment attach : existingAssign.getAttachmentSet()) { AssignmentAttachmentBase attach = (AssignmentAttachmentBase) next; if (attach != null) { if (!updatedAttachSetRefs.contains(attach.getAttachmentReference())) { // we need to delete this attachment attachToRemove.add(attach); if (log.isDebugEnabled()) log.debug("Attach to remove: " + attach.getAttachmentReference()); } } } } return attachToRemove; } /** * * @param existingAssignment * @param updatedAssignment * @return a set of attachments associated with the updatedAssignment that do not * currently exist. this is determined by checking to see if there is * already an attachment in the given existingAssignment attachment set with the same * attachmentReference as each attachment in the updatedAssignment. */ private Set identifyAttachmentsToCreate(Set existingAttachments, Set updatedAttachments) { Set attachToCreate = new HashSet(); // make a set of attachment references in case the id wasn't populated // properly Set<String> existingAttachSetRefs = new HashSet<String>(); if (existingAttachments != null) { for (Object next : existingAttachments) { AssignmentAttachmentBase attach = (AssignmentAttachmentBase) next; existingAttachSetRefs.add(attach.getAttachmentReference()); } } if (updatedAttachments != null) { for (Object next : updatedAttachments) { AssignmentAttachmentBase attach = (AssignmentAttachmentBase) next; if (attach != null) { if (!existingAttachSetRefs.contains(attach.getAttachmentReference())) { attachToCreate.add(attach); } } } } return attachToCreate; } private Set<AssignmentGroup> identifyGroupsToDelete(Assignment2 existingAssign, Assignment2 updatedAssign) { Set<AssignmentGroup> groupsToRemove = new HashSet<AssignmentGroup>(); if (updatedAssign != null && existingAssign != null && existingAssign.getAssignmentGroupSet() != null) { for (AssignmentGroup group : existingAssign.getAssignmentGroupSet()) { if (group != null) { if (updatedAssign.getAssignmentGroupSet() == null || !updatedAssign.getAssignmentGroupSet().contains(group)) { // we need to delete this group groupsToRemove.add(group); if (log.isDebugEnabled()) log.debug("Group to remove: " + group.getGroupId()); } } } } return groupsToRemove; } /** * Given the originalAssignment and the updated (or newly created) version, will determine if an * announcement needs to be added, updated, or deleted. Announcements are updated * if there is a change in title, open date, or group restrictions. They are * deleted if the assignment is changed to draft status. Does not re-check permissions, so * make sure you are authorized to update assignments if you call this method. * @param originalAssignmentWithGroups - original assignment with the group info populated * @param updatedAssignment - updated (or newly created) assignment with the group info populated */ private void saveAssignmentAnnouncement(Assignment2 originalAssignment, Assignment2 updatedAssignment) { if (updatedAssignment == null) { throw new IllegalArgumentException("Null updatedAssignment passed to saveAssignmentAnnouncement"); } if (updatedAssignment.getId() == null) { throw new IllegalArgumentException( "The updatedAssignment passed to saveAssignmentAnnouncement must have an id"); } // make the open date locale-aware // use a date which is related to the current users locale DateFormat df = externalLogic.getDateFormat(null, DateFormat.FULL, bundleLogic.getLocale(), true); // create url to point back to this assignment to be included in the description // ASNN-477 //String assignUrl = externalLogic.getAssignmentViewUrl(REDIRECT_ASSIGNMENT_VIEW_ID) + "/" + updatedAssignment.getId(); String toolTitle = externalLogic.getToolTitle(); String newAnncSubject = bundleLogic.getFormattedMessage("assignment2.assignment_annc_subject", new Object[] { toolTitle, updatedAssignment.getTitle() }); String newAnncBody = bundleLogic.getFormattedMessage("assignment2.assignment_annc_body", new Object[] { updatedAssignment.getTitle(), df.format(updatedAssignment.getOpenDate()), toolTitle }); String updAnncSubject = bundleLogic.getFormattedMessage("assignment2.assignment_annc_subject_edited", new Object[] { toolTitle, updatedAssignment.getTitle() }); String updAnncBody = bundleLogic.getFormattedMessage("assignment2.assignment_annc_body_edited", new Object[] { updatedAssignment.getTitle(), df.format(updatedAssignment.getOpenDate()), toolTitle }); if (originalAssignment == null) { // this was a new assignment // check to see if there will be an announcement for the open date if (updatedAssignment.getHasAnnouncement() && !updatedAssignment.isDraft()) { // add an announcement for the open date for this assignment String announcementId = announcementLogic.addOpenDateAnnouncement( updatedAssignment.getListOfAssociatedGroupReferences(), updatedAssignment.getContextId(), newAnncSubject, newAnncBody, updatedAssignment.getOpenDate()); updatedAssignment.setAnnouncementId(announcementId); dao.update(updatedAssignment); } } else if (updatedAssignment.isDraft()) { if (updatedAssignment.getAnnouncementId() != null) { announcementLogic.deleteOpenDateAnnouncement(updatedAssignment.getAnnouncementId(), updatedAssignment.getContextId()); updatedAssignment.setAnnouncementId(null); dao.update(updatedAssignment); } } else if (originalAssignment.getAnnouncementId() == null && updatedAssignment.getHasAnnouncement()) { // this is a new announcement String announcementId = announcementLogic.addOpenDateAnnouncement( updatedAssignment.getListOfAssociatedGroupReferences(), updatedAssignment.getContextId(), newAnncSubject, newAnncBody, updatedAssignment.getOpenDate()); updatedAssignment.setAnnouncementId(announcementId); dao.update(updatedAssignment); } else if (originalAssignment.getAnnouncementId() != null && !updatedAssignment.getHasAnnouncement()) { // we must remove the original announcement announcementLogic.deleteOpenDateAnnouncement(updatedAssignment.getAnnouncementId(), updatedAssignment.getContextId()); updatedAssignment.setAnnouncementId(null); dao.update(updatedAssignment); } else if (updatedAssignment.getHasAnnouncement()) { // if title, open date, or group restrictions were updated, we need to update the announcement Date oldTime = (Date) originalAssignment.getOpenDate(); Date newTime = updatedAssignment.getOpenDate(); if (!originalAssignment.getTitle().equals(updatedAssignment.getTitle()) || (oldTime.after(newTime) || oldTime.before(newTime)) || !originalAssignment.getListOfAssociatedGroupReferences() .equals(updatedAssignment.getListOfAssociatedGroupReferences())) { announcementLogic.updateOpenDateAnnouncement(updatedAssignment.getAnnouncementId(), updatedAssignment.getListOfAssociatedGroupReferences(), updatedAssignment.getContextId(), updAnncSubject, updAnncBody, updatedAssignment.getOpenDate()); // don't need to re-save assignment b/c id already exists } } } /** * will handle the business logic and updates required to determine if an event * needs to be added, updated, or deleted from the Schedule (Calendar) tool. * Compares the existing assignment (if not null) to the new assignment to * carry out any actions that are required for the relationship with the * Schedule tool. Events are updated upon a change in the due date, title, or * group restrictions for the assignment. Events are deleted if the assignment * is deleted, changed to draft status, or the due date is removed. will also * add event when appropriate. Does not re-check permissions, so * make sure you are authorized to update assignments if you call this method. * @param originalAssignment - null if "updatedAssignment" is newly created * @param updatedAssignment */ private void handleDueDateEvent(Assignment2 originalAssignment, Assignment2 updatedAssignment) { if (updatedAssignment == null) { throw new IllegalArgumentException("Null updatedAssignment passed to saveDueDateEvent"); } if (updatedAssignment.getId() == null) { throw new IllegalArgumentException( "The updatedAssignment passed to " + "saveDueDateEvent must have an id"); } String contextId = updatedAssignment.getContextId(); // make the due date locale-aware // use a date which is related to the current users locale DateFormat df = externalLogic.getDateFormat(null, DateFormat.FULL, bundleLogic.getLocale(), true); // create url to point back to this assignment to be included in the description // ASNN-477 // String assignUrl = externalLogic.getAssignmentViewUrl(REDIRECT_ASSIGNMENT_VIEW_ID) + "/" + updatedAssignment.getId(); String eventTitle = ""; String eventDescription = ""; if (updatedAssignment.getDueDate() != null) { String toolTitle = externalLogic.getToolTitle(); eventTitle = bundleLogic.getFormattedMessage("assignment2.schedule_event_title", new Object[] { toolTitle, updatedAssignment.getTitle() }); eventDescription = bundleLogic.getFormattedMessage("assignment2.schedule_event_description", new Object[] { updatedAssignment.getTitle(), df.format(updatedAssignment.getDueDate()), toolTitle }); } if (originalAssignment == null) { // this was a new assignment // check to see if there will be an event added for the due date if (updatedAssignment.getAddedToSchedule() && !updatedAssignment.isDraft() && updatedAssignment.getDueDate() != null) { // add an event for the due date for this assignment String eventId = calendarLogic.addDueDateToSchedule( updatedAssignment.getListOfAssociatedGroupReferences(), contextId, eventTitle, eventDescription, updatedAssignment.getDueDate(), updatedAssignment.getId()); updatedAssignment.setEventId(eventId); dao.update(updatedAssignment); } } else if (updatedAssignment.isDraft()) { if (updatedAssignment.getEventId() != null) { calendarLogic.deleteDueDateEvent(updatedAssignment.getEventId(), contextId); updatedAssignment.setEventId(null); dao.update(updatedAssignment); } } else if (originalAssignment.getEventId() == null && updatedAssignment.getAddedToSchedule()) { // this is a new event String eventIdId = calendarLogic.addDueDateToSchedule( updatedAssignment.getListOfAssociatedGroupReferences(), contextId, eventTitle, eventDescription, updatedAssignment.getDueDate(), updatedAssignment.getId()); updatedAssignment.setEventId(eventIdId); dao.update(updatedAssignment); } else if (originalAssignment.getEventId() != null && !updatedAssignment.getAddedToSchedule()) { // we must remove the original event calendarLogic.deleteDueDateEvent(originalAssignment.getEventId(), contextId); updatedAssignment.setEventId(null); dao.update(updatedAssignment); } else if (updatedAssignment.getAddedToSchedule()) { // if title, due date, or group restrictions were updated, we need to update the event Date oldDueDate = originalAssignment.getDueDate(); Date newDueDate = updatedAssignment.getDueDate(); if (oldDueDate != null && newDueDate == null) { // we need to remove this event because no longer has a due date calendarLogic.deleteDueDateEvent(originalAssignment.getEventId(), contextId); updatedAssignment.setEventId(null); dao.update(updatedAssignment); } else if (!originalAssignment.getTitle().equals(updatedAssignment.getTitle()) || (oldDueDate.after(newDueDate) || oldDueDate.before(newDueDate)) || !originalAssignment.getListOfAssociatedGroupReferences() .equals(updatedAssignment.getListOfAssociatedGroupReferences())) { // otherwise, we update only if there is a change in the assignment title, due date, // or group restrictions calendarLogic.updateDueDateEvent(updatedAssignment.getEventId(), updatedAssignment.getListOfAssociatedGroupReferences(), contextId, eventTitle, eventDescription, updatedAssignment.getDueDate(), updatedAssignment.getId()); // don't need to re-save assignment b/c id already exists } } } /** * ensure that the attachments and groups are populated with everything * required for saving * @param attachSet * @param groupSet * @throws IllegalArgumentException if any group or attachment is invalid */ private void validateAttachmentsAndGroups(Set<ModelAnswerAttachment> modelAnswerAttachSet, Set<AssignmentAttachment> attachSet, Set<AssignmentGroup> groupSet) { if (modelAnswerAttachSet != null) { for (ModelAnswerAttachment attach : modelAnswerAttachSet) { if (!attach.isAttachmentValid()) { throw new IllegalArgumentException("At least one attachment associated " + "with the model view answer data is missing necessary data. Check to see " + "if your attachmentReference is populated."); } } } // ensure that the necessary data was populated for the attachments if (attachSet != null) { for (AssignmentAttachment attach : attachSet) { if (!attach.isAttachmentValid()) { throw new IllegalArgumentException("At least one attachment associated " + "with the assignment is missing necessary data. Check to see " + "if your attachmentReference is populated."); } } } // ensure group info required for saving was populated if (groupSet != null) { for (AssignmentGroup group : groupSet) { if (!group.isAssignmentGroupValid()) { throw new IllegalArgumentException("At least one AssignmentGroup " + "associated with this assignment is not valid. Check to " + "see if all required info is populated."); } } } } public String getDuplicatedAssignmentTitle(String contextId, String titleToDuplicate) { if (contextId == null || titleToDuplicate == null) { throw new IllegalArgumentException( "Null contextId or titleToDuplicate passed to getDuplicatedAssignmentTitle." + " contextId:" + contextId + " titleToDuplicate:" + titleToDuplicate); } // first, get all of the existing assignment titles Search search = new Search(new String[] { "contextId", "removed" }, new Object[] { contextId, false }); List<Assignment2> allAssigns = dao.findBySearch(Assignment2.class, search); List<String> existingAssignTitles = new ArrayList<String>(); if (allAssigns != null) { for (Assignment2 assign : allAssigns) { existingAssignTitles.add(assign.getTitle()); } } String duplicatedTitle = Assignment2Utils.getVersionedString(titleToDuplicate); while (existingAssignTitles.contains(duplicatedTitle)) { duplicatedTitle = Assignment2Utils.getVersionedString(duplicatedTitle); } return duplicatedTitle; } public AssignmentDefinition getAssignmentDefinition(Assignment2 assignment, Map<Long, GradebookItem> gbIdItemMap, Map<String, String> groupIdToTitleMap) { if (assignment == null) { throw new IllegalArgumentException("Null assignment passed to getAssignmentDefinition"); } AssignmentDefinition assignDef = new AssignmentDefinition(); assignDef.setId(assignment.getId()); assignDef.setAcceptUntilDate(assignment.getAcceptUntilDate()); assignDef.setDraft(assignment.isDraft()); assignDef.setDueDate(assignment.getDueDate()); assignDef.setHasAnnouncement(assignment.getHasAnnouncement()); assignDef.setHonorPledge(assignment.isHonorPledge()); assignDef.setInstructions(assignment.getInstructions()); assignDef.setSendSubmissionNotifications(assignment.isSendSubmissionNotifications()); assignDef.setNumSubmissionsAllowed(assignment.getNumSubmissionsAllowed()); assignDef.setOpenDate(assignment.getOpenDate()); assignDef.setSortIndex(assignment.getSortIndex()); assignDef.setSubmissionType(assignment.getSubmissionType()); assignDef.setTitle(assignment.getTitle()); assignDef.setGraded(assignment.isGraded()); assignDef.setRequiresSubmission(assignment.isRequiresSubmission()); assignDef.setContentReviewEnabled(assignment.isContentReviewEnabled()); assignDef.setContentReviewStudentViewReport(assignment.isContentReviewStudentViewReport()); // if it is graded, we need to retrieve the name of the associated gb item if (assignment.isGraded() && assignment.getGradebookItemId() != null && gbIdItemMap != null) { GradebookItem gbItem = (GradebookItem) gbIdItemMap.get(assignment.getGradebookItemId()); if (gbItem != null) { assignDef.setAssociatedGbItemName(gbItem.getTitle()); assignDef.setAssociatedGbItemPtsPossible(gbItem.getPointsPossible()); } } // we need to make a list of the attachment references List<String> attachRefList = new ArrayList<String>(); if (assignment.getAttachmentSet() != null) { for (AssignmentAttachment attach : assignment.getAttachmentSet()) { if (attach != null) { attachRefList.add(attach.getAttachmentReference()); } } } assignDef.setAttachmentReferences(attachRefList); // we need to make a list of the group names List<String> associatedGroupNames = new ArrayList<String>(); if (assignment.getAssignmentGroupSet() != null && groupIdToTitleMap != null) { for (AssignmentGroup aGroup : assignment.getAssignmentGroupSet()) { if (aGroup != null) { String groupName = (String) groupIdToTitleMap.get(aGroup.getGroupId()); if (groupName != null) { associatedGroupNames.add(groupName); } } } } assignDef.setGroupRestrictionGroupTitles(associatedGroupNames); assignDef.setProperties(assignment.getProperties()); return assignDef; } @Override public List<Assignment2> getAssignmentsWithLinkedGradebookItemId(Long id) { // TODO Permissions I'm assuming at the moment, that if someone had // permissions to update the gradebook, they can update the assignment // too, but that may not be true... return dao.getAssignmentsWithLinkedGradebookItemId(id); } }