From ace9b610eb0c663ebe4a0b136cb125cd8cb61370 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 21 Mar 2017 12:03:11 +0100
Subject: [PATCH] OO-2626: change behavior of cache, add a lot of course node
 indexers, fix issue with Open document indexer, remove cache in search
 controller, add the filename (without suffix) if not title in meta
 information found, add a batch of XSD in blacklist...

---
 .../org/olat/search/_spring/searchContext.xml | 47 +++++++++++
 .../org/olat/search/model/OlatDocument.java   |  2 +-
 .../search/service/SearchResourceContext.java | 18 ++---
 .../service/document/CourseNodeDocument.java  | 45 +++++++----
 .../service/document/file/FileDocument.java   | 13 +++-
 .../document/file/FileDocumentFactory.java    | 60 ++++++++------
 .../service/document/file/HtmlDocument.java   |  2 +-
 .../service/document/file/OpenDocument.java   |  6 +-
 .../indexer/AbstractHierarchicalIndexer.java  | 12 +--
 .../search/service/indexer/LeafIndexer.java   |  5 +-
 .../indexer/repository/CourseIndexer.java     | 16 ++--
 .../course/AbstractCourseNodeIndexer.java     | 78 +++++++++++++++++++
 .../course/BCCourseNodeIndexer.java           | 57 +++++++++++---
 .../course/BasicLTICourseNodeIndexer.java     | 38 +++++++++
 .../course/COCourseNodeIndexer.java           | 37 +++++++++
 .../course/CPCourseNodeIndexer.java           | 12 +--
 .../course/CalCourseNodeIndexer.java          | 37 +++++++++
 .../course/CheckListCourseNodeIndexer.java    | 37 +++++++++
 .../repository/course/CourseNodeIndexer.java  | 13 ++++
 .../course/DENCourseNodeIndexer.java          | 37 +++++++++
 .../course/DialogCourseNodeIndexer.java       | 10 +--
 .../course/ENCourseNodeIndexer.java           | 37 +++++++++
 .../course/FOCourseNodeIndexer.java           | 11 +--
 .../course/GTACourseNodeIndexer.java          | 37 +++++++++
 .../course/GoToMeetingCourseNodeIndexer.java  | 37 +++++++++
 .../course/IQSELFCourseNodeIndexer.java       | 37 +++++++++
 .../course/IQSURVCourseNodeIndexer.java       | 37 +++++++++
 .../course/IQTESTCourseNodeIndexer.java       | 37 +++++++++
 .../course/InfoCourseNodeIndexer.java         | 16 ++--
 .../course/LLCourseNodeIndexer.java           | 37 +++++++++
 .../course/MSCourseNodeIndexer.java           | 37 +++++++++
 .../course/MembersCourseNodeIndexer.java      | 37 +++++++++
 .../course/OpenMeetingsCourseNodeIndexer.java | 37 +++++++++
 .../course/PFCourseNodeIndexer.java           | 37 +++++++++
 .../course/PortfolioCourseNodeIndexer.java    | 18 ++---
 .../ProjectBrokerCourseNodeIndexer.java       | 15 ++--
 .../course/SPCourseNodeIndexer.java           | 38 ++++-----
 .../course/STCourseNodeIndexer.java           |  7 +-
 .../course/ScormCourseNodeIndexer.java        | 14 ++--
 .../course/TACourseNodeIndexer.java           | 11 +--
 .../course/TUCourseNodeIndexer.java           | 37 +++++++++
 .../course/VCCourseNodeIndexer.java           | 37 +++++++++
 .../course/VideoCourseNodeIndexer.java        | 37 +++++++++
 .../course/ViteroCourseNodeIndexer.java       | 37 +++++++++
 .../course/WikiCourseNodeIndexer.java         | 14 ++--
 .../olat/search/ui/SearchInputController.java | 33 +-------
 .../search/ui/StandardResultController.java   |  4 -
 .../ui/_i18n/LocalStrings_de.properties       | 20 +++++
 .../ui/_i18n/LocalStrings_en.properties       | 19 +++++
 49 files changed, 1145 insertions(+), 212 deletions(-)
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/AbstractCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/CalCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/IQSELFCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/LLCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/OpenMeetingsCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/PFCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/TUCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/VCCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/VideoCourseNodeIndexer.java
 create mode 100644 src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java

diff --git a/src/main/java/org/olat/search/_spring/searchContext.xml b/src/main/java/org/olat/search/_spring/searchContext.xml
index 14736634f9f..70058a66e93 100644
--- a/src/main/java/org/olat/search/_spring/searchContext.xml
+++ b/src/main/java/org/olat/search/_spring/searchContext.xml
@@ -89,6 +89,15 @@
 			<list>
 				<!-- list of files which will not be indexed -->
 				<value>imsmanifest.xml</value>
+				<value>ims_xml.xsd</value>
+				<value>imscp_v1p1.xsd</value>
+				<value>imscp_rootv1p1p2.xsd</value>
+				<value>imsmd_v1p2p2.xsd</value>
+				<value>imsmd_rootv1p2p1.xsd</value>
+				<value>XMLSchema.dtd</value>
+				<value>adlcp_rootv1p2.xsd</value>
+				<value>datatypes.dtd</value>
+				<value>SCORM_API_wrapper.js</value>
 			</list>
 		</constructor-arg>
 	</bean>
@@ -176,10 +185,48 @@
 				<ref bean="scormCourseNodeIndexer" />
 				<ref bean="portfolioCourseNodeIndexer" />
 				<ref bean="infoCourseNodeIndexer" />
+				<ref bean="calCourseNodeIndexer" />
+				<ref bean="ltiCourseNodeIndexer" />
+				<ref bean="checkListCourseNodeIndexer" />
+				<ref bean="denCourseNodeIndexer" />
+				<ref bean="enCourseNodeIndexer" />
+				<ref bean="goToMeetingCourseNodeIndexer" />
+				<ref bean="gtaCourseNodeIndexer" />
+				<ref bean="iqsurvCourseNodeIndexer" />
+				<ref bean="iqselfCourseNodeIndexer" />
+				<ref bean="iqtestCourseNodeIndexer" />
+				<ref bean="llCourseNodeIndexer" />
+				<ref bean="membersCourseNodeIndexer" />
+				<ref bean="msCourseNodeIndexer" />
+				<ref bean="pfCourseNodeIndexer" />
+				<ref bean="openMeetingsCourseNodeIndexer" />
+				<ref bean="tuCourseNodeIndexer" />
+				<ref bean="vcCourseNodeIndexer" />
+				<ref bean="videoCourseNodeIndexer" />
+				<ref bean="viteroCourseNodeIndexer" />
 			</list>
 		</property>
 	</bean>
 	
+	<bean id="tuCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.TUCourseNodeIndexer" />
+	<bean id="vcCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.VCCourseNodeIndexer" />
+	<bean id="videoCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.VideoCourseNodeIndexer" />
+	<bean id="viteroCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.ViteroCourseNodeIndexer" />
+	<bean id="ltiCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.BasicLTICourseNodeIndexer" />
+	<bean id="calCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.CalCourseNodeIndexer" />
+	<bean id="checkListCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.CheckListCourseNodeIndexer" />
+	<bean id="denCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.DENCourseNodeIndexer" />
+	<bean id="enCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.ENCourseNodeIndexer" />
+	<bean id="goToMeetingCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.GoToMeetingCourseNodeIndexer" />
+	<bean id="gtaCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.GTACourseNodeIndexer" />
+	<bean id="iqsurvCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.IQSURVCourseNodeIndexer" />
+	<bean id="iqselfCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.IQSELFCourseNodeIndexer" />
+	<bean id="iqtestCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.IQTESTCourseNodeIndexer" />
+	<bean id="llCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.LLCourseNodeIndexer" />
+	<bean id="membersCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.MembersCourseNodeIndexer" />
+	<bean id="msCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.MSCourseNodeIndexer" />
+	<bean id="pfCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.PFCourseNodeIndexer" />
+	<bean id="openMeetingsCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.OpenMeetingsCourseNodeIndexer" />
 	<bean id="spCourseNodeIndexer" class="org.olat.search.service.indexer.repository.course.SPCourseNodeIndexer" />
 	<bean id="foCourseNodeIndexer"	   class="org.olat.search.service.indexer.repository.course.FOCourseNodeIndexer" />
 	<bean id="stCourseNodeIndexer"	   class="org.olat.search.service.indexer.repository.course.STCourseNodeIndexer" />
