Skip to content
Snippets Groups Projects
Commit 89f99ac9 authored by srosse's avatar srosse
Browse files

OO-533: embbed QTI 1.2 editor in the question pool

parent 2930b4c3
No related branches found
No related tags found
No related merge requests found
Showing
with 725 additions and 571 deletions
......@@ -42,7 +42,7 @@ import org.olat.course.nodes.ProjectBrokerCourseNode;
import org.olat.course.nodes.TACourseNode;
import org.olat.course.nodes.ta.DropboxController;
import org.olat.course.nodes.ta.ReturnboxController;
import org.olat.ims.qti.editor.QTIEditorPackage;
import org.olat.ims.qti.editor.QTIEditorPackageImpl;
import org.olat.resource.OLATResource;
import org.olat.resource.OLATResourceManager;
import org.olat.user.UserDataDeletable;
......@@ -116,7 +116,7 @@ public class UserFileDeletionManager extends BasicManager implements UserDataDel
private void deleteAllTempQtiEditorFilesOf(Identity identity) {
// Temp QTI-editor File path e.g. /usr/local/olatfs/olat/olatdata/tmp/qtieditor/schuessler
File userTempQtiEditorDir = new File(QTIEditorPackage.getQTIEditorBaseDir(),identity.getName());
File userTempQtiEditorDir = new File(QTIEditorPackageImpl.getQTIEditorBaseDir(),identity.getName());
if (userTempQtiEditorDir.exists()) {
FileUtils.deleteDirsAndFiles(userTempQtiEditorDir, true, true);
logAudit("User-Deletion: identity=" + identity.getName() +" : QTI editor temp files deleted under dir=" + userTempQtiEditorDir.getAbsolutePath());
......
......@@ -31,8 +31,6 @@ import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.controllers.linkchooser.CustomLinkTreeModel;
import org.olat.core.commons.modules.bc.commands.CmdCreateFile;
......@@ -45,7 +43,6 @@ import org.olat.core.commons.modules.bc.commands.FolderCommand;
import org.olat.core.commons.modules.bc.commands.FolderCommandFactory;
import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
import org.olat.core.commons.modules.bc.components.FolderComponent;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.download.DisplayOrDownloadComponent;
......@@ -59,8 +56,6 @@ import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.context.BusinessControl;
import org.olat.core.id.context.BusinessControlFactory;
......@@ -79,10 +74,9 @@ import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.vfs.OlatRelPathImpl;
import org.olat.core.util.vfs.Quota;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSManager;
import org.olat.core.util.vfs.VFSMediaResource;
import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
import org.olat.core.util.vfs.filters.VFSItemFilter;
import org.olat.search.SearchServiceUIFactory;
......@@ -511,16 +505,7 @@ public class FolderRunController extends BasicController implements Activateable
// and can not reuse the standard briefcase way of file delivering, some
// very old fancy code
// Mapper is cleaned up automatically by basic controller
String baseUrl = registerMapper(ureq, new Mapper() {
public MediaResource handle(String relPath, HttpServletRequest request) {
VFSLeaf vfsfile = (VFSLeaf) folderComponent.getRootContainer().resolve(relPath);
if (vfsfile == null) {
return new NotFoundMediaResource(relPath);
} else {
return new VFSMediaResource(vfsfile);
}
}
});
String baseUrl = registerMapper(ureq, new VFSContainerMapper(folderComponent.getRootContainer()));
// Trigger auto-download
DisplayOrDownloadComponent dordc = new DisplayOrDownloadComponent("downloadcomp",baseUrl + path);
folderContainer.put("autoDownloadComp", dordc);
......
......@@ -58,6 +58,7 @@ import org.olat.core.logging.activity.CourseLoggingAction;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.Formatter;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSManager;
/**
......@@ -314,7 +315,7 @@ public class SinglePageController extends BasicController implements CloneableCo
final VFSContainer finalRootContainer = g_new_rootContainer;
if (amapPath == null) {
Mapper mapper = new SinglePageMediaMapper(finalRootContainer);
Mapper mapper = new VFSContainerMapper(finalRootContainer);
// Register mapper as cacheable
String mapperID = VFSManager.getRealPath(finalRootContainer);
if (mapperID == null) {
......
package org.olat.core.commons.modules.singlepage;
import javax.servlet.http.HttpServletRequest;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;
/**
*
* Initial date: 22.03.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class SinglePageMediaMapper implements Mapper {
private VFSContainer rootContainer;
public SinglePageMediaMapper() {
//for serialize/deserialize
}
public SinglePageMediaMapper(VFSContainer rootContainer) {
this.rootContainer = rootContainer;
}
public MediaResource handle(String relPath,HttpServletRequest request) {
VFSItem currentItem = rootContainer.resolve(relPath);
if (currentItem == null || (currentItem instanceof VFSContainer)) {
return new NotFoundMediaResource(relPath);
}
return new VFSMediaResource((VFSLeaf)currentItem);
}
}
......@@ -50,6 +50,7 @@ import org.olat.core.util.Util;
import org.olat.core.util.i18n.I18nManager;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSManager;
/**
......@@ -1353,7 +1354,7 @@ public class RichTextConfiguration implements Disposable {
public void setDocumentMediaBase(final VFSContainer documentBaseContainer, String relFilePath, UserSession usess) {
linkBrowserRelativeFilePath = relFilePath;
// get a usersession-local mapper for the file storage (and tinymce's references to images and such)
contentMapper = new RichTextMediaMapper(documentBaseContainer);
contentMapper = new VFSContainerMapper(documentBaseContainer);
// Register mapper for this user. This mapper is cleaned up in the
// dispose method (RichTextElementImpl will clean it up)
......
......@@ -21,22 +21,16 @@ package org.olat.core.gui.components.htmlheader.jscss;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.olat.core.CoreSpringFactory;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.dispatcher.mapper.MapperService;
import org.olat.core.gui.control.Disposable;
import org.olat.core.gui.control.JSAndCSSAdder;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.logging.LogDelegator;
import org.olat.core.util.UserSession;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSManager;
import org.olat.core.util.vfs.VFSMediaResource;
/**
* Description:<br>
......@@ -118,21 +112,8 @@ public class CustomCSS extends LogDelegator implements Disposable {
* @param cssBaseContainer
*/
private void createCSSUriMapper(final VFSContainer cssBaseContainer) {
cssUriMapper = new Mapper() {
public MediaResource handle(String relPath,
HttpServletRequest request) {
VFSItem vfsItem = cssBaseContainer.resolve(relPath);
MediaResource mr;
if (vfsItem == null || !(vfsItem instanceof VFSLeaf))
mr = new NotFoundMediaResource(relPath);
else
mr = new VFSMediaResource((VFSLeaf) vfsItem);
return mr;
}
};
cssUriMapper = new VFSContainerMapper(cssBaseContainer);
}
/**
* Get the js and css component that embedds the CSS file
......
......@@ -499,7 +499,7 @@ public class ServletUtil {
// buffer size: assume average length of a char in bytes is max 2
int encLen = result.length();
Reader reader = result.getReader();
response.setContentLength(encLen);
//response.setContentLength(encLen);
PrintWriter os = response.getWriter();
IOUtils.copy(reader, os);
......@@ -531,6 +531,7 @@ public class ServletUtil {
public static void setJSONResourceHeaders(HttpServletResponse response) {
// we ignore the accept-charset from the request and always write in utf-8
// -> see comment below
//response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
// never allow to cache pages since they contain a timestamp valid only once
// HTTP 1.1
......
......@@ -17,42 +17,41 @@
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.core.gui.components.form.flexible.impl.elements.richText;
package org.olat.core.util.vfs;
import javax.servlet.http.HttpServletRequest;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;
/**
* Simple mapper for a VFS container
*
* Initial date: 22.03.2013<br>
*
* Initial date: 12.04.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class RichTextMediaMapper implements Mapper {
private VFSContainer documentBaseContainer;
public class VFSContainerMapper implements Mapper {
private VFSContainer container;
public RichTextMediaMapper() {
//
public VFSContainerMapper() {
//serialization
}
public RichTextMediaMapper(VFSContainer documentBaseContainer) {
this.documentBaseContainer = documentBaseContainer;
public VFSContainerMapper(VFSContainer container) {
this.container = container;
}
public MediaResource handle(String relPath, HttpServletRequest request) {
VFSItem vfsItem = documentBaseContainer.resolve(relPath);
VFSItem vfsItem = container.resolve(relPath);
MediaResource mr;
if (vfsItem == null || !(vfsItem instanceof VFSLeaf)) mr = new NotFoundMediaResource(relPath);
else mr = new VFSMediaResource((VFSLeaf) vfsItem);
if (vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
mr = new NotFoundMediaResource(relPath);
} else {
mr = new VFSMediaResource((VFSLeaf) vfsItem);
}
return mr;
}
}
}
\ No newline at end of file
......@@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletRequest;
import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.download.DisplayOrDownloadComponent;
......@@ -55,6 +54,7 @@ import org.olat.core.id.UserConstants;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;
import org.olat.course.nodes.CourseNode;
......@@ -280,18 +280,9 @@ public class ProjectDetailsDisplayController extends BasicController {
// and can not reuse the standard briefcase way of file delivering, some
// very old fancy code
// Mapper is cleaned up automatically by basic controller
String baseUrl = registerMapper(ureq, new Mapper() {
public MediaResource handle(String relPath, HttpServletRequest request) {
OlatRootFolderImpl rootFolder = new OlatRootFolderImpl(ProjectBrokerManagerFactory.getProjectBrokerManager().getAttamchmentRelativeRootPath(project,courseEnv,cNode),null);
//ignore the relPath, we know it from the constructor of the DisplayOrDownloadComponent usin the mapper
VFSLeaf vfsfile = (VFSLeaf) rootFolder.resolve(project.getAttachmentFileName());
if (vfsfile == null) {
return new NotFoundMediaResource(relPath);
} else {
return new VFSMediaResource(vfsfile);
}
}
});
OlatRootFolderImpl rootFolder = new OlatRootFolderImpl(ProjectBrokerManagerFactory.getProjectBrokerManager().getAttamchmentRelativeRootPath(project,courseEnv,cNode),null);
String baseUrl = registerMapper(ureq, new VFSContainerMapper(rootFolder));
// Trigger auto-download
if(isLogDebugEnabled()) {
......
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.qti;
import java.io.InputStream;
import org.dom4j.Document;
import org.dom4j.Element;
import org.olat.core.CoreSpringFactory;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.tabbedpane.TabbedPane;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.xml.XMLParser;
import org.olat.ims.qti.editor.ItemNodeTabbedFormController;
import org.olat.ims.qti.editor.QTIEditorPackage;
import org.olat.ims.qti.editor.beecom.objects.Item;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.parser.ParserManager;
import org.olat.ims.qti.qpool.QTI12ItemEditorPackage;
import org.olat.ims.resources.IMSEntityResolver;
import org.olat.modules.qpool.QPoolService;
import org.olat.modules.qpool.QuestionItem;
/**
*
* Initial date: 21.02.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class QTI12EditorController extends BasicController {
private final TabbedPane mainPanel;
private final VelocityContainer mainVC;
private ItemNodeTabbedFormController previewCtrl;
private final QPoolService qpoolService;
public QTI12EditorController(UserRequest ureq, WindowControl wControl, QuestionItem qitem) {
super(ureq, wControl);
qpoolService = CoreSpringFactory.getImpl(QPoolService.class);
mainVC = createVelocityContainer("qti_preview");
mainPanel = new TabbedPane("tabbedPane", ureq.getLocale());
VFSLeaf leaf = qpoolService.getRootFile(qitem);
if(leaf == null) {
//no data to preview
} else {
Item item = readItemXml(leaf);
if(item != null) {
Translator translator = Util.createPackageTranslator(QTIEditorPackage.class, getLocale());
VFSContainer directory = qpoolService.getRootDirectory(qitem);
String mapperUrl = registerMapper(ureq, new VFSContainerMapper(directory));
QTIDocument doc = new QTIDocument();
QTIEditorPackage qtiPackage = new QTI12ItemEditorPackage(item, doc, mapperUrl, leaf, directory);
previewCtrl = new ItemNodeTabbedFormController(item, qtiPackage, ureq, getWindowControl(), translator, false);
previewCtrl.addTabs(mainPanel);
listenTo(previewCtrl);
}
}
mainVC.put("preview", mainPanel);
putInitialPanel(mainVC);
}
private Item readItemXml(VFSLeaf leaf) {
Document doc = null;
try {
InputStream is = leaf.getInputStream();
XMLParser xmlParser = new XMLParser(new IMSEntityResolver());
doc = xmlParser.parse(is, false);
Element item = (Element)doc.selectSingleNode("questestinterop/item");
ParserManager parser = new ParserManager();
Item qtiItem = (Item)parser.parse(item);
is.close();
return qtiItem;
} catch (Exception e) {
logError("", e);
return null;
}
}
@Override
protected void doDispose() {
//
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
//
}
}
......@@ -21,12 +21,9 @@ package org.olat.ims.qti;
import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.olat.core.CoreSpringFactory;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.panel.Panel;
......@@ -34,14 +31,11 @@ import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSContainerMapper;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;
import org.olat.core.util.xml.XMLParser;
import org.olat.ims.qti.editor.ItemPreviewController;
import org.olat.ims.qti.editor.QTIEditorPackage;
......@@ -80,7 +74,7 @@ public class QTI12PreviewController extends BasicController {
if(item != null) {
Translator translator = Util.createPackageTranslator(QTIEditorPackage.class, getLocale());
VFSContainer directory = qpoolService.getRootDirectory(qitem);
String mapperUrl = registerMapper(ureq, new QItemDirectoryMapper(directory));
String mapperUrl = registerMapper(ureq, new VFSContainerMapper(directory));
previewCtrl = new ItemPreviewController(wControl, item, mapperUrl, translator);
listenTo(previewCtrl);
mainPanel.setContent(previewCtrl.getInitialComponent());
......@@ -123,23 +117,4 @@ public class QTI12PreviewController extends BasicController {
protected void event(UserRequest ureq, Component source, Event event) {
//
}
private class QItemDirectoryMapper implements Mapper {
private final VFSContainer itemBaseContainer;
private QItemDirectoryMapper(VFSContainer container) {
itemBaseContainer = container;
}
public MediaResource handle(String relPath, HttpServletRequest request) {
VFSItem vfsItem = itemBaseContainer.resolve(relPath);
MediaResource mr;
if (vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
mr = new NotFoundMediaResource(relPath);
} else {
mr = new VFSMediaResource((VFSLeaf) vfsItem);
}
return mr;
}
}
}
......@@ -64,7 +64,7 @@ public class AddNewQTIDocumentController extends DefaultController implements IA
private FileResource resource;
private Locale locale;
private Translator translator;
QTIEditorPackage tmpPackage;
private QTIEditorPackageImpl tmpPackage;
/**
* @param type
......@@ -102,7 +102,7 @@ public class AddNewQTIDocumentController extends DefaultController implements IA
*/
public boolean transactionFinishBeforeCreate() {
File fTempQTI = new File(WebappHelper.getTmpDir(), CodeHelper.getUniqueID() + ".zip");
tmpPackage = new QTIEditorPackage(DUMMY_TITLE, type, locale);
tmpPackage = new QTIEditorPackageImpl(DUMMY_TITLE, type, locale);
// we need to save the package in order to be able to create a file resource entry.
// package will be created again after changing title.
if (!tmpPackage.savePackageTo(fTempQTI)) return false;
......
......@@ -87,7 +87,6 @@ import org.olat.ims.qti.QTIResult;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion;
import org.olat.ims.qti.editor.beecom.objects.Item;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.objects.QTIObject;
import org.olat.ims.qti.editor.beecom.objects.Question;
import org.olat.ims.qti.editor.beecom.objects.Response;
......@@ -189,15 +188,14 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
//
//public static final ReentrantReadWriteLock IS_SAVING_RWL = new ReentrantReadWriteLock();
private QTIEditorPackage qtiPackage;
private QTIEditorPackageImpl qtiPackage;
private VelocityContainer main, exitVC, chngMsgFormVC, restrictedEditWarningVC;
private ToolController mainToolC;
private MenuTree menuTree;
private Panel mainPanel, wrapperPanel;
private Panel mainPanel;
private LayoutMain3ColsController columnLayoutCtr;
private QTIDocument qtiDoc;
private QTIEditorTreeModel menuTreeModel;
private DialogBoxController deleteDialog;
private DialogBoxController deleteMediaDialog;
......@@ -206,7 +204,6 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
private InsertItemTreeModel insertTreeModel;
private GenericQtiNode insertObject;
private LockResult lockEntry;
private Controller failedMonolog, lockMonolog;
private boolean restrictedEdit;
private Map history = null;
private String startedWithTitle;
......@@ -243,7 +240,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
}
this.referencees = referencees;
qtiPackage = new QTIEditorPackage(ureq.getIdentity(), fileResource, getTranslator());
qtiPackage = new QTIEditorPackageImpl(ureq.getIdentity(), fileResource, getTranslator());
// try to get lock which lives longer then the browser session in case of a closing browser window
lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().aquirePersistentLock(qtiPackage.getRepresentingResourceable(), ureq.getIdentity(), null);
......@@ -252,8 +249,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
//fileResource has the RepositoryEntre.getOlatResource within, which is used in qtiPackage
activeSessionLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(qtiPackage.getRepresentingResourceable(), ureq.getIdentity(), null);
//
qtiDoc = qtiPackage.getQTIDocument();
if (qtiDoc == null) {
if (qtiPackage.getQTIDocument() == null) {
notEditable = true;
} else if (qtiPackage.isResumed()) {
showInfo("info.resumed", null);
......@@ -297,7 +293,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
Panel panel = new Panel("notEditable");
panel.setContent(notEditable);
columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, null, panel, null);
wrapperPanel = putInitialPanel(columnLayoutCtr.getInitialComponent());
putInitialPanel(columnLayoutCtr.getInitialComponent());
return;
}
......@@ -351,7 +347,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
} else {
columnLayoutCtr.addCssClassToMain("o_editor_qti");
}
wrapperPanel = putInitialPanel(columnLayoutCtr.getInitialComponent());
putInitialPanel(columnLayoutCtr.getInitialComponent());
if (restrictedEdit) {
restrictedEditWarningVC = createVelocityContainer("restrictedEditDialog");
......@@ -928,7 +924,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
RepositoryEntry entry = rm.lookupRepositoryEntry(course, false);
String courseTitle = course.getCourseTitle();
SecurityGroup owners = entry.getOwnerGroup();
List stakeHoldersIds = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(owners);
List<Identity> stakeHoldersIds = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(owners);
// add stakeholders as group
cl = new ContactList(courseTitle);
......
/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.qti.editor;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.olat.core.commons.modules.bc.FolderConfig;
import org.olat.core.gui.translator.PackageTranslator;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.FileUtils;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.ZipUtil;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.NamedContainerImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.xml.XMLParser;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.fileresource.FileResourceManager;
import org.olat.fileresource.types.FileResource;
import org.olat.ims.qti.QTIChangeLogMessage;
import org.olat.ims.qti.editor.beecom.objects.Assessment;
import org.olat.ims.qti.editor.beecom.objects.Metadata;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.objects.Section;
import org.olat.ims.qti.editor.beecom.parser.ParserManager;
import org.olat.ims.qti.process.AssessmentInstance;
import org.olat.ims.qti.process.ImsRepositoryResolver;
import org.olat.ims.resources.IMSEntityResolver;
/**
*Initial Date: 27.08.2003
* @author Mike Stock
*
* Initial date: 12.04.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class QTIEditorPackage {
public static final String FOLDERNAMEFOR_CHANGELOG = "changelog";
/*
* Files are store in tmp directory as
* tmp/qtieditor/{login}/{repositoryEntryID}/ extracted from the repositoryEntry
*/
private static final String SERIALIZED_QTI_DOCUMENT = "__qti.xstream.xml";
private static final String CURRENT_HISTORY ="__qti.history.xml";
private Identity identity = null;
private FileResource fileResource = null;
private String packageSubDir = null;
private File packageDir = null;
private QTIDocument qtiDocument = null;
private boolean resumed = false;
private static OutputFormat outformat;
private OLog log = Tracing.createLoggerFor(this.getClass());
private Translator translator;
static {
outformat = OutputFormat.createPrettyPrint();
outformat.setEncoding("UTF-8");
}
/**
* @param identity
* @param fileResource
*/
public QTIEditorPackage(Identity identity, FileResource fileResource, Translator translator) {
this.identity = identity;
this.fileResource = fileResource;
this.translator = translator;
init();
}
/**
* Create a new qtipackage.
* @param title
* @param type
* @param locale
*/
public QTIEditorPackage(String title, String type, Locale locale) {
// create new qti document
translator = new PackageTranslator("org.olat.ims.qti", locale);
qtiDocument = new QTIDocument();
Assessment assessment = QTIEditHelper.createAssessment(title, type);
qtiDocument.setAssessment(assessment);
Section section = QTIEditHelper.createSection(translator);
List sectionList = new ArrayList();
sectionList.add(section);
assessment.setSections(sectionList);
List itemList = new ArrayList();
itemList.add(QTIEditHelper.createSCItem(translator));
section.setItems(itemList);
// initialize package
packageSubDir = CodeHelper.getGlobalForeverUniqueID();
packageDir = new File(getQTIEditorBaseDir(), packageSubDir);
packageDir.mkdirs();
getMediaBaseDir().mkdirs();
getChangelogBaseDir().mkdirs();
}
private QTIEditorPackage() {
//
}
/**
* Return the underlying resourceable.
* @return OLATResourceable
*/
public OLATResourceable getRepresentingResourceable() {
return fileResource;
}
private void init() {
packageSubDir = getPackageSubDir(identity, fileResource);
packageDir = new File(getQTIEditorBaseDir(), packageSubDir);
packageDir.mkdirs();
getMediaBaseDir().mkdirs();
getChangelogBaseDir().mkdirs();
}
/**
* Returns the sub directory within the base temp directory for this package.
* @param i
* @param fr
* @return Sub directory relative to temporary base directory.
*/
private String getPackageSubDir(Identity i, FileResource fr) {
return i.getName() + "/" + fr.getResourceableId();
}
/**
* Get the temporary root dir where all packages are located.
* @return The editor's package temp base directory.
*/
public static File getQTIEditorBaseDir() {
return new File(WebappHelper.getUserDataRoot() + "/qtieditor/");
}
/**
* Return the media base URL for delivering media of this package.
* @return Complete media base URL.
*/
public String getMediaBaseURL() {
return WebappHelper.getServletContextPath() + "/secstatic/qtieditor/" + packageSubDir;
}
/**
* Returns the package's media directory.
* @return the media directory
*/
public File getMediaBaseDir() {
return new File(packageDir, "/media");
}
public interface QTIEditorPackage {
public VFSContainer getBaseDir() {
NamedContainerImpl namedBaseDir = new NamedContainerImpl(translator.translate("qti.basedir.displayname"), new LocalFolderImpl(packageDir));
return namedBaseDir;
}
public VFSContainer getBaseDir();
/**
* Returns the package's change log directory
* @return change log directory
*/
public File getChangelogBaseDir(){
return new File(packageDir,"/"+FOLDERNAMEFOR_CHANGELOG);
}
/**
* Unzip package into temporary directory.
* @return true if successfull, false otherwise
*/
private boolean unzipPackage() {
FileResourceManager frm = FileResourceManager.getInstance();
File fPackageZIP = frm.getFileResource(fileResource);
return ZipUtil.unzip(fPackageZIP, packageDir);
}
public String getMediaBaseURL();
/**
* @return Reutrns the QTIDocument structure
*/
public QTIDocument getQTIDocument() {
if (qtiDocument == null) {
if (hasSerializedQTIDocument()) {
qtiDocument = loadSerializedQTIDocument();
resumed = true;
} else {
unzipPackage();
Document doc = loadQTIDocument();
if(doc!=null) {
ParserManager parser = new ParserManager();
qtiDocument = (QTIDocument)parser.parse(doc);
// grab assessment type
Metadata meta = qtiDocument.getAssessment().getMetadata();
String assessType = meta.getField(AssessmentInstance.QMD_LABEL_TYPE);
if (assessType != null) {
qtiDocument.setSurvey(assessType.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY));
}
resumed = false;
} else {
qtiDocument = null;
}
}
}
return qtiDocument;
}
/**
* @return True upon success, false otherwise.
*/
public boolean savePackageToRepository() {
FileResourceManager frm = FileResourceManager.getInstance();
File tmpZipFile = new File(WebappHelper.getTmpDir(), CodeHelper.getUniqueID() + ".zip");
// first save complete ZIP package to repository
if (!savePackageTo(tmpZipFile)) return false;
// move file from temp to repository root and rename
File fRepositoryZip = frm.getFileResource(fileResource);
if (!FileUtils.moveFileToDir(tmpZipFile, frm.getFileResourceRoot(fileResource))) {
tmpZipFile.delete();
return false;
}
fRepositoryZip.delete();
new File(frm.getFileResourceRoot(fileResource), tmpZipFile.getName()).renameTo(fRepositoryZip);
// delete old unzip content. If the repository entry gets called in the meantime,
// the package will get unzipped again.
tmpZipFile.delete();
frm.deleteUnzipContent(fileResource);
// to be prepared for the next start, unzip right now.
return (frm.unzipFileResource(fileResource) != null);
}
/**
* save the change log in the changelog folder, must be called before savePackageToRepository.
* @param changelog
*/
public void commitChangelog(QTIChangeLogMessage clm) {
Date tmp = new Date(clm.getTimestmp());
java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ss");
String filname = formatter.format(tmp);
filname += clm.isPublic() ? ".all" : ".group";
filname+=".txt";
File changelogFile = new File(getChangelogBaseDir(),filname);
FileUtils.save(changelogFile,clm.getLogMessage(),"utf-8");
}
/**
* Package the package to the given file.
* @param fOut
* @return True upon success.
*/
public boolean savePackageTo(File fOut) {
saveQTIDocument(qtiDocument.getDocument());
Set files = new HashSet(3);
files.add(ImsRepositoryResolver.QTI_FILE);
files.add("media");
files.add("changelog");
return ZipUtil.zip(files, packageDir, fOut, false);
}
/**
* Remove the media files specified in the input set (removable contains filenames)
* @param removable
*/
public void removeMediaFiles(Set<String> removable) {
LocalFolderImpl mediaFolder = new LocalFolderImpl(new File(packageDir,"media"));
List<VFSItem> allMedia = mediaFolder.getItems();
QTIEditHelper.removeUnusedMedia(removable, allMedia);
}
/**
* Saves a serialized versionof the underlying QTIDocument.
*
*/
public void serializeQTIDocument() {
XStreamHelper.writeObject(new File(packageDir, SERIALIZED_QTI_DOCUMENT), qtiDocument);
}
private boolean hasSerializedQTIDocument() {
return new File(packageDir, SERIALIZED_QTI_DOCUMENT).exists();
}
private QTIDocument loadSerializedQTIDocument() {
return (QTIDocument)XStreamHelper.readObject(new File(packageDir, SERIALIZED_QTI_DOCUMENT));
}
public QTIDocument getQTIDocument();
/**
* save a temporary file with the change history
* @param history
*/
public void serializeChangelog(Map history){
XStreamHelper.writeObject(new File(packageDir, CURRENT_HISTORY), history);
}
/**
* check if a serialized change log exists
* @return
*/
public boolean hasSerializedChangelog(){
return new File(packageDir, CURRENT_HISTORY).exists();
}
/**
* resume the change log from the temporary file
* @return
*/
public Map loadChangelog(){
return (Map)XStreamHelper.readObject(new File(packageDir, CURRENT_HISTORY));
}
/**
* Load a document from file.
*
* @return the loaded document or null if loading failed
*/
private Document loadQTIDocument() {
File fIn = null;
FileInputStream in = null;
BufferedInputStream bis = null;
Document doc = null;
try {
fIn = new File(packageDir, ImsRepositoryResolver.QTI_FILE);
in = new FileInputStream(fIn);
bis = new BufferedInputStream(in);
XMLParser xmlParser = new XMLParser(new IMSEntityResolver());
doc = xmlParser.parse(bis, true);
} catch (Exception e) {
log.warn("Exception when parsing input QTI input stream for " + fIn != null ? fIn.getAbsolutePath() : "qti.xml", e);
return null;
} finally {
try {
if (in != null) in.close();
if (bis != null) bis.close();
} catch (Exception e) {
throw new OLATRuntimeException(this.getClass(), "Could not close input file stream ", e);
}
}
return doc;
}
/**
* SaveQTIDocument in temporary folder.
*
* @param doc
* @return true: save was successful, false otherwhise
*/
private boolean saveQTIDocument(Document doc) {
File fOut = null;
OutputStream out = null;
try {
fOut = new File(packageDir, ImsRepositoryResolver.QTI_FILE);
out = new FileOutputStream(fOut);
XMLWriter writer = new XMLWriter(out, outformat);
writer.write(doc);
writer.close();
} catch (Exception e) {
throw new OLATRuntimeException(this.getClass(), "Exception when saving QTI document to " + fOut != null ? fOut.getAbsolutePath() : "qti.xml", e);
} finally {
if (out != null) try {
out.close();
} catch (IOException e1) {
throw new OLATRuntimeException(this.getClass(), "Could not close output file stream ", e1);
}
}
return true;
}
/**
* Cleanup any temporary directory for this qti file only.
*/
public void cleanupTmpPackageDir() {
FileUtils.deleteDirsAndFiles(packageDir, true, true);
}
/**
* @return True if package has been resumed.
*/
public boolean isResumed() {
return resumed;
}
/**
* @param b
*/
public void setResumed(boolean b) {
resumed = b;
}
public void serializeQTIDocument();
}
\ No newline at end of file
/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
package org.olat.ims.qti.editor;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.olat.core.gui.translator.PackageTranslator;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.FileUtils;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.ZipUtil;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.NamedContainerImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.xml.XMLParser;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.fileresource.FileResourceManager;
import org.olat.fileresource.types.FileResource;
import org.olat.ims.qti.QTIChangeLogMessage;
import org.olat.ims.qti.editor.beecom.objects.Assessment;
import org.olat.ims.qti.editor.beecom.objects.Metadata;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.objects.Section;
import org.olat.ims.qti.editor.beecom.parser.ParserManager;
import org.olat.ims.qti.process.AssessmentInstance;
import org.olat.ims.qti.process.ImsRepositoryResolver;
import org.olat.ims.resources.IMSEntityResolver;
/**
*Initial Date: 27.08.2003
* @author Mike Stock
*/
public class QTIEditorPackageImpl implements QTIEditorPackage {
public static final String FOLDERNAMEFOR_CHANGELOG = "changelog";
/*
* Files are store in tmp directory as
* tmp/qtieditor/{login}/{repositoryEntryID}/ extracted from the repositoryEntry
*/
private static final String SERIALIZED_QTI_DOCUMENT = "__qti.xstream.xml";
private static final String CURRENT_HISTORY ="__qti.history.xml";
private Identity identity = null;
private FileResource fileResource = null;
private String packageSubDir = null;
private File packageDir = null;
private QTIDocument qtiDocument = null;
private boolean resumed = false;
private static OutputFormat outformat;
private OLog log = Tracing.createLoggerFor(this.getClass());
private Translator translator;
static {
outformat = OutputFormat.createPrettyPrint();
outformat.setEncoding("UTF-8");
}
/**
* @param identity
* @param fileResource
*/
public QTIEditorPackageImpl(Identity identity, FileResource fileResource, Translator translator) {
this.identity = identity;
this.fileResource = fileResource;
this.translator = translator;
init();
}
/**
* Create a new qtipackage.
* @param title
* @param type
* @param locale
*/
public QTIEditorPackageImpl(String title, String type, Locale locale) {
// create new qti document
translator = new PackageTranslator("org.olat.ims.qti", locale);
qtiDocument = new QTIDocument();
Assessment assessment = QTIEditHelper.createAssessment(title, type);
qtiDocument.setAssessment(assessment);
Section section = QTIEditHelper.createSection(translator);
List sectionList = new ArrayList();
sectionList.add(section);
assessment.setSections(sectionList);
List itemList = new ArrayList();
itemList.add(QTIEditHelper.createSCItem(translator));
section.setItems(itemList);
// initialize package
packageSubDir = CodeHelper.getGlobalForeverUniqueID();
packageDir = new File(getQTIEditorBaseDir(), packageSubDir);
packageDir.mkdirs();
getMediaBaseDir().mkdirs();
getChangelogBaseDir().mkdirs();
}
private QTIEditorPackageImpl() {
//
}
/**
* Return the underlying resourceable.
* @return OLATResourceable
*/
public OLATResourceable getRepresentingResourceable() {
return fileResource;
}
private void init() {
packageSubDir = getPackageSubDir(identity, fileResource);
packageDir = new File(getQTIEditorBaseDir(), packageSubDir);
packageDir.mkdirs();
getMediaBaseDir().mkdirs();
getChangelogBaseDir().mkdirs();
}
/**
* Returns the sub directory within the base temp directory for this package.
* @param i
* @param fr
* @return Sub directory relative to temporary base directory.
*/
private String getPackageSubDir(Identity i, FileResource fr) {
return i.getName() + "/" + fr.getResourceableId();
}
/**
* Get the temporary root dir where all packages are located.
* @return The editor's package temp base directory.
*/
public static File getQTIEditorBaseDir() {
return new File(WebappHelper.getUserDataRoot() + "/qtieditor/");
}
/**
* Return the media base URL for delivering media of this package.
* @return Complete media base URL.
*/
public String getMediaBaseURL() {
return WebappHelper.getServletContextPath() + "/secstatic/qtieditor/" + packageSubDir;
}
/**
* Returns the package's media directory.
* @return the media directory
*/
public File getMediaBaseDir() {
return new File(packageDir, "/media");
}
public VFSContainer getBaseDir() {
NamedContainerImpl namedBaseDir = new NamedContainerImpl(translator.translate("qti.basedir.displayname"), new LocalFolderImpl(packageDir));
return namedBaseDir;
}
/**
* Returns the package's change log directory
* @return change log directory
*/
public File getChangelogBaseDir(){
return new File(packageDir,"/"+FOLDERNAMEFOR_CHANGELOG);
}
/**
* Unzip package into temporary directory.
* @return true if successfull, false otherwise
*/
private boolean unzipPackage() {
FileResourceManager frm = FileResourceManager.getInstance();
File fPackageZIP = frm.getFileResource(fileResource);
return ZipUtil.unzip(fPackageZIP, packageDir);
}
/**
* @return Reutrns the QTIDocument structure
*/
public QTIDocument getQTIDocument() {
if (qtiDocument == null) {
if (hasSerializedQTIDocument()) {
qtiDocument = loadSerializedQTIDocument();
resumed = true;
} else {
unzipPackage();
Document doc = loadQTIDocument();
if(doc!=null) {
ParserManager parser = new ParserManager();
qtiDocument = (QTIDocument)parser.parse(doc);
// grab assessment type
Metadata meta = qtiDocument.getAssessment().getMetadata();
String assessType = meta.getField(AssessmentInstance.QMD_LABEL_TYPE);
if (assessType != null) {
qtiDocument.setSurvey(assessType.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY));
}
resumed = false;
} else {
qtiDocument = null;
}
}
}
return qtiDocument;
}
/**
* @return True upon success, false otherwise.
*/
public boolean savePackageToRepository() {
FileResourceManager frm = FileResourceManager.getInstance();
File tmpZipFile = new File(WebappHelper.getTmpDir(), CodeHelper.getUniqueID() + ".zip");
// first save complete ZIP package to repository
if (!savePackageTo(tmpZipFile)) return false;
// move file from temp to repository root and rename
File fRepositoryZip = frm.getFileResource(fileResource);
if (!FileUtils.moveFileToDir(tmpZipFile, frm.getFileResourceRoot(fileResource))) {
tmpZipFile.delete();
return false;
}
fRepositoryZip.delete();
new File(frm.getFileResourceRoot(fileResource), tmpZipFile.getName()).renameTo(fRepositoryZip);
// delete old unzip content. If the repository entry gets called in the meantime,
// the package will get unzipped again.
tmpZipFile.delete();
frm.deleteUnzipContent(fileResource);
// to be prepared for the next start, unzip right now.
return (frm.unzipFileResource(fileResource) != null);
}
/**
* save the change log in the changelog folder, must be called before savePackageToRepository.
* @param changelog
*/
public void commitChangelog(QTIChangeLogMessage clm) {
Date tmp = new Date(clm.getTimestmp());
java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ss");
String filname = formatter.format(tmp);
filname += clm.isPublic() ? ".all" : ".group";
filname+=".txt";
File changelogFile = new File(getChangelogBaseDir(),filname);
FileUtils.save(changelogFile,clm.getLogMessage(),"utf-8");
}
/**
* Package the package to the given file.
* @param fOut
* @return True upon success.
*/
public boolean savePackageTo(File fOut) {
saveQTIDocument(qtiDocument.getDocument());
Set files = new HashSet(3);
files.add(ImsRepositoryResolver.QTI_FILE);
files.add("media");
files.add("changelog");
return ZipUtil.zip(files, packageDir, fOut, false);
}
/**
* Remove the media files specified in the input set (removable contains filenames)
* @param removable
*/
public void removeMediaFiles(Set<String> removable) {
LocalFolderImpl mediaFolder = new LocalFolderImpl(new File(packageDir,"media"));
List<VFSItem> allMedia = mediaFolder.getItems();
QTIEditHelper.removeUnusedMedia(removable, allMedia);
}
/**
* Saves a serialized versionof the underlying QTIDocument.
*
*/
public void serializeQTIDocument() {
XStreamHelper.writeObject(new File(packageDir, SERIALIZED_QTI_DOCUMENT), qtiDocument);
}
private boolean hasSerializedQTIDocument() {
return new File(packageDir, SERIALIZED_QTI_DOCUMENT).exists();
}
private QTIDocument loadSerializedQTIDocument() {
return (QTIDocument)XStreamHelper.readObject(new File(packageDir, SERIALIZED_QTI_DOCUMENT));
}
/**
* save a temporary file with the change history
* @param history
*/
public void serializeChangelog(Map history){
XStreamHelper.writeObject(new File(packageDir, CURRENT_HISTORY), history);
}
/**
* check if a serialized change log exists
* @return
*/
public boolean hasSerializedChangelog(){
return new File(packageDir, CURRENT_HISTORY).exists();
}
/**
* resume the change log from the temporary file
* @return
*/
public Map loadChangelog(){
return (Map)XStreamHelper.readObject(new File(packageDir, CURRENT_HISTORY));
}
/**
* Load a document from file.
*
* @return the loaded document or null if loading failed
*/
private Document loadQTIDocument() {
File fIn = null;
FileInputStream in = null;
BufferedInputStream bis = null;
Document doc = null;
try {
fIn = new File(packageDir, ImsRepositoryResolver.QTI_FILE);
in = new FileInputStream(fIn);
bis = new BufferedInputStream(in);
XMLParser xmlParser = new XMLParser(new IMSEntityResolver());
doc = xmlParser.parse(bis, true);
} catch (Exception e) {
log.warn("Exception when parsing input QTI input stream for " + fIn != null ? fIn.getAbsolutePath() : "qti.xml", e);
return null;
} finally {
try {
if (in != null) in.close();
if (bis != null) bis.close();
} catch (Exception e) {
throw new OLATRuntimeException(this.getClass(), "Could not close input file stream ", e);
}
}
return doc;
}
/**
* SaveQTIDocument in temporary folder.
*
* @param doc
* @return true: save was successful, false otherwhise
*/
private boolean saveQTIDocument(Document doc) {
File fOut = null;
OutputStream out = null;
try {
fOut = new File(packageDir, ImsRepositoryResolver.QTI_FILE);
out = new FileOutputStream(fOut);
XMLWriter writer = new XMLWriter(out, outformat);
writer.write(doc);
writer.close();
} catch (Exception e) {
throw new OLATRuntimeException(this.getClass(), "Exception when saving QTI document to " + fOut != null ? fOut.getAbsolutePath() : "qti.xml", e);
} finally {
if (out != null) try {
out.close();
} catch (IOException e1) {
throw new OLATRuntimeException(this.getClass(), "Could not close output file stream ", e1);
}
}
return true;
}
/**
* Cleanup any temporary directory for this qti file only.
*/
public void cleanupTmpPackageDir() {
FileUtils.deleteDirsAndFiles(packageDir, true, true);
}
/**
* @return True if package has been resumed.
*/
public boolean isResumed() {
return resumed;
}
/**
* @param b
*/
public void setResumed(boolean b) {
resumed = b;
}
}
\ No newline at end of file
......@@ -61,7 +61,7 @@ public class QTIEditorStaticsHandler implements PathHandler {
*/
public InputStream getInputStream(HttpServletRequest request, ResourceDescriptor rd) {
try {
File f = new File(QTIEditorPackage.getQTIEditorBaseDir() + rd.getRelPath());
File f = new File(QTIEditorPackageImpl.getQTIEditorBaseDir() + rd.getRelPath());
return new BufferedInputStream(new FileInputStream(f));
} catch (Exception e) {
return null;
......@@ -74,7 +74,7 @@ public class QTIEditorStaticsHandler implements PathHandler {
public ResourceDescriptor getResourceDescriptor(HttpServletRequest request, String relPath) {
try {
ResourceDescriptor rd = new ResourceDescriptor(relPath);
File f = new File(QTIEditorPackage.getQTIEditorBaseDir() + relPath);
File f = new File(QTIEditorPackageImpl.getQTIEditorBaseDir() + relPath);
rd.setLastModified(f.lastModified());
rd.setSize(f.length());
String mimeType = WebappHelper.getMimeType(relPath);
......
......@@ -43,8 +43,8 @@ public class QTIDocument {
private Assessment assessment = null; // occurs 0 or 1 time
private boolean survey = false;
private static String DOCUMENT_ROOT = "questestinterop";
private static String DOCUMENT_DTD = "ims_qtiasiv1p2p1.dtd";
public static String DOCUMENT_ROOT = "questestinterop";
public static String DOCUMENT_DTD = "ims_qtiasiv1p2p1.dtd";
/**
* Get the structure as an XML Document.
......
......@@ -17,43 +17,85 @@
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.wiki.gui.components.wikiToHtml;
package org.olat.ims.qti.qpool;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;
import org.olat.ims.qti.QTIConstants;
import org.olat.ims.qti.editor.QTIEditorPackage;
import org.olat.ims.qti.editor.beecom.objects.Item;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
/**
*
* Initial date: 22.03.2013<br>
* Initial date: 12.04.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class WikiImageMapper implements Mapper {
private static final long serialVersionUID = 7196247178430531780L;
private VFSContainer wikiContainer;
public class QTI12ItemEditorPackage implements QTIEditorPackage {
private static final OLog log = Tracing.createLoggerFor(QTI12ItemEditorPackage.class);
private Item item;
private VFSLeaf itemLeaf;
private final String mediaUrl;
private final QTIDocument document;
private final VFSContainer directory;
public WikiImageMapper() {
//for serialize/deserialize
private static OutputFormat outformat;
static {
outformat = OutputFormat.createPrettyPrint();
outformat.setEncoding("UTF-8");
}
public WikiImageMapper(VFSContainer wikiContainer) {
this.wikiContainer = wikiContainer;
public QTI12ItemEditorPackage(Item item, QTIDocument document, String mediaUrl, VFSLeaf itemLeaf, VFSContainer directory) {
this.item = item;
this.document = document;
this.directory = directory;
this.mediaUrl = mediaUrl;
this.itemLeaf = itemLeaf;
}
@Override
public VFSContainer getBaseDir() {
return directory;
}
@Override
public String getMediaBaseURL() {
return mediaUrl;
}
@Override
public QTIDocument getQTIDocument() {
return document;
}
@Override
public MediaResource handle(String relPath, HttpServletRequest request) {
VFSItem vfsItem = wikiContainer.resolve(relPath);
MediaResource mr;
if (vfsItem == null || !(vfsItem instanceof VFSLeaf)) mr = new NotFoundMediaResource(relPath);
else mr = new VFSMediaResource((VFSLeaf) vfsItem);
return mr;
public void serializeQTIDocument() {
try {
OutputStream out = itemLeaf.getOutputStream(false);
XMLWriter writer = new XMLWriter(out, outformat);
DocumentFactory df = DocumentFactory.getInstance();
Document doc = df.createDocument();
doc.addDocType(QTIConstants.XML_DOCUMENT_ROOT, null, QTIConstants.XML_DOCUMENT_DTD);
Element questestinteropEl = df.createElement(QTIDocument.DOCUMENT_ROOT);
doc.setRootElement(questestinteropEl);
item.addToElement(questestinteropEl);
writer.write(doc);
writer.close();
} catch (IOException e) {
log.error("", e);
}
}
}
......@@ -51,6 +51,7 @@ import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.xml.XMLParser;
import org.olat.ims.qti.QTIConstants;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.parser.ItemParser;
import org.olat.ims.resources.IMSEntityResolver;
import org.olat.modules.qpool.QuestionItem;
......@@ -276,7 +277,7 @@ class QTIImportProcessor {
//embed in <questestinterop>
DocumentFactory df = DocumentFactory.getInstance();
Document itemDoc = df.createDocument();
Element questestinteropEl = df.createElement("questestinterop");
Element questestinteropEl = df.createElement(QTIDocument.DOCUMENT_ROOT);
itemDoc.setRootElement(questestinteropEl);
Element deepClone = (Element)itemInfos.getItemEl().clone();
questestinteropEl.add(deepClone);
......
......@@ -32,6 +32,7 @@ import org.olat.core.id.Identity;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSManager;
import org.olat.ims.qti.QTI12EditorController;
import org.olat.ims.qti.QTI12PreviewController;
import org.olat.ims.qti.QTIConstants;
import org.olat.modules.qpool.QPoolSPI;
......@@ -127,7 +128,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
@Override
public Controller getEditableController(UserRequest ureq, WindowControl wControl, QuestionItem item) {
QTI12PreviewController previewCtrl = new QTI12PreviewController(ureq, wControl, item);
QTI12EditorController previewCtrl = new QTI12EditorController(ureq, wControl, item);
return previewCtrl;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment