diff --git a/CHANGES.txt b/CHANGES.txt index 7c1c90eef84..012d62b80e3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -296,6 +296,8 @@ New Features Also includes ability to add your own SolrSpellChecker implementation that plugs in. See http://wiki.apache.org/solr/SpellCheckComponent for more details (Shalin Shekhar Mangar, Bojan Smid, gsingers) + +54. SOLR-423: Added Request Handler close hook notification so that RequestHandlers can be notified when a core is closing. (gsingers, ryan) Changes in runtime behavior 1. SOLR-559: use Lucene updateDocument, deleteDocuments methods. This diff --git a/src/java/org/apache/solr/core/CloseHook.java b/src/java/org/apache/solr/core/CloseHook.java new file mode 100644 index 00000000000..739769d2e4a --- /dev/null +++ b/src/java/org/apache/solr/core/CloseHook.java @@ -0,0 +1,33 @@ +package org.apache.solr.core; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * Interface to request notification when the core is closed. + *

+ * Call {@link org.apache.solr.core.SolrCore#addCloseHook(org.apache.solr.core.CloseHook)} during the {@link org.apache.solr.util.plugin.SolrCoreAware#inform(SolrCore)} method to + * add a close hook to your object. + *

+ * The close hook can be useful for releasing objects related to the request handler (for instance, if you have a JDBC DataSource or something like that) + * + * + */ + + public interface CloseHook { + void close( SolrCore core ); + } diff --git a/src/java/org/apache/solr/core/SolrCore.java b/src/java/org/apache/solr/core/SolrCore.java index 95f0f11b670..c5a9ae231f6 100644 --- a/src/java/org/apache/solr/core/SolrCore.java +++ b/src/java/org/apache/solr/core/SolrCore.java @@ -452,8 +452,14 @@ public final class SolrCore { return factory; } + /** + * Close all resources allocated by the core. + * 1. searcher + * 2. updateHandler + * 3. all CloseHooks will be notified + */ public void close() { - log.info(logid+"CLOSING SolrCore!"); + log.info(logid+" CLOSING SolrCore!"); try { closeSearcher(); } catch (Exception e) { @@ -469,6 +475,11 @@ public final class SolrCore { } catch (Exception e) { SolrException.log(log,e); } + if( closeHooks != null ) { + for( CloseHook hook : closeHooks ) { + hook.close( this ); + } + } } public boolean isClosed() { @@ -478,6 +489,19 @@ public final class SolrCore { @Override protected void finalize() { close(); } + private List closeHooks = null; + + /** + * Add a close callback hook + */ + public void addCloseHook( CloseHook hook ) + { + if( closeHooks == null ) { + closeHooks = new ArrayList(); + } + closeHooks.add( hook ); + } + /** * Returns a Request object based on the admin/pingQuery section * of the Solr config file. diff --git a/src/test/org/apache/solr/core/SolrCoreTest.java b/src/test/org/apache/solr/core/SolrCoreTest.java index 7ece1f9f7d1..88a85ce0016 100755 --- a/src/test/org/apache/solr/core/SolrCoreTest.java +++ b/src/test/org/apache/solr/core/SolrCoreTest.java @@ -22,6 +22,7 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryResponse; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.util.AbstractSolrTestCase; +import org.apache.solr.util.plugin.SolrCoreAware; public class SolrCoreTest extends AbstractSolrTestCase { @@ -34,17 +35,42 @@ public class SolrCoreTest extends AbstractSolrTestCase { EmptyRequestHandler handler1 = new EmptyRequestHandler(); EmptyRequestHandler handler2 = new EmptyRequestHandler(); - + String path = "/this/is A path /that won't be registered!"; SolrRequestHandler old = core.registerRequestHandler( path, handler1 ); assertNull( old ); // should not be anything... - assertEquals( core.getRequestHandlers().get( path ), handler1 ); + assertEquals( core.getRequestHandlers().get( path ), handler1 ); old = core.registerRequestHandler( path, handler2 ); assertEquals( old, handler1 ); // should pop out the old one - assertEquals( core.getRequestHandlers().get( path ), handler2 ); + assertEquals( core.getRequestHandlers().get( path ), handler2 ); + } + + public void testClose() throws Exception { + SolrCore core = h.getCore(); + + ClosingRequestHandler handler1 = new ClosingRequestHandler(); + handler1.inform( core ); + + String path = "/this/is A path /that won't be registered!"; + SolrRequestHandler old = core.registerRequestHandler( path, handler1 ); + assertNull( old ); // should not be anything... + assertEquals( core.getRequestHandlers().get( path ), handler1 ); + core.close(); + assertTrue("Handler not closed", handler1.closed == true); } } +class ClosingRequestHandler extends EmptyRequestHandler implements SolrCoreAware { + boolean closed = false; + + public void inform(SolrCore core) { + core.addCloseHook( new CloseHook() { + public void close(SolrCore core) { + closed = true; + } + }); + } +} /** * An empty handler for testing @@ -55,9 +81,9 @@ class EmptyRequestHandler extends RequestHandlerBase public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { // nothing! } - + @Override public String getDescription() { return null; } @Override public String getSource() { return null; } @Override public String getSourceId() { return null; } - @Override public String getVersion() { return null; } + @Override public String getVersion() { return null; } }