/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/servlet/delivery/DownloadAllMediaServlet.java $
* $Id: DownloadAllMediaServlet.java 108729 2012-05-30 10:31:44Z david.horwitz@uct.ac.za $
***********************************************************************************
*
* Copyright (c) 2005, 2006, 2007, 2008, 2009 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.assessment.ui.servlet.delivery;
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.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.tool.assessment.data.dao.grading.ItemGradingData;
import org.sakaiproject.tool.assessment.data.dao.grading.MediaData;
import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.PublishedAssessmentIfc;
import org.sakaiproject.tool.assessment.facade.AgentFacade;
import org.sakaiproject.tool.assessment.integration.helper.integrated.AgentHelperImpl;
import org.sakaiproject.tool.assessment.services.GradingService;
import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService;
import org.sakaiproject.tool.assessment.shared.impl.assessment.PublishedAssessmentServiceImpl;
import org.sakaiproject.tool.assessment.ui.bean.authz.AuthorizationBean;
import org.sakaiproject.tool.assessment.ui.bean.evaluation.QuestionScoresBean;
import org.sakaiproject.tool.assessment.ui.bean.shared.PersonBean;
import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil;
/**
* <p>Title: Samigo</p>
* <p>Description: Sakai Assessment Manager</p>
* @author Ed Smiley
* @version $Id: DownloadAllMediaServlet.java 108729 2012-05-30 10:31:44Z david.horwitz@uct.ac.za $
*/
public class DownloadAllMediaServlet extends HttpServlet
{
/**
*
*/
private static final long serialVersionUID = 1465451058167004991L;
private static Log log = LogFactory.getLog(DownloadAllMediaServlet.class);
private GradingService gradingService = new GradingService();
public DownloadAllMediaServlet()
{
}
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
doPost(req,res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
String publishedItemId = req.getParameter("publishedItemId");
log.debug("publishedItemId = " + publishedItemId);
// who can access the zip file? You can,
// if you have a assessment.grade.any or assessment.grade.own permission
boolean accessDenied = true;
String agentIdString = getAgentString(req, res);
String currentSiteId="";
String assessmentName = "";
PublishedAssessmentIfc pub = gradingService.getPublishedAssessmentByPublishedItemId(publishedItemId);
if (pub != null){
assessmentName = pub.getTitle();
PublishedAssessmentService service = new PublishedAssessmentService();
log.debug("pub.getPublishedAssessmentId() = " + pub.getPublishedAssessmentId());
currentSiteId = service.getPublishedAssessmentOwner(pub.getPublishedAssessmentId());
}
// get assessment's ownerId
String assessmentCreatedBy = req.getParameter("createdBy");
if (canGrade(req, res, agentIdString, currentSiteId, assessmentCreatedBy)) {
accessDenied = false;
}
if (accessDenied){
String path = "/jsf/delivery/mediaAccessDenied.faces";
RequestDispatcher dispatcher = req.getRequestDispatcher(path);
dispatcher.forward(req, res);
}
else {
res.setContentType("application/x-zip-compressed");
StringBuilder zipFilename = new StringBuilder();
zipFilename.append(assessmentName);
String partAndQues = getPartNumAndQuestionNum(publishedItemId);
log.debug("partAndQues = " + partAndQues);
zipFilename.append(partAndQues);
zipFilename.append((".zip"));
log.debug("zipFilename = " + zipFilename);
res.setHeader("Content-Disposition", "attachment;filename=\"" + zipFilename + "\";");
String anonymous = req.getParameter("anonymous");
if ("true".equals(anonymous)) {
processAnonymous(req, res);
}
else {
processNonAnonymous(req, res);
}
}
}
private void processAnonymous(HttpServletRequest req, HttpServletResponse res){
String publishedId = req.getParameter("publishedId");
String publishedItemId = req.getParameter("publishedItemId");
String scoringType = req.getParameter("scoringType");
log.debug("publishedId = " + publishedId);
log.debug("publishedItemId = " + publishedItemId);
log.debug("scoringType = " + scoringType);
GradingService gradingService = new GradingService();
List<MediaData> mediaList = gradingService.getMediaArray(publishedId,publishedItemId, scoringType);
MediaData mediaData;
log.debug("mediaList.size() = " + mediaList.size());
ZipOutputStream zos = null;
try{
ServletOutputStream outputStream = res.getOutputStream();
zos = new ZipOutputStream(outputStream);
for (int i = 0; i < mediaList.size(); i++){
mediaData = (MediaData) mediaList.get(i);
processOneMediaData(zos, mediaData, true, -1);
}
}
catch(IOException e){
log.error(e.getMessage());
e.printStackTrace();
}
finally {
if (zos != null) {
try {
zos.close();
}
catch(IOException e) {
log.error(e.getMessage());
}
}
}
}
private void processNonAnonymous(HttpServletRequest req, HttpServletResponse res){
String publishedId = req.getParameter("publishedId");
String publishedItemId = req.getParameter("publishedItemId");
String scoringType = req.getParameter("scoringType");
log.debug("publishedId = " + publishedId);
log.debug("publishedItemId = " + publishedItemId);
log.debug("scoringType = " + scoringType);
Map<String, Map<Long, List<MediaData>>> hashByAgentId = new HashMap<String, Map<Long, List<MediaData>>>();
Map<Long, List<MediaData>> subHashByAssessmentGradingId;
MediaData mediaData;
List<MediaData> list;
ItemGradingData itemGradingData;
List<MediaData> mediaList;
mediaList = gradingService.getMediaArray(publishedId, publishedItemId, scoringType);
log.debug("mediaList.size() = " + mediaList.size());
QuestionScoresBean questionScoresBean = (QuestionScoresBean) ContextUtil.lookupBeanFromExternalServlet(
"questionScores", req, res);
Map userIdMap = questionScoresBean.getUserIdMap();
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 (!userIdMap.containsKey(agentId)) {
log.debug("Do not download files from this user - agentId = " + agentId);
continue;
}
if (hashByAgentId.containsKey(agentId)) {
log.debug("same agentId");
subHashByAssessmentGradingId = hashByAgentId.get(agentId);
if (subHashByAssessmentGradingId.containsKey(assessmentGradingId)) {
log.debug("same assessmentGradingId");
list = subHashByAssessmentGradingId.get(assessmentGradingId);
list.add(mediaData);
}
else {
log.debug("different assessmentGradingId");
list = new ArrayList<MediaData>();
list.add(mediaData);
subHashByAssessmentGradingId.put(assessmentGradingId, list);
}
}
else {
log.debug("different agentId");
list = new ArrayList<MediaData>();
list.add(mediaData);
subHashByAssessmentGradingId = new HashMap<Long, List<MediaData>>();
subHashByAssessmentGradingId.put(assessmentGradingId, list);
hashByAgentId.put(agentId, subHashByAssessmentGradingId);
}
}
log.debug("HashMap built successfully");
ZipOutputStream zos = null;
try {
ServletOutputStream outputStream = res.getOutputStream();
zos = new ZipOutputStream(outputStream);
Map 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
List<Long> keyList = new ArrayList<Long>();
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);
}
}
}
// 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);
}
}
}
}
}
catch (IOException e) {
log.error(e.getMessage());
e.printStackTrace();
}
finally {
if (zos != null) {
try {
zos.close();
}
catch(IOException e) {
log.error(e.getMessage());
}
}
}
}
private void processOneMediaData(ZipOutputStream zos, MediaData mediaData, boolean anonymous, int numberSubmission)
throws IOException {
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);
//SAM-1468 we need to ensure the fileName is unique
filename = getUniqueFilename(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());
throw e;
}
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());
}
}
}
}
//A list of the files in the Zip
private List<String> filesInZip = new ArrayList<String>();
public String getUniqueFilename(String fileName) {
if (!filesInZip.contains(fileName)) {
filesInZip.add(fileName);
return fileName;
} else {
//there already is a file of this name
int i = 1;
String origFileName = fileName;
while (filesInZip.contains(fileName)) {
String extension = "";
if (origFileName.contains(".")) {
extension = origFileName.substring(origFileName.lastIndexOf("."));
}
fileName = origFileName.substring(0, origFileName.length() - extension.length());
fileName = fileName + "-" + i + extension;
i++;
}
filesInZip.add(fileName);
}
return fileName;
}
private FileInputStream getFileStream(String mediaLocation){
FileInputStream inputStream=null;
try{
File media=new File(mediaLocation);
inputStream = new FileInputStream(media);
}
catch (FileNotFoundException ex) {
log.warn("file not found="+ex.getMessage());
}
return inputStream;
}
public String getAgentString(HttpServletRequest req, HttpServletResponse res){
String agentIdString = AgentFacade.getAgentString();
if (agentIdString == null || agentIdString.equals("")){ // try this
PersonBean person = (PersonBean) ContextUtil.lookupBeanFromExternalServlet(
"person", req, res);
agentIdString = person.getAnonymousId();
}
return agentIdString;
}
public boolean canGrade(HttpServletRequest req, HttpServletResponse res,
String agentId, String currentSiteId, String assessmentCreatedBy){
AuthorizationBean authzBean = (AuthorizationBean) ContextUtil.lookupBeanFromExternalServlet(
"authorization", req, res);
log.debug("agentId=" + agentId);
log.debug("currentSiteId=" + currentSiteId);
log.debug("assessmentCreatedBy=" + assessmentCreatedBy);
boolean hasPrivilege_any = authzBean.getGradeAnyAssessment(req, currentSiteId);
boolean hasPrivilege_own0 = authzBean.getGradeOwnAssessment(req, currentSiteId);
boolean hasPrivilege_own = (hasPrivilege_own0 && isOwner(agentId, assessmentCreatedBy));
boolean hasPrivilege = (hasPrivilege_any || hasPrivilege_own);
log.debug("hasPrivilege_any=" + hasPrivilege_any);
log.debug("hasPrivilege_own0=" + hasPrivilege_own0);
log.debug("hasPrivilege_own=" + hasPrivilege_own);
log.debug("hasPrivilege=" + hasPrivilege);
return hasPrivilege;
}
public boolean isOwner(String agentId, String ownerId){
boolean isOwner = false;
isOwner = agentId.equals(ownerId);
log.debug("isOwner=" + isOwner);
return isOwner;
}
private String getPartNumAndQuestionNum(String itemId){
log.debug("itemId = " + itemId);
PublishedAssessmentServiceImpl pubAssessmentServiceImpl = new PublishedAssessmentServiceImpl();
ItemDataIfc item = pubAssessmentServiceImpl.loadPublishedItem(itemId);
Integer partNum = item.getSection().getSequence();
log.debug("partNum = " + partNum);
Integer questionNum = item.getSequence();
log.debug("questionNum=" + questionNum);
StringBuilder partAndQues = new StringBuilder("_Part");
partAndQues.append(partNum);
partAndQues.append("_Ques");
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();
}
}