0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/sam/trunk/component/src/java/org/sakaiproject/tool/assessment/qti/helper/ExtractionHelper.java $
0003: * $Id: ExtractionHelper.java 9274 2006-05-10 22:50:48Z daisyf@stanford.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the"License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.tool.assessment.qti.helper;
0021:
0022: import java.io.IOException;
0023: import java.util.ArrayList;
0024: import java.util.Calendar;
0025: import java.util.Date;
0026: import java.util.HashSet;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.Set;
0031:
0032: import javax.activation.MimetypesFileTypeMap;
0033: import javax.xml.parsers.ParserConfigurationException;
0034:
0035: import org.apache.commons.logging.Log;
0036: import org.apache.commons.logging.LogFactory;
0037: import org.sakaiproject.component.cover.ServerConfigurationService;
0038: import org.sakaiproject.content.api.ContentResource;
0039: import org.sakaiproject.content.cover.ContentHostingService;
0040: import org.sakaiproject.tool.assessment.data.dao.assessment.Answer;
0041: import org.sakaiproject.tool.assessment.data.dao.assessment.AnswerFeedback;
0042: import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl;
0043: import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentFeedback;
0044: import org.sakaiproject.tool.assessment.data.dao.assessment.EvaluationModel;
0045: import org.sakaiproject.tool.assessment.data.dao.assessment.ItemText;
0046: import org.sakaiproject.tool.assessment.data.dao.assessment.SecuredIPAddress;
0047: import org.sakaiproject.tool.assessment.data.ifc.assessment.AnswerFeedbackIfc;
0048: import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAccessControlIfc;
0049: import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAttachmentIfc;
0050: import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentBaseIfc;
0051: import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentIfc;
0052: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemAttachmentIfc;
0053: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc;
0054: import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionAttachmentIfc;
0055: import org.sakaiproject.tool.assessment.data.ifc.shared.TypeIfc;
0056: import org.sakaiproject.tool.assessment.facade.AssessmentFacade;
0057: import org.sakaiproject.tool.assessment.facade.ItemFacade;
0058: import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade;
0059: import org.sakaiproject.tool.assessment.facade.SectionFacade;
0060: import org.sakaiproject.tool.assessment.qti.asi.ASIBaseClass;
0061: import org.sakaiproject.tool.assessment.qti.asi.Assessment;
0062: import org.sakaiproject.tool.assessment.qti.asi.Item;
0063: import org.sakaiproject.tool.assessment.qti.asi.Section;
0064: import org.sakaiproject.tool.assessment.qti.constants.AuthoringConstantStrings;
0065: import org.sakaiproject.tool.assessment.qti.constants.QTIVersion;
0066: import org.sakaiproject.tool.assessment.qti.exception.Iso8601FormatException;
0067: import org.sakaiproject.tool.assessment.qti.helper.item.ItemTypeExtractionStrategy;
0068: import org.sakaiproject.tool.assessment.qti.util.Iso8601DateFormat;
0069: import org.sakaiproject.tool.assessment.qti.util.Iso8601TimeInterval;
0070: import org.sakaiproject.tool.assessment.qti.util.XmlMapper;
0071: import org.sakaiproject.tool.assessment.qti.util.XmlUtil;
0072: import org.sakaiproject.tool.assessment.services.assessment.AssessmentService;
0073: import org.sakaiproject.tool.cover.ToolManager;
0074: import org.sakaiproject.user.api.User;
0075: import org.sakaiproject.user.cover.UserDirectoryService;
0076: import org.w3c.dom.DOMException;
0077: import org.w3c.dom.Document;
0078: import org.w3c.dom.Node;
0079: import org.xml.sax.SAXException;
0080:
0081: /**
0082: * <p>Has helper methods for data extraction (import) from QTI</p>
0083: * <p> </p>
0084: * <p>Copyright: Copyright (c) 2005 Sakai</p>
0085: * @author Ed Smiley esmiley@stanford.edu
0086: * @version $Id: ExtractionHelper.java 9274 2006-05-10 22:50:48Z daisyf@stanford.edu $
0087: */
0088:
0089: public class ExtractionHelper {
0090: private static final String QTI_VERSION_1_2_PATH = "v1p2";
0091: private static final String QTI_VERSION_2_0_PATH = "v2p0";
0092: private static final String TRANSFORM_PATH = "xml/xsl/dataTransform/import";
0093:
0094: private static final String ASSESSMENT_TRANSFORM = "extractAssessment.xsl";
0095: private static final String SECTION_TRANSFORM = "extractSection.xsl";
0096: private static final String ITEM_TRANSFORM = "extractItem.xsl";
0097: private static Log log = LogFactory.getLog(ExtractionHelper.class);
0098:
0099: private int qtiVersion = QTIVersion.VERSION_1_2;
0100: private String overridePath = null; // override defaults and settings
0101: private String FIB_BLANK_INDICATOR = " {} ";
0102:
0103: private String unzipLocation;
0104:
0105: // versioning title string that it will look for/use, followed by a number
0106: private static final String VERSION_START = " - ";
0107:
0108: /**
0109: * @deprecated
0110: */
0111: public ExtractionHelper() {
0112: this .setQtiVersion(QTIVersion.VERSION_1_2);
0113:
0114: }
0115:
0116: /**
0117: * Get ExtractionHelper for QTIVersion.VERSION_1_2
0118: * or QTIVersion.VERSION_2_0
0119: * @param qtiVersion
0120: */
0121: public ExtractionHelper(int qtiVersion) {
0122: this .setQtiVersion(qtiVersion);
0123: }
0124:
0125: /**
0126: * Path to XSL transform code.
0127: * @return context-relative path to XSL transform code.
0128: */
0129: public String getTransformPath() {
0130: // first check to see if normal computed path has been overridden
0131: if (overridePath != null) {
0132: return overridePath;
0133: }
0134:
0135: return TRANSFORM_PATH + "/" + getQtiPath();
0136: }
0137:
0138: private String getQtiPath() {
0139: return qtiVersion == QTIVersion.VERSION_1_2 ? QTI_VERSION_1_2_PATH
0140: : QTI_VERSION_2_0_PATH;
0141: }
0142:
0143: /**
0144: * Get QTI version flag.
0145: * Either QTIVersion.VERSION_1_2 or QTIVersion.VERSION_2_0;
0146: * @return QTI version flag
0147: */
0148: public int getQtiVersion() {
0149: return qtiVersion;
0150: }
0151:
0152: /**
0153: * Set QTI version flag.
0154: * Either QTIVersion.VERSION_1_2 or QTIVersion.VERSION_2_0;
0155: * @param qtiVersion
0156: */
0157: public void setQtiVersion(int qtiVersion) {
0158: if (!QTIVersion.isValid(qtiVersion)) {
0159: throw new IllegalArgumentException("NOT Legal Qti Version.");
0160: }
0161: this .qtiVersion = qtiVersion;
0162: }
0163:
0164: /**
0165: * Get an XML document for the transform
0166: * @param template
0167: * @return
0168: */
0169: public Document getTransformDocument(String template) {
0170: //Document document = null;
0171:
0172: if (!isOKtransform(template)) {
0173: throw new IllegalArgumentException("NOT valid template.");
0174: }
0175: String templateContextPath = this .getTransformPath() + "/"
0176: + template;
0177: return XmlUtil.readDocument(templateContextPath);
0178: }
0179:
0180: /**
0181: * Get map of data to set from assessment XML
0182: * @param assessmentXml
0183: * @return a Map
0184: */
0185: public Map mapAssessment(Assessment assessmentXml) {
0186: log.debug("inside: mapAssessment");
0187: return map(ASSESSMENT_TRANSFORM, assessmentXml);
0188: }
0189:
0190: /**
0191: * Get map of data to set from section XML
0192: * @param sectionXml
0193: * @return a Map
0194: */
0195: public Map mapSection(Section sectionXml) {
0196: return map(SECTION_TRANSFORM, sectionXml);
0197: }
0198:
0199: /**
0200: * Get map of data to set from item XML
0201: * @param itemXml
0202: * @return a Map
0203: */
0204: public Map mapItem(Item itemXml) {
0205: return map(ITEM_TRANSFORM, itemXml);
0206: }
0207:
0208: /**
0209: * Helper method
0210: * @param transformType ASSESSMENT_TRANSFORM, SECTION_TRANSFORM, ITEM_TRANSFORM
0211: * @param asi ASIBaseClass: Assessment, Section, or Item XML
0212: * @return
0213: */
0214: private Map map(String transformType, ASIBaseClass asi) {
0215: if (!isOKasi(asi)) {
0216: throw new IllegalArgumentException(
0217: "Incorrect ASI subclass.");
0218: }
0219: if (!isOKtransform(transformType)) {
0220: throw new IllegalArgumentException("Incorrect transform: "
0221: + transformType + ".");
0222: }
0223: Map map = null;
0224: try {
0225: Document transform = getTransformDocument(transformType);
0226: Document xml = asi.getDocument();
0227: Document model = XmlUtil.transformDocument(xml, transform);
0228: map = XmlMapper.map(model);
0229: } catch (IOException ex) {
0230: log.error(ex);
0231: ex.printStackTrace(System.out);
0232: } catch (SAXException ex) {
0233: log.error(ex);
0234: ex.printStackTrace(System.out);
0235: } catch (ParserConfigurationException ex) {
0236: log.error(ex);
0237: ex.printStackTrace(System.out);
0238: }
0239: return map;
0240:
0241: }
0242:
0243: /**
0244: * Look up a List of Section XML from Assessment Xml
0245: * @return a List of Section XML objects
0246: */
0247: public List getSectionXmlList(Assessment assessmentXml) {
0248: List nodeList = assessmentXml.selectNodes("//section");
0249: List sectionXmlList = new ArrayList();
0250:
0251: // now convert our list of Nodes to a list of section xml
0252: for (int i = 0; i < nodeList.size(); i++) {
0253: try {
0254: Node node = (Node) nodeList.get(i);
0255: // create a document for a section xml object
0256: Document sectionDoc = XmlUtil.createDocument();
0257: // Make a copy for inserting into the new document
0258: Node importNode = sectionDoc.importNode(node, true);
0259: // Insert the copy into sectionDoc
0260: sectionDoc.appendChild(importNode);
0261: Section sectionXml = new Section(sectionDoc, this
0262: .getQtiVersion());
0263: // add the new section xml object to the list
0264: sectionXmlList.add(sectionXml);
0265: } catch (DOMException ex) {
0266: log.error(ex);
0267: ex.printStackTrace(System.out);
0268: }
0269: }
0270: return sectionXmlList;
0271: }
0272:
0273: /**
0274: * Look up a List of Item XML from Section Xml
0275: * @param Section sectionXml
0276: * @return a List of Item XML objects
0277: */
0278: public List getItemXmlList(Section sectionXml) {
0279: String itemElementName = qtiVersion == QTIVersion.VERSION_1_2 ? "//item"
0280: : "//assessmentItem";
0281:
0282: // now convert our list of Nodes to a list of section xml
0283: List nodeList = sectionXml.selectNodes(itemElementName);
0284: List itemXmlList = new ArrayList();
0285: for (int i = 0; i < nodeList.size(); i++) {
0286: try {
0287: Node node = (Node) nodeList.get(i);
0288: // create a document for a item xml object
0289: Document itemDoc = XmlUtil.createDocument();
0290: // Make a copy for inserting into the new document
0291: Node importNode = itemDoc.importNode(node, true);
0292: // Insert the copy into itemDoc
0293: itemDoc.appendChild(importNode);
0294: Item itemXml = new Item(itemDoc, this .getQtiVersion());
0295: // add the new section xml object to the list
0296: itemXmlList.add(itemXml);
0297: } catch (DOMException ex) {
0298: log.error(ex);
0299: ex.printStackTrace(System.out);
0300: }
0301: }
0302: return itemXmlList;
0303: }
0304:
0305: /**
0306: * Used internally.
0307: * @param transform
0308: * @return true if OK
0309: */
0310: private boolean isOKtransform(String transform) {
0311: return (transform == this .ASSESSMENT_TRANSFORM
0312: || transform == this .SECTION_TRANSFORM || transform == this .ITEM_TRANSFORM) ? true
0313: : false;
0314: }
0315:
0316: /**
0317: * Used internally.
0318: * @param asi
0319: * @return true if OK
0320: */
0321: private boolean isOKasi(ASIBaseClass asi) {
0322: return (asi instanceof Assessment || asi instanceof Section || asi instanceof Item) ? true
0323: : false;
0324: }
0325:
0326: // /**
0327: // * Create assessment from the extracted properties.
0328: // * @param assessmentMap the extracted properties
0329: // * @return an assessment, which has been persisted
0330: // */
0331: // public AssessmentFacade createAssessment(Map assessmentMap)
0332: // {
0333: // String description = (String) assessmentMap.get("description");
0334: // String title = (String) assessmentMap.get("title");
0335: // AssessmentService assessmentService = new AssessmentService();
0336: // AssessmentFacade assessment = assessmentService.createAssessment(
0337: // title, description, null, null);
0338: // return assessment;
0339: // }
0340:
0341: /**
0342: * Update assessment from the extracted properties.
0343: * Note: you need to do a save when you are done.
0344: * @param assessment the assessment, which will be persisted
0345: * @param assessmentMap the extracted properties
0346: */
0347: public void updateAssessment(AssessmentFacade assessment,
0348: Map assessmentMap) {
0349: String title;
0350: String displayName;
0351: String description;
0352: String comments;
0353:
0354: String instructorNotification;
0355: String testeeNotification;
0356: String multipartAllowed;
0357: String createdBy;
0358: String createdDate;
0359:
0360: title = (String) assessmentMap.get("title");
0361: displayName = (String) assessmentMap.get("title");
0362: comments = (String) assessmentMap.get("comments");
0363:
0364: log.debug("ASSESSMENT updating metadata information");
0365: // set meta data
0366: List metalist = (List) assessmentMap.get("metadata");
0367: MetaDataList metadataList = new MetaDataList(metalist);
0368: metadataList.setDefaults(assessment);
0369: metadataList.addTo(assessment);
0370: createdBy = assessment.getAssessmentMetaDataByLabel("CREATOR");
0371:
0372: log.debug("ASSESSMENT updating basic information");
0373: // set basic properties
0374: assessment.setCreatedBy(createdBy);
0375: assessment.setComments(comments);
0376: assessment.setCreatedDate(new Date());
0377: assessment.setLastModifiedBy("Sakai Import");
0378: assessment.setLastModifiedDate(new Date());
0379:
0380: // additional information
0381:
0382: // restricted IP address
0383: log
0384: .debug("ASSESSMENT updating access control, evaluation model, feedback");
0385:
0386: // access control
0387: String duration = (String) assessmentMap.get("duration");
0388: log.debug("duration: " + duration);
0389:
0390: makeAccessControl(assessment, duration);
0391: String submissionMsg = metadataList.getSubmissionMessage();
0392: updateSubmissionMessage(assessment, submissionMsg);
0393:
0394: // evaluation model control
0395: makeEvaluationModel(assessment);
0396:
0397: // assessment feedback control
0398: makeAssessmentFeedback(assessment);
0399:
0400: }
0401:
0402: /**
0403: * Put feedback settings into assessment (bi-directional)
0404: * @param assessment
0405: */
0406: private void makeAssessmentFeedback(AssessmentFacade assessment) {
0407: AssessmentFeedback feedback = (AssessmentFeedback) assessment
0408: .getAssessmentFeedback();
0409: if (feedback == null) {
0410: feedback = new AssessmentFeedback();
0411: // Need to fix AssessmentFeedback so it can take AssessmentFacade later
0412: feedback.setAssessmentBase(assessment.getData());
0413: }
0414:
0415: if ("TRUE"
0416: .equalsIgnoreCase(assessment
0417: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_QUESTION"))) {
0418: feedback.setShowQuestionText(Boolean.TRUE);
0419: } else {
0420: feedback.setShowQuestionText(Boolean.FALSE);
0421: }
0422:
0423: if ("TRUE"
0424: .equalsIgnoreCase(assessment
0425: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_RESPONSE"))) {
0426: feedback.setShowStudentResponse(Boolean.TRUE);
0427: } else {
0428: feedback.setShowStudentResponse(Boolean.FALSE);
0429: }
0430:
0431: if ("TRUE"
0432: .equalsIgnoreCase(assessment
0433: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_CORRECT_RESPONSE"))) {
0434: feedback.setShowCorrectResponse(Boolean.TRUE);
0435: } else {
0436: feedback.setShowCorrectResponse(Boolean.FALSE);
0437: }
0438:
0439: if ("TRUE"
0440: .equalsIgnoreCase(assessment
0441: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_STUDENT_SCORE"))) {
0442: feedback.setShowStudentScore(Boolean.TRUE);
0443: } else {
0444: feedback.setShowStudentScore(Boolean.FALSE);
0445: }
0446:
0447: if ("TRUE"
0448: .equalsIgnoreCase(assessment
0449: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_STUDENT_QUESTIONSCORE"))) {
0450: feedback.setShowStudentQuestionScore(Boolean.TRUE);
0451: } else {
0452: feedback.setShowStudentQuestionScore(Boolean.FALSE);
0453: }
0454:
0455: if ("TRUE"
0456: .equalsIgnoreCase(assessment
0457: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_ITEM_LEVEL"))) {
0458: feedback.setShowQuestionLevelFeedback(Boolean.TRUE);
0459: } else {
0460: feedback.setShowQuestionLevelFeedback(Boolean.FALSE);
0461: }
0462:
0463: if ("TRUE"
0464: .equalsIgnoreCase(assessment
0465: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_SELECTION_LEVEL"))) {
0466: feedback.setShowSelectionLevelFeedback(Boolean.TRUE);
0467: } else {
0468: feedback.setShowSelectionLevelFeedback(Boolean.FALSE);
0469: }
0470:
0471: if ("TRUE"
0472: .equalsIgnoreCase(assessment
0473: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_GRADER_COMMENT"))) {
0474: feedback.setShowGraderComments(Boolean.TRUE);
0475: } else {
0476: feedback.setShowGraderComments(Boolean.FALSE);
0477: }
0478:
0479: if ("TRUE".equalsIgnoreCase(assessment
0480: .getAssessmentMetaDataByLabel("FEEDBACK_SHOW_STATS"))) {
0481: feedback.setShowStatistics(Boolean.TRUE);
0482: } else {
0483: feedback.setShowStatistics(Boolean.FALSE);
0484: }
0485:
0486: if (this
0487: .notNullOrEmpty(assessment
0488: .getAssessmentMetaDataByLabel("FEEDBACK_DELIVERY_DATE"))
0489: || "DATED"
0490: .equalsIgnoreCase(assessment
0491: .getAssessmentMetaDataByLabel("FEEDBACK_DELIVERY"))) {
0492: feedback.setFeedbackDelivery(feedback.FEEDBACK_BY_DATE);
0493: } else if ("IMMEDIATE".equalsIgnoreCase(assessment
0494: .getAssessmentMetaDataByLabel("FEEDBACK_DELIVERY"))) {
0495: feedback.setFeedbackDelivery(feedback.IMMEDIATE_FEEDBACK);
0496: } else {
0497: feedback.setFeedbackDelivery(feedback.NO_FEEDBACK);
0498: }
0499:
0500: if ("QUESTION".equalsIgnoreCase(assessment
0501: .getAssessmentMetaDataByLabel("FEEDBACK_AUTHORING"))) {
0502: feedback
0503: .setFeedbackAuthoring(feedback.QUESTIONLEVEL_FEEDBACK);
0504: } else if ("SECTION".equalsIgnoreCase(assessment
0505: .getAssessmentMetaDataByLabel("FEEDBACK_AUTHORING"))) {
0506: feedback
0507: .setFeedbackAuthoring(feedback.SECTIONLEVEL_FEEDBACK);
0508: } else {
0509: feedback.setFeedbackAuthoring(feedback.BOTH_FEEDBACK);
0510: }
0511:
0512: assessment.setAssessmentFeedback(feedback);
0513: }
0514:
0515: /**
0516: * Put evaluation settings into assessment (bi-directional)
0517: * @param assessment
0518: */
0519: private void makeEvaluationModel(AssessmentFacade assessment) {
0520: EvaluationModel evaluationModel = (EvaluationModel) assessment
0521: .getEvaluationModel();
0522: if (evaluationModel == null) {
0523: evaluationModel = new EvaluationModel();
0524: // Need to fix EvaluationModel so it can take AssessmentFacade later
0525: evaluationModel.setAssessmentBase(assessment.getData());
0526: }
0527:
0528: // anonymous
0529: if ("TRUE".equalsIgnoreCase(assessment
0530: .getAssessmentMetaDataByLabel("ANONYMOUS_GRADING"))) {
0531: evaluationModel
0532: .setAnonymousGrading(EvaluationModel.ANONYMOUS_GRADING);
0533: } else {
0534: evaluationModel
0535: .setAnonymousGrading(EvaluationModel.NON_ANONYMOUS_GRADING);
0536: }
0537:
0538: // gradebook options, don't know how this is supposed to work, leave alone for now
0539: if ("DEFAULT".equalsIgnoreCase(assessment
0540: .getAssessmentMetaDataByLabel("GRADEBOOK_OPTIONS"))) {
0541: evaluationModel
0542: .setToGradeBook(EvaluationModel.TO_DEFAULT_GRADEBOOK
0543: .toString());
0544: } else if ("SELECTED".equalsIgnoreCase(assessment
0545: .getAssessmentMetaDataByLabel("GRADEBOOK_OPTIONS"))) {
0546: evaluationModel
0547: .setToGradeBook(EvaluationModel.NOT_TO_GRADEBOOK
0548: .toString()); // this is for backward compatibility.
0549: // we've always used 2 for 'None' option. Old exported XML will have 'SELECTED' for assessemnts that are set not to send to gradebook, so we need to accomodate those.
0550: // TO_SELECTED_GRADEBOOK is not really used.
0551: }
0552: // SAK-7162
0553: else if ("NONE".equalsIgnoreCase(assessment
0554: .getAssessmentMetaDataByLabel("GRADEBOOK_OPTIONS"))) {
0555: evaluationModel
0556: .setToGradeBook(EvaluationModel.NOT_TO_GRADEBOOK
0557: .toString());
0558: }
0559:
0560: // highest or last
0561: if ("HIGHEST_SCORE".equalsIgnoreCase(assessment
0562: .getAssessmentMetaDataByLabel("GRADE_SCORE"))) {
0563: evaluationModel
0564: .setScoringType(EvaluationModel.HIGHEST_SCORE);
0565: }
0566: /*
0567: // not implementing average for now
0568: else if ("AVERAGE".equalsIgnoreCase(assessment.getAssessmentMetaDataByLabel(
0569: "GRADE_SCORE")))
0570: {
0571: evaluationModel.setScoringType(EvaluationModel.AVERAGE_SCORE);
0572: }
0573: */
0574: else if ("LAST_SCORE".equalsIgnoreCase(assessment
0575: .getAssessmentMetaDataByLabel("GRADE_SCORE"))) {
0576: evaluationModel.setScoringType(EvaluationModel.LAST_SCORE);
0577: }
0578: assessment.setEvaluationModel(evaluationModel);
0579: }
0580:
0581: private void updateSubmissionMessage(AssessmentFacade assessment,
0582: String submissionMsg) {
0583: AssessmentAccessControl control = (AssessmentAccessControl) assessment
0584: .getAssessmentAccessControl();
0585: if (control == null) {
0586: control = new AssessmentAccessControl();
0587: // need to fix accessControl so it can take AssessmentFacade later
0588: control.setAssessmentBase(assessment.getData());
0589: }
0590: if (submissionMsg != null) {
0591: control
0592: .setSubmissionMessage(makeFCKAttachment(submissionMsg));
0593: }
0594:
0595: }
0596:
0597: /**
0598: * Put access control settings into assessment (bi-directional)
0599: * @param assessment
0600: * @param duration Time interval for timed assessment (Iso8601 format)
0601: */
0602: private void makeAccessControl(AssessmentFacade assessment,
0603: String duration) {
0604: AssessmentAccessControl control = (AssessmentAccessControl) assessment
0605: .getAssessmentAccessControl();
0606: if (control == null) {
0607: control = new AssessmentAccessControl();
0608: // need to fix accessControl so it can take AssessmentFacade later
0609: control.setAssessmentBase(assessment.getData());
0610: }
0611:
0612: // Control dates
0613: Iso8601DateFormat iso = new Iso8601DateFormat();
0614: String startDate = assessment
0615: .getAssessmentMetaDataByLabel("START_DATE");
0616: String dueDate = assessment
0617: .getAssessmentMetaDataByLabel("END_DATE");
0618: String retractDate = assessment
0619: .getAssessmentMetaDataByLabel("RETRACT_DATE");
0620: String feedbackDate = assessment
0621: .getAssessmentMetaDataByLabel("FEEDBACK_DELIVERY_DATE");
0622:
0623: try {
0624: control.setStartDate(iso.parse(startDate).getTime());
0625: assessment.getData().addAssessmentMetaData(
0626: "hasAvailableDate", "true");
0627:
0628: } catch (Iso8601FormatException ex) {
0629: log.debug("Cannot set startDate.");
0630: }
0631: try {
0632: control.setDueDate(iso.parse(dueDate).getTime());
0633: // assessment.getData().addAssessmentMetaData("hasDueDate", "true");
0634: assessment.getData().addAssessmentMetaData("dueDate",
0635: "true");
0636: } catch (Iso8601FormatException ex) {
0637: log.debug("Cannot set dueDate.");
0638: }
0639: try {
0640: control.setRetractDate(iso.parse(retractDate).getTime());
0641: assessment.getData().addAssessmentMetaData(
0642: "hasRetractDate", "true");
0643: } catch (Iso8601FormatException ex) {
0644: log.debug("Cannot set retractDate.");
0645: }
0646: try {
0647: control.setFeedbackDate(iso.parse(feedbackDate).getTime());
0648: assessment.getData().addAssessmentMetaData(
0649: "FEEDBACK_DELIVERY", "DATED");
0650: } catch (Iso8601FormatException ex) {
0651: log.debug("Cannot set feedbackDate.");
0652: }
0653:
0654: // don't know what site you will have in a new environment
0655: // but registered as a BUG in SAM-271 so turning it on.
0656:
0657: String releasedTo = assessment
0658: .getAssessmentMetaDataByLabel("ASSESSMENT_RELEASED_TO");
0659:
0660: // for backwards compatibility with version 1.5 exports.
0661: if (releasedTo != null
0662: && releasedTo.indexOf("Authenticated Users") > -1) {
0663: log
0664: .debug("Fixing obsolete reference to 'Authenticated Users', setting released to 'Anonymous Users'.");
0665: releasedTo = AuthoringConstantStrings.ANONYMOUS;
0666: }
0667:
0668: // for backwards compatibility with version 1.5 exports.
0669: if (releasedTo != null
0670: && releasedTo.indexOf("Authenticated Users") > -1) {
0671: log
0672: .debug("Fixing obsolete reference to 'Authenticated Users', setting released to 'Anonymous Users'.");
0673: releasedTo = AuthoringConstantStrings.ANONYMOUS;
0674: }
0675:
0676: log.debug("control.setReleaseTo(releasedTo)='" + releasedTo
0677: + "'.");
0678: control.setReleaseTo(releasedTo);
0679:
0680: // Timed Assessment
0681: if (duration != null) {
0682: try {
0683: Iso8601TimeInterval tiso = new Iso8601TimeInterval(
0684: duration);
0685: log.debug("tiso.getDuration(): " + tiso.getDuration());
0686:
0687: if (tiso == null) {
0688: throw new Iso8601FormatException(
0689: "Assessment duration could not be resolved.");
0690: }
0691: long millisecondsDuration = tiso.getDuration();
0692: int seconds = (int) millisecondsDuration / 1000;
0693: control.setTimeLimit(new Integer(seconds));
0694: if (seconds != 0) {
0695: control
0696: .setTimedAssessment(AssessmentAccessControl.TIMED_ASSESSMENT);
0697: assessment.getData().addAssessmentMetaData(
0698: "hasTimeAssessment", "true");
0699: } else {
0700: control.setTimeLimit(new Integer(0));
0701: control
0702: .setTimedAssessment(AssessmentAccessControl.DO_NOT_TIMED_ASSESSMENT);
0703: }
0704: } catch (Iso8601FormatException ex) {
0705: log.warn("Can't format assessment duration. " + ex);
0706: control.setTimeLimit(new Integer(0));
0707: control
0708: .setTimedAssessment(AssessmentAccessControl.DO_NOT_TIMED_ASSESSMENT);
0709: }
0710: } else {
0711: control.setTimeLimit(new Integer(0));
0712: control
0713: .setTimedAssessment(AssessmentAccessControl.DO_NOT_TIMED_ASSESSMENT);
0714: }
0715:
0716: log
0717: .debug("assessment.getAssessmentMetaDataByLabel(AUTO_SUBMIT): "
0718: + assessment
0719: .getAssessmentMetaDataByLabel("AUTO_SUBMIT"));
0720:
0721: if ("TRUE".equalsIgnoreCase(assessment
0722: .getAssessmentMetaDataByLabel("AUTO_SUBMIT"))) {
0723: log.debug("AUTO SUBMIT IS TRUE");
0724: control.setAutoSubmit(AssessmentAccessControl.AUTO_SUBMIT);
0725: assessment.getData().addAssessmentMetaData("hasAutoSubmit",
0726: "true");
0727: } else {
0728: control
0729: .setAutoSubmit(AssessmentAccessControl.DO_NOT_AUTO_SUBMIT);
0730: }
0731:
0732: // Assessment Organization
0733: // navigation
0734: if ("LINEAR".equalsIgnoreCase(assessment
0735: .getAssessmentMetaDataByLabel("NAVIGATION"))) {
0736: control.setItemNavigation(control.LINEAR_ACCESS);
0737: } else {
0738: control.setItemNavigation(control.RANDOM_ACCESS);
0739: }
0740:
0741: // numbering
0742: if ("CONTINUOUS".equalsIgnoreCase(assessment
0743: .getAssessmentMetaDataByLabel("QUESTION_NUMBERING"))) {
0744: control.setItemNumbering(control.CONTINUOUS_NUMBERING);
0745: } else if ("RESTART".equalsIgnoreCase(assessment
0746: .getAssessmentMetaDataByLabel("QUESTION_NUMBERING"))) {
0747: control.setItemNumbering(control.RESTART_NUMBERING_BY_PART);
0748: }
0749:
0750: //question layout
0751: if ("I".equalsIgnoreCase(assessment
0752: .getAssessmentMetaDataByLabel("QUESTION_LAYOUT"))) {
0753: control.setAssessmentFormat(control.BY_QUESTION);
0754: } else if ("S".equalsIgnoreCase(assessment
0755: .getAssessmentMetaDataByLabel("QUESTION_LAYOUT"))) {
0756: control.setAssessmentFormat(control.BY_PART);
0757: } else {
0758: control.setAssessmentFormat(control.BY_ASSESSMENT);
0759: }
0760:
0761: //Submissions
0762: // submissions allowed
0763: String maxAttempts = ""
0764: + assessment
0765: .getAssessmentMetaDataByLabel("MAX_ATTEMPTS");
0766: String unlimited = AuthoringConstantStrings.UNLIMITED_SUBMISSIONS;
0767: log.debug("maxAttempts: '" + maxAttempts + "'");
0768: log.debug("unlimited: '" + unlimited + "'");
0769:
0770: if (unlimited.equals(maxAttempts.trim())) {
0771: log.debug("unlimited.equals(maxAttempts.trim()");
0772: control.setUnlimitedSubmissions(Boolean.TRUE);
0773: control
0774: .setSubmissionsAllowed(AssessmentAccessControlIfc.UNLIMITED_SUBMISSIONS);
0775: } else {
0776: control.setUnlimitedSubmissions(Boolean.FALSE);
0777: try {
0778: control.setSubmissionsAllowed(new Integer(maxAttempts));
0779: } catch (NumberFormatException ex1) {
0780: control.setSubmissionsAllowed(new Integer("1"));
0781: }
0782: }
0783: log.debug("Set: control.getSubmissionsAllowed()="
0784: + control.getSubmissionsAllowed());
0785: log.debug("Set: control.getUnlimitedSubmissions()="
0786: + control.getUnlimitedSubmissions());
0787:
0788: // late submissions
0789: // I am puzzled as to why there is no ACCEPT_LATE_SUBMISSION, assuming it =T
0790: if ("FALSE".equalsIgnoreCase(assessment
0791: .getAssessmentMetaDataByLabel("LATE_HANDLING"))) {
0792: control.setLateHandling(control.NOT_ACCEPT_LATE_SUBMISSION);
0793: } else {
0794: control.setLateHandling(new Integer(1));
0795:
0796: }
0797:
0798: // auto save
0799: if ("TRUE".equalsIgnoreCase(assessment
0800: .getAssessmentMetaDataByLabel("AUTO_SAVE"))) {
0801: control.setAutoSubmit(control.AUTO_SAVE);
0802: }
0803:
0804: // Submission Message
0805: /*
0806: String submissionMessage = assessment.getAssessmentMetaDataByLabel(
0807: "SUBMISSION_MESSAGE");
0808: if (submissionMessage != null)
0809: {
0810: control.setSubmissionMessage(submissionMessage);
0811: }
0812: */
0813:
0814: // Username, password, finalPageUrl
0815: // String considerUserId = assessment.getAssessmentMetaDataByLabel(
0816: // "CONSIDER_USERID"); //
0817: String userId = assessment
0818: .getAssessmentMetaDataByLabel("USERID");
0819: String password = assessment
0820: .getAssessmentMetaDataByLabel("PASSWORD");
0821: String finalPageUrl = assessment
0822: .getAssessmentMetaDataByLabel("FINISH_URL");
0823:
0824: if (//"TRUE".equalsIgnoreCase(considerUserId) &&
0825: notNullOrEmpty(userId) && notNullOrEmpty(password)) {
0826: control.setUsername(userId);
0827: control.setPassword(password);
0828: assessment.getData().addAssessmentMetaData(
0829: "hasUsernamePassword", "true");
0830: }
0831: control.setFinalPageUrl(finalPageUrl);
0832:
0833: assessment.setAssessmentAccessControl(control);
0834: }
0835:
0836: /**
0837: * the ip address is in a newline delimited string
0838: * @param assessment
0839: */
0840: public void makeSecuredIPAddressSet(AssessmentFacade assessment,
0841: String ipList) {
0842: Set securedIPAddressSet = (Set) assessment
0843: .getSecuredIPAddressSet();
0844: AssessmentBaseIfc data = assessment.getData();
0845:
0846: if (securedIPAddressSet == null) {
0847: securedIPAddressSet = new HashSet();
0848: }
0849: //log.info("Getting securedIPAddressSet=" + securedIPAddressSet);
0850:
0851: //log.info("ipList: " + ipList);
0852:
0853: if (ipList == null)
0854: ipList = "";
0855: String[] ip = ipList.split("\\n");
0856:
0857: for (int j = 0; j < ip.length; j++) {
0858: //log.info("ip # " + j + ": " + ip[j]);
0859: if (ip[j] != null) {
0860: SecuredIPAddress sip = new SecuredIPAddress(data, null,
0861: ip[j]);
0862: //sip.setAssessment(data);
0863: securedIPAddressSet.add(sip);
0864: }
0865: }
0866:
0867: //log.info("securedIPAddressSet.size()=" + securedIPAddressSet.size());
0868: if (securedIPAddressSet.size() > 0) {
0869: //log.info("Setting securedIPAddressSet;addAssessmentMetaData(hasIpAddress, true)");
0870: //AssessmentService assessmentService = new AssessmentService();
0871: // assessment.getData().setSecuredIPAddressSet(securedIPAddressSet);
0872: // assessment.getData().addAssessmentMetaData("hasIpAddress", "true");
0873: // assessment.getData().addAssessmentMetaData("hasSpecificIP", "true");
0874: // data.setSecuredIPAddressSet(securedIPAddressSet);
0875: data.addAssessmentMetaData("hasIpAddress", "true");
0876: data.addAssessmentMetaData("hasSpecificIP", "true");
0877: assessment.updateData(data);
0878: assessment.setSecuredIPAddressSet(securedIPAddressSet);
0879:
0880: }
0881: }
0882:
0883: /**
0884: * the ip address is in a newline delimited string
0885: * @param assessment
0886: */
0887: public void makeAssessmentAttachmentSet(AssessmentFacade assessment) {
0888: // if unzipLocation is null, there is no assessment attachment - no action is needed
0889: if (unzipLocation == null) {
0890: return;
0891: }
0892: // first check if there is any attachment
0893: // if no attachment - no action is needed
0894: String attachment = assessment
0895: .getAssessmentAttachmentMetaData();
0896: if (attachment == null || "".equals(attachment)) {
0897: return;
0898: }
0899:
0900: Set assessmentAttachmentSet = (Set) assessment
0901: .getAssessmentAttachmentSet();
0902: if (assessmentAttachmentSet == null) {
0903: assessmentAttachmentSet = new HashSet();
0904: }
0905:
0906: AssessmentAttachmentIfc assessmentAttachment;
0907: String[] attachmentArray = attachment.split("\\n");
0908: HashSet set = new HashSet();
0909: for (int i = 0; i < attachmentArray.length; i++) {
0910: String[] attachmentInfo = attachmentArray[i].split("\\|");
0911: String fullFilePath = unzipLocation + "/"
0912: + attachmentInfo[0];
0913: String filename = attachmentInfo[1];
0914: AttachmentHelper attachementHelper = new AttachmentHelper();
0915: ContentResource contentResource = attachementHelper
0916: .createContentResource(fullFilePath, filename,
0917: attachmentInfo[2]);
0918: AssessmentService assessmentService = new AssessmentService();
0919: assessmentAttachment = assessmentService
0920: .createAssessmentAttachment(assessment,
0921: contentResource.getId(), filename,
0922: ServerConfigurationService.getServerUrl());
0923: assessmentAttachment
0924: .setAssessment((AssessmentIfc) assessment.getData());
0925: set.add(assessmentAttachment);
0926: }
0927: assessment.setAssessmentAttachmentSet(set);
0928: }
0929:
0930: /**
0931: * the ip address is in a newline delimited string
0932: * @param assessment
0933: */
0934: public void makeSectionAttachmentSet(SectionFacade section,
0935: Map sectionMap) {
0936: // if unzipLocation is null, there is no assessment attachment - no action is needed
0937: if (unzipLocation == null) {
0938: return;
0939: }
0940: // first check if there is any attachment
0941: // if no attachment - no action is needed
0942: String attachment = (String) sectionMap.get("attachment");
0943: if (attachment == null || "".equals(attachment)) {
0944: return;
0945: }
0946:
0947: Set sectionAttachmentSet = (Set) section
0948: .getSectionAttachmentSet();
0949: if (sectionAttachmentSet == null) {
0950: sectionAttachmentSet = new HashSet();
0951: }
0952:
0953: SectionAttachmentIfc sectionAttachment;
0954: String[] attachmentArray = attachment.split("\\n");
0955: HashSet set = new HashSet();
0956: for (int i = 0; i < attachmentArray.length; i++) {
0957: String[] attachmentInfo = attachmentArray[i].split("\\|");
0958: String fullFilePath = unzipLocation + "/"
0959: + attachmentInfo[0];
0960: String filename = attachmentInfo[1];
0961: AttachmentHelper attachementHelper = new AttachmentHelper();
0962: ContentResource contentResource = attachementHelper
0963: .createContentResource(fullFilePath, filename,
0964: attachmentInfo[2]);
0965: AssessmentService assessmentService = new AssessmentService();
0966: sectionAttachment = assessmentService
0967: .createSectionAttachment(section, contentResource
0968: .getId(), filename,
0969: ServerConfigurationService.getServerUrl());
0970: sectionAttachment.setSection(section.getData());
0971: set.add(sectionAttachment);
0972: }
0973: section.setSectionAttachmentSet(set);
0974: }
0975:
0976: /**
0977: * the ip address is in a newline delimited string
0978: * @param assessment
0979: */
0980: public void makeItemAttachmentSet(ItemFacade item) {
0981: // if unzipLocation is null, there is no assessment attachment - no action is needed
0982: if (unzipLocation == null) {
0983: return;
0984: }
0985: // first check if there is any attachment
0986: // if no attachment - no action is needed
0987: String attachment = item.getItemAttachmentMetaData();
0988: if (attachment == null || "".equals(attachment)) {
0989: return;
0990: }
0991:
0992: Set itemAttachmentSet = (Set) item.getItemAttachmentSet();
0993: if (itemAttachmentSet == null) {
0994: itemAttachmentSet = new HashSet();
0995: }
0996:
0997: ItemAttachmentIfc itemAttachment;
0998: String[] attachmentArray = attachment.split("\\n");
0999: HashSet set = new HashSet();
1000: for (int i = 0; i < attachmentArray.length; i++) {
1001: String[] attachmentInfo = attachmentArray[i].split("\\|");
1002: String fullFilePath = unzipLocation + "/"
1003: + attachmentInfo[0];
1004: String filename = attachmentInfo[1];
1005: AttachmentHelper attachementHelper = new AttachmentHelper();
1006: ContentResource contentResource = attachementHelper
1007: .createContentResource(fullFilePath, filename,
1008: attachmentInfo[2]);
1009: AssessmentService assessmentService = new AssessmentService();
1010: itemAttachment = assessmentService.createItemAttachment(
1011: item, contentResource.getId(), filename,
1012: ServerConfigurationService.getServerUrl());
1013: itemAttachment.setItem(item.getData());
1014: set.add(itemAttachment);
1015: }
1016: item.setItemAttachmentSet(set);
1017: }
1018:
1019: /**
1020: * the ip address is in a newline delimited string
1021: * @param assessment
1022: */
1023: public String makeFCKAttachment(String text) {
1024: // if unzipLocation is null, there is no assessment attachment - no action is needed
1025: if (unzipLocation == null) {
1026: return text;
1027: }
1028: // first check if there is any content resource attachment
1029: // if no - no action is needed
1030: String accessURL = ServerConfigurationService.getAccessUrl();
1031: String referenceRoot = ContentHostingService.REFERENCE_ROOT;
1032: String prependString = accessURL + referenceRoot;
1033: String importedPrependString = getImportedPrependString(text);
1034: if (text == null || importedPrependString == null) {
1035: return text;
1036: } else {
1037: String[] splittedString = text.split(importedPrependString);
1038: int endIndex = 0;
1039: String filename = null;
1040: String contentType = null;
1041: String fullFilePath = null;
1042: String oldResourceId = null;
1043: String resourceId = null;
1044: ContentResource contentResource = null;
1045: StringBuffer updatedText = new StringBuffer(
1046: splittedString[0]);
1047: for (int i = 1; i < splittedString.length; i++) {
1048: log.debug("splittedString[" + i + "] = "
1049: + splittedString[i]);
1050: // Here is an example, splittedString will be something like:
1051: // /group/b917f0b9-e21d-4819-80ee-35feac91c9eb/Blue Hill.jpg" alt="... or
1052: // /user/ktsao/Blue Hill.jpg" alt="...
1053: // oldResourceId = /group/b917f0b9-e21d-4819-80ee-35feac91c9eb/Blue Hill.jpg or /user/ktsao/Blue Hill.jpg
1054: // oldSplittedResourceId[0] = ""
1055: // oldSplittedResourceId[1] = group or user
1056: // oldSplittedResourceId[2] = b917f0b9-e21d-4819-80ee-35feac91c9eb or ktsao
1057: // oldSplittedResourceId[3] = Blue Hill.jpg
1058: endIndex = splittedString[i].indexOf("\"");
1059: oldResourceId = splittedString[i]
1060: .substring(0, endIndex);
1061: String[] oldSplittedResourceId = oldResourceId
1062: .split("/");
1063: fullFilePath = unzipLocation + "/"
1064: + oldResourceId.replace(" ", "");
1065: filename = oldSplittedResourceId[3];
1066: MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();
1067: contentType = mimetypesFileTypeMap
1068: .getContentType(filename);
1069: AttachmentHelper attachementHelper = new AttachmentHelper();
1070: contentResource = attachementHelper
1071: .createContentResource(fullFilePath, filename,
1072: contentType);
1073:
1074: if (contentResource != null) {
1075: resourceId = contentResource.getId();
1076: updatedText.append(prependString);
1077: updatedText.append(resourceId);
1078: updatedText.append(splittedString[i]
1079: .substring(endIndex));
1080: } else {
1081: throw new RuntimeException("resourceId is null");
1082: }
1083: }
1084: return updatedText.toString();
1085: }
1086: }
1087:
1088: private String getImportedPrependString(String text) {
1089: String accessPath = ServerConfigurationService.getAccessPath();
1090: String referenceRoot = ContentHostingService.REFERENCE_ROOT;
1091: String importedPrependString = accessPath + referenceRoot;
1092:
1093: String[] splittedString = text.split("src=\"");
1094: for (int i = 0; i < splittedString.length; i++) {
1095: if (splittedString[i].indexOf(importedPrependString) > -1) {
1096: int length = importedPrependString.length();
1097: return splittedString[i].substring(0, splittedString[i]
1098: .indexOf(importedPrependString)
1099: + length);
1100: }
1101: }
1102: return null;
1103: }
1104:
1105: /**
1106: * Update questionpool from the extracted properties.
1107: * Note: you need to do a save when you are done.
1108: * @param questionpool, which will be persisted
1109: * @param assessmentMap, the extracted properties
1110: */
1111: public void updateQuestionPool(QuestionPoolFacade questionpool,
1112: Map assessmentMap) {
1113:
1114: String title = ((String) assessmentMap.get("title"));
1115: questionpool.setDescription((String) assessmentMap
1116: .get("description"));
1117: //questionpool.setLastModifiedById("Sakai Import");
1118: questionpool.setLastModified(new Date());
1119: // note: currently dateCreated field not in use
1120: //questionpool.setDateCreated(new Date());
1121: questionpool.setOrganizationName((String) assessmentMap
1122: .get("ASSESSMENT_ORGANIZATIONNAME"));
1123: questionpool.setObjectives((String) assessmentMap
1124: .get("ASSESSMENT_OBJECTIVES"));
1125: questionpool.setKeywords((String) assessmentMap
1126: .get("ASSESSMENT_KEYWORDS"));
1127: questionpool.setRubric((String) assessmentMap
1128: .get("ASSESSMENT_RUBRICS"));
1129: questionpool.setIntellectualPropertyId((Long) assessmentMap
1130: .get("INTELLECTUALPROPERTYID"));
1131:
1132: log.debug("QPOOL ASSESSMENT updating metadata information");
1133:
1134: }
1135:
1136: /**
1137: * Update section from the extracted properties.
1138: * Note: you need to do a save when you are done.
1139: * @param section the section, which will be persisted
1140: * @param sectionMap the extracted properties
1141: */
1142: public void updateSection(SectionFacade section, Map sectionMap) {
1143: section.setTitle((String) sectionMap.get("title"));
1144: section.setDescription(makeFCKAttachment((String) sectionMap
1145: .get("description")));
1146: section.setLastModifiedBy("Sakai Import");
1147: section.setLastModifiedDate(new Date());
1148: }
1149:
1150: /**
1151: * Update item from the extracted properties.
1152: * Note: you need to do a save when you are done.
1153: * @param item the item, which will be persisted
1154: * @param itemMap the extracted properties
1155: */
1156: public void updateItem(ItemFacade item, Map itemMap) {
1157: // type and title
1158: String title = (String) itemMap.get("title");
1159: item.setDescription(title);
1160:
1161: // set meta data
1162: List metalist = (List) itemMap.get("metadata");
1163: MetaDataList metadataList = new MetaDataList(metalist);
1164: metadataList.addTo(item);
1165:
1166: // type
1167: log.debug("itemMap=" + itemMap);
1168: String qmd = item.getItemMetaDataByLabel("qmd_itemtype");
1169: String itemIntrospect = (String) itemMap.get("itemIntrospect");
1170: log.debug("Calling ItemTypeExtractionStrategy.calculate(");
1171: log.debug(" title=" + title);
1172: log.debug(" , itemIntrospect=" + itemIntrospect);
1173: log.debug(" , qmd=" + qmd);
1174: log.debug(");");
1175:
1176: Long typeId = ItemTypeExtractionStrategy.calculate(title,
1177: itemIntrospect, qmd);
1178: item.setTypeId(typeId);
1179:
1180: // basic properties
1181: addItemProperties(item, itemMap);
1182:
1183: // feedback
1184: // correct, incorrect, general
1185: addFeedback(item, itemMap, typeId);
1186:
1187: // item text and answers
1188: if (TypeIfc.FILL_IN_BLANK.longValue() == typeId.longValue()) {
1189: addFibTextAndAnswers(item, itemMap);
1190: }
1191:
1192: else if (TypeIfc.FILL_IN_NUMERIC.longValue() == typeId
1193: .longValue()) {
1194: addFibTextAndAnswers(item, itemMap);
1195: //addFinTextAndAnswers(item, itemMap); // 10/3/2006: Diego's code, duplicate of addFibTextAndAnswers
1196: }
1197:
1198: else if (TypeIfc.MATCHING.longValue() == typeId.longValue()) {
1199: addMatchTextAndAnswers(item, itemMap);
1200: } else {
1201: addTextAndAnswers(item, itemMap);
1202: }
1203:
1204: }
1205:
1206: /**
1207: *
1208: * @param item
1209: * @param itemMap
1210: */
1211: private void addItemProperties(ItemFacade item, Map itemMap) {
1212: //String duration = (String) itemMap.get("duration");
1213: //String triesAllowed = (String) itemMap.get("triesAllowed");
1214:
1215: String score = (String) itemMap.get("score");
1216: String hasRationale = item
1217: .getItemMetaDataByLabel("hasRationale");//rshastri :SAK-1824
1218: String status = (String) itemMap.get("status");
1219: String createdBy = (String) itemMap.get("createdBy");
1220:
1221: // not being set yet
1222: String instruction = (String) itemMap.get("instruction");
1223: String hint = (String) itemMap.get("hint");
1224:
1225: // created by is not nullable
1226: if (createdBy == null) {
1227: createdBy = "Imported by Sakai";
1228: }
1229:
1230: String createdDate = (String) itemMap.get("createdDate");
1231:
1232: // get Duration and TriesAllowed from metadata.
1233: /*
1234: if (notNullOrEmpty(duration))
1235: {
1236: item.setDuration(new Integer(duration));
1237: }
1238: if (notNullOrEmpty(triesAllowed))
1239: {
1240: item.setTriesAllowed(new Integer(triesAllowed));
1241: }
1242: */
1243:
1244: item.setInstruction((String) itemMap.get("instruction"));
1245: if (notNullOrEmpty(score)) {
1246: item.setScore(new Float(score));
1247: } else {
1248: item.setScore(new Float(0));
1249: }
1250: item.setHint((String) itemMap.get("hint"));
1251: if (notNullOrEmpty(hasRationale)) {
1252: item.setHasRationale(new Boolean(hasRationale));
1253: }
1254: if (notNullOrEmpty(status)) {
1255: item.setStatus(new Integer(status));
1256: }
1257: item.setCreatedBy(createdBy);
1258: try {
1259: Iso8601DateFormat iso = new Iso8601DateFormat();
1260: Calendar cal = iso.parse(createdDate);
1261: item.setCreatedDate(cal.getTime());
1262: } catch (Exception ex) {
1263: item.setCreatedDate(new Date());
1264: }
1265: item.setLastModifiedBy("Sakai Import");
1266: item.setLastModifiedDate(new Date());
1267: }
1268:
1269: /**
1270: * add feedback
1271: * @param item
1272: * @param itemMap
1273: * @param typeId
1274: */
1275: private void addFeedback(ItemFacade item, Map itemMap, Long typeId) {
1276: // write the map out
1277: Iterator iter = itemMap.keySet().iterator();
1278: while (iter.hasNext()) {
1279: String key = (String) iter.next();
1280: Object o = itemMap.get(key);
1281: log.debug("itemMap: " + key + "=" + itemMap.get(key));
1282: }
1283:
1284: String correctItemFeedback = (String) itemMap
1285: .get("correctItemFeedback");
1286: String incorrectItemFeedback = (String) itemMap
1287: .get("incorrectItemFeedback");
1288: String generalItemFeedback = (String) itemMap
1289: .get("generalItemFeedback");
1290: if (generalItemFeedback == null)
1291: generalItemFeedback = "";
1292:
1293: // NOTE:
1294: // in early Samigo (aka Navigo) general feedback exported as "InCorrect"!
1295: // now if this is an Audio, File Upload or Short Answer question additional
1296: // feedback will append feedback to general, this should be OK, since
1297: // QTI with general feedback for these types will leave them empty
1298: if (TypeIfc.AUDIO_RECORDING.longValue() == typeId.longValue()
1299: || TypeIfc.FILE_UPLOAD.longValue() == typeId
1300: .longValue()
1301: || TypeIfc.ESSAY_QUESTION.longValue() == typeId
1302: .longValue()) {
1303: if (notNullOrEmpty(incorrectItemFeedback)) {
1304: generalItemFeedback += " " + incorrectItemFeedback;
1305: }
1306: if (notNullOrEmpty(correctItemFeedback)) {
1307: generalItemFeedback += " " + correctItemFeedback;
1308: }
1309: }
1310:
1311: if (notNullOrEmpty(correctItemFeedback)) {
1312: item
1313: .setCorrectItemFeedback(makeFCKAttachment(correctItemFeedback));
1314: }
1315: if (notNullOrEmpty(incorrectItemFeedback)) {
1316: item
1317: .setInCorrectItemFeedback(makeFCKAttachment(incorrectItemFeedback));
1318: }
1319: if (notNullOrEmpty(generalItemFeedback)) {
1320: item
1321: .setGeneralItemFeedback(makeFCKAttachment(generalItemFeedback));
1322: }
1323:
1324: }
1325:
1326: /**
1327: * create the answer feedback set for an answer
1328: * @param item
1329: * @param itemMap
1330: */
1331: private void addAnswerFeedback(Answer answer, String value) {
1332: HashSet answerFeedbackSet = new HashSet();
1333: answerFeedbackSet.add(new AnswerFeedback(answer,
1334: AnswerFeedbackIfc.ANSWER_FEEDBACK, value));
1335: answer.setAnswerFeedbackSet(answerFeedbackSet);
1336: }
1337:
1338: /**
1339: * @param item
1340: * @param itemMap
1341: */
1342: private void addTextAndAnswers(ItemFacade item, Map itemMap) {
1343: List itemTextList = (List) itemMap.get("itemText");
1344: HashSet itemTextSet = new HashSet();
1345: for (int i = 0; i < itemTextList.size(); i++) {
1346: ItemText itemText = new ItemText();
1347: String text = (String) itemTextList.get(i);
1348: // should be allow this or, continue??
1349: // for now, empty string OK, setting to empty string if null
1350: if (text == null) {
1351: text = "";
1352: }
1353: text = text.replaceAll("\\?\\?", " ");//SAK-2298
1354: log.debug("text: " + text);
1355:
1356: itemText.setText(makeFCKAttachment(text));
1357: itemText.setItem(item.getData());
1358: itemText.setSequence(new Long(i + 1));
1359: List answerList = new ArrayList();
1360: List aList = (List) itemMap.get("itemAnswer");
1361: answerList = aList == null ? answerList : aList;
1362: HashSet answerSet = new HashSet();
1363: char answerLabel = 'A';
1364: List answerFeedbackList = (List) itemMap
1365: .get("itemAnswerFeedback");
1366:
1367: ArrayList correctLabels;
1368: correctLabels = (ArrayList) itemMap
1369: .get("itemAnswerCorrectLabel");
1370: if (correctLabels == null) {
1371: correctLabels = new ArrayList();
1372: }
1373: for (int a = 0; a < answerList.size(); a++) {
1374: Answer answer = new Answer();
1375: String answerText = (String) answerList.get(a);
1376: // these are not supposed to be empty
1377: if (notNullOrEmpty(answerText)) {
1378: answerText = answerText.replaceAll("\\?\\?", " ");//SAK-2298
1379: log.debug("answerText: " + answerText);
1380:
1381: // normalize all true/false questions
1382: if (answerList.size() == 2) {
1383: if (answerText.equalsIgnoreCase("true"))
1384: answerText = "true";
1385: if (answerText.equalsIgnoreCase("false"))
1386: answerText = "false";
1387: }
1388: String label = "" + answerLabel++;
1389: answer.setLabel(label); // up to 26, is this a problem?
1390:
1391: // correct answer and score
1392: float score = 0;
1393: // if label matches correct answer it is correct
1394: if (isCorrectLabel(label, correctLabels)) {
1395: answer.setIsCorrect(Boolean.TRUE);
1396: // manual authoring disregards correctness
1397: // commented out: what we'd have if we looked at correctness
1398: // score = getCorrectScore(item, 1);
1399: } else {
1400: answer.setIsCorrect(Boolean.FALSE);
1401: }
1402: // manual authoring disregards correctness
1403: // so we will do the same.
1404: score = getCorrectScore(item, 1);
1405: log.debug("setting answer" + label + " score to:"
1406: + score);
1407: answer.setScore(new Float(score));
1408:
1409: answer.setText(makeFCKAttachment(answerText));
1410: answer.setItemText(itemText);
1411: answer.setItem(item.getData());
1412: int sequence = a + 1;
1413: answer.setSequence(new Long(sequence));
1414: // prepare answer feedback - daisyf added this on 2/21/05
1415: // need to check if this works for question type other than
1416: // MC
1417: HashSet set = new HashSet();
1418: if (answerFeedbackList != null) {
1419: AnswerFeedback answerFeedback = new AnswerFeedback();
1420: answerFeedback.setAnswer(answer);
1421: answerFeedback
1422: .setTypeId(AnswerFeedbackIfc.GENERAL_FEEDBACK);
1423: if (answerFeedbackList.get(sequence - 1) != null) {
1424: answerFeedback
1425: .setText(makeFCKAttachment((String) answerFeedbackList
1426: .get(sequence - 1)));
1427: set.add(answerFeedback);
1428: answer.setAnswerFeedbackSet(set);
1429: }
1430: }
1431:
1432: answerSet.add(answer);
1433: }
1434: }
1435: itemText.setAnswerSet(answerSet);
1436: itemTextSet.add(itemText);
1437: }
1438: item.setItemTextSet(itemTextSet);
1439: }
1440:
1441: private float getCorrectScore(ItemDataIfc item, int answerSize) {
1442: float score = 0;
1443: if (answerSize > 0 && item != null && item.getScore() != null) {
1444: score = item.getScore().floatValue() / answerSize;
1445: }
1446: return score;
1447: }
1448:
1449: /**
1450: * Check to find out it response label is in the list of correct responses
1451: * @param testLabel response label
1452: * @param labels the list of correct responses
1453: * @return
1454: */
1455: private boolean isCorrectLabel(String testLabel, ArrayList labels) {
1456: if (testLabel == null || labels == null
1457: || labels.indexOf(testLabel) == -1) {
1458: return false;
1459: }
1460:
1461: return true;
1462: }
1463:
1464: /**
1465: * FIB questions ONLY
1466: * @param item
1467: * @param itemMap
1468: */
1469: private void addFibTextAndAnswers(ItemFacade item, Map itemMap) {
1470: List itemTextList = new ArrayList();
1471: List iList = (List) itemMap.get("itemFibText");
1472: itemTextList = iList == null ? itemTextList : iList;
1473:
1474: List itemTList = new ArrayList();
1475: List tList = (List) itemMap.get("itemText");
1476: itemTList = iList == null ? itemTList : tList;
1477:
1478: HashSet itemTextSet = new HashSet();
1479: ItemText itemText = new ItemText();
1480: String itemTextString = "";
1481: List answerFeedbackList = (List) itemMap.get("itemFeedback");
1482:
1483: List answerList = new ArrayList();
1484: List aList = (List) itemMap.get("itemFibAnswer");
1485: answerList = aList == null ? answerList : aList;
1486:
1487: // handle FIB with instructional text
1488: // sneak it into first text
1489: if (!itemTList.isEmpty() && !itemTextList.isEmpty()
1490: && !(itemTextList.size() > 1)) {
1491: try {
1492: String firstFib = (String) itemTextList.get(0);
1493: String firstText = (String) itemTList.get(0);
1494: if (firstFib.equals(firstText)) {
1495: log.debug("Setting FIB instructional text.");
1496: // itemTextList.remove(0);
1497: String newFirstFib = firstFib + "<br />"
1498: + itemTextList.get(0);
1499: itemTextList.set(0, newFirstFib);
1500: }
1501: } catch (Exception ex) {
1502: log
1503: .warn("Thought we found an instructional text but couldn't put it in."
1504: + " " + ex);
1505: }
1506: }
1507: // loop through all our extracted FIB texts interposing FIB_BLANK_INDICATOR
1508: for (int i = 0; i < itemTextList.size(); i++) {
1509: String text = (String) itemTextList.get(i);
1510: // we are assuming non-empty text/answer/non-empty text/answer etc.
1511: if (text == null || text == "") {
1512: continue;
1513: }
1514: itemTextString += text;
1515: if (i < answerList.size()) {
1516: itemTextString += FIB_BLANK_INDICATOR;
1517: }
1518: }
1519: itemTextString = itemTextString.replaceAll("\\?\\?", " ");//SAK-2298
1520: log.debug("itemTextString=" + itemTextString);
1521: itemText.setText(makeFCKAttachment(itemTextString));
1522: itemText.setItem(item.getData());
1523: itemText.setSequence(new Long(0));
1524: HashSet answerSet = new HashSet();
1525: char answerLabel = 'A';
1526: for (int a = 0; a < answerList.size(); a++) {
1527: Answer answer = new Answer();
1528: String answerText = (String) answerList.get(a);
1529: // these are not supposed to be empty
1530: if (notNullOrEmpty(answerText)) {
1531: answerText = answerText.replaceAll("\\?\\?", " ");//SAK-2298
1532: log.debug("answerText=" + answerText);
1533:
1534: String label = "" + answerLabel++;
1535: answer.setLabel(label); // up to 26, is this a problem?
1536: answer.setText(makeFCKAttachment(answerText));
1537: answer.setItemText(itemText);
1538:
1539: // correct answer and score
1540: answer.setIsCorrect(Boolean.TRUE);
1541: // manual authoring disregards the number of partial answers
1542: // so we will do the same.
1543: float score = getCorrectScore(item, 1);
1544: // float score = getCorrectScore(item, answerList.size());
1545:
1546: log.debug("setting answer " + label + " score to:"
1547: + score);
1548: answer.setScore(new Float(score));
1549:
1550: answer.setItem(item.getData());
1551: int sequence = a + 1;
1552: answer.setSequence(new Long(sequence));
1553: HashSet set = new HashSet();
1554: if (answerFeedbackList != null) {
1555: AnswerFeedback answerFeedback = new AnswerFeedback();
1556: answerFeedback.setAnswer(answer);
1557: answerFeedback
1558: .setTypeId(AnswerFeedbackIfc.GENERAL_FEEDBACK);
1559: if (answerFeedbackList.get(sequence - 1) != null) {
1560: answerFeedback
1561: .setText(makeFCKAttachment((String) answerFeedbackList
1562: .get(sequence - 1)));
1563: set.add(answerFeedback);
1564: answer.setAnswerFeedbackSet(set);
1565: }
1566: }
1567: answerSet.add(answer);
1568: }
1569: }
1570:
1571: itemText.setAnswerSet(answerSet);
1572: itemTextSet.add(itemText);
1573: item.setItemTextSet(itemTextSet);
1574: }
1575:
1576: /**
1577: * MATCHING questions ONLY
1578: * @param item
1579: * @param itemMap
1580: */
1581: private void addMatchTextAndAnswers(ItemFacade item, Map itemMap) {
1582:
1583: List sourceList = (List) itemMap.get("itemMatchSourceText");
1584: List targetList = (List) itemMap.get("itemMatchTargetText");
1585: List indexList = (List) itemMap.get("itemMatchIndex");
1586: List answerFeedbackList = (List) itemMap.get("itemFeedback");
1587: List correctMatchFeedbackList = (List) itemMap
1588: .get("itemMatchCorrectFeedback");
1589: List incorrectMatchFeedbackList = (List) itemMap
1590: .get("itemMatchIncorrectFeedback");
1591: List itemTextList = (List) itemMap.get("itemText");
1592:
1593: sourceList = sourceList == null ? new ArrayList() : sourceList;
1594: targetList = targetList == null ? new ArrayList() : targetList;
1595: indexList = indexList == null ? new ArrayList() : indexList;
1596: answerFeedbackList = answerFeedbackList == null ? new ArrayList()
1597: : answerFeedbackList;
1598: correctMatchFeedbackList = correctMatchFeedbackList == null ? new ArrayList()
1599: : correctMatchFeedbackList;
1600: incorrectMatchFeedbackList = incorrectMatchFeedbackList == null ? new ArrayList()
1601: : incorrectMatchFeedbackList;
1602:
1603: log.debug("*** original incorrect order");
1604: for (int i = 0; i < incorrectMatchFeedbackList.size(); i++) {
1605: log.debug("incorrectMatchFeedbackList.get(" + i + ")="
1606: + incorrectMatchFeedbackList.get(i));
1607: }
1608: int maxNumCorrectFeedback = sourceList.size();
1609: int numIncorrectFeedback = incorrectMatchFeedbackList.size();
1610:
1611: if (maxNumCorrectFeedback > 0 && numIncorrectFeedback > 0) {
1612: incorrectMatchFeedbackList = reassembleIncorrectMatches(
1613: incorrectMatchFeedbackList, maxNumCorrectFeedback);
1614: }
1615:
1616: log.debug("*** NEW order");
1617: for (int i = 0; i < incorrectMatchFeedbackList.size(); i++) {
1618: log.debug("incorrectMatchFeedbackList.get(" + i + ")="
1619: + incorrectMatchFeedbackList.get(i));
1620:
1621: }
1622:
1623: itemTextList = itemTextList == null ? new ArrayList()
1624: : itemTextList;
1625:
1626: if (targetList.size() < indexList.size()) {
1627: log.debug("targetList.size(): " + targetList.size());
1628: log.debug("indexList.size(): " + indexList.size());
1629: }
1630:
1631: String itemTextString = "";
1632: if (itemTextList.size() > 0) {
1633: itemTextString = (String) itemTextList.get(0);
1634: }
1635:
1636: HashSet itemTextSet = new HashSet();
1637:
1638: // first, add the question text
1639: if (itemTextString == null)
1640: itemTextString = "";
1641: itemTextString = itemTextString.replaceAll("\\?\\?", " ");//SAK-2298
1642: log.debug("item.setInstruction itemTextString: "
1643: + itemTextString);
1644: item.setInstruction(itemTextString);
1645:
1646: // loop through source texts indicating answers (targets)
1647: for (int i = 0; i < sourceList.size(); i++) {
1648: // create the entry for the matching item (source)
1649: String sourceText = (String) sourceList.get(i);
1650: if (sourceText == null)
1651: sourceText = "";
1652: sourceText = sourceText.replaceAll("\\?\\?", " ");//SAK-2298
1653: log.debug("sourceText: " + sourceText);
1654:
1655: ItemText sourceItemText = new ItemText();
1656: sourceItemText.setText(makeFCKAttachment(sourceText));
1657: sourceItemText.setItem(item.getData());
1658: sourceItemText.setSequence(new Long(i + 1));
1659:
1660: // find the matching answer (target)
1661: HashSet targetSet = new HashSet();
1662: String targetString;
1663: int targetIndex = 999;// obviously not matching value
1664: try {
1665: targetIndex = Integer.parseInt((String) indexList
1666: .get(i));
1667: } catch (NumberFormatException ex) {
1668: log.warn("No match for " + sourceText + "."); // default to no match
1669: } catch (IndexOutOfBoundsException ex) {
1670: log
1671: .error("Corrupt index list. Cannot assign match for: "
1672: + sourceText + ".");
1673: }
1674: // loop through all possible targets (matching answers)
1675: char answerLabel = 'A';
1676: for (int a = 0; a < targetList.size(); a++) {
1677: targetString = (String) targetList.get(a);
1678: if (targetString == null) {
1679: targetString = "";
1680: }
1681: targetString = targetString.replaceAll("\\?\\?", " ");//SAK-2298
1682: log.debug("targetString: " + targetString);
1683:
1684: Answer target = new Answer();
1685:
1686: //feedback
1687: HashSet answerFeedbackSet = new HashSet();
1688:
1689: if (correctMatchFeedbackList.size() > i) {
1690: String fb = (String) correctMatchFeedbackList
1691: .get(i);
1692: answerFeedbackSet.add(new AnswerFeedback(target,
1693: AnswerFeedbackIfc.CORRECT_FEEDBACK, fb));
1694: }
1695: if (incorrectMatchFeedbackList.size() > i) {
1696: String fb = (String) incorrectMatchFeedbackList
1697: .get(i);
1698: log.debug("setting incorrect fb=" + fb);
1699: answerFeedbackSet.add(new AnswerFeedback(target,
1700: AnswerFeedbackIfc.INCORRECT_FEEDBACK, fb));
1701: }
1702:
1703: target.setAnswerFeedbackSet(answerFeedbackSet);
1704:
1705: String label = "" + answerLabel++;
1706: target.setLabel(label); // up to 26, is this a problem?
1707: target.setText(makeFCKAttachment(targetString));
1708: target.setItemText(sourceItemText);
1709: target.setItem(item.getData());
1710: target.setSequence(new Long(a + 1));
1711:
1712: // correct answer and score
1713: // manual authoring disregards the number of partial answers
1714: // or whether the answer is correct so we will do the same.
1715: // float score = 0;
1716: float score = getCorrectScore(item, 1);
1717:
1718: // if this answer is the indexed one, flag as correct
1719: if (a + 1 == targetIndex) {
1720: target.setIsCorrect(Boolean.TRUE);
1721: // score = getCorrectScore(item, targetList.size());
1722: log.debug("source: " + sourceText
1723: + " matches target: " + targetString);
1724: } else {
1725: target.setIsCorrect(Boolean.FALSE);
1726: }
1727: log.debug("setting answer " + a + " score to:" + score);
1728: target.setScore(new Float(score));
1729:
1730: if (answerFeedbackList != null) {
1731: Set targetFeedbackSet = new HashSet();
1732: AnswerFeedback tAnswerFeedback = new AnswerFeedback();
1733: tAnswerFeedback.setAnswer(target);
1734: tAnswerFeedback
1735: .setTypeId(AnswerFeedbackIfc.GENERAL_FEEDBACK);
1736: String targetFeedback = "";
1737: if (answerFeedbackList.size() > 0) {
1738: targetFeedback = (String) answerFeedbackList
1739: .get(targetIndex);
1740: }
1741: if (targetFeedback.length() > 0) {
1742: tAnswerFeedback
1743: .setText(makeFCKAttachment(targetFeedback));
1744: targetFeedbackSet.add(tAnswerFeedback);
1745: target.setAnswerFeedbackSet(targetFeedbackSet);
1746: }
1747: }
1748: targetSet.add(target);
1749: }
1750:
1751: sourceItemText.setAnswerSet(targetSet);
1752: itemTextSet.add(sourceItemText);
1753: }
1754:
1755: item.setItemTextSet(itemTextSet);
1756: }
1757:
1758: /**
1759: * Helper method rotates the first n.
1760: * This will work with Samigo matching where
1761: * incorrect matches (n) = the square of the correct matches (n**2)
1762: * and the 0th displayfeedback is correct and the next n are incorrect
1763: * feedback. In export Samigo uses the incorrect feedback redundantly.
1764: *
1765: * For example, if there are 5 matches, there are 25 matches and mismatched,
1766: * 5 of which are correct and 20 of which are not, so there is redundancy in
1767: * Samigo.
1768: *
1769: * In non-Samigo matching, there may be more than one incorrect
1770: * feedback for a failed matching.
1771: *
1772: * @param list the list
1773: * @return a reassembled list of size n
1774: */
1775: private List reassembleIncorrectMatches(List list, int n) {
1776: // make sure we have a reasonable value
1777: if (n < 0)
1778: n = -n;
1779: if (n == 0)
1780: return list;
1781:
1782: // pad input list if too small or null
1783: if (list == null)
1784: list = new ArrayList();
1785: for (int i = 0; i < n && list.size() < n + 1; i++) {
1786: list.add("");
1787: }
1788:
1789: // our output value
1790: List newList = new ArrayList();
1791:
1792: // move the last of the n entries (0-index) up to the front
1793: newList.add(list.get(n - 1));
1794:
1795: // add the 2nd entry and so forth
1796: for (int i = 0; i < n - 1; i++) {
1797: String s = (String) list.get(i);
1798: newList.add(s);
1799: }
1800:
1801: return newList;
1802: }
1803:
1804: /**
1805: * helper method
1806: * @param s
1807: * @return
1808: */
1809: private boolean notNullOrEmpty(String s) {
1810: return s != null && s.trim().length() > 0 ? true : false;
1811: }
1812:
1813: /**
1814: * Append " - 2", " - 3", etc. incrementing as you go.
1815: * @param title the original
1816: * @return the title with versioning appended
1817: */
1818: public String renameDuplicate(String title) {
1819: if (title == null)
1820: title = "";
1821:
1822: String rename = "";
1823: int index = title.lastIndexOf(VERSION_START);
1824:
1825: if (index > -1)//if is versioned
1826: {
1827: String mainPart = "";
1828: String versionPart = title.substring(index);
1829: if (index > 0) {
1830: mainPart = title.substring(0, index);
1831: }
1832:
1833: int nindex = index + VERSION_START.length();
1834:
1835: String version = title.substring(nindex);
1836:
1837: int versionNumber = 0;
1838: try {
1839: versionNumber = Integer.parseInt(version);
1840: if (versionNumber < 2)
1841: versionNumber = 2;
1842: versionPart = VERSION_START + (versionNumber + 1);
1843:
1844: rename = mainPart + versionPart;
1845: } catch (NumberFormatException ex) {
1846: rename = title + VERSION_START + "2";
1847: }
1848: } else {
1849: rename = title + VERSION_START + "2";
1850: }
1851:
1852: return rename;
1853:
1854: }
1855:
1856: /**
1857: * Primarily for testing purposes.
1858: * @return an overridden path if not null
1859: */
1860: public String getOverridePath() {
1861: return overridePath;
1862: }
1863:
1864: /**
1865: * Primarily for testing purposes.
1866: * @param overridePath an overriding path
1867: */
1868: public void setOverridePath(String overridePath) {
1869: this .overridePath = overridePath;
1870: }
1871:
1872: public void setUnzipLocation(String unzipLocation) {
1873: this.unzipLocation = unzipLocation;
1874: }
1875: }
|