diff --git a/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java b/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java index 1362bf3fcf85f2f0313038f2b533610d783b08a1..2e33fbdee0dcf8689b6f5129e1deee7017ed1ef2 100644 --- a/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java +++ b/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java @@ -33,9 +33,12 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.util.notifications.NotificationsManager; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; import org.springframework.scheduling.quartz.CronTriggerBean; + /** * Description:<br> * Manually trigger sending of notification email which are normally sent only once a day. @@ -74,12 +77,17 @@ public class NotificationsEmailAdminController extends BasicController { * org.olat.core.gui.control.Event) */ @Override - @SuppressWarnings("unused") public void event(UserRequest ureq, Component source, Event event) { if (source == startNotifyButton) { - NotificationsManager.getInstance().notifyAllSubscribersByEmail(); + //trigger the cron job + try { + Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); + JobDetail detail = scheduler.getJobDetail("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); + scheduler.triggerJob(detail.getName(), detail.getGroup()); + } catch (SchedulerException e) { + logError("", e); + } } - } /** diff --git a/src/main/java/org/olat/admin/search/SearchAdminController.java b/src/main/java/org/olat/admin/search/SearchAdminController.java index 367170b5b2c66b70632e2e6492d4fd043f05eded..f8dc8cbaf03f9fc978cfca5e33e954250c591fc7 100644 --- a/src/main/java/org/olat/admin/search/SearchAdminController.java +++ b/src/main/java/org/olat/admin/search/SearchAdminController.java @@ -100,17 +100,19 @@ public class SearchAdminController extends BasicController { putInitialPanel(main); } + protected void doDispose() { + // + } + /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ public void event(UserRequest ureq, Component source, Event event) { if (source == startIndexingButton) { - SearchServiceFactory.getService().startIndexing(); - logInfo("Indexing started via Admin", SearchAdminController.class.getName()); + doStartIndexer(); myContent.setDirty(true); } else if (source == stopIndexingButton) { - SearchServiceFactory.getService().stopIndexing(); - logInfo("Indexing stopped via Admin", SearchAdminController.class.getName()); + doStopIndexer(); myContent.setDirty(true); } } @@ -133,11 +135,13 @@ public class SearchAdminController extends BasicController { } } - /** - * - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - protected void doDispose() { - // + private void doStartIndexer() { + SearchServiceFactory.getService().startIndexing(); + logInfo("Indexing started via Admin", SearchAdminController.class.getName()); + } + + private void doStopIndexer() { + SearchServiceFactory.getService().stopIndexing(); + logInfo("Indexing started via Admin", SearchAdminController.class.getName()); } } diff --git a/src/main/java/org/olat/core/commons/services/search/SearchModule.java b/src/main/java/org/olat/core/commons/services/search/SearchModule.java index b1865bf0bada9cc8d5c0a70ef3bb2e5ef0785b73..a2453eaca62ead938ceb4793fe8d93fbdc48d313 100644 --- a/src/main/java/org/olat/core/commons/services/search/SearchModule.java +++ b/src/main/java/org/olat/core/commons/services/search/SearchModule.java @@ -54,7 +54,6 @@ public class SearchModule extends AbstractOLATModule { public final static String CONF_TEMP_INDEX_PATH = "tempIndexPath"; public final static String CONF_TEMP_SPELL_CHECK_PATH = "tempSpellCheckPath"; public final static String CONF_GENERATE_AT_STARTUP = "generateIndexAtStartup"; - private static final String CONF_RESTART_INTERVAL = "restartInterval"; private static final String CONF_INDEX_INTERVAL = "indexInterval"; private static final String CONF_MAX_HITS = "maxHits"; private static final String CONF_MAX_RESULTS = "maxResults"; @@ -77,7 +76,6 @@ public class SearchModule extends AbstractOLATModule { private static final String CONF_FILE_BLACK_LIST = "fileBlackList"; // Default values - private static final int DEFAULT_RESTART_INTERVAL = 0; private static final int DEFAULT_INDEX_INTERVAL = 0; private static final int DEFAULT_MAX_HITS = 1000; private static final int DEFAULT_MAX_RESULTS = 100; @@ -94,7 +92,6 @@ public class SearchModule extends AbstractOLATModule { private String fullTempIndexPath; private String fullTempSpellCheckPath; private long indexInterval; - private long restartInterval; private boolean generateAtStartup; private int maxHits; private int maxResults; @@ -170,7 +167,6 @@ public class SearchModule extends AbstractOLATModule { fullPdfTextBufferPath = buildPath(tempPdfTextBufferPath); generateAtStartup = getBooleanConfigParameter(CONF_GENERATE_AT_STARTUP, true); - restartInterval = getIntConfigParameter(CONF_RESTART_INTERVAL, DEFAULT_RESTART_INTERVAL); indexInterval = getIntConfigParameter(CONF_INDEX_INTERVAL, DEFAULT_INDEX_INTERVAL); maxHits = getIntConfigParameter(CONF_MAX_HITS, DEFAULT_MAX_HITS); maxResults = getIntConfigParameter(CONF_MAX_RESULTS, DEFAULT_MAX_RESULTS); @@ -280,13 +276,6 @@ public class SearchModule extends AbstractOLATModule { return generateAtStartup; } - /** - * @return Time in millisecond between restart generation of a full-index. - */ - public long getRestartInterval() { - return restartInterval; - } - /** * @return Sleep time in millisecond between indexing documents. */ diff --git a/src/main/java/org/olat/core/commons/services/search/SearchService.java b/src/main/java/org/olat/core/commons/services/search/SearchService.java index d22b89955c73c181b01beca235eac512bb86a662..34feb9ed880f2964e20842887d3aab9b225b59c3 100644 --- a/src/main/java/org/olat/core/commons/services/search/SearchService.java +++ b/src/main/java/org/olat/core/commons/services/search/SearchService.java @@ -28,7 +28,6 @@ package org.olat.core.commons.services.search; import java.util.List; import java.util.Set; -import org.apache.lucene.document.Document; import org.apache.lucene.queryParser.ParseException; import org.olat.core.id.Identity; import org.olat.core.id.Roles; @@ -77,18 +76,6 @@ public interface SearchService { * @return */ public SearchServiceStatus getStatus(); - - /** - * Add a document to existing index. - * @param document New document. - */ - public void addToIndex(Document document); - - /** - * Delete a document in existing index. - * @param document Delete this document. - */ - public void deleteFromIndex(Document document); /** * Get index-interval of running system diff --git a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java index a273947d1b38b214f5f83a47b810b22b4a38deaa..1951dc1ba936da8e2367bf047208e54a0c057e54 100644 --- a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java +++ b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java @@ -71,6 +71,7 @@ public class RestApiLoginFilter implements Filter { private static final String BASIC_AUTH_REALM = "OLAT Rest API"; private static List<String> openUrls; + private static List<String> alwaysEnabledUrls; private static String LOGIN_URL; /** @@ -98,8 +99,9 @@ public class RestApiLoginFilter implements Filter { HttpServletRequest httpRequest = (HttpServletRequest)request; HttpServletResponse httpResponse = (HttpServletResponse)response; + String requestURI = httpRequest.getRequestURI(); RestModule restModule = (RestModule)CoreSpringFactory.getBean("restModule"); - if(!restModule.isEnabled()) { + if(!restModule.isEnabled() && !isRequestURIAlwaysEnabled(requestURI)) { httpResponse.sendError(403); return; } @@ -114,7 +116,6 @@ public class RestApiLoginFilter implements Filter { //use the available session followSession(httpRequest, httpResponse, chain); } else { - String requestURI = httpRequest.getRequestURI(); if(requestURI.startsWith(getLoginUrl())) { followForAuthentication(requestURI, uress, httpRequest, httpResponse, chain); } else if(isRequestURIInOpenSpace(requestURI)) { @@ -209,6 +210,15 @@ public class RestApiLoginFilter implements Filter { return false; } + private boolean isRequestURIAlwaysEnabled(String requestURI) { + for(String openURI : getAlwaysEnabledURIs()) { + if(requestURI.startsWith(openURI)) { + return true; + } + } + return false; + } + private void followForAuthentication(String requestURI, UserSession uress, HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { //create a session for login without security check @@ -319,6 +329,19 @@ public class RestApiLoginFilter implements Filter { return LOGIN_URL; } + private List<String> getAlwaysEnabledURIs() { + if(alwaysEnabledUrls == null) { + String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT); + alwaysEnabledUrls = new ArrayList<String>(); + alwaysEnabledUrls.add(context + "/i18n"); + alwaysEnabledUrls.add(context + "/api"); + alwaysEnabledUrls.add(context + "/ping"); + alwaysEnabledUrls.add(context + "/openmeetings"); + alwaysEnabledUrls.add(context + "/system"); + } + return alwaysEnabledUrls; + } + private List<String> getOpenURIs() { if(openUrls == null) { String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT); diff --git a/src/main/java/org/olat/restapi/system/IndexerWebService.java b/src/main/java/org/olat/restapi/system/IndexerWebService.java new file mode 100644 index 0000000000000000000000000000000000000000..01de03c8078a3eed5763331731d0c0aa7824126a --- /dev/null +++ b/src/main/java/org/olat/restapi/system/IndexerWebService.java @@ -0,0 +1,110 @@ +/** + * <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.restapi.system; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.olat.core.commons.services.search.SearchServiceStatus; +import org.olat.restapi.system.vo.IndexerStatisticsVO; +import org.olat.restapi.system.vo.IndexerStatus; +import org.olat.search.service.SearchServiceFactory; +import org.olat.search.service.SearchServiceStatusImpl; +import org.olat.search.service.indexer.FullIndexerStatus; + +/** + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class IndexerWebService { + + /** + * Return the statistics about the indexer + * @response.representation.200.qname {http://www.example.com}releaseVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The verison of the instance + * @response.representation.200.example {@link org.olat.restapi.system.vo.Examples#SAMPLE_OO_INDEXERSTATSVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + + * @return The statistics about the indexer + */ + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getStatistics() { + IndexerStatisticsVO stats = getIndexerStatistics(); + return Response.ok(stats).build(); + } + + @GET + @Path("status") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getStatus(@Context HttpServletRequest request) { + SearchServiceStatus serviceStatus = SearchServiceFactory.getService().getStatus(); + String status = serviceStatus.getStatus(); + return Response.ok(new IndexerStatus(status)).build(); + } + + @GET + @Path("status") + @Produces({MediaType.TEXT_PLAIN}) + public Response getPlainTextStatus(@Context HttpServletRequest request) { + SearchServiceStatus serviceStatus = SearchServiceFactory.getService().getStatus(); + return Response.ok(serviceStatus.getStatus()).build(); + } + + @POST + @Path("status") + public Response setStatus(@FormParam("status") String status, @Context HttpServletRequest request) { + if(FullIndexerStatus.STATUS_RUNNING.equals(status)) { + SearchServiceFactory.getService().startIndexing(); + } else if(FullIndexerStatus.STATUS_STOPPED.equals(status)) { + SearchServiceFactory.getService().stopIndexing(); + } + return Response.ok().build(); + } + + protected IndexerStatisticsVO getIndexerStatistics() { + IndexerStatisticsVO stats = new IndexerStatisticsVO(); + + SearchServiceStatus status = SearchServiceFactory.getService().getStatus(); + if(status instanceof SearchServiceStatusImpl) { + SearchServiceStatusImpl statusImpl = (SearchServiceStatusImpl)status; + FullIndexerStatus fStatus = statusImpl.getFullIndexerStatus(); + stats.setIndexedDocumentCount(fStatus.getDocumentCount()); + stats.setExcludedDocumentCount(fStatus.getExcludedDocumentCount()); + stats.setIndexSize(fStatus.getIndexSize()); + stats.setIndexingTime(fStatus.getIndexingTime()); + stats.setFullIndexStartedAt(fStatus.getFullIndexStartedAt()); + stats.setDocumentQueueSize(fStatus.getDocumentQueueSize()); + stats.setRunningFolderIndexerCount(fStatus.getNumberRunningFolderIndexer()); + stats.setAvailableFolderIndexerCount(fStatus.getNumberAvailableFolderIndexer()); + stats.setLastFullIndexTime(fStatus.getLastFullIndexTime()); + } + stats.setStatus(status.getStatus()); + return stats; + } +} diff --git a/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java b/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java new file mode 100644 index 0000000000000000000000000000000000000000..7db133f80cbbbb7886cc926d38faf0ac982fe78d --- /dev/null +++ b/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java @@ -0,0 +1,96 @@ +/** + * <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.restapi.system; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.restapi.system.vo.NotificationsStatus; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; + +/** + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class NotificationsAdminWebService { + + private static final OLog log = Tracing.createLoggerFor(NotificationsAdminWebService.class); + + @GET + @Path("status") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getStatus(@Context HttpServletRequest request) { + return Response.ok(new NotificationsStatus(getJobStatus())).build(); + } + + @GET + @Path("status") + @Produces({MediaType.TEXT_PLAIN}) + public Response getPlainTextStatus(@Context HttpServletRequest request) { + return Response.ok(getJobStatus()).build(); + } + + private String getJobStatus() { + try { + Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); + @SuppressWarnings("unchecked") + List<JobExecutionContext> jobs = scheduler.getCurrentlyExecutingJobs(); + for(JobExecutionContext job:jobs) { + if("org.olat.notifications.job.enabled".equals(job.getJobDetail().getName())) { + return "running"; + } + } + return "stopped"; + } catch (SchedulerException e) { + log.error("", e); + return "error"; + } + } + + @POST + @Path("status") + public Response setStatus(@FormParam("status") String status, @Context HttpServletRequest request) { + if("running".equals(status)) { + try { + Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); + JobDetail detail = scheduler.getJobDetail("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); + scheduler.triggerJob(detail.getName(), detail.getGroup()); + } catch (SchedulerException e) { + log.error("", e); + } + } + return Response.ok().build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java b/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java index 553deac27c452f6d65abeae73c4e421926cb8a55..dfa9d9f89f90ef5ce2be1c72b0042d4634887326 100644 --- a/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java +++ b/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java @@ -31,7 +31,6 @@ import javax.ws.rs.core.Response; import org.olat.basesecurity.BaseSecurity; import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.services.search.SearchServiceStatus; import org.olat.core.util.SessionInfo; import org.olat.core.util.UserSession; import org.olat.core.util.session.UserSessionManager; @@ -40,14 +39,10 @@ import org.olat.group.BusinessGroupService; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; -import org.olat.restapi.system.vo.IndexerStatisticsVO; import org.olat.restapi.system.vo.OpenOLATStatisticsVO; import org.olat.restapi.system.vo.RepositoryStatisticsVO; import org.olat.restapi.system.vo.SessionsVO; import org.olat.restapi.system.vo.UserStatisticsVO; -import org.olat.search.service.SearchServiceFactory; -import org.olat.search.service.SearchServiceStatusImpl; -import org.olat.search.service.indexer.FullIndexerStatus; /** * @@ -55,6 +50,8 @@ import org.olat.search.service.indexer.FullIndexerStatus; */ public class OpenOLATStatisticsWebService { + private final IndexerWebService indexerWebService = new IndexerWebService(); + /** * Return the statistics about OpenOLAT, users count, courses count... * @response.representation.200.qname {http://www.example.com}releaseVO @@ -72,7 +69,7 @@ public class OpenOLATStatisticsWebService { stats.setSessions(getSessionsVO()); stats.setUserStatistics(getUserStatistics()); stats.setRepositoryStatistics(getRepositoryStatistics()); - stats.setIndexerStatistics(getIndexerStatistics()); + stats.setIndexerStatistics(indexerWebService.getIndexerStatistics()); return Response.ok(stats).build(); } @@ -122,12 +119,9 @@ public class OpenOLATStatisticsWebService { * @param request The HTTP request * @return The statistics about the indexer */ - @GET @Path("indexer") - @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) - public Response getIndexerStatistics(@Context HttpServletRequest request) { - IndexerStatisticsVO stats = getIndexerStatistics(); - return Response.ok(stats).build(); + public IndexerWebService getIndexerStatistics(@Context HttpServletRequest request) { + return indexerWebService; } /** @@ -171,28 +165,6 @@ public class OpenOLATStatisticsWebService { return stats; } - private IndexerStatisticsVO getIndexerStatistics() { - IndexerStatisticsVO stats = new IndexerStatisticsVO(); - - SearchServiceStatus status = SearchServiceFactory.getService().getStatus(); - if(status instanceof SearchServiceStatusImpl) { - SearchServiceStatusImpl statusImpl = (SearchServiceStatusImpl)status; - FullIndexerStatus fStatus = statusImpl.getFullIndexerStatus(); - stats.setIndexedDocumentCount(fStatus.getDocumentCount()); - stats.setExcludedDocumentCount(fStatus.getExcludedDocumentCount()); - stats.setIndexSize(fStatus.getIndexSize()); - stats.setIndexingTime(fStatus.getIndexingTime()); - stats.setFullIndexStartedAt(fStatus.getFullIndexStartedAt()); - stats.setDocumentQueueSize(fStatus.getDocumentQueueSize()); - stats.setRunningFolderIndexerCount(fStatus.getNumberRunningFolderIndexer()); - stats.setAvailableFolderIndexerCount(fStatus.getNumberAvailableFolderIndexer()); - stats.setLastFullIndexTime(fStatus.getLastFullIndexTime()); - } - stats.setStatus(status.getStatus()); - - return stats; - } - private SessionsVO getSessionsVO() { SessionsVO vo = new SessionsVO(); diff --git a/src/main/java/org/olat/restapi/system/SystemWebService.java b/src/main/java/org/olat/restapi/system/SystemWebService.java index fb3749d45f618cb0953e490a764a69f97bab4ac4..f3b27963c1485d77060a07d6d75dc7b360870d35 100644 --- a/src/main/java/org/olat/restapi/system/SystemWebService.java +++ b/src/main/java/org/olat/restapi/system/SystemWebService.java @@ -118,6 +118,22 @@ public class SystemWebService { return new MonitoringWebService(); } + @Path("indexer") + public IndexerWebService getIndexer(@Context HttpServletRequest request) { + if(!isAdmin(request)) { + return null; + } + return new IndexerWebService(); + } + + @Path("notifications") + public NotificationsAdminWebService getNotifications(@Context HttpServletRequest request) { + if(!isAdmin(request)) { + return null; + } + return new NotificationsAdminWebService(); + } + private boolean isMonitoringEnabled() { MonitoringModule module = CoreSpringFactory.getImpl(MonitoringModule.class); return module.isEnabled(); diff --git a/src/main/java/org/olat/restapi/system/vo/IndexerStatus.java b/src/main/java/org/olat/restapi/system/vo/IndexerStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..0f131a8948cc9562f23ab6f12fe3c5fd9b467aca --- /dev/null +++ b/src/main/java/org/olat/restapi/system/vo/IndexerStatus.java @@ -0,0 +1,56 @@ +/** + * <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.restapi.system.vo; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +import org.olat.core.commons.services.search.SearchServiceStatus; + +/** + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "indexerStatusVO") +public class IndexerStatus implements SearchServiceStatus { + + @XmlAttribute(name="status") + private String status; + + public IndexerStatus() { + // + } + + public IndexerStatus(String status) { + this.status = status; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/src/main/java/org/olat/restapi/system/vo/NotificationsStatus.java b/src/main/java/org/olat/restapi/system/vo/NotificationsStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..25531aa7c8c03a6980a6eb0f486f531997af85a8 --- /dev/null +++ b/src/main/java/org/olat/restapi/system/vo/NotificationsStatus.java @@ -0,0 +1,54 @@ +/** + * <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.restapi.system.vo; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "notificationsStatusVO") +public class NotificationsStatus { + + @XmlAttribute(name="status") + private String status; + + public NotificationsStatus() { + // + } + + public NotificationsStatus(String status) { + this.status = status; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/src/main/java/org/olat/search/_spring/searchContext.xml b/src/main/java/org/olat/search/_spring/searchContext.xml index 21f9378f6aaa0e280aceaca9a2f55a9377cb2615..f8684d98d21de27750eec26f6ba6868872f4c376 100644 --- a/src/main/java/org/olat/search/_spring/searchContext.xml +++ b/src/main/java/org/olat/search/_spring/searchContext.xml @@ -15,6 +15,7 @@ <constructor-arg index="0" ref="searchModule" /> <constructor-arg index="1" ref="mainIndexer" /> <constructor-arg index="2" ref="searchProvider" /> + <constructor-arg index="3" ref="schedulerFactoryBean"/> <!-- When index is older than maxIndexTime in millis, an error will be logged 432000000 = 5d, 86400 = 1d --> <property name="maxIndexTime" value="432000000"/> <property name="metadataFields" ref="SearchMetadataFieldsProvider" /> @@ -69,9 +70,6 @@ <property name="arguments"> <value> generateIndexAtStartup=${generate.index.at.startup} - <!-- restartInterval in ms (0=no restart) - fxdiff FXOLAT-221: start indexer at different times for each instance --> - restartInterval=${search.indexing.restart.interval} tempIndexPath=${search.index.tempIndex} tempSpellCheckPath=${search.index.tempSpellcheck} pdfTextBufferPath=${search.index.pdfBuffer} diff --git a/src/main/java/org/olat/search/service/SearchServiceImpl.java b/src/main/java/org/olat/search/service/SearchServiceImpl.java index 5067b9fc353adb3d546c56f74476144ca5e22900..b2e788c2769c4d2ac6683186965c798990aa42a2 100644 --- a/src/main/java/org/olat/search/service/SearchServiceImpl.java +++ b/src/main/java/org/olat/search/service/SearchServiceImpl.java @@ -34,7 +34,6 @@ import java.util.Set; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.ParseException; @@ -48,6 +47,7 @@ import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; +import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.search.AbstractOlatDocument; import org.olat.core.commons.services.search.SearchModule; import org.olat.core.commons.services.search.SearchResults; @@ -67,7 +67,9 @@ import org.olat.search.service.indexer.MainIndexer; import org.olat.search.service.searcher.JmsSearchProvider; import org.olat.search.service.searcher.SearchResultsImpl; import org.olat.search.service.spell.SearchSpellChecker; -import org.olat.search.service.update.IndexUpdater; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; /** * @@ -78,8 +80,8 @@ public class SearchServiceImpl implements SearchService { private Index indexer; private SearchModule searchModuleConfig; - private IndexUpdater indexUpdater; private MainIndexer mainIndexer; + private Scheduler scheduler; private long maxIndexTime; private Analyzer analyzer; @@ -101,37 +103,49 @@ public class SearchServiceImpl implements SearchService { /** * [used by spring] */ - private SearchServiceImpl(SearchModule searchModule, MainIndexer mainIndexer, JmsSearchProvider searchProvider) { + private SearchServiceImpl(SearchModule searchModule, MainIndexer mainIndexer, JmsSearchProvider searchProvider, Scheduler scheduler) { log.info("Start SearchServiceImpl constructor..."); + this.scheduler = scheduler; this.searchModuleConfig = searchModule; this.mainIndexer = mainIndexer; - analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); + analyzer = new StandardAnalyzer(Version.LUCENE_30); searchProvider.setSearchService(this); - - } - - public void addToIndex(Document document) { - if (indexUpdater==null) throw new AssertException ("Try to call addToIndex() but indexUpdater is null!"); - log.info("addToIndex document=" + document); - indexUpdater.addToIndex(document); } + /** + * Start the job indexer + */ public void startIndexing() { if (indexer==null) throw new AssertException ("Try to call startIndexing() but indexer is null"); - indexer.startFullIndex(); - log.info("startIndexing..."); + + try { + Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); + JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + scheduler.triggerJob(detail.getName(), detail.getGroup()); + log.info("startIndexing..."); + } catch (SchedulerException e) { + log.error("Error trigerring the indexer job: ", e); + } } + /** + * Interrupt the job indexer + */ public void stopIndexing() { if (indexer==null) throw new AssertException ("Try to call stopIndexing() but indexer is null"); - indexer.stopFullIndex(); - log.info("stopIndexing."); - } - public void deleteFromIndex(Document document) { - if (indexUpdater==null) throw new AssertException ("Try to call deleteFromIndex() but indexUpdater is null"); - log.info("deleteFromIndex document=" + document); - indexUpdater.deleteFromIndex(document); + try { + Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); + JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + scheduler.interrupt(detail.getName(), detail.getGroup()); + log.info("stopIndexing."); + } catch (SchedulerException e) { + log.error("Error interrupting the indexer job: ", e); + } + } + + public Index getInternalIndexer() { + return indexer; } public void init() { @@ -140,7 +154,6 @@ public class SearchServiceImpl implements SearchService { log.info("Running with indexPath=" + searchModuleConfig.getFullIndexPath()); log.info(" tempIndexPath=" + searchModuleConfig.getFullTempIndexPath()); log.info(" generateAtStartup=" + searchModuleConfig.getGenerateAtStartup()); - log.info(" restartInterval=" + searchModuleConfig.getRestartInterval()); log.info(" indexInterval=" + searchModuleConfig.getIndexInterval()); searchSpellChecker = new SearchSpellChecker(); @@ -149,7 +162,6 @@ public class SearchServiceImpl implements SearchService { searchSpellChecker.setSpellCheckEnabled(searchModuleConfig.getSpellCheckEnabled()); indexer = new Index(searchModuleConfig, searchSpellChecker, mainIndexer); - indexUpdater = new IndexUpdater(searchModuleConfig.getFullIndexPath(), searchModuleConfig.getUpdateInterval()); indexPath = searchModuleConfig.getFullIndexPath(); @@ -160,7 +172,12 @@ public class SearchServiceImpl implements SearchService { } if (startingFullIndexingAllowed()) { - indexer.startFullIndex(); + try { + JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + scheduler.triggerJob(detail.getName(), detail.getGroup()); + } catch (SchedulerException e) { + log.error("", e); + } } log.info("init DONE"); } diff --git a/src/main/java/org/olat/search/service/indexer/OlatFullIndexer.java b/src/main/java/org/olat/search/service/indexer/OlatFullIndexer.java index dadd70dfef08b2470e876e3ad530278505fe024e..ef56dd4ed600e017955d469d2771cf161dd4ff05 100644 --- a/src/main/java/org/olat/search/service/indexer/OlatFullIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/OlatFullIndexer.java @@ -32,13 +32,13 @@ import java.util.List; import java.util.Map; import java.util.Vector; +import org.apache.lucene.LucenePackage; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; -import org.apache.lucene.LucenePackage; import org.apache.lucene.util.Version; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.commons.services.search.OlatDocument; @@ -51,14 +51,14 @@ import org.olat.search.service.SearchResourceContext; * Controls the hole generation of a full-index. Runs in own thread. * @author Christian Guretzki */ -public class OlatFullIndexer implements Runnable { +public class OlatFullIndexer { private OLog log = Tracing.createLoggerFor(OlatFullIndexer.class); /* TODO:chg: define merge-factor in olat-config.*/ private static final int INDEX_MERGE_FACTOR = 1000; - private static final int MAX_SIZE_QUEUE = 10000; + private static final int MAX_SIZE_QUEUE = 500; private int numberIndexWriter = 5; private String tempIndexPath; @@ -67,17 +67,10 @@ public class OlatFullIndexer implements Runnable { * Reference to indexer for done callback. */ private Index index; - - private Thread indexingThread = null; - private IndexWriter indexWriter = null; /** Flag to stop indexing. */ private boolean stopIndexing; - - - /** When restartIndexingWhenFinished is true, the restart interval in ms can be set. */ - private long restartInterval; /** When restartIndexingWhenFinished is true, the restart interval in ms can be set. */ private long indexInterval = 500; @@ -116,7 +109,6 @@ public class OlatFullIndexer implements Runnable { this.index = index; this.mainIndexer = mainIndexer; tempIndexPath = searchModuleConfig.getFullTempIndexPath(); - restartInterval = searchModuleConfig.getRestartInterval(); indexInterval = searchModuleConfig.getIndexInterval(); numberIndexWriter = searchModuleConfig.getNumberIndexWriter(); documentsPerInterval = searchModuleConfig.getDocumentsPerInterval(); @@ -133,19 +125,11 @@ public class OlatFullIndexer implements Runnable { */ public void startIndexing() { // Start updateThread - if ( (indexingThread == null) || !indexingThread.isAlive()) { - if (stopIndexing) { - log.info("start full indexing thread..."); - indexingThread = new Thread(this, "FullIndexer"); - stopIndexing = false; - resetDocumentCounters(); - // Set to lowest priority - indexingThread.setPriority(Thread.MIN_PRIORITY); - indexingThread.setDaemon(true); - indexingThread.start(); - } - } else { - log.debug("indexing allready running"); + if (stopIndexing) { + log.info("start full indexing thread..."); + stopIndexing = false; + resetDocumentCounters(); + run(); } } @@ -153,11 +137,8 @@ public class OlatFullIndexer implements Runnable { * Stop full indexer thread asynchron. */ public void stopIndexing() { - if ( (indexingThread != null) && indexingThread.isAlive()) { - stopIndexing = true; - indexingThread.interrupt(); - if (log.isDebug()) log.debug("stop current indexing when"); - } + stopIndexing = true; + if (log.isDebug()) log.debug("stop current indexing when"); } /** @@ -262,41 +243,30 @@ public class OlatFullIndexer implements Runnable { * @see java.lang.Runnable#run() */ public void run() { - boolean runAgain = true; try { //TODO: Workround : does not start immediately Thread.sleep(10000); - while (runAgain && !this.stopIndexing) { - log.info("full indexing starts... Lucene-version:" + LucenePackage.get().getImplementationVersion()); - fullIndexerStatus.indexingStarted(); - doIndex(); - index.indexingIsDone(); - fullIndexerStatus.indexingFinished(); - log.info("full indexing done in " + fullIndexerStatus.getIndexingTime() + "ms"); - - //OLAT-5630 - dump more infos about the indexer run - for analysis later - FullIndexerStatus status = getStatus(); - log.info("full indexing summary: started: "+status.getFullIndexStartedAt()); - log.info("full indexing summary: counter: "+status.getDocumentCount()); - log.info("full indexing summary: index.per.minute: "+status.getIndexPerMinute()); - log.info("full indexing summary: finished: "+status.getLastFullIndexTime()); - log.info("full indexing summary: time: "+status.getIndexingTime()+" ms"); - log.info("full indexing summary: size: "+status.getIndexSize()); - - log.info("full indexing summary: document counters: "+status.getDocumentCounters()); - log.info("full indexing summary: file type counters:"+status.getFileTypeCounters()); - log.info("full indexing summary: excluded counter: "+status.getExcludedDocumentCount()); - if (restartInterval == 0) { - log.debug("do not run again"); - runAgain = false; - } else { - if (log.isDebug()) log.debug("Indexing sleep=" + restartInterval + "ms"); - fullIndexerStatus.setStatus(FullIndexerStatus.STATUS_SLEEPING); - Thread.sleep(restartInterval); - if (log.isDebug()) log.debug("Restart indexing"); - } - } + log.info("full indexing starts... Lucene-version:" + LucenePackage.get().getImplementationVersion()); + fullIndexerStatus.indexingStarted(); + doIndex(); + index.indexingIsDone(); + fullIndexerStatus.indexingFinished(); + log.info("full indexing done in " + fullIndexerStatus.getIndexingTime() + "ms"); + + //OLAT-5630 - dump more infos about the indexer run - for analysis later + FullIndexerStatus status = getStatus(); + log.info("full indexing summary: started: "+status.getFullIndexStartedAt()); + log.info("full indexing summary: counter: "+status.getDocumentCount()); + log.info("full indexing summary: index.per.minute: "+status.getIndexPerMinute()); + log.info("full indexing summary: finished: "+status.getLastFullIndexTime()); + log.info("full indexing summary: time: "+status.getIndexingTime()+" ms"); + log.info("full indexing summary: size: "+status.getIndexSize()); + + log.info("full indexing summary: document counters: "+status.getDocumentCounters()); + log.info("full indexing summary: file type counters:"+status.getFileTypeCounters()); + log.info("full indexing summary: excluded counter: "+status.getExcludedDocumentCount()); + } catch(InterruptedException iex) { log.info("FullIndexer was interrupted ;" + iex.getMessage()); } catch(Throwable ex) { @@ -308,13 +278,11 @@ public class OlatFullIndexer implements Runnable { } fullIndexerStatus.setStatus(FullIndexerStatus.STATUS_STOPPED); stopIndexing = true; - indexingThread = null; try { log.info("quit indexing run."); } catch (NullPointerException nex) { // no logging available (shut down)=> do nothing } - } /** @@ -331,7 +299,7 @@ public class OlatFullIndexer implements Runnable { Thread.sleep(indexInterval); } else { // do not sleep, check for stopping indexing - if (this.stopIndexing) { + if (stopIndexing) { throw new InterruptedException("Do stop indexing at element=" + indexWriter.maxDoc()); } } @@ -349,7 +317,7 @@ public class OlatFullIndexer implements Runnable { countIndexPerMinute(); if (log.isDebug()) log.debug("documentQueue.add size=" + documentQueue.size()); // check for stopping indexing - if (this.stopIndexing) { + if (stopIndexing) { throw new InterruptedException("Do stop indexing at element=" + indexWriter.maxDoc()); } } diff --git a/src/main/java/org/olat/search/service/indexer/SearchIndexingJob.java b/src/main/java/org/olat/search/service/indexer/SearchIndexingJob.java index cc3c51da890f438e6906df899460311fd4b1f8b5..4b2488fc7579a88e1d94f3fc3e613b85ca65d9f9 100644 --- a/src/main/java/org/olat/search/service/indexer/SearchIndexingJob.java +++ b/src/main/java/org/olat/search/service/indexer/SearchIndexingJob.java @@ -25,11 +25,15 @@ package org.olat.search.service.indexer; import org.olat.core.commons.scheduler.JobWithDB; +import org.olat.core.commons.services.search.SearchService; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.search.service.SearchServiceFactory; +import org.olat.search.service.SearchServiceImpl; +import org.quartz.InterruptableJob; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import org.quartz.UnableToInterruptJobException; /** * Description:<br> @@ -39,7 +43,7 @@ import org.quartz.JobExecutionException; * Initial Date: 09.09.2008 <br> * @author Christian Guretzki */ -public class SearchIndexingJob extends JobWithDB { +public class SearchIndexingJob extends JobWithDB implements InterruptableJob { private OLog log = Tracing.createLoggerFor(SearchIndexingJob.class); /** @@ -49,7 +53,18 @@ public class SearchIndexingJob extends JobWithDB { @Override public void executeWithDB(JobExecutionContext arg0) throws JobExecutionException { log.info("Search indexer started via cronjob."); - SearchServiceFactory.getService().startIndexing(); + SearchService searchService = SearchServiceFactory.getService(); + if(searchService instanceof SearchServiceImpl) { + ((SearchServiceImpl)searchService).getInternalIndexer().startFullIndex(); + } } + @Override + public void interrupt() throws UnableToInterruptJobException { + log.info("Interrupt indexer via quartz."); + SearchService searchService = SearchServiceFactory.getService(); + if(searchService instanceof SearchServiceImpl) { + ((SearchServiceImpl)searchService).getInternalIndexer().stopFullIndex(); + } + } } diff --git a/src/main/java/org/olat/search/service/update/IndexUpdater.java b/src/main/java/org/olat/search/service/update/IndexUpdater.java deleted file mode 100644 index cfa6f357fb1fea5d8eb77935567f0ec31cd0266e..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/search/service/update/IndexUpdater.java +++ /dev/null @@ -1,229 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ - -package org.olat.search.service.update; - -import java.io.File; -import java.util.List; -import java.util.Vector; - -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.document.Document; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.index.Term; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FSDirectory; -import org.apache.lucene.util.Version; -import org.olat.core.commons.services.search.OlatDocument; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; - -/** - * The IndexUpdater thread controls the update of existing search index. - * The update thread could be disabled with config parameter 'updateInterval=0'. - * @author Christian Guretzki - */ -public class IndexUpdater implements Runnable { - private static final int INDEX_MERGE_FACTOR = 1000; - private static OLog log = Tracing.createLoggerFor(IndexUpdater.class); - - private String indexPath; - - private Thread updaterThread = null; - private long updateInterval; - - private boolean stopUpdater; - - private List<Document> updateQueue; - private List<Document> deleteQueue; - - /** - * - * @param indexPath Absolute file-path of existing index-directory which will be updated - * @param updateInterval Updater sleeps this time [ms] between running again. - */ - public IndexUpdater(String indexPath, long updateInterval) { - this.indexPath = indexPath; - updateQueue = new Vector<Document>(); - deleteQueue = new Vector<Document>(); - this.updateInterval = updateInterval; - stopUpdater = true; - if (updateInterval != 0) { - startUpdater(); - } else { - log.info("IndexUpdater is disabled"); - } - } - - /** - * Add new or changed index document to update-queue. - * @param document New or changed index document. - */ - // o_clusterNOK: IndexUpdater is only prove of concept (with groups) and NOT designed for cluster !!! - public void addToIndex(Document document) { - // The IndexUpdate is disabled with updateInterval == 0 => do not add documents - if (updateInterval != 0) { - updateQueue.add(document); - } - } - - /** - * Add index document to delete-queue. - * @param document Delete this index document. - */ - // o_clusterNOK: IndexUpdater is only prove of concept (with groups) and NOT designed for cluster !!! - public void deleteFromIndex(Document document) { - // The IndexUpdate is disabled with updateInterval == 0 => do not add documents - if (updateInterval != 0) { - deleteQueue.add(document); - } - } - - public void run() { - boolean runAgain = true; - try { - while (runAgain && !this.stopUpdater) { - log.info("Updater starts..."); - doUpdate(); - log.info("Updater done "); - if (updateInterval == 0) { - log.debug("do not run again"); - runAgain = false; - } else { - if (log.isDebug()) log.debug("Updater sleep=" + updateInterval + "ms"); - Thread.sleep(updateInterval); - if (log.isDebug()) log.debug("Restart updater"); - } - } - } catch(InterruptedException iex) { - log.info("FullIndexer was interrupted ;" + iex.getMessage()); - } - stopUpdater = true; - log.info("quit indexing run."); - } - - /** - * Check update and delete-queue. Update existing index and writes new index file. - * - */ - private void doUpdate() { - if (!updateQueue.isEmpty() || !deleteQueue.isEmpty()) { - try { - log.info("updateQueue.size=" + updateQueue.size() + " deleteQueue.size" + deleteQueue.size()); - // 0. make copy of queue's and delete it - List<Document> updateCopy; - synchronized (updateQueue) { - updateCopy = new Vector<Document>(updateQueue); - updateQueue.clear(); - } - List<Document> deleteCopy; - synchronized (deleteQueue) { - deleteCopy = new Vector<Document>(deleteQueue); - deleteQueue.clear(); - } - // 1. Open Index Reader - File indexFile = new File(indexPath); - Directory directory = FSDirectory.open(indexFile); - IndexReader indexReader = IndexReader.open(directory); - - log.info("befor delete: indexReader.numDocs()=" + indexReader.numDocs()); - // 2. Delete old Document - // loop over all documents in updateQueue - for (int i = 0; i < updateCopy.size(); i++) { - String resourceUrl = updateCopy.get(i).get(OlatDocument.RESOURCEURL_FIELD_NAME); - Term term = new Term(OlatDocument.RESOURCEURL_FIELD_NAME, resourceUrl ); - log.info("updateQueue:delete documents with resourceUrl=" + resourceUrl ); - indexReader.deleteDocuments(term); - } - // loop over all documents in deleteQueue - for (int i = 0; i < deleteCopy.size(); i++) { - String resourceUrl = deleteCopy.get(i).get(OlatDocument.RESOURCEURL_FIELD_NAME); - Term term = new Term(OlatDocument.RESOURCEURL_FIELD_NAME, resourceUrl ); - log.info("deleteQueue:delete documents with resourceUrl='" + resourceUrl + "'"); - indexReader.deleteDocuments(term); - - } - log.info("after delete: indexReader.numDocs()=" + indexReader.numDocs()); - // 3. Close reader - indexReader.close(); - directory.close(); - - // 4. open writer - IndexWriter indexWriter = new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_CURRENT), false, IndexWriter.MaxFieldLength.UNLIMITED); - indexWriter.setMergeFactor(INDEX_MERGE_FACTOR); //for better performance - // 5. Add new Document - for (int i = 0; i < updateCopy.size(); i++) { - Document document = updateCopy.get(i); - log.info("addDocument:" + document); - indexWriter.addDocument(document); - } - // 6. Close writer - long startOptimizeTime = 0; - if (log.isDebug()) startOptimizeTime = System.currentTimeMillis(); - indexWriter.optimize();// TODO:chg: dauert ev. zulange oder nocht noetig - if (log.isDebug()) log.debug("Optimized in " + (System.currentTimeMillis() - startOptimizeTime) + "ms"); - indexWriter.close(); - } catch (Exception ex) { - log.warn("Exception during doUpdate. ", ex); - } - } else { - log.debug("Queues are ampty."); - } - } - - /** - * Start updater thread. - */ - public void startUpdater() { - // Start updateThread - if ( (updaterThread == null) || !updaterThread.isAlive()) { - log.info("start Updater thread..."); - if (stopUpdater) { - updaterThread = new Thread(this, "Updater"); - stopUpdater = false; - // Set to lowest priority - updaterThread.setPriority(Thread.MIN_PRIORITY); - updaterThread.setDaemon(true); - updaterThread.start(); - } - } else { - if (log.isDebug()) log.debug("Updater allready running"); - } - } - - /** - * Stop update thread asynchron. - */ - public void stopUpdater() { - if (updaterThread.isAlive()) { - stopUpdater = true; - updaterThread.interrupt(); - if (log.isDebug()) log.debug("stop Updater"); - } - } - - -} diff --git a/src/main/java/org/olat/search/service/update/package.html b/src/main/java/org/olat/search/service/update/package.html deleted file mode 100644 index f76e0bbda8dec4db1b20adda65ea63d8a69c6c40..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/search/service/update/package.html +++ /dev/null @@ -1,9 +0,0 @@ -<html> -<head> -</head> - -<body> -This package includes all classes to update an existing index. -Update includes adding new elements, delete existing elements or modify existing index-elements. -</body> -</html> \ No newline at end of file diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index d2bd215ec6f424a62e1cb50f2d6fbbcf4359524f..0bfebbc901135d8f0c4e88e34b5ccb250158bdb5 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -193,6 +193,8 @@ notification.interval.daily=true notification.interval.half-daily=true notification.interval.four-hourly=true notification.interval.two-hourly=true +#notification cron job +notification.cronjob.expression=0 10 */2 * * ? #################################################### # Groups @@ -557,6 +559,8 @@ search.indexing.cronjob=enabled # expression but have set search.indexing.cronjob=enabled, the system will generate a # cron expression that triggers the indexer every four hour depending on your tomcat.id variable search.indexing.cronjob.expression=0 0 3 * * ? +#examples: +# never fire: 0 0 0 1 1 ? 3000 ######################################################################## # REST API diff --git a/src/main/resources/serviceconfig/org/olat/notifications/_spring/olatdefaultconfig.xml b/src/main/resources/serviceconfig/org/olat/notifications/_spring/olatdefaultconfig.xml index e62f85aa925eb22eb04a6c80a057a5b624b1412f..c767c84375e578b19e6dfb1e534279d1324911aa 100644 --- a/src/main/resources/serviceconfig/org/olat/notifications/_spring/olatdefaultconfig.xml +++ b/src/main/resources/serviceconfig/org/olat/notifications/_spring/olatdefaultconfig.xml @@ -30,7 +30,7 @@ As of OLAT 6.3 it's best to let the cronjob run every two hours since users can now choose how often they will get notified. The shortest interval is set to two hours. --> - <property name="cronExpression" value="0 10 */2 * * ?" /> + <property name="cronExpression" value="${notification.cronjob.expression}" /> <!-- OLAT-5093 start delay ensures there's no conflict with server startup and db not being ready yet --> <property name="startDelay" value="300000" />