package org.sakaiproject.tool.assessment.util; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.tool.assessment.data.dao.grading.ItemGradingData; import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc; import org.sakaiproject.tool.assessment.data.dao.grading.MediaData; import org.sakaiproject.tool.assessment.integration.helper.integrated.AgentHelperImpl; import org.sakaiproject.tool.assessment.services.GradingService; import org.sakaiproject.tool.assessment.ui.bean.evaluation.DownloadFileSubmissionsBean; import org.sakaiproject.tool.assessment.ui.bean.evaluation.TotalScoresBean; import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; public class DownloadFileUtil { private static Log log = LogFactory.getLog(DownloadFileUtil.class); public void processWholeSiteOrOneSection(HttpServletRequest req, HttpServletResponse res, ArrayList<ItemDataIfc> idataList, ArrayList<String> userUidList) { processWholeSiteOrOneSection(req, res, idataList, userUidList, null); } public void processWholeSiteOrOneSection(HttpServletRequest req, HttpServletResponse res, ArrayList<ItemDataIfc> idataList, ArrayList<String> userUidList, String sectionName){ ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.EvaluationMessages"); res.setContentType("application/x-zip-compressed"); TotalScoresBean totalScores = (TotalScoresBean) ContextUtil.lookupBean("totalScores"); StringBuilder zipFilename = new StringBuilder(); zipFilename.append(totalScores.getAssessmentName()); if (idataList.size() == 1) { ItemDataIfc idata = (ItemDataIfc) idataList.get(0); zipFilename.append("_"); zipFilename.append(getPartNumAndQuestionNum(idata)); } if (sectionName != null) { zipFilename.append("_"); zipFilename.append(sectionName); } zipFilename.append((".zip")); res.setHeader("Content-Disposition", "attachment;filename=\"" + zipFilename + "\";"); String anonymous = totalScores.getAnonymous(); String publishedAssessmentId = totalScores.getPublishedId(); String scoringType = totalScores.getSortType(); ServletOutputStream outputStream = null; ZipOutputStream zos = null; try { outputStream = res.getOutputStream(); zos = new ZipOutputStream(outputStream); Iterator iter = idataList.iterator(); while (iter.hasNext()) { ItemDataIfc idata = (ItemDataIfc) iter.next(); String itemId = idata.getItemId().toString(); StringBuffer questionFolderPath = new StringBuffer(); try { if (idataList.size() != 1) { questionFolderPath.append(getPartNumAndQuestionNum(idata)); questionFolderPath.append("/"); ZipEntry questionFolderEntry = new ZipEntry(questionFolderPath.toString()); zos.putNextEntry(questionFolderEntry); } if ("true".equals(anonymous)) { processAnonymous(zos, publishedAssessmentId, itemId, scoringType, userUidList, questionFolderPath.toString()); } else { processNonAnonymous(zos, publishedAssessmentId, itemId, scoringType, userUidList, questionFolderPath.toString()); } } catch (IOException e) { log.error(e.getMessage()); } finally { if (idataList.size() != 1 && zos != null) { try { zos.closeEntry(); } catch(IOException e) { log.error(e.getMessage()); } } } } } catch (IOException e) { log.error(e.getMessage()); } finally { if (zos != null) { try { zos.close(); } catch(IOException e) { log.error(e.getMessage()); } } if (outputStream != null) { try { outputStream.flush(); outputStream.flush(); } catch (IOException e) { log.error(e.getMessage()); } } } } public void processMultipleSection(HttpServletRequest req, HttpServletResponse res, ArrayList<ItemDataIfc> idataList, HashMap sectionUsersMap){ TotalScoresBean totalScores = (TotalScoresBean) ContextUtil.lookupBean("totalScores"); DownloadFileSubmissionsBean downloadFileSubmissionsBean = (DownloadFileSubmissionsBean) ContextUtil .lookupBean("downloadFileSubmissions"); StringBuilder zipFilename = new StringBuilder(); zipFilename.append(totalScores.getAssessmentName()); if (idataList.size() == 1) { ItemDataIfc idata = (ItemDataIfc) idataList.get(0); zipFilename.append("_"); zipFilename.append(getPartNumAndQuestionNum(idata)); zipFilename.append(idata.getSequence()); } zipFilename.append((".zip")); String anonymous = totalScores.getAnonymous(); res.setHeader("Content-Disposition", "attachment;filename=\"" + zipFilename + "\";"); ServletOutputStream outputStream = null; ZipOutputStream zos = null; try { outputStream = res.getOutputStream(); zos = new ZipOutputStream(outputStream); Iterator iter = idataList.iterator(); while (iter.hasNext()) { ItemDataIfc idata = (ItemDataIfc) iter.next(); String itemId = idata.getItemId().toString(); StringBuffer questionFolderPath = new StringBuffer(); if (idataList.size() != 1) { questionFolderPath.append(getPartNumAndQuestionNum(idata)); questionFolderPath.append("_"); } Set<String> sectoinSet = sectionUsersMap.keySet(); Iterator iter2 = sectoinSet.iterator(); String sectionId; String sectionName; HashMap<String, String> sectionUuidNameMap = downloadFileSubmissionsBean.getSectionUuidNameMap(); String publishedAssessmentId = totalScores.getPublishedId(); String scoringType = totalScores.getSortType(); while (iter2.hasNext()) { sectionId = (String) iter2.next(); sectionName = (String) sectionUuidNameMap.get(sectionId); ArrayList<String> userUidList = (ArrayList<String>) sectionUsersMap.get(sectionId); String sectionFolderPath = questionFolderPath.toString() + sectionName + "/"; ZipEntry sectionFolderEntry = new ZipEntry(sectionFolderPath); try { zos.putNextEntry(sectionFolderEntry); if ("true".equals(anonymous)) { processAnonymous(zos, publishedAssessmentId, itemId, scoringType, userUidList, sectionFolderPath); } else { processNonAnonymous(zos, publishedAssessmentId, itemId, scoringType, userUidList, sectionFolderPath); } } catch(IOException e) { log.error(e.getMessage()); } finally { if (zos != null) { try { zos.closeEntry(); } catch(IOException e) { log.error(e.getMessage()); } } } } } } catch (IOException e) { log.error(e.getMessage()); } finally { if (zos != null) { try { zos.closeEntry(); } catch(IOException e) { log.error(e.getMessage()); } } if (zos != null) { try { zos.close(); } catch(IOException e) { log.error(e.getMessage()); } } if (outputStream != null) { try { outputStream.flush(); outputStream.flush(); } catch (IOException e) { log.error(e.getMessage()); } } } } public void processAnonymous(ZipOutputStream zos, String publishedAssessmentId, String publishedItemId, String scoringType, ArrayList<String> userUidList){ processAnonymous(zos, publishedAssessmentId, publishedItemId, scoringType, userUidList, null); } public void processAnonymous(ZipOutputStream zos, String publishedAssessmentId, String publishedItemId, String scoringType, ArrayList<String> userUidList, String sectionFolderPath){ GradingService gradingService = new GradingService(); List mediaList = gradingService.getMediaArray(publishedAssessmentId,publishedItemId, scoringType); MediaData mediaData; log.debug("mediaList.size() = " + mediaList.size()); ItemGradingData itemGradingData; String agentId; for (int i = 0; i < mediaList.size(); i++){ mediaData = (MediaData) mediaList.get(i); itemGradingData = (ItemGradingData) mediaData.getItemGradingData(); agentId = itemGradingData.getAgentId(); if (!userUidList.contains(agentId)) { log.debug("Do not download files from this user - agentId = " + agentId); continue; } processOneMediaData(zos, mediaData, true, -1, sectionFolderPath); } } public void processNonAnonymous(ZipOutputStream zos, String publishedAssessmentId, String publishedItemId, String scoringType, ArrayList<String> userUidList){ processNonAnonymous(zos, publishedAssessmentId, publishedItemId, scoringType, userUidList, null); } public void processNonAnonymous(ZipOutputStream zos, String publishedAssessmentId, String publishedItemId, String scoringType, ArrayList<String> userUidList, String sectionFolderPath){ HashMap hashByAgentId = new HashMap(); HashMap subHashByAssessmentGradingId; MediaData mediaData; ArrayList list; ItemGradingData itemGradingData; List mediaList; GradingService gradingService = new GradingService(); mediaList = gradingService.getMediaArray(publishedAssessmentId, publishedItemId, scoringType); log.debug("mediaList.size() = " + mediaList.size()); String agentId; Long assessmentGradingId; for (int i = 0; i < mediaList.size(); i++) { mediaData = (MediaData) mediaList.get(i); itemGradingData = (ItemGradingData) mediaData.getItemGradingData(); agentId = itemGradingData.getAgentId(); assessmentGradingId = itemGradingData.getAssessmentGradingId(); log.debug("agentId = " + agentId); log.debug("assessmentGradingId = " + assessmentGradingId); if (!userUidList.contains(agentId)) { log.debug("Do not download files from this user - agentId = " + agentId); continue; } if (hashByAgentId.containsKey(agentId)) { log.debug("same agentId"); subHashByAssessmentGradingId = (HashMap) hashByAgentId.get(agentId); if (subHashByAssessmentGradingId.containsKey(assessmentGradingId)) { log.debug("same assessmentGradingId"); list = (ArrayList) subHashByAssessmentGradingId.get(assessmentGradingId); list.add(mediaData); } else { log.debug("different assessmentGradingId"); list = new ArrayList(); list.add(mediaData); subHashByAssessmentGradingId.put(assessmentGradingId, list); } } else { log.debug("different agentId"); list = new ArrayList(); list.add(mediaData); subHashByAssessmentGradingId = new HashMap(); subHashByAssessmentGradingId.put(assessmentGradingId, list); hashByAgentId.put(agentId, subHashByAssessmentGradingId); } } log.debug("HashMap built successfully"); HashMap hashMap; Iterator iter = hashByAgentId.values().iterator(); int numberSubmission; while (iter.hasNext()) { hashMap = (HashMap) iter.next(); numberSubmission = hashMap.size(); log.debug("numberSubmission = " + numberSubmission); Iterator subIter = hashMap.keySet().iterator(); // this student has submitted more than once if (numberSubmission > 1) { // Because Hashmap makes no guarantees as to the order of the map; // and it does not guarantee that the order will remain constant over time, // following implementation is to make sure we get the correct order // that is, if there are two submissions from John Doe: // submission id 24 submitted on Jun 28, 2006 (file A.txt) // submission id 33 submitted on Jul 03, 2006 (file B.txt) // We want to make sure the filename of these two are: // Doe_John_sub1_A.txt and Doe_John_sub2_B.txt // If we don't sort it, the outcome might be: // Doe_John_sub2_A.txt and Doe_John_sub1_B.txt which are not what we want ArrayList keyList = new ArrayList(); Long key; while(subIter.hasNext()) { key = (Long) subIter.next(); log.debug("key = " + key); keyList.add(key); Collections.sort(keyList); } ArrayList valueList; Long sortedKey; for (int i = 0; i < keyList.size(); i++) { sortedKey = (Long) keyList.get(i); valueList = (ArrayList) hashMap.get(sortedKey); for (int j = 0; j < valueList.size(); j++) { log.debug("j = " + j); mediaData = (MediaData) valueList.get(j); processOneMediaData(zos, mediaData, false, i+1, sectionFolderPath); } } } // this student has only one submission else if (numberSubmission == 1){ ArrayList valueList; while(subIter.hasNext()) { valueList = (ArrayList) hashMap.get(subIter.next()); log.debug("valueList.size() = " + valueList.size()); for (int i = 0; i < valueList.size(); i++) { log.debug("i = " + i); mediaData = (MediaData) valueList.get(i); // we use "-1" to indicate one submission // "sub" will not be instered into filename processOneMediaData(zos, mediaData, false, -1, sectionFolderPath); } } } } } private void processOneMediaData(ZipOutputStream zos, MediaData mediaData, boolean anonymous, int numberSubmission, String sectionFolderPath) { int BUFFER_SIZE = 2048; byte data[] = new byte[ BUFFER_SIZE ]; int count = 0; BufferedInputStream bufInputStream = null; ZipEntry ze = null; String mediaLocation = mediaData.getLocation(); log.debug("mediaLocation = " + mediaLocation); String filename = getFilename(mediaData, anonymous, numberSubmission); if (sectionFolderPath != null) { filename = sectionFolderPath + filename; } if (mediaLocation == null || (mediaLocation.trim()).equals("")){ byte[] media = mediaData.getMedia(); log.debug("media.length = " + media.length); bufInputStream = new BufferedInputStream(new ByteArrayInputStream(media)); } else { bufInputStream = new BufferedInputStream(getFileStream(mediaLocation)); } ze = new ZipEntry(filename); try { zos.putNextEntry(ze); while( (count = bufInputStream.read(data, 0, BUFFER_SIZE)) != -1 ) { zos.write(data, 0, count); } } catch(IOException e){ log.error(e.getMessage()); } finally { if (bufInputStream != null) { try { bufInputStream.close(); } catch(IOException e) { log.error(e.getMessage()); } } if (zos != null) { try { zos.closeEntry(); } catch(IOException e) { log.error(e.getMessage()); } } } } private FileInputStream getFileStream(String mediaLocation){ ExternalContext external = FacesContext.getCurrentInstance().getExternalContext(); String repositoryPath = (String)((ServletContext)external.getContext()).getAttribute("FILEUPLOAD_REPOSITORY_PATH"); // If there is a "/" at the end, remove it if (repositoryPath.endsWith("/") && mediaLocation.startsWith("/")) { repositoryPath = repositoryPath.substring(0, repositoryPath.length() - 1); } FileInputStream inputStream=null; try{ File media=new File(repositoryPath + mediaLocation); inputStream = new FileInputStream(media); } catch (FileNotFoundException ex) { log.warn("file not found="+ex.getMessage()); } return inputStream; } private String getPartNumAndQuestionNum(ItemDataIfc item) { ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.EvaluationMessages"); Integer partNum = item.getSection().getSequence(); Integer questionNum = item.getSequence(); StringBuilder partAndQues = new StringBuilder(rb.getString("part")); partAndQues.append(partNum); partAndQues.append("_"); partAndQues.append(rb.getString("q")); partAndQues.append(questionNum); log.debug("partAndQues = " + partAndQues); return partAndQues.toString(); } private String getFilename(MediaData mediaData, boolean anonymous, int numberSubmission) { log.debug("numberSubmission = " + numberSubmission); StringBuilder filename = new StringBuilder(); ItemGradingData itemGradingData = (ItemGradingData) mediaData.getItemGradingData(); if (anonymous) { Long assessmentGradingId = itemGradingData.getAssessmentGradingId(); log.debug("submissionId(assessmentGradingId) = " + assessmentGradingId); filename.append(assessmentGradingId); filename.append("_"); filename.append(mediaData.getFilename()); log.debug("filename = " + filename); } else { AgentHelperImpl helper = new AgentHelperImpl(); String agentId = itemGradingData.getAgentId(); String lastName = helper.getLastName(agentId); String firstName = helper.getFirstName(agentId); String eid = helper.getEidById(agentId); filename.append(lastName); filename.append("_"); filename.append(firstName); filename.append("_"); filename.append(eid); filename.append("_"); log.debug("filename = " + filename); if (numberSubmission == -1) { filename.append(mediaData.getFilename()); log.debug("filename = " + filename); } else { filename.append("sub"); filename.append(numberSubmission); filename.append("_"); filename.append(mediaData.getFilename()); log.debug("filename = " + filename); } } return filename.toString(); } }