From 88aaa65f212128b3b3692656b9adf7662dd682da Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 20 Jan 2017 20:21:23 +0100
Subject: [PATCH] OO-2464: send publish after publishing is finished, speed up
 batch update of check lists and efficency statements...

---
 .../coursecreation/CourseCreationHelper.java  |  2 +-
 .../java/org/olat/course/CourseFactory.java   |  2 +-
 .../course/assessment/AssessmentModule.java   |  4 ++-
 .../manager/EfficiencyStatementManager.java   | 13 +++++----
 .../course/editor/EditorMainController.java   |  3 +--
 .../olat/course/editor/PublishProcess.java    | 27 ++++++++++---------
 .../course/editor/QuickPublishController.java |  3 +--
 .../course/nodes/CheckListCourseNode.java     | 10 +++----
 .../nodes/cl/manager/CheckboxManagerImpl.java |  2 --
 .../course/editor/PublishProcessTest.java     |  2 +-
 10 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java
index a122759544d..6febc5fb69e 100644
--- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java
+++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java
@@ -336,7 +336,7 @@ public class CourseCreationHelper {
 			// no error and no warnings -> return immediate
 			log.error("Course Publishing failed", new AssertionError());
 		}
-		pp.applyPublishSet(ureq.getIdentity(), ureq.getLocale());
+		pp.applyPublishSet(ureq.getIdentity(), ureq.getLocale(), true);
 		CourseFactory.closeCourseEditSession(course.getResourceableId(), true);
 
 		// save catalog entry
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 8373677bfa0..5b581a887db 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -635,7 +635,7 @@ public class CourseFactory {
 
 			 try {
 				 course = CourseFactory.openCourseEditSession(course.getResourceableId());
-				 publishProcess.applyPublishSet(identity, locale);
+				 publishProcess.applyPublishSet(identity, locale, false);
 			 } catch(Exception e) {
 				 log.error("",  e);
 			 } finally {
diff --git a/src/main/java/org/olat/course/assessment/AssessmentModule.java b/src/main/java/org/olat/course/assessment/AssessmentModule.java
index 636c64ab2ba..84439742e33 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentModule.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentModule.java
@@ -154,7 +154,9 @@ public class AssessmentModule extends AbstractSpringModule implements GenericEve
 		synchronized (upcomingWork) { //o_clusterOK by:ld synchronized OK - only one cluster node must update the EfficiencyStatements (the course is locked for editing) (same as e.g. file indexer)
 			recalc = upcomingWork.contains(resId);
 			if (recalc) {
-				upcomingWork.remove(resId);
+				for(; upcomingWork.remove(resId); ) {
+					//remove all with the same res id
+				}
 			}
 		}
 		if (recalc) {
diff --git a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
index e1507218aad..d607533bda7 100644
--- a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
+++ b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
@@ -35,6 +35,7 @@ import java.util.Map;
 
 import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.OLog;
@@ -677,8 +678,8 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 			log.audit("Updating efficiency statements for course::" + course.getResourceableId() + ", this might produce temporary heavy load on the CPU");
 
 			// preload cache to speed up things
-			long start = System.currentTimeMillis();
 			AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();		
+			int count = 0;
 			for (Identity identity : identities) {			
 				//o_clusterOK: by ld
 				OLATResourceable efficiencyStatementResourceable = am.createOLATResourceableForLocking(identity);
@@ -693,12 +694,10 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 				if (Thread.interrupted()) {
 					break;
 				}
-			}
-			
-			if (log.isDebug()) {
-				long end = System.currentTimeMillis();
-				log.debug("Updated efficiency statements for course::" + course.getResourceableId() 
-					 + "ms; Updating statements: " + (end-start) + "ms; Users: " + identities.size());
+				
+				if(++count % 10 == 0) {
+					DBFactory.getInstance().commitAndCloseSession();
+				}
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java
index a902980c9b4..2101aeaf1ae 100644
--- a/src/main/java/org/olat/course/editor/EditorMainController.java
+++ b/src/main/java/org/olat/course/editor/EditorMainController.java
@@ -1086,8 +1086,7 @@ public class EditorMainController extends MainLayoutBasicController implements G
 					Collection<String> selectedNodeIds = (Collection<String>) runContext.get("publishSetCreatedFor");
 					hasChanges = (selectedNodeIds != null) && (selectedNodeIds.size() > 0);
 					if (hasChanges) {
-						publishManager.applyPublishSet(ureq1.getIdentity(), ureq1.getLocale());
-						publishManager.applyUpdateSet(ureq1.getIdentity(), ureq1.getLocale());
+						publishManager.applyPublishSet(ureq1.getIdentity(), ureq1.getLocale(), false);
 					}
 				}
 				
diff --git a/src/main/java/org/olat/course/editor/PublishProcess.java b/src/main/java/org/olat/course/editor/PublishProcess.java
index 0298ee8b52e..27bebd32fb0 100644
--- a/src/main/java/org/olat/course/editor/PublishProcess.java
+++ b/src/main/java/org/olat/course/editor/PublishProcess.java
@@ -367,14 +367,14 @@ public class PublishProcess {
 			childNode.removeAllChildren(); // remove all children after calling convertInCourseEditorTreeNode
 		}
 	}
-
-	
 	
 	/**
+	 * 
 	 * @param identity
 	 * @param locale
+	 * @param newCourse Optimization for new courses, it doesn't call upddateOnPublish of inserted/updated course nodes
 	 */
-	public void applyPublishSet(Identity identity, Locale locale) {
+	public void applyPublishSet(Identity identity, Locale locale, boolean newCourse) {
 		// the active runstructure and the new created runstructure
 		Structure existingCourseRun = course.getRunStructure();
 		EventBus orec = CoordinatorManager.getInstance().getCoordinator().getEventBus();
@@ -416,7 +416,7 @@ public class PublishProcess {
 		// old course structure accessible
 		orec.fireEventToListenersOf(beforePublish, course);
 		/*
-		 * TODO:pb: disucss with fj: listeners could add information to
+		 * TODO:pb: discuss with fj: listeners could add information to
 		 * beforePublish event such as a right to veto or add identities who is
 		 * currently in the course, thus stopping the publishing author from
 		 * publishing! i.e. if people are in a test or something like this.... we
@@ -492,6 +492,16 @@ public class PublishProcess {
 		existingCourseRun.setRootNode(resultingCourseRun.getRootNode());
 		CourseFactory.saveCourse(course.getResourceableId());
 		
+		//on old course, apply update to published nodes
+		if(!newCourse) {
+			for (CourseEditorTreeNode cetn:editorModelInsertedNodes) {
+				cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
+			}
+			for (CourseEditorTreeNode cetn:editorModelModifiedNodes) {
+				cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
+			}
+		}
+		
 		/*
 		 * broadcast event
 		 */
@@ -508,15 +518,6 @@ public class PublishProcess {
 		 */
 	}
 	
-	public void applyUpdateSet(Identity identity, Locale locale) {
-		for (CourseEditorTreeNode cetn:editorModelInsertedNodes) {
-			cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
-		}
-		for (CourseEditorTreeNode cetn:editorModelModifiedNodes) {
-			cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
-		}
-	}
-	
 	private void archiveDeletedNode(Identity identity, CourseNode cn, CourseNode oldCn, Locale locale, String charset) {
 		File exportDirectory = CourseFactory.getOrCreateDataExportDirectory(identity, course.getCourseTitle());
 		String archiveName = cn.getType() + "_"
diff --git a/src/main/java/org/olat/course/editor/QuickPublishController.java b/src/main/java/org/olat/course/editor/QuickPublishController.java
index 48807d1a6cb..3cc653a3f61 100644
--- a/src/main/java/org/olat/course/editor/QuickPublishController.java
+++ b/src/main/java/org/olat/course/editor/QuickPublishController.java
@@ -163,8 +163,7 @@ public class QuickPublishController extends BasicController {
 			
 			PublishEvents publishEvents = publishProcess.getPublishEvents();
 			try {
-				publishProcess.applyPublishSet(getIdentity(), getLocale());
-				publishProcess.applyUpdateSet(getIdentity(), getLocale());
+				publishProcess.applyPublishSet(getIdentity(), getLocale(), false);
 			} catch(Exception e) {
 				logError("",  e);
 			}
diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
index dbcf2961080..04658b2f496 100644
--- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
@@ -31,6 +31,7 @@ import java.util.logging.Level;
 import java.util.zip.ZipOutputStream;
 
 import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.control.Controller;
@@ -54,7 +55,6 @@ import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.EfficiencyStatementEvent;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
@@ -689,17 +689,17 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 		CoursePropertyManager pm = course.getCourseEnvironment().getCoursePropertyManager();
 		List<Identity> assessedUsers = pm.getAllIdentitiesWithCourseAssessmentData(null);
 
+		int count = 0;
 		for(Identity assessedIdentity: assessedUsers) {
 			updateScorePassedOnPublish(assessedIdentity, publisher, checkboxManager, course);
+			if(++count % 10 == 0) {
+				DBFactory.getInstance().commitAndCloseSession();
+			}
 		}
 		super.updateOnPublish(locale, course, publisher, publishEvents);
-		
-		EfficiencyStatementEvent recalculateEvent = new EfficiencyStatementEvent(EfficiencyStatementEvent.CMD_RECALCULATE, course.getResourceableId());
-		publishEvents.addPostPublishingEvent(recalculateEvent);
 	}
 	
 	private void updateScorePassedOnPublish(Identity assessedIdentity, Identity coachIdentity, CheckboxManager checkboxManager, ICourse course) {
-		
 		AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
 		
 		Float currentScore = am.getNodeScore(this, assessedIdentity);
diff --git a/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java b/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
index dee62ad9eef..7c753736d11 100644
--- a/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
@@ -395,7 +395,6 @@ public class CheckboxManagerImpl implements CheckboxManager {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select count(check) from clcheck check")
 		  .append(" inner join check.checkbox box")
-		  .append(" inner join check.identity ident")
 		  .append(" where check.identity.key=:identityKey and box.resName=:resName and box.resId=:resId")
 		  .append("  and check.checked=true");
 		if(StringHelper.containsNonWhitespace(resSubPath)) {
@@ -420,7 +419,6 @@ public class CheckboxManagerImpl implements CheckboxManager {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select sum(check.score) from clcheck check")
 		  .append(" inner join check.checkbox box")
-		  .append(" inner join check.identity ident")
 		  .append(" where check.identity.key=:identityKey and check.checked=true and box.resName=:resName and box.resId=:resId");
 		if(StringHelper.containsNonWhitespace(resSubPath)) {
 			sb.append(" and box.resSubPath=:resSubPath");
diff --git a/src/test/java/org/olat/course/editor/PublishProcessTest.java b/src/test/java/org/olat/course/editor/PublishProcessTest.java
index e301ff32fbc..620c5febc8b 100644
--- a/src/test/java/org/olat/course/editor/PublishProcessTest.java
+++ b/src/test/java/org/olat/course/editor/PublishProcessTest.java
@@ -286,7 +286,7 @@ public class PublishProcessTest extends OlatTestCase {
 		StatusDescription[] sds = set.getWarnings();
 		Assert.assertNotNull(sds);
 		Assert.assertEquals(0, sds.length);
-		pp.applyPublishSet(author, locale);
+		pp.applyPublishSet(author, locale, true);
 		CourseFactory.closeCourseEditSession(course.getResourceableId(), true);
 	}
 	
-- 
GitLab