package org.sakaiproject.tool.assessment.services.assessment;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.SecurityAdvisor;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.EntityTransferrer;
import org.sakaiproject.entity.api.EntityTransferrerRefMigrator;
import org.sakaiproject.entity.api.HttpAccess;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.cover.EntityManager;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.exception.TypeException;
import org.sakaiproject.tool.assessment.data.dao.assessment.Answer;
import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentData;
import org.sakaiproject.tool.assessment.data.dao.assessment.ItemData;
import org.sakaiproject.tool.assessment.data.dao.assessment.ItemText;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentIfc;
import org.sakaiproject.tool.assessment.facade.AssessmentFacade;
import org.sakaiproject.tool.assessment.facade.SectionFacade;
import org.sakaiproject.tool.assessment.shared.api.qti.QTIServiceAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class AssessmentEntityProducer implements EntityTransferrer,
EntityProducer, EntityTransferrerRefMigrator {
private static final int QTI_VERSION = 1;
private static final String ARCHIVED_ELEMENT = "assessment";
private static Log log = LogFactory.getLog(AssessmentEntityProducer.class);
private QTIServiceAPI qtiService;
public void init() {
log.info("init()");
try {
EntityManager.registerEntityProducer(this, Entity.SEPARATOR
+ "samigo");
} catch (Exception e) {
log.warn("Error registering Samigo Entity Producer", e);
}
}
public void destroy() {
}
public void setQtiService(QTIServiceAPI qtiService) {
this.qtiService = qtiService;
}
public String[] myToolIds() {
String[] toolIds = { "sakai.samigo" };
return toolIds;
}
public void transferCopyEntities(String fromContext, String toContext, List resourceIds)
{
transferCopyEntitiesRefMigrator(fromContext, toContext, resourceIds);
}
public Map<String, String> transferCopyEntitiesRefMigrator(String fromContext, String toContext, List resourceIds)
{
AssessmentService service = new AssessmentService();
service.copyAllAssessments(fromContext, toContext);
// At a minimum, we need to remap all the attachment URLs to point to the new site
Map<String, String> transversalMap = new HashMap<String, String>();
transversalMap.put("/content/attachment/" + fromContext + "/", "/content/attachment/" + toContext + "/");
return transversalMap;
}
public String archive(String siteId, Document doc, Stack stack,
String archivePath, List attachments) {
StringBuilder results = new StringBuilder();
results.append("archiving ").append(getLabel()).append("\n");
String qtiPath = archivePath + File.separator + "qti";
File qtiDir = new File(qtiPath);
if (!qtiDir.isDirectory() && !qtiDir.mkdir()) {
log.error("Could not create directory " + qtiPath);
results.append("Could not create " + qtiPath + "\n");
return results.toString();
}
Element element = doc.createElement(this.getClass().getName());
((Element) stack.peek()).appendChild(element);
stack.push(element);
AssessmentService assessmentService = new AssessmentService();
List<AssessmentData> assessmentList
= (List<AssessmentData>) assessmentService.getAllActiveAssessmentsbyAgent(siteId);
for (AssessmentData data : assessmentList) {
Element assessmentXml = doc.createElement(ARCHIVED_ELEMENT);
String id = data.getAssessmentId().toString();
assessmentXml.setAttribute("id", id);
FileWriter writer = null;
try {
File assessmentFile = new File(qtiPath + File.separator + ARCHIVED_ELEMENT + id + ".xml");
writer = new FileWriter(assessmentFile);
writer.write(qtiService.getExportedAssessmentAsString(id, QTI_VERSION));
} catch (IOException e) {
results.append(e.getMessage() + "\n");
log.error(e.getMessage(), e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Throwable t) {
log.error(t.getMessage(), t);
}
}
}
element.appendChild(assessmentXml);
}
stack.pop();
return results.toString();
}
public Entity getEntity(Reference ref) {
return null;
}
public Collection getEntityAuthzGroups(Reference ref, String userId) {
return null;
}
public String getEntityDescription(Reference ref) {
return null;
}
public ResourceProperties getEntityResourceProperties(Reference ref) {
return null;
}
public String getEntityUrl(Reference ref) {
return null;
}
public HttpAccess getHttpAccess() {
return null;
}
public String getLabel() {
return "samigo";
}
public String merge(String siteId, Element root, String archivePath,
String fromSiteId, Map attachmentNames, Map userIdTrans,
Set userListAllowImport) {
if (log.isDebugEnabled()) log.debug("merging " + getLabel());
StringBuilder results = new StringBuilder();
String qtiPath = (new File(archivePath)).getParent()
+ File.separator + "qti" + File.separator;
//TODO: replaced by getChildren when we make sure we have the
NodeList assessments = root.getElementsByTagName(ARCHIVED_ELEMENT);
DocumentBuilder dbuilder = null;
try {
dbuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (Throwable t) {
log.error(t.getMessage(), t);
return getLabel() + " Error: " + t.getMessage();
}
for (int i=0; i<assessments.getLength(); ++i) {
Element element = (Element) assessments.item(i);
String id = element.getAttribute("id");
String path = qtiPath + ARCHIVED_ELEMENT + id + ".xml";
try {
AssessmentIfc assessment = qtiService.createImportedAssessment(path, QTI_VERSION, siteId);
results.append(getLabel() + " imported assessment '" + assessment.getTitle() + "'\n");
} catch (Throwable t) {
log.error(t.getMessage(), t);
results.append(getLabel() + " error with assessment "
+ id + ": " + t.getMessage() + "\n");
}
}
return results.toString();
}
public boolean parseEntityReference(String reference, Reference ref) {
return false;
}
public boolean willArchiveMerge() {
return true;
}
public void transferCopyEntities(String fromContext, String toContext, List ids, boolean cleanup)
{
transferCopyEntitiesRefMigrator(fromContext, toContext, ids, cleanup);
}
public Map<String, String> transferCopyEntitiesRefMigrator(String fromContext, String toContext, List ids, boolean cleanup)
{
try
{
if(cleanup == true)
{
if (log.isDebugEnabled()) log.debug("deleting assessments from " + toContext);
AssessmentService service = new AssessmentService();
List assessmentList = service.getAllActiveAssessmentsbyAgent(toContext);
log.debug("found " + assessmentList.size() + " assessments in site: " + toContext);
Iterator iter =assessmentList.iterator();
while (iter.hasNext()) {
AssessmentData oneassessment = (AssessmentData) iter.next();
log.debug("removing assessemnt id = " +oneassessment.getAssessmentId() );
service.removeAssessment(oneassessment.getAssessmentId().toString());
}
}
}
catch (Exception e)
{
e.printStackTrace();
log.info("transferCopyEntities: End removing Assessment data");
}
return transferCopyEntitiesRefMigrator(fromContext, toContext, ids);
}
/**
* {@inheritDoc}
*/
public void updateEntityReferences(String toContext, Map<String, String> transversalMap){
if(transversalMap != null && transversalMap.size() > 0){
Set<Entry<String, String>> entrySet = (Set<Entry<String, String>>) transversalMap.entrySet();
AssessmentService service = new AssessmentService();
List assessmentList = service.getAllActiveAssessmentsbyAgent(toContext);
Iterator assessmentIter =assessmentList.iterator();
while (assessmentIter.hasNext()) {
AssessmentData assessment = (AssessmentData) assessmentIter.next();
//get initialized assessment
AssessmentFacade assessmentFacade = (AssessmentFacade) service.getAssessment(assessment.getAssessmentId());
boolean needToUpdate = false;
String assessmentDesc = assessmentFacade.getDescription();
if(assessmentDesc != null){
assessmentDesc = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, assessmentDesc);
if(!assessmentDesc.equals(assessmentFacade.getDescription())){
//need to save since a ref has been updated:
needToUpdate = true;
assessmentFacade.setDescription(assessmentDesc);
}
}
List sectionList = assessmentFacade.getSectionArray();
for(int i = 0; i < sectionList.size(); i++){
SectionFacade section = (SectionFacade) sectionList.get(i);
String sectionDesc = section.getDescription();
if(sectionDesc != null){
sectionDesc = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, sectionDesc);
if(!sectionDesc.equals(section.getDescription())){
//need to save since a ref has been updated:
needToUpdate = true;
section.setDescription(sectionDesc);
}
}
List itemList = section.getItemArray();
for(int j = 0; j < itemList.size(); j++){
ItemData item = (ItemData) itemList.get(j);
String itemIntr = item.getInstruction();
if(itemIntr != null){
itemIntr = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, itemIntr);
if(!itemIntr.equals(item.getInstruction())){
//need to save since a ref has been updated:
needToUpdate = true;
item.setInstruction(itemIntr);
}
}
String itemDesc = item.getDescription();
if(itemDesc != null){
itemDesc = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, itemDesc);
if(!itemDesc.equals(item.getDescription())){
//need to save since a ref has been updated:
needToUpdate = true;
item.setDescription(itemDesc);
}
}
List itemTextList = item.getItemTextArray();
if(itemTextList != null){
for(int k = 0; k < itemTextList.size(); k++){
ItemText itemText = (ItemText) itemTextList.get(k);
String text = itemText.getText();
if(text != null){
// Transfer all of the attachments to the new site
text = service.copyContentHostingAttachments(text, toContext);
text = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, text);
if(!text.equals(itemText.getText())){
//need to save since a ref has been updated:
needToUpdate = true;
itemText.setText(text);
}else{
log.info("Migration - now update");
}
}
List answerSetList = itemText.getAnswerArray();
if (answerSetList != null) {
for (int l = 0; l < answerSetList.size(); l++) {
Answer answer = (Answer) answerSetList.get(l);
String answerText = answer.getText();
if (answerText != null) {
// Transfer all of the attachments embedded in the answer text
answerText = service.copyContentHostingAttachments(answerText, toContext);
// Now rewrite the answerText with links to the new site
answerText = org.sakaiproject.util.cover.LinkMigrationHelper.migrateAllLinks(entrySet, answerText);
if (!answerText.equals(answer.getText())) {
needToUpdate = true;
answer.setText(answerText);
}
}
}
}
}
}
}
}
if(needToUpdate){
//since the text changes were direct manipulations (no iterators),
//hibernate will take care of saving everything that changed:
service.saveAssessment(assessmentFacade);
}
}
}
}
}