From 77fc3789ec4e12a89798056b927bae0dcd381c98 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Thu, 21 Feb 2019 11:26:56 +0100
Subject: [PATCH] OO-3900: restore the course folder at the right place
 (+documentation)

---
 .../org/olat/core/util/xml/XStreamHelper.java | 13 ++--
 .../java/org/olat/course/CourseFactory.java   |  3 +-
 .../org/olat/course/PersistingCourseImpl.java | 72 +++++++------------
 3 files changed, 35 insertions(+), 53 deletions(-)

diff --git a/src/main/java/org/olat/core/util/xml/XStreamHelper.java b/src/main/java/org/olat/core/util/xml/XStreamHelper.java
index 6d2914f3eb8..13b6c23aaa8 100644
--- a/src/main/java/org/olat/core/util/xml/XStreamHelper.java
+++ b/src/main/java/org/olat/core/util/xml/XStreamHelper.java
@@ -39,7 +39,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 
 import org.olat.core.logging.OLATRuntimeException;
-import org.olat.core.util.FileUtils;
 import org.olat.core.util.vfs.VFSLeaf;
 
 import com.thoughtworks.xstream.XStream;
@@ -332,17 +331,13 @@ public class XStreamHelper {
 	 * @return
 	 */
 	public static Object readObject(XStream xStream, InputStream is) {
-		try {
-			InputStreamReader isr = new InputStreamReader(is, ENCODING);
+		try(InputStreamReader isr = new InputStreamReader(is, ENCODING)) {
 			Object obj = xStream.fromXML(isr);
-			isr.close();
 			is.close();
 			return obj;
 		} catch (Exception e) {
 			throw new OLATRuntimeException(XStreamHelper.class,
 					"could not read Object from inputstream: " + is, e);
-		} finally {
-			FileUtils.closeSafely(is);
 		}
 	}
 	
@@ -374,7 +369,11 @@ public class XStreamHelper {
 	 *            the object to be serialized
 	 */
 	public static void writeObject(XStream xStream, VFSLeaf vfsLeaf, Object obj) {
-		writeObject(xStream, vfsLeaf.getOutputStream(false), obj);
+		try(OutputStream out=vfsLeaf.getOutputStream(false)) {
+			writeObject(xStream, out, obj);
+		} catch(Exception e) {
+			throw new OLATRuntimeException(XStreamHelper.class, "Could not write object to file: " + vfsLeaf, e);
+		}
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index e24eb7dbdab..1c611faa0fd 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -567,7 +567,8 @@ public class CourseFactory {
 				//course folder
 				File courseFolderZip = new File(fCanonicalCourseBasePath, "oocoursefolder.zip");
 				if(courseFolderZip.exists()) {
-					ZipUtil.unzipNonStrict(courseFolderZip, courseBaseContainer, null, false);
+					VFSContainer courseFolder = VFSManager.getOrCreateContainer(courseBaseContainer, PersistingCourseImpl.COURSEFOLDER);
+					ZipUtil.unzipNonStrict(courseFolderZip, courseFolder, null, false);
 					FileUtils.deleteFile(courseFolderZip);
 				}
 				return newCourse;
diff --git a/src/main/java/org/olat/course/PersistingCourseImpl.java b/src/main/java/org/olat/course/PersistingCourseImpl.java
index 05464385838..4ff1c1bc956 100644
--- a/src/main/java/org/olat/course/PersistingCourseImpl.java
+++ b/src/main/java/org/olat/course/PersistingCourseImpl.java
@@ -25,7 +25,9 @@
 
 package org.olat.course;
 
+import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.InputStream;
 import java.io.Serializable;
 
 import org.olat.admin.quota.QuotaConstants;
@@ -93,7 +95,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 	private static final String EDITORTREEMODEL_XML = "editortreemodel.xml";
 	private static final String RUNSTRUCTURE_XML = "runstructure.xml";
 	private static final String ORES_TYPE_NAME = CourseModule.getCourseTypeName();
-	private static final String COURSEFOLDER = "coursefolder";
+	public static final String COURSEFOLDER = "coursefolder";
 
 	private Long resourceableId;
 	private Structure runStructure;
@@ -239,6 +241,9 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 			throw new OLATRuntimeException(this.getClass(), "Could not create course base path:" + courseRootContainer, null);
 	}
 
+	/**
+	 * @return The directory "coursefolder" or storage folder of the course
+	 */
 	protected LocalFolderImpl getIsolatedCourseFolder() {
 		// create local course folder
 		LocalFolderImpl isolatedCourseFolder = VFSManager.olatRootContainer(courseRootContainer.getRelPath() + File.separator + COURSEFOLDER, null);
@@ -254,11 +259,17 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		return isolatedCourseFolder;
 	}
 	
+	/**
+	 * @return The directory "coursefolder" or storage folder of the course
+	 */
 	protected File getIsolatedCourseBaseFolder() {
 		// create local course folder
 		return VFSManager.olatRootDirectory(courseRootContainer.getRelPath() + File.separator + COURSEFOLDER);
 	}
 	
+	/**
+	 * @return The directory "coursefolder" or storage folder of the course
+	 */
 	protected VFSContainer getIsolatedCourseBaseContainer() {
 		// create local course folder
 		return VFSManager.olatRootContainer(courseRootContainer.getRelPath() + File.separator + COURSEFOLDER, null);
@@ -322,11 +333,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		tv.visitAll();
 		log.info("exportToFilesystem: exporting course "+this+": exporting all nodes...done.");
 		
-		//OLAT-5368: do intermediate commit to avoid transaction timeout
-		// discussion intermediatecommit vs increased transaction timeout:
-		//  pro intermediatecommit: not much
-		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
-		//@TODO OLAT-2597: real solution is a long-running background-task concept...
+		// Do intermediate commit to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
 
 		// export shared folder
@@ -343,11 +350,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 			log.info("exportToFilesystem: exporting course "+this+": shared folder...done.");
 		}
 		
-		//OLAT-5368: do intermediate commit to avoid transaction timeout
-		// discussion intermediatecommit vs increased transaction timeout:
-		//  pro intermediatecommit: not much
-		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
-		//@TODO OLAT-2597: real solution is a long-running background-task concept...
+		// Do intermediate commit to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
 
 		// export glossary
@@ -365,11 +368,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 			log.info("exportToFilesystem: exporting course "+this+": glossary...done.");
 		}
 		
-		//OLAT-5368: do intermediate commit to avoid transaction timeout
-		// discussion intermediatecommit vs increased transaction timeout:
-		//  pro intermediatecommit: not much
-		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
-		//@TODO OLAT-2597: real solution is a long-running background-task concept...
+		// Do intermediate commit to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
 
 		log.info("exportToFilesystem: exporting course "+this+": configuration and repo data...");
@@ -382,11 +381,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		RepositoryEntryImportExport importExport = new RepositoryEntryImportExport(myRE, fExportedDataDir);
 		importExport.exportDoExportProperties();
 		
-		//OLAT-5368: do intermediate commit to avoid transaction timeout
-		// discussion intermediatecommit vs increased transaction timeout:
-		//  pro intermediatecommit: not much
-		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
-		//@TODO OLAT-2597: real solution is a long-running background-task concept...
+		// Do intermediate commit to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
 		
 		//export reminders
@@ -476,28 +471,25 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 	 */
 	private Object readObject(String fileName) {
 		VFSItem vfsItem = getCourseBaseContainer().resolve(fileName);
-		if (vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
+		if (!(vfsItem instanceof VFSLeaf)) {
 			throw new CorruptedCourseException("Cannot resolve file: " + fileName + " course=" + toString());
 		}
-		try {
+		try(InputStream in = ((VFSLeaf)vfsItem).getInputStream();
+				BufferedInputStream bis = new BufferedInputStream(in)) {
 			XStream xstream = CourseXStreamAliases.getReadCourseXStream();
-			return XStreamHelper.readObject(xstream, ((VFSLeaf)vfsItem).getInputStream());
+			return XStreamHelper.readObject(xstream, bis);
 		} catch (Exception e) {
 			log.error("Cannot read course tree file: " + fileName, e);
 			throw new CorruptedCourseException("Cannot resolve file: " + fileName + " course=" + toString(), e);
 		}
 	}
 
-	/**
-	 * @see org.olat.core.id.OLATResourceablegetResourceableTypeName()
-	 */
+	@Override
 	public String getResourceableTypeName() {
 		return ORES_TYPE_NAME;
 	}
 
-	/**
-	 * @see org.olat.core.id.OLATResourceablegetResourceableId()
-	 */
+	@Override
 	public Long getResourceableId() {
 		return resourceableId;
 	}
@@ -531,10 +523,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		CoreSpringFactory.getImpl(CourseConfigManager.class).saveConfigTo(this, courseConfig);
 	}
 	
-	/**
-	 * 
-	 * @return
-	 */
+	@Override
 	public CourseConfig getCourseConfig() {
 		return courseConfig;
 	}
@@ -548,16 +537,12 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		this.hasAssessableNodes = AssessmentHelper.checkForAssessableNodes(runStructure.getRootNode());
 	}
 
-	/**
-	 * @see org.olat.course.ICourse#hasAssessableNodes()
-	 */
+	@Override
 	public boolean hasAssessableNodes() {
 		return hasAssessableNodes;
 	}
 
-	/**
-	 * @see java.lang.Object#toString()
-	 */
+	@Override
 	public String toString() {
 		return "Course:[" + getResourceableId() + "," + courseTitle + "], " + super.toString();
 	}
@@ -654,14 +639,11 @@ class NodeExportVisitor implements Visitor {
 	 * 
 	 * @see org.olat.core.util.tree.Visitor#visit(org.olat.core.util.nodes.INode)
 	 */
+	@Override
 	public void visit(INode node) {
 		CourseEditorTreeNode cNode = (CourseEditorTreeNode) node;
 		cNode.getCourseNode().exportNode(exportDirectory, course);
-		//OLAT-5368: do frequent intermediate commits to avoid transaction timeout
-		// discussion intermediatecommit vs increased transaction timeout:
-		//  pro intermediatecommit: not much
-		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
-		//@TODO OLAT-2597: real solution is a long-running background-task concept...
+		// Do frequent intermediate commits to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
 	}
 
-- 
GitLab