diff --git a/src/main/java/org/olat/search/model/OlatDocument.java b/src/main/java/org/olat/search/model/OlatDocument.java
index f43ed11a2af..7f27d78944d 100644
--- a/src/main/java/org/olat/search/model/OlatDocument.java
+++ b/src/main/java/org/olat/search/model/OlatDocument.java
@@ -92,7 +92,7 @@ public class OlatDocument extends AbstractOlatDocument {
 		document.add(new StringField(RESOURCEURL_MD5_FIELD_NAME, Encoder.md5hash(getResourceUrl()), Field.Store.YES));
 		document.add(new StringField(DOCUMENTTYPE_FIELD_NAME, getDocumentType(), Field.Store.YES));
 		if(getCssIcon() != null) {
-			document.add(new StringField(CSS_ICON,getCssIcon(), Field.Store.YES));
+			document.add(new StringField(CSS_ICON, getCssIcon(), Field.Store.YES));
 		}
 		document.add(new StringField(FILETYPE_FIELD_NAME, getFileType(), Field.Store.YES));
 		document.add(createTextField(AUTHOR_FIELD_NAME, getAuthor(), 2));
diff --git a/src/main/java/org/olat/search/service/SearchResourceContext.java b/src/main/java/org/olat/search/service/SearchResourceContext.java
index 63e41495546..ae39ee4ce1a 100644
--- a/src/main/java/org/olat/search/service/SearchResourceContext.java
+++ b/src/main/java/org/olat/search/service/SearchResourceContext.java
@@ -54,16 +54,16 @@ public class SearchResourceContext {
 	// Parameter to pass from parent to child
 	private Date lastModified;
 	private Date createdDate;
-	private String documentType = null;
-	private String title = null;
-	private String description = null;
-	private String parentContextType = null;
-	private String parentContextName = null;
+	private String documentType;
+	private String title;
+	private String description;
+	private String parentContextType;
+	private String parentContextName;
 
 	private BusinessControl myBusinessControl;
 	private BusinessControl parentBusinessControl;
 	
-  private String filePath = null;
+	private String filePath;
 
 
 	/**
@@ -106,10 +106,8 @@ public class SearchResourceContext {
 		String resourceUrl = BusinessControlFactory.getInstance().getAsString(bControl);
 		if (filePath != null) {
 			// It is a file resource => Append file path
-	    StringBuilder buf = new StringBuilder(resourceUrl);
-			buf.append(FILEPATH_PREFIX);
-			buf.append(filePath);
-			buf.append(ENDTAG);
+			StringBuilder buf = new StringBuilder(resourceUrl);
+			buf.append(FILEPATH_PREFIX).append(filePath).append(ENDTAG);
 			resourceUrl = buf.toString();
 		}
 		return resourceUrl;
diff --git a/src/main/java/org/olat/search/service/document/CourseNodeDocument.java b/src/main/java/org/olat/search/service/document/CourseNodeDocument.java
index da3d65eb87d..1aec69f47c8 100644
--- a/src/main/java/org/olat/search/service/document/CourseNodeDocument.java
+++ b/src/main/java/org/olat/search/service/document/CourseNodeDocument.java
@@ -26,9 +26,11 @@
 package org.olat.search.service.document;
 
 import org.apache.lucene.document.Document;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.filter.FilterFactory;
 import org.olat.course.nodes.CourseNode;
+import org.olat.course.nodes.CourseNodeConfiguration;
+import org.olat.course.nodes.CourseNodeFactory;
 import org.olat.search.model.OlatDocument;
 import org.olat.search.service.SearchResourceContext;
 
@@ -39,7 +41,6 @@ import org.olat.search.service.SearchResourceContext;
 public class CourseNodeDocument extends OlatDocument {
 
 	private static final long serialVersionUID = -2035945166792451137L;
-	private static final OLog log = Tracing.createLoggerFor(CourseNodeDocument.class);
 
 	// Must correspond with LocalString_xx.properties
 	// Do not use '_' because we want to seach for certain documenttype and lucene haev problems with '_' 
@@ -54,25 +55,39 @@ public class CourseNodeDocument extends OlatDocument {
 
 		// Set all know attributes
 		courseNodeDocument.setResourceUrl(searchResourceContext.getResourceUrl());
-		if (searchResourceContext.getDocumentType() != null && !searchResourceContext.getDocumentType().equals("") ) {
+		if (StringHelper.containsNonWhitespace(searchResourceContext.getDocumentType())) {
 			courseNodeDocument.setDocumentType(searchResourceContext.getDocumentType());
 		} else {
-		  courseNodeDocument.setDocumentType(TYPE);
+			courseNodeDocument.setDocumentType(TYPE);
 		}
-		courseNodeDocument.setCssIcon("o_course_icon");
-		courseNodeDocument.setTitle(courseNode.getShortTitle());
-		courseNodeDocument.setDescription(courseNode.getLongTitle());
-		// Get dates from paraent object via context because course node has no dates 
+		CourseNodeConfiguration nodeConfig = CourseNodeFactory.getInstance().getCourseNodeConfigurationEvenForDisabledBB(courseNode.getType());
+		if(nodeConfig != null && StringHelper.containsNonWhitespace(nodeConfig.getIconCSSClass())) {
+			courseNodeDocument.setCssIcon(nodeConfig.getIconCSSClass());
+		} else {
+			courseNodeDocument.setCssIcon("o_course_icon");
+		}
+		
+		if(StringHelper.containsNonWhitespace(courseNode.getShortTitle())) {
+			courseNodeDocument.setTitle(courseNode.getShortTitle());
+		} else if(StringHelper.containsNonWhitespace(courseNode.getLongTitle())) {
+			courseNodeDocument.setTitle(courseNode.getLongTitle());
+			courseNodeDocument.setDescription(courseNode.getLongTitle());
+		}
+		if(StringHelper.containsNonWhitespace(courseNode.getLongTitle())) {
+			courseNodeDocument.setDescription(courseNode.getLongTitle());
+		}
+		if(StringHelper.containsNonWhitespace(courseNode.getLearningObjectives())) {
+			String objectives = courseNode.getLearningObjectives();
+			objectives = FilterFactory.getHtmlTagsFilter().filter(objectives);
+			courseNodeDocument.setContent(objectives);
+		}
+		
+		// Get dates from parent object via context because course node has no dates 
 		courseNodeDocument.setCreatedDate(searchResourceContext.getCreatedDate());
 		courseNodeDocument.setLastChange(searchResourceContext.getLastModified());
 		courseNodeDocument.setParentContextType(searchResourceContext.getParentContextType());
 		courseNodeDocument.setParentContextName(searchResourceContext.getParentContextName());
-    // unused course-node attributtes
-		//	courseNode.getShortName();
-    //	courseNode.getType();
 
-		if (log.isDebug()) log.debug(courseNodeDocument.toString());
 		return courseNodeDocument.getLuceneDocument();
 	}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/search/service/document/file/FileDocument.java b/src/main/java/org/olat/search/service/document/file/FileDocument.java
index 7986d098755..3f4f7865210 100644
--- a/src/main/java/org/olat/search/service/document/file/FileDocument.java
+++ b/src/main/java/org/olat/search/service/document/file/FileDocument.java
@@ -60,7 +60,7 @@ public abstract class FileDocument extends OlatDocument {
 		setResourceUrl(leafResourceContext.getResourceUrl());
 		setLastChange(new Date(leaf.getLastModified()));
 		// Check if there are documents attributes set in resource context
-		if (leafResourceContext.getDocumentType() != null && !leafResourceContext.getDocumentType().equals("")) {
+		if (StringHelper.containsNonWhitespace(leafResourceContext.getDocumentType())) {
 			// document-type in context is set => get from there
 			setDocumentType(leafResourceContext.getDocumentType());
 		} else {
@@ -74,8 +74,13 @@ public abstract class FileDocument extends OlatDocument {
 		} else if(content != null && StringHelper.containsNonWhitespace(content.getTitle())) {
 			metaTitle = content.getTitle();
 		} else {
-			metaTitle = null;
-		} 
+			String beautfiedName = leaf.getName();
+			int dotpos = beautfiedName.lastIndexOf('.');
+			if (dotpos > 0) {
+				beautfiedName = beautfiedName.substring(0, dotpos);
+			}
+			metaTitle = beautfiedName.replace('_', ' ');
+		}
 		
 		StringBuilder title = new StringBuilder();
 		if (StringHelper.containsNonWhitespace(leafResourceContext.getTitle())) {
@@ -92,7 +97,7 @@ public abstract class FileDocument extends OlatDocument {
 		setTitle(title.toString());
 
 		String metaDesc = (meta == null ? null : meta.getComment());
-		if (leafResourceContext.getDescription() != null && !leafResourceContext.getDescription().equals("")) {
+		if (StringHelper.containsNonWhitespace(leafResourceContext.getDescription())) {
 			// Title in context is set => get from there
 			setDescription(leafResourceContext.getDescription() + (metaDesc == null ? "" : " " + metaDesc));
 		} else if (metaDesc != null) {
diff --git a/src/main/java/org/olat/search/service/document/file/FileDocumentFactory.java b/src/main/java/org/olat/search/service/document/file/FileDocumentFactory.java
index 7583cc93ff6..3ec43c2c64d 100644
--- a/src/main/java/org/olat/search/service/document/file/FileDocumentFactory.java
+++ b/src/main/java/org/olat/search/service/document/file/FileDocumentFactory.java
@@ -43,6 +43,7 @@ import org.olat.search.SearchModule;
 import org.olat.search.SearchService;
 import org.olat.search.ServiceNotAvailableException;
 import org.olat.search.model.AbstractOlatDocument;
+import org.olat.search.model.OlatDocument;
 import org.olat.search.service.SearchResourceContext;
 import org.olat.search.service.SearchServiceImpl;
 
@@ -100,36 +101,45 @@ public class FileDocumentFactory {
 		return searchModule == null ? 120000 : (int)searchModule.getMaxFileSize();
 	}
 	
-	public Document createDocument(SearchResourceContext leafResourceContext, VFSLeaf leaf)
-	throws IOException, DocumentAccessException {
+	private Document getDocumentFromCurrentIndex(SearchResourceContext leafResourceContext, VFSLeaf leaf) {
 		try {
-			Document doc = null;
-			try {
-				String resourceUrl = leafResourceContext.getResourceUrl();
-				SearchService searchService = CoreSpringFactory.getImpl(SearchServiceImpl.class);
-				
-				Document indexedDoc = searchService.doSearch(resourceUrl);
-				if(indexedDoc != null) {
-					String timestamp = indexedDoc.get(AbstractOlatDocument.TIME_STAMP_NAME);
-					if(timestamp != null) {
-						Date indexLastModification = DateTools.stringToDate(timestamp);
-						Date docLastModificationDate = new Date(leaf.getLastModified());
-						if(leaf instanceof MetaTagged) {
-							MetaInfo metaInfo = ((MetaTagged)leaf).getMetaInfo();
-							Date metaDate = metaInfo.getMetaLastModified();
-							if(metaDate != null && metaDate.after(docLastModificationDate)) {
-								docLastModificationDate = metaDate;
-							}
-						}
-						if(docLastModificationDate.compareTo(indexLastModification) < 0) {
-							return indexedDoc;
+			String resourceUrl = leafResourceContext.getResourceUrl();
+			SearchService searchService = CoreSpringFactory.getImpl(SearchServiceImpl.class);
+			
+			Document indexedDoc = searchService.doSearch(resourceUrl);
+			if(indexedDoc != null) {
+				String timestamp = indexedDoc.get(AbstractOlatDocument.TIME_STAMP_NAME);
+				if(timestamp != null) {
+					Date indexLastModification = DateTools.stringToDate(timestamp);
+					Date docLastModificationDate = new Date(leaf.getLastModified());
+					if(leaf instanceof MetaTagged) {
+						MetaInfo metaInfo = ((MetaTagged)leaf).getMetaInfo();
+						Date metaDate = metaInfo.getMetaLastModified();
+						if(metaDate != null && metaDate.after(docLastModificationDate)) {
+							docLastModificationDate = metaDate;
 						}
 					}
+					if(docLastModificationDate.compareTo(indexLastModification) < 0) {
+						OlatDocument olatDoc = new OlatDocument(indexedDoc);
+						return olatDoc.getLuceneDocument();
+					}
 				}
-			} catch (ServiceNotAvailableException | ParseException | QueryException | java.text.ParseException e) {
-				log.error("", e);
 			}
-			
+		} catch (ServiceNotAvailableException | ParseException | QueryException | java.text.ParseException e) {
+			log.error("", e);
+		}
+		return null;
+	}
+	
+	public Document createDocument(SearchResourceContext leafResourceContext, VFSLeaf leaf)
+	throws IOException, DocumentAccessException {
+		Document indexedDocument = getDocumentFromCurrentIndex(leafResourceContext, leaf);
+		if(indexedDocument != null) {
+			return indexedDocument;
+		}
+
+		try {
+			Document doc = null;
 			String fileName = leaf.getName();
 			String suffix = FileTypeDetector.getSuffix(leaf);
 			if (log.isDebug()) log.debug("suffix=" + suffix);
diff --git a/src/main/java/org/olat/search/service/document/file/HtmlDocument.java b/src/main/java/org/olat/search/service/document/file/HtmlDocument.java
index 0aa234d4be4..acd6481af3c 100644
--- a/src/main/java/org/olat/search/service/document/file/HtmlDocument.java
+++ b/src/main/java/org/olat/search/service/document/file/HtmlDocument.java
@@ -53,7 +53,7 @@ public class HtmlDocument extends FileDocument {
 	
 	public static Document createDocument(SearchResourceContext leafResourceContext, VFSLeaf leaf) throws IOException,DocumentException,DocumentAccessException {
 		HtmlDocument htmlDocument = new HtmlDocument();
-		htmlDocument.init(leafResourceContext,leaf);
+		htmlDocument.init(leafResourceContext, leaf);
 		htmlDocument.setFileType(FILE_TYPE);
 		htmlDocument.setCssIcon(CSSHelper.createFiletypeIconCssClassFor(leaf.getName()));
 		if (log.isDebug() ) log.debug(htmlDocument.toString());
diff --git a/src/main/java/org/olat/search/service/document/file/OpenDocument.java b/src/main/java/org/olat/search/service/document/file/OpenDocument.java
index 91f59ec4a18..b6c083cbeb7 100644
--- a/src/main/java/org/olat/search/service/document/file/OpenDocument.java
+++ b/src/main/java/org/olat/search/service/document/file/OpenDocument.java
@@ -104,7 +104,7 @@ public class OpenDocument extends FileDocument {
 			FileUtils.closeSafely(zip);
 			FileUtils.closeSafely(stream);
 		}
-		return new FileContent(dh.toString());
+		return new FileContent(dh.getContent());
 	}
 	
 	private void parse(InputStream stream, DefaultHandler handler) throws DocumentException {
@@ -144,5 +144,9 @@ public class OpenDocument extends FileDocument {
 			}
 			sb.write(ch, start, length);
 		}
+		
+		public String getContent() {
+			return sb.toString();
+		}
 	}
 }
diff --git a/src/main/java/org/olat/search/service/indexer/AbstractHierarchicalIndexer.java b/src/main/java/org/olat/search/service/indexer/AbstractHierarchicalIndexer.java
index 38debcfc7e2..1ba8d42bfa9 100644
--- a/src/main/java/org/olat/search/service/indexer/AbstractHierarchicalIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/AbstractHierarchicalIndexer.java
@@ -46,7 +46,6 @@ public abstract class AbstractHierarchicalIndexer extends DefaultIndexer {
 	
 	private final List<Indexer> childIndexers = new ArrayList<Indexer>();
 	
-	
 	public List<Indexer> getChildIndexers() {
 		return childIndexers;
 	}
@@ -56,16 +55,17 @@ public abstract class AbstractHierarchicalIndexer extends DefaultIndexer {
 	 * @param indexerList
 	 */
 	public void setIndexerList(List<Indexer> indexerList) {
-		if (indexerList == null)
+		if (indexerList == null) {
 			throw new AssertException("null value for indexerList not allowed.");
+		}
 
 		try {
 			for (Indexer indexer:indexerList) {
 				childIndexers.add(indexer);
 				logDebug("Adding indexer from configuraton. TypeName=" + indexer.getSupportedTypeName());
 			} 
-		}	catch (ClassCastException cce) {
-				throw new StartupException("Configured indexer is not of type Indexer", cce);
+		} catch (ClassCastException cce) {
+			throw new StartupException("Configured indexer is not of type Indexer", cce);
 		}
 	}
 	
@@ -74,7 +74,7 @@ public abstract class AbstractHierarchicalIndexer extends DefaultIndexer {
 			childIndexers.add(indexer);
 			logDebug("Adding indexer from configuraton. TypeName=" + indexer.getSupportedTypeName());
 		}	catch (ClassCastException cce) {
-				throw new StartupException("Configured indexer is not of type Indexer", cce);
+			throw new StartupException("Configured indexer is not of type Indexer", cce);
 		}
 	}
 
@@ -90,7 +90,7 @@ public abstract class AbstractHierarchicalIndexer extends DefaultIndexer {
 			  indexer.doIndex(searchResourceContext, object, indexerWriter);
 			} catch (InterruptedException iex) {
 				throw iex;
-			}	catch (Throwable ex) {
+			} catch (Throwable ex) {
 				// FIXME:chg: Workaround to fix indexing-abort
 				logWarn("Exception in diIndex indexer.typeName=" + indexer.getSupportedTypeName(),ex);
 			}
diff --git a/src/main/java/org/olat/search/service/indexer/LeafIndexer.java b/src/main/java/org/olat/search/service/indexer/LeafIndexer.java
index 03f6211e693..492691c7aa2 100644
--- a/src/main/java/org/olat/search/service/indexer/LeafIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/LeafIndexer.java
@@ -46,7 +46,8 @@ public abstract class LeafIndexer extends AbstractHierarchicalIndexer {
 	protected void doIndexVFSLeafByMySelf(SearchResourceContext leafResourceContext, VFSLeaf leaf, OlatFullIndexer indexWriter, String filePath) throws InterruptedException {
 		if (isLogDebugEnabled()) logDebug("Analyse VFSLeaf=" + leaf.getName());
 		try {
-			if (CoreSpringFactory.getImpl(FileDocumentFactory.class).isFileSupported(leaf)) {
+			FileDocumentFactory documentFactory = CoreSpringFactory.getImpl(FileDocumentFactory.class);
+			if (documentFactory.isFileSupported(leaf)) {
 				String myFilePath = "";
 				if (filePath.endsWith("/")) {
 					myFilePath = filePath + leaf.getName();
@@ -55,7 +56,7 @@ public abstract class LeafIndexer extends AbstractHierarchicalIndexer {
 				}
 				leafResourceContext.setFilePath(myFilePath);
 
-				Document document = CoreSpringFactory.getImpl(FileDocumentFactory.class).createDocument(leafResourceContext, leaf);
+				Document document = documentFactory.createDocument(leafResourceContext, leaf);
 				indexWriter.addDocument(document);
 			} else {
 				if (isLogDebugEnabled()) logDebug("Documenttype not supported. file=" + leaf.getName());
diff --git a/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java
index 57525c7f930..2003a877efe 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java
@@ -127,15 +127,13 @@ public class CourseIndexer extends AbstractHierarchicalIndexer {
 					logWarn("Can not index course node=" + childCourseNode.getIdent(), e);
 				}
 			}
-		} else if (isLogDebugEnabled()) {
-			logDebug("ChildNode is no CourseNode, " + node);
 		}
 		
 		//loop over all child nodes
 		int childCount = node.getChildCount();
 		for (int i=0;i<childCount; i++) {
 			INode childNode = node.getChildAt(i);
-  		doIndexCourse(repositoryResourceContext, course, childNode, indexWriter);
+			doIndexCourse(repositoryResourceContext, course, childNode, indexWriter);
 		}
 	}
 
@@ -169,7 +167,7 @@ public class CourseIndexer extends AbstractHierarchicalIndexer {
 		Long nodeId = bcContextEntry.getOLATResourceable().getResourceableId();
 		if (isLogDebugEnabled()) logDebug("nodeId=" + nodeId );
 		
-		ICourse course = CourseFactory.loadCourse(repositoryEntry.getOlatResource());
+		ICourse course = CourseFactory.loadCourse(repositoryEntry);
 		IdentityEnvironment ienv = new IdentityEnvironment();
 		ienv.setIdentity(identity);
 		ienv.setRoles(roles);
@@ -212,11 +210,9 @@ public class CourseIndexer extends AbstractHierarchicalIndexer {
 	private CourseNodeIndexer getCourseNodeIndexer(CourseNode node) {
 		String courseNodeName = node.getClass().getName();
 		List<Indexer> courseNodeIndexer = getIndexerByType(courseNodeName);
-    if (courseNodeIndexer != null && !courseNodeIndexer.isEmpty()) {
-    	return (CourseNodeIndexer)courseNodeIndexer.get(0);
-    } else if (isLogDebugEnabled()) {
-    	logDebug("No indexer found for node=" + node);
-    }
-    return null;
+		if (courseNodeIndexer != null && !courseNodeIndexer.isEmpty()) {
+			return (CourseNodeIndexer)courseNodeIndexer.get(0);
+		}
+		return null;
 	}
 }
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/AbstractCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/AbstractCourseNodeIndexer.java
new file mode 100644
index 00000000000..bc145275e4a
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/AbstractCourseNodeIndexer.java
@@ -0,0 +1,78 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+import java.io.IOException;
+
+import org.apache.lucene.document.Document;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.id.context.BusinessControl;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.course.ICourse;
+import org.olat.course.nodes.CourseNode;
+import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
+import org.olat.search.service.indexer.OlatFullIndexer;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public abstract class AbstractCourseNodeIndexer implements CourseNodeIndexer {
+	
+	private final String type;
+	private final String supportedType;
+	
+	public AbstractCourseNodeIndexer(String type, String supportedType) {
+		this.type = type;
+		this.supportedType = supportedType;
+	}
+	
+	public String getType() {
+		return type;
+	}
+
+	@Override
+	public String getSupportedTypeName() {
+		return supportedType;
+	}
+
+	@Override
+	public void doIndex(SearchResourceContext searchResourceContext, Object parentObject, OlatFullIndexer indexer)
+	throws IOException, InterruptedException {
+		//
+	}
+	
+	@Override
+	public void doIndex(SearchResourceContext courseResourceContext, ICourse course, CourseNode node, OlatFullIndexer indexWriter)
+	throws IOException, InterruptedException {
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(courseResourceContext, node, getType());
+		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, node);
+		indexWriter.addDocument(document);
+	}
+
+	@Override
+	public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) {
+		return true;
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java
index 179854487ce..020165e9341 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java
@@ -27,11 +27,20 @@ package org.olat.search.service.indexer.repository.course;
 
 import java.io.IOException;
 
-import org.olat.core.commons.modules.bc.vfs.OlatNamedContainerImpl;
+import org.apache.lucene.document.Document;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.id.context.BusinessControl;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.util.vfs.NamedContainerImpl;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.BCCourseNode;
 import org.olat.course.nodes.CourseNode;
+import org.olat.course.nodes.bc.BCCourseNodeEditController;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.FolderIndexer;
 import org.olat.search.service.indexer.FolderIndexerAccess;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -43,7 +52,7 @@ import org.olat.search.service.indexer.OlatFullIndexer;
 public class BCCourseNodeIndexer extends FolderIndexer implements CourseNodeIndexer {
 
 	// Must correspond with LocalString_xx.properties
-	// Do not use '_' because we want to seach for certain documenttype and lucene haev problems with '_' 
+	// Do not use '_' because we want to seach for certain documenttype and lucene have problems with '_' 
 	public static final String TYPE = "type.course.node.bc";
 
 	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.BCCourseNode";
@@ -51,19 +60,45 @@ public class BCCourseNodeIndexer extends FolderIndexer implements CourseNodeInde
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
 		if (isLogDebugEnabled()) logDebug("Index Briefcase..." );
-
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-    	courseNodeResourceContext.setBusinessControlFor(courseNode);
-    	courseNodeResourceContext.setDocumentType(TYPE);
-    	courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-    	courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-
-		OlatNamedContainerImpl namedContainer = BCCourseNode.getNodeFolderContainer((BCCourseNode) courseNode, course.getCourseEnvironment());
-		doIndexVFSContainer(courseNodeResourceContext,namedContainer,indexWriter,"", FolderIndexerAccess.FULL_ACCESS);
+		
+		BCCourseNode bcNode = (BCCourseNode)courseNode;
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, bcNode, TYPE);
+		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, bcNode);
+		indexWriter.addDocument(document);
+		
+		VFSContainer bcContainer = null;
+		
+		if(bcNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){
+			bcContainer = BCCourseNode.getNodeFolderContainer(bcNode, course.getCourseEnvironment());
+		} else {
+			String subpath = courseNode.getModuleConfiguration().getStringValue(BCCourseNodeEditController.CONFIG_SUBPATH);
+			if(subpath != null) {
+				VFSItem item = course.getCourseEnvironment().getCourseFolderContainer().resolve(subpath);
+				if(item instanceof VFSContainer){
+					bcContainer = new NamedContainerImpl(courseNode.getShortTitle(), (VFSContainer) item);
+				}
+			}
+		}
+		
+		if(bcContainer != null) {
+			doIndexVFSContainer(courseNodeResourceContext, bcContainer, indexWriter, "", FolderIndexerAccess.FULL_ACCESS);
+		}
 	}
 
 	@Override
 	public String getSupportedTypeName() {
 		return SUPPORTED_TYPE_NAME;
 	}
+
+	@Override
+	public boolean checkAccess(BusinessControl businessControl, Identity identity, Roles roles) {
+		return super.checkAccess(businessControl, identity, roles);
+	}
+
+	@Override
+	public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) {
+		return super.checkAccess(contextEntry, businessControl, identity, roles);
+	}
+	
+	
 }
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java
new file mode 100644
index 00000000000..a34d8f82ef7
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java
@@ -0,0 +1,38 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BasicLTICourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.lti";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.BasicLTICourseNode";
+	
+	public BasicLTICourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java
new file mode 100644
index 00000000000..3d75400c63c
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class COCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.co";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.COCourseNode";
+	
+	public COCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CPCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CPCourseNodeIndexer.java
index 45f2d2439a9..8e72cd2afc2 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/CPCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/CPCourseNodeIndexer.java
@@ -28,6 +28,7 @@ package org.olat.search.service.indexer.repository.course;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.lucene.document.Document;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.ICourse;
@@ -36,6 +37,7 @@ import org.olat.course.nodes.cp.CPEditController;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.repository.RepositoryEntry;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.FolderIndexer;
 import org.olat.search.service.indexer.FolderIndexerAccess;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -55,14 +57,12 @@ public class CPCourseNodeIndexer extends FolderIndexer implements CourseNodeInde
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter)
 	throws IOException,InterruptedException  {
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
+		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(document);
+		
 	    RepositoryEntry re = CPEditController.getCPReference(courseNode.getModuleConfiguration(), false);
 	    if(re != null) {
-	    	SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-	    	courseNodeResourceContext.setBusinessControlFor(courseNode);
-	    	courseNodeResourceContext.setDocumentType(TYPE);
-	    	courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-	    	courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-    
 	    	File cpRoot = FileResourceManager.getInstance().unzipFileResource(re.getOlatResource());
 	    	if(cpRoot != null) {
 	    		VFSContainer rootContainer = new LocalFolderImpl(cpRoot);
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CalCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CalCourseNodeIndexer.java
new file mode 100644
index 00000000000..0e415fd0a0f
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/CalCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CalCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.cal";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.CalCourseNode";
+	
+	public CalCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java
new file mode 100644
index 00000000000..58f3c5d595f
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CheckListCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.checklist";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.CheckListCourseNode";
+	
+	public CheckListCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java
index 3e5f140f430..5739b590aa2 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java
@@ -28,6 +28,7 @@ package org.olat.search.service.indexer.repository.course;
 
 import java.io.IOException;
 
+import org.olat.core.util.StringHelper;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.search.service.SearchResourceContext;
@@ -42,4 +43,16 @@ public interface CourseNodeIndexer extends Indexer {
 	
 	public void doIndex(SearchResourceContext searchResourceContext, ICourse course, CourseNode node, OlatFullIndexer indexWriter) throws IOException,InterruptedException;
 
+	
+	public default SearchResourceContext createSearchResourceContext(SearchResourceContext courseResourceContext, CourseNode node, String type) {
+		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(courseResourceContext);
+    	courseNodeResourceContext.setBusinessControlFor(node);
+    	courseNodeResourceContext.setDocumentType(type);
+    	if(StringHelper.containsNonWhitespace(node.getShortTitle())) {
+    		courseNodeResourceContext.setTitle(node.getShortTitle());
+    	} else if(StringHelper.containsNonWhitespace(node.getLongTitle())) {
+    		courseNodeResourceContext.setTitle(node.getLongTitle());
+    	}
+		return courseNodeResourceContext;
+	}
 }
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java
new file mode 100644
index 00000000000..0cc8b2b60d8
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class DENCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.den";
+
+	private final static String SUPPORTED_TYPE_NAME = "de.bps.course.nodes.DENCourseNode";
+	
+	public DENCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
index 5f69ec1b34b..21fcae12146 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
@@ -55,6 +55,7 @@ import org.olat.modules.fo.Message;
 import org.olat.modules.fo.Status;
 import org.olat.modules.fo.manager.ForumManager;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.document.ForumMessageDocument;
 import org.olat.search.service.document.file.DocumentAccessException;
 import org.olat.search.service.document.file.FileDocumentFactory;
@@ -81,11 +82,10 @@ public class DialogCourseNodeIndexer extends DefaultIndexer implements CourseNod
 
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-		courseNodeResourceContext.setBusinessControlFor(courseNode);
-		courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-		courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-    
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, null);
+		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(document);
+		
 		CoursePropertyManager coursePropMgr = course.getCourseEnvironment().getCoursePropertyManager();
 		DialogElementsPropertyManager dialogElmsMgr = DialogElementsPropertyManager.getInstance();
 		DialogPropertyElements elements = dialogElmsMgr.findDialogElements(coursePropMgr, courseNode);
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java
new file mode 100644
index 00000000000..7735b2edd70
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ENCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.en";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.ENCourseNode";
+	
+	public ENCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java
index cf73e575a9d..44b10763782 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java
@@ -27,6 +27,7 @@ package org.olat.search.service.indexer.repository.course;
 
 import java.io.IOException;
 
+import org.apache.lucene.document.Document;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.core.id.Identity;
@@ -45,6 +46,7 @@ import org.olat.modules.fo.Status;
 import org.olat.modules.fo.manager.ForumManager;
 import org.olat.properties.Property;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.ForumIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
 
@@ -63,11 +65,10 @@ public class FOCourseNodeIndexer extends ForumIndexer implements CourseNodeIndex
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) {
 		try {
-			SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-			courseNodeResourceContext.setBusinessControlFor(courseNode);
-			courseNodeResourceContext.setDocumentType(TYPE);
-			courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-			courseNodeResourceContext.setDescription(courseNode.getLongTitle());
+			SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
+			Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+			indexWriter.addDocument(document);
+			
 			doIndexForum(courseNodeResourceContext, course, courseNode, indexWriter);
 		} catch(Exception ex) {
 			log.error("Exception indexing courseNode=" + courseNode, ex);
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java
new file mode 100644
index 00000000000..a8cf9940c33
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class GTACourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.gta";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.GTACourseNode";
+	
+	public GTACourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java
new file mode 100644
index 00000000000..6cf0ed37040
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class GoToMeetingCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.gotomeeting";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.GoToMeetingCourseNode";
+	
+	public GoToMeetingCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/IQSELFCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/IQSELFCourseNodeIndexer.java
new file mode 100644
index 00000000000..b3e0e522c3d
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/IQSELFCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class IQSELFCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.iqself";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.IQSELFCourseNode";
+	
+	public IQSELFCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java
new file mode 100644
index 00000000000..36a1bc1002f
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class IQSURVCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.iqsurv";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.IQSURVCourseNode";
+	
+	public IQSURVCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java
new file mode 100644
index 00000000000..23a3c41b0c3
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class IQTESTCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.iqtest";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.IQTESTCourseNode";
+	
+	public IQTESTCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
index 57372eaf3a3..911f50bb9a1 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
@@ -38,6 +38,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.document.InfoMessageDocument;
 import org.olat.search.service.indexer.DefaultIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -74,14 +75,14 @@ public class InfoCourseNodeIndexer extends DefaultIndexer  implements CourseNode
 		//
 	}
 
+	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) {
 		try {
-			SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-	    courseNodeResourceContext.setBusinessControlFor(courseNode);
-	    courseNodeResourceContext.setDocumentType(TYPE);
-	    courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-	    courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-	    doIndexInfos(courseNodeResourceContext, course, courseNode, indexWriter);
+			SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
+			Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+			indexWriter.addDocument(document);
+			
+			doIndexInfos(courseNodeResourceContext, course, courseNode, indexWriter);
 		} catch(Exception ex) {
 			log.error("Exception indexing courseNode=" + courseNode, ex);
 		} catch (Error err) {
@@ -89,6 +90,7 @@ public class InfoCourseNodeIndexer extends DefaultIndexer  implements CourseNode
 		}
 	}
 
+	@Override
 	public String getSupportedTypeName() {
 		return SUPPORTED_TYPE_NAME;
 	}
@@ -101,7 +103,7 @@ public class InfoCourseNodeIndexer extends DefaultIndexer  implements CourseNode
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(InfoMessage.class, message.getKey());
 			searchResourceContext.setBusinessControlFor(ores);
 			Document document = InfoMessageDocument.createDocument(searchResourceContext, message);
-		  indexWriter.addDocument(document);
+			indexWriter.addDocument(document);
 		}
 	}
 }
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/LLCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/LLCourseNodeIndexer.java
new file mode 100644
index 00000000000..078eb78343f
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/LLCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class LLCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.ll";
+
+	private final static String SUPPORTED_TYPE_NAME = "de.bps.course.nodes.LLCourseNode";
+	
+	public LLCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java
new file mode 100644
index 00000000000..cfb36dab8b0
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MSCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.ms";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.MSCourseNode";
+	
+	public MSCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java
new file mode 100644
index 00000000000..3fe92d6833c
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MembersCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.membersCourseNodeConf";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.MembersCourseNode";
+	
+	public MembersCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/OpenMeetingsCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/OpenMeetingsCourseNodeIndexer.java
new file mode 100644
index 00000000000..4a919998533
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/OpenMeetingsCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OpenMeetingsCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.openmeetings";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.OpenMeetingsCourseNode";
+	
+	public OpenMeetingsCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/PFCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/PFCourseNodeIndexer.java
new file mode 100644
index 00000000000..6091625ed84
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/PFCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class PFCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.pf";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.PFCourseNode";
+	
+	public PFCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java
index 26d259a29ef..0fdc83fe704 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java
@@ -31,6 +31,7 @@ import org.olat.portfolio.model.structel.PortfolioStructure;
 import org.olat.repository.RepositoryEntry;
 import org.olat.resource.OLATResource;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.document.PortfolioMapDocument;
 import org.olat.search.service.indexer.DefaultIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -84,20 +85,17 @@ public class PortfolioCourseNodeIndexer extends DefaultIndexer implements Course
 	throws IOException, InterruptedException {
 		if(!portfolioModule.isEnabled()) return;
 		
-    PortfolioCourseNode portfolioNode = (PortfolioCourseNode)courseNode;
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(searchResourceContext, courseNode, NODE_TYPE);
+		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(document);
+		
+		PortfolioCourseNode portfolioNode = (PortfolioCourseNode)courseNode;
 		RepositoryEntry repoEntry = portfolioNode.getReferencedRepositoryEntry();
 		if(repoEntry != null) {
 			OLATResource ores = repoEntry.getOlatResource();
 			PortfolioStructure element = structureManager.loadPortfolioStructure(ores);
-			
-			SearchResourceContext courseNodeResourceContext = new SearchResourceContext(searchResourceContext);
-	    courseNodeResourceContext.setBusinessControlFor(courseNode);
-	    courseNodeResourceContext.setDocumentType(NODE_TYPE);
-			courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-	    courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-
-			Document document = PortfolioMapDocument.createDocument(courseNodeResourceContext, element);
-			indexWriter.addDocument(document);
+			Document pDocument = PortfolioMapDocument.createDocument(courseNodeResourceContext, element);
+			indexWriter.addDocument(pDocument);
 		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java
index a0e3052f7d1..920ed0b45ba 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java
@@ -26,7 +26,6 @@
 package org.olat.search.service.indexer.repository.course;
 
 import java.io.IOException;
-import java.util.Iterator;
 import java.util.List;
 
 import org.apache.lucene.document.Document;
@@ -39,6 +38,7 @@ import org.olat.course.nodes.projectbroker.datamodel.Project;
 import org.olat.course.nodes.projectbroker.service.ProjectBrokerManager;
 import org.olat.course.properties.CoursePropertyManager;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.document.ProjectBrokerProjectDocument;
 import org.olat.search.service.indexer.AbstractHierarchicalIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -56,20 +56,17 @@ public class ProjectBrokerCourseNodeIndexer extends AbstractHierarchicalIndexer
 
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-		courseNodeResourceContext.setBusinessControlFor(courseNode);
-		courseNodeResourceContext.setDocumentType(TYPE);
-		courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-		courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-       
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
+		Document nodeDocument = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(nodeDocument);
+		
 		// go further, index my projects
 		CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();
 		ProjectBrokerManager projectBrokerManager = CoreSpringFactory.getImpl(ProjectBrokerManager.class);
 		Long projectBrokerId = projectBrokerManager.getProjectBrokerId(cpm, courseNode);
 		if (projectBrokerId != null) {
 			List<Project> projects = projectBrokerManager.getProjectListBy(projectBrokerId);
-			for (Iterator<Project> iterator = projects.iterator(); iterator.hasNext();) {
-				Project project = iterator.next();
+			for (Project project: projects) {
 				Document document = ProjectBrokerProjectDocument.createDocument(courseNodeResourceContext, project);
 				indexWriter.addDocument(document);
 			}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/SPCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/SPCourseNodeIndexer.java
index 624ef12c181..54037dd3e9e 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/SPCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/SPCourseNodeIndexer.java
@@ -34,17 +34,18 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.lucene.document.Document;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 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.VFSManager;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.sp.SPEditController;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.LeafIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
 
@@ -66,15 +67,13 @@ public class SPCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 	private static final String HTML_SUFFIXES = "html htm xhtml xml";
 
 	@Override
-	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
+	public void doIndex(SearchResourceContext courseResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
 		if (log.isDebug()) log.debug("Index SinglePage...");
 
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-		courseNodeResourceContext.setBusinessControlFor(courseNode);
-		courseNodeResourceContext.setDocumentType(TYPE);
-		courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-		courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(courseResourceContext, courseNode, TYPE);
+		Document nodeDocument = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(nodeDocument);
+		
 		// The root of the configured single page. Depends on the configuration
 		// whether to follow relative links or not. When relative links are
 		// followed, the root is the course folder root, if not, it is folder
@@ -85,10 +84,6 @@ public class SPCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 		
 		// Read the course node configuration
 		VFSContainer courseFolderContainer = course.getCourseEnvironment().getCourseFolderContainer();
-//		String path = course.getCourseEnvironment().getCourseBaseContainer().getRelPath() + "/coursefolder";
-//		VFSContainer courseFolderContainer = new OlatRootFolderImpl(path, null);
-		
-		
 		boolean allowRelativeLinks = courseNode.getModuleConfiguration().getBooleanSafe(SPEditController.CONFIG_KEY_ALLOW_RELATIVE_LINKS);
 		String fileName = (String) courseNode.getModuleConfiguration().get(SPEditController.CONFIG_KEY_FILE);
 
@@ -99,7 +94,7 @@ public class SPCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 			rootContainer = courseFolderContainer;
 			chosenFile = fileName;
 		} else {
-			// Csae 2: relative links are NOT allowed. We have to calculate the
+			// Case 2: relative links are NOT allowed. We have to calculate the
 			// new root and remove the relative path to the course folder form
 			// the file.
 			String startURI = ( (fileName.charAt(0) == '/')? fileName.substring(1) : fileName);
@@ -118,21 +113,15 @@ public class SPCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 			}
 			chosenFile = startURI;
 		}
-		
-		// First: Index configured HTML file
-		if (log.isDebug()) {
-			log.debug("-------------------- Indexing course node::" + courseNode.getIdent() + "  " + courseNode.getShortName());
-			log.debug("Config: allow relative links::" + allowRelativeLinks);
-			log.debug("Config: filename::" + fileName);
-			log.debug("Base dir::" + VFSManager.getRealPath(rootContainer));
-			log.debug("chosenFile::" + chosenFile);
-		}
+
 		VFSLeaf leaf = (VFSLeaf)rootContainer.resolve(chosenFile);
 		if (leaf != null) {
 			String filePath = getPathFor(leaf);
-			if (log.isDebug()) log.debug("Found chosen file in SP. filePath=" + filePath );
 			// Use inherited method from LeafIndexer for the actual indexing of the content 
-			doIndexVFSLeafByMySelf(courseNodeResourceContext, leaf, indexWriter, filePath);
+
+			SearchResourceContext fileContext = new SearchResourceContext(courseNodeResourceContext);
+			doIndexVFSLeafByMySelf(fileContext, leaf, indexWriter, filePath);
+			
 			if (!indexOnlyChosenFile) {
 				if (log.isDebug()) log.debug("Index sub pages in SP.");
 				Set<String> alreadyIndexFileNames = new HashSet<String>();
@@ -147,6 +136,7 @@ public class SPCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 		}
 	}
 
+	@Override
 	public String getSupportedTypeName() {
 		return SUPPORTED_TYPE_NAME;
 	}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/STCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/STCourseNodeIndexer.java
index 7a9ffc0a9e9..0925c35f5af 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/STCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/STCourseNodeIndexer.java
@@ -64,12 +64,7 @@ public class STCourseNodeIndexer extends LeafIndexer implements CourseNodeIndexe
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter)
 	throws IOException,InterruptedException {
 		if (log.isDebug()) log.debug("Index StructureNode...");
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-		courseNodeResourceContext.setBusinessControlFor(courseNode);
-		courseNodeResourceContext.setDocumentType(TYPE);
-		courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-		courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-    
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
 		Document document = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
 		indexWriter.addDocument(document);
 		
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ScormCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ScormCourseNodeIndexer.java
index a6878989c3a..9a8bbffd92f 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/ScormCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/ScormCourseNodeIndexer.java
@@ -22,12 +22,14 @@ package org.olat.search.service.indexer.repository.course;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.lucene.document.Document;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.repository.RepositoryEntry;
 import org.olat.resource.OLATResource;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.OlatFullIndexer;
 import org.olat.search.service.indexer.repository.ScormRepositoryIndexer;
 
@@ -47,18 +49,14 @@ public class ScormCourseNodeIndexer extends ScormRepositoryIndexer implements Co
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter)
 			throws IOException, InterruptedException {
-
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, NODE_TYPE);
+		Document nodeDocument = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(nodeDocument);
+		
 		RepositoryEntry repoEntry = courseNode.getReferencedRepositoryEntry();
 		if(repoEntry != null) {
-			SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-			courseNodeResourceContext.setBusinessControlFor(courseNode);
-			courseNodeResourceContext.setDocumentType(NODE_TYPE);
-			courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-			courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-			
 			OLATResource ores = repoEntry.getOlatResource();
 			File cpRoot = FileResourceManager.getInstance().unzipFileResource(ores);
-			
 			doIndex(courseNodeResourceContext, indexWriter, cpRoot);
 		}
 	}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java
index ae3ba59f83d..6fbe0c0d21f 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java
@@ -28,6 +28,7 @@ package org.olat.search.service.indexer.repository.course;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.lucene.document.Document;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
@@ -38,6 +39,7 @@ import org.olat.course.nodes.ta.DropboxController;
 import org.olat.course.nodes.ta.ReturnboxController;
 import org.olat.course.nodes.ta.SolutionController;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.indexer.FolderIndexer;
 import org.olat.search.service.indexer.FolderIndexerAccess;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -58,11 +60,10 @@ public class TACourseNodeIndexer extends FolderIndexer implements CourseNodeInde
 
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) throws IOException,InterruptedException  {
-		SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-		courseNodeResourceContext.setBusinessControlFor(courseNode);
-		courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-		courseNodeResourceContext.setDescription(courseNode.getLongTitle());
-    
+		SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, null);
+		Document nodeDocument = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+		indexWriter.addDocument(nodeDocument);
+		
 		// Index Task
 		File fTaskfolder = new File(FolderConfig.getCanonicalRoot() + TACourseNode.getTaskFolderPathRelToFolderRoot(course.getCourseEnvironment(), courseNode));
 		VFSContainer taskRootContainer = new LocalFolderImpl(fTaskfolder);
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/TUCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/TUCourseNodeIndexer.java
new file mode 100644
index 00000000000..ae73d3ccde2
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/TUCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class TUCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.tu";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.TUCourseNode";
+	
+	public TUCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/VCCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/VCCourseNodeIndexer.java
new file mode 100644
index 00000000000..4e0be7dd921
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/VCCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VCCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.vc";
+
+	private final static String SUPPORTED_TYPE_NAME = "de.bps.course.nodes.VCCourseNode";
+	
+	public VCCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/VideoCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/VideoCourseNodeIndexer.java
new file mode 100644
index 00000000000..a84ca5963d0
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/VideoCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VideoCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.video";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.VideoCourseNode";
+	
+	public VideoCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java
new file mode 100644
index 00000000000..433644d3cc6
--- /dev/null
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java
@@ -0,0 +1,37 @@
+/**
+ * <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.search.service.indexer.repository.course;
+
+/**
+ * 
+ * Initial date: 20 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ViteroCourseNodeIndexer extends AbstractCourseNodeIndexer {
+	
+	public static final String TYPE = "type.course.node.vitero";
+
+	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.ViteroCourseNode";
+	
+	public ViteroCourseNodeIndexer() {
+		super(TYPE, SUPPORTED_TYPE_NAME);
+	}
+}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/WikiCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/WikiCourseNodeIndexer.java
index aa1678b1ffd..56e5f4c3a6e 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/WikiCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/WikiCourseNodeIndexer.java
@@ -37,6 +37,7 @@ import org.olat.modules.wiki.WikiManager;
 import org.olat.modules.wiki.WikiPage;
 import org.olat.repository.RepositoryEntry;
 import org.olat.search.service.SearchResourceContext;
+import org.olat.search.service.document.CourseNodeDocument;
 import org.olat.search.service.document.WikiPageDocument;
 import org.olat.search.service.indexer.AbstractHierarchicalIndexer;
 import org.olat.search.service.indexer.OlatFullIndexer;
@@ -56,23 +57,20 @@ public class WikiCourseNodeIndexer extends AbstractHierarchicalIndexer implement
 	
 	@Override
 	public void doIndex(SearchResourceContext repositoryResourceContext, ICourse course, CourseNode courseNode, OlatFullIndexer indexWriter) {
-		if (log.isDebug()) log.debug("Index wiki...");
 		String repoEntryName = "*name not available*";
 		try {
-			RepositoryEntry repositoryEntry = courseNode.getReferencedRepositoryEntry();
-			if(repositoryEntry == null) return;
+			SearchResourceContext courseNodeResourceContext = createSearchResourceContext(repositoryResourceContext, courseNode, TYPE);
+			Document nodeDocument = CourseNodeDocument.createDocument(courseNodeResourceContext, courseNode);
+			indexWriter.addDocument(nodeDocument);
 			
+			RepositoryEntry repositoryEntry = courseNode.getReferencedRepositoryEntry();
+			if(repositoryEntry == null) return;		
 			repoEntryName = repositoryEntry.getDisplayname();
 			Wiki wiki = WikiManager.getInstance().getOrLoadWiki(repositoryEntry.getOlatResource());
 			// loop over all wiki pages
 			List<WikiPage> wikiPageList = wiki.getAllPagesWithContent();
 			for (WikiPage wikiPage : wikiPageList) {
 				try {
-					SearchResourceContext courseNodeResourceContext = new SearchResourceContext(repositoryResourceContext);
-					courseNodeResourceContext.setBusinessControlFor(courseNode);
-					courseNodeResourceContext.setDocumentType(TYPE);
-					courseNodeResourceContext.setTitle(courseNode.getShortTitle());
-					courseNodeResourceContext.setDescription(courseNode.getLongTitle());
 					courseNodeResourceContext.setFilePath(wikiPage.getPageName());
 
 					Document document = WikiPageDocument.createDocument(courseNodeResourceContext, wikiPage);
diff --git a/src/main/java/org/olat/search/ui/SearchInputController.java b/src/main/java/org/olat/search/ui/SearchInputController.java
index ededb34a509..d4fc064f9c3 100644
--- a/src/main/java/org/olat/search/ui/SearchInputController.java
+++ b/src/main/java/org/olat/search/ui/SearchInputController.java
@@ -86,7 +86,6 @@ public class SearchInputController extends FormBasicController implements Generi
 	private static final String FUZZY_SEARCH = "~0.7";
 	private static final String CMD_DID_YOU_MEAN_LINK = "didYouMeanLink-";
 	private static final String SEARCH_STORE_KEY = "search-store-key";
-	private static final String SEARCH_CACHE_KEY = "search-cache-key";
 	
 	private String parentContext;
 	private String documentType;
@@ -103,7 +102,6 @@ public class SearchInputController extends FormBasicController implements Generi
 	protected List<FormLink> didYouMeanLinks;
 	
 	private Map<String,Properties> prefs;
-	private SearchLRUCache searchCache;
 	private SearchClient searchClient;
 	
 	public SearchInputController(UserRequest ureq, WindowControl wControl, String resourceUrl, DisplayOption displayOption) {
@@ -256,12 +254,6 @@ public class SearchInputController extends FormBasicController implements Generi
 			prefs = new HashMap<String,Properties>();
 			ureq.getUserSession().putEntry(SEARCH_STORE_KEY, prefs);
 		}
-		
-		searchCache = (SearchLRUCache)ureq.getUserSession().getEntry(SEARCH_CACHE_KEY);
-		if(searchCache == null) {
-			searchCache = new SearchLRUCache();
-			ureq.getUserSession().putEntry(SEARCH_CACHE_KEY, searchCache);
-		}
 	}
 	
 	@Override
@@ -271,7 +263,7 @@ public class SearchInputController extends FormBasicController implements Generi
 
 	@Override
 	public void formOK(UserRequest ureq) {
-	fireEvent(ureq, QuickSearchEvent.QUICKSEARCH_EVENT);
+		fireEvent(ureq, QuickSearchEvent.QUICKSEARCH_EVENT);
 		doSearch(ureq);
 	}
 	
@@ -477,11 +469,8 @@ public class SearchInputController extends FormBasicController implements Generi
 
 			query = getQueryString(searchString, false);
 			condQueries = getCondQueryStrings(condSearchStrings, parentCtxt, docType, rsrcUrl);
-			SearchResults searchResults = searchCache.get(getQueryCacheKey(firstResult, query, condQueries));
-			if(searchResults == null || true) {
-				searchResults = searchClient.doSearch(query, condQueries, ureq.getIdentity(), ureq.getUserSession().getRoles(), firstResult, maxReturns, true);
-				searchCache.put(getQueryCacheKey(firstResult, query, condQueries), searchResults);
-			}	
+			SearchResults searchResults = searchClient.doSearch(query, condQueries, ureq.getIdentity(), ureq.getUserSession().getRoles(), firstResult, maxReturns, true);
+
 			if (firstResult == 0 && searchResults.size() == 0 && !query.endsWith(FUZZY_SEARCH)) {
 				// result-list was empty => first try to find word via spell-checker
 		    	if (doSpellCheck) {
@@ -519,21 +508,7 @@ public class SearchInputController extends FormBasicController implements Generi
 		hideDidYouMeanWords();
 		String query = getQueryString(searchString, true);
 		List<String> condQueries = getCondQueryStrings(condSearchStrings, parentCtxt, docType, rsrcUrl);
-		SearchResults searchResults = searchCache.get(getQueryCacheKey(firstResult, query, condQueries));
-		if(searchResults == null) {
-			searchResults = searchClient.doSearch(query, condQueries, ureq.getIdentity(), ureq.getUserSession().getRoles(), firstResult, maxReturns, true);
-			searchCache.put(getQueryCacheKey(firstResult, query, condQueries), searchResults);
-		}
-		return searchResults;
-	}
-	
-	private Object getQueryCacheKey(int firstResult, String query, List<String> condQueries) {
-		StringBuilder sb = new StringBuilder();
-		sb.append('[').append(firstResult).append(']').append(query).append(' ');
-		for(String condQuery:condQueries) {
-			sb.append(condQuery).append(' ');
-		}
-		return sb.toString();
+		return searchClient.doSearch(query, condQueries, ureq.getIdentity(), ureq.getUserSession().getRoles(), firstResult, maxReturns, true);
 	}
 	
 	public Set<String> getDidYouMeanWords() {
diff --git a/src/main/java/org/olat/search/ui/StandardResultController.java b/src/main/java/org/olat/search/ui/StandardResultController.java
index 46a538f4137..76c442a5295 100644
--- a/src/main/java/org/olat/search/ui/StandardResultController.java
+++ b/src/main/java/org/olat/search/ui/StandardResultController.java
@@ -133,8 +133,4 @@ public class StandardResultController extends FormBasicController implements Res
 			}
 		}
 	}
-	
-	public FormItem getInitialFormItem() {
-		return flc;
-	}
 }
diff --git a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_de.properties
index 11aae66266e..f7f7f93d15c 100644
--- a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_de.properties
@@ -60,17 +60,37 @@ toolfolder=Ordner
 toolforum=Foren
 type.course.node=Kursbaustein
 type.course.node.bc=Kursbaustein, Ordner
+type.course.node.cal=Kursbaustein, Kalender
 type.course.node.cp=Kursbaustein, CP-Lerninhalt
+type.course.node.checklist=Kurbautein, Checkliste
+type.course.node.co=Kursbaustein, E-Mail
+type.course.node.den=Kursbaustein, Terminvergabe
 type.course.node.dialog.file=Kursbaustein, Dateidiskussion (Datei)
 type.course.node.dialog.forum.message=Kursbaustein Dateidiskussion (Diskussion)
+type.course.node.en=Kursbaustein, Einschreibung
 type.course.node.ep=Kursbaustein, Portfolioaufgabe
+type.course.node.iqself=Kursbaustein, Selbsttest
+type.course.node.iqsurv=Kursbaustein, Fragebogen
+type.course.node.iqtest=Kursbaustein, Test
 type.course.node.forum.message=Kursbaustein, Forum
+type.course.node.gotomeeting=Kursbaustein, GoToMeeting
+type.course.node.gta=Kursbaustein, Aufgabe
+type.course.node.ll=Kursbaustein, Linkliste
+type.course.node.lti=Kursbaustein, LTI-Seite
+type.course.node.membersCourseNodeConf=Kursbaustein, Teilnehmerliste
+type.course.node.ms=Kursbaustein, Bewertung
+type.course.node.openmeetings=Kursbaustein, OpenMeetings
+type.course.node.pf=Kursbaustein, Teilnehmer Ordner
 type.course.node.sp=Kursbaustein, Einzelne Seite
 type.course.node.st=Kursbaustein, Struktur
 type.course.node.ta.dropbox=Kursbaustein, Aufgabe (Abgabeordner)
 type.course.node.ta.returnbox=Kursbaustein, Aufgabe (R\u00FCckgabeordner)
 type.course.node.ta.solutionbox=Kursbaustein, Aufgabe (Musterl\u00F6sung)
 type.course.node.ta.task=Kursbaustein, Aufgabe (Aufgabenordner)
+type.course.node.tu=Kursbaustein, Externe Seite
+type.course.node.vc=Kursbaustein, Virtuelles Klassenzimmer
+type.course.node.video=Kursbaustein, Video
+type.course.node.vitero=Kursbaustein, vitero
 type.course.node.wiki=Kursbaustein, Wiki
 type.course.node.projectbroker=Kursbaustein, Themenb\u00F6rse
 type.course.node.blog=Kursbaustein, Blog
diff --git a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties
index eb277da3f6d..28a25d0024e 100644
--- a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties
@@ -66,10 +66,25 @@ type.course.node=Course element
 type.course.node.bc=Course element, folder
 type.course.node.blog=Course element, blog
 type.course.node.cp=Course element, CP learning content
+type.course.node.checklist=Course element, checklist
+type.course.node.co=Course element, E-mail
+type.course.node.den=Course element, assignment of dates
 type.course.node.dialog.file=Course element, file dialog (file)
 type.course.node.dialog.forum.message=Course element, file dialog (discussion)
+type.course.node.en=Course element, enrolment
 type.course.node.ep=Course element, portfolio task
+type.course.node.iqself=Course element, self-test
+type.course.node.iqsurv=Course element, survey
+type.course.node.iqtest=Course element, test
 type.course.node.forum.message=Course element, forum
+type.course.node.gotomeeting=Course element, GoToMeeting
+type.course.node.gta=Course element, task
+type.course.node.ll=Course element, link list
+type.course.node.lti=Course element, LTI page
+type.course.node.membersCourseNodeConf=Course element, participant list
+type.course.node.ms=Course element, assessment
+type.course.node.openmeetings=Course element, OpenMeetings
+type.course.node.pf=Course element, participant folder
 type.course.node.podcast=Course element, Podcast
 type.course.node.projectbroker=Course element, topic assignment
 type.course.node.scorm=Course element, SCORM
@@ -79,6 +94,10 @@ type.course.node.ta.dropbox=Course element, task (drop box)
 type.course.node.ta.returnbox=Course element, task (return box)
 type.course.node.ta.solutionbox=Course element, task (sample solution)
 type.course.node.ta.task=Course element, task (task folder)
+type.course.node.tu=Course element, external page
+type.course.node.vc=Course element, virtual classroom
+type.course.node.video=Course element, video
+type.course.node.vitero=Course element, vitero
 type.course.node.wiki=Course element, Wiki
 type.db.EPDefaultMap=Portfolio folder
 type.db.EPStructuredMap=Portfolio task
-- 
GitLab