/**
* 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.
*/
package org.apache.solr.handler.admin;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.params.UpdateParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.util.RefCounted;
import org.apache.solr.update.MergeIndexesCommand;
import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.apache.lucene.store.Directory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Set;
/**
* @version $Id: CoreAdminHandler.java 898152 2010-01-12 02:19:56Z ryan $
* @since solr 1.3
*/
public class CoreAdminHandler extends RequestHandlerBase {
protected final CoreContainer coreContainer;
public CoreAdminHandler() {
super();
// Unlike most request handlers, CoreContainer initialization
// should happen in the constructor...
this.coreContainer = null;
}
/**
* Overloaded ctor to inject CoreContainer into the handler.
*
* @param coreContainer Core Container of the solr webapp installed.
*/
public CoreAdminHandler(final CoreContainer coreContainer) {
this.coreContainer = coreContainer;
}
@Override
final public void init(NamedList args) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"CoreAdminHandler should not be configured in solrconf.xml\n" +
"it is a special Handler configured directly by the RequestDispatcher");
}
/**
* The instance of CoreContainer this handler handles. This should be the CoreContainer instance that created this
* handler.
*
* @return a CoreContainer instance
*/
public CoreContainer getCoreContainer() {
return this.coreContainer;
}
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
// Make sure the cores is enabled
CoreContainer cores = getCoreContainer();
if (cores == null) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Core container instance missing");
}
boolean doPersist = false;
// Pick the action
SolrParams params = req.getParams();
CoreAdminAction action = CoreAdminAction.STATUS;
String a = params.get(CoreAdminParams.ACTION);
if (a != null) {
action = CoreAdminAction.get(a);
if (action == null) {
doPersist = this.handleCustomAction(req, rsp);
}
}
if (action != null) {
switch (action) {
case CREATE: {
doPersist = this.handleCreateAction(req, rsp);
break;
}
case RENAME: {
doPersist = this.handleRenameAction(req, rsp);
break;
}
case ALIAS: {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "'ALIAS' is not supported " +
req.getParams().get(CoreAdminParams.ACTION));
}
case UNLOAD: {
doPersist = this.handleUnloadAction(req, rsp);
break;
}
case STATUS: {
doPersist = this.handleStatusAction(req, rsp);
break;
}
case PERSIST: {
doPersist = this.handlePersistAction(req, rsp);
break;
}
case RELOAD: {
doPersist = this.handleReloadAction(req, rsp);
break;
}
case SWAP: {
doPersist = this.handleSwapAction(req, rsp);
break;
}
case MERGEINDEXES: {
doPersist = this.handleMergeAction(req, rsp);
break;
}
default: {
doPersist = this.handleCustomAction(req, rsp);
break;
}
case LOAD:
break;
}
}
// Should we persist the changes?
if (doPersist) {
cores.persist();
rsp.add("saved", cores.getConfigFile().getAbsolutePath());
}
rsp.setHttpCaching(false);
}
protected boolean handleMergeAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
boolean doPersist = false;
SolrParams params = req.getParams();
SolrParams required = params.required();
String cname = required.get(CoreAdminParams.CORE);
SolrCore core = coreContainer.getCore(cname);
if (core != null) {
try {
doPersist = coreContainer.isPersistent();
String[] dirNames = required.getParams(CoreAdminParams.INDEX_DIR);
DirectoryFactory dirFactory = core.getDirectoryFactory();
Directory[] dirs = new Directory[dirNames.length];
for (int i = 0; i < dirNames.length; i++) {
dirs[i] = dirFactory.open(dirNames[i]);
}
UpdateRequestProcessorChain processorChain =
core.getUpdateProcessingChain(params.get(UpdateParams.UPDATE_PROCESSOR));
SolrQueryRequest wrappedReq = new LocalSolrQueryRequest(core, req.getParams());
UpdateRequestProcessor processor =
processorChain.createProcessor(wrappedReq, rsp);
processor.processMergeIndexes(new MergeIndexesCommand(dirs));
} finally {
core.close();
}
}
return doPersist;
}
/**
* Handle Custom Action.
* <p/>
* This method could be overridden by derived classes to handle custom actions. <br> By default - this method throws a
* solr exception. Derived classes are free to write their derivation if necessary.
*/
protected boolean handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported operation: " +
req.getParams().get(CoreAdminParams.ACTION));
}
/**
* Handle 'CREATE' action.
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*
* @throws SolrException in case of a configuration error.
*/
protected boolean handleCreateAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
try {
SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.NAME);
CoreDescriptor dcore = new CoreDescriptor(coreContainer, name, params.get(CoreAdminParams.INSTANCE_DIR));
// fillup optional parameters
String opts = params.get(CoreAdminParams.CONFIG);
if (opts != null)
dcore.setConfigName(opts);
opts = params.get(CoreAdminParams.SCHEMA);
if (opts != null)
dcore.setSchemaName(opts);
opts = params.get(CoreAdminParams.DATA_DIR);
if (opts != null)
dcore.setDataDir(opts);
dcore.setCoreProperties(null);
SolrCore core = coreContainer.create(dcore);
coreContainer.register(name, core, false);
rsp.add("core", core.getName());
return coreContainer.isPersistent();
} catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Error executing default implementation of CREATE", ex);
}
}
/**
* Handle "RENAME" Action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*
* @throws SolrException
*/
protected boolean handleRenameAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.OTHER);
String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = false;
if (cname.equals(name)) return doPersist;
SolrCore core = coreContainer.getCore(cname);
if (core != null) {
doPersist = coreContainer.isPersistent();
coreContainer.register(name, core, false);
coreContainer.remove(cname);
core.close();
}
return doPersist;
}
/**
* Handle "ALIAS" action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/
@Deprecated
protected boolean handleAliasAction(SolrQueryRequest req, SolrQueryResponse rsp) {
SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.OTHER);
String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = false;
if (cname.equals(name)) return doPersist;
SolrCore core = coreContainer.getCore(cname);
if (core != null) {
doPersist = coreContainer.isPersistent();
coreContainer.register(name, core, false);
// no core.close() since each entry in the cores map should increase the ref
}
return doPersist;
}
/**
* Handle "UNLOAD" Action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/
protected boolean handleUnloadAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
SolrParams params = req.getParams();
String cname = params.get(CoreAdminParams.CORE);
SolrCore core = coreContainer.remove(cname);
if(core == null){
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"No such core exists '"+cname+"'");
}
core.close();
return coreContainer.isPersistent();
}
/**
* Handle "STATUS" action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/
protected boolean handleStatusAction(SolrQueryRequest req, SolrQueryResponse rsp)
throws SolrException {
SolrParams params = req.getParams();
String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = false;
NamedList<Object> status = new SimpleOrderedMap<Object>();
try {
if (cname == null) {
for (String name : coreContainer.getCoreNames()) {
status.add(name, getCoreStatus(coreContainer, name));
}
} else {
status.add(cname, getCoreStatus(coreContainer, cname));
}
rsp.add("status", status);
doPersist = false; // no state change
return doPersist;
} catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Error handling 'status' action ", ex);
}
}
/**
* Handler "PERSIST" action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*
* @throws SolrException
*/
protected boolean handlePersistAction(SolrQueryRequest req, SolrQueryResponse rsp)
throws SolrException {
SolrParams params = req.getParams();
boolean doPersist = false;
String fileName = params.get(CoreAdminParams.FILE);
if (fileName != null) {
File file = new File(coreContainer.getConfigFile().getParentFile(), fileName);
coreContainer.persistFile(file);
rsp.add("saved", file.getAbsolutePath());
doPersist = false;
} else if (!coreContainer.isPersistent()) {
throw new SolrException(SolrException.ErrorCode.FORBIDDEN, "Persistence is not enabled");
} else
doPersist = true;
return doPersist;
}
/**
* Handler "RELOAD" action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/
protected boolean handleReloadAction(SolrQueryRequest req, SolrQueryResponse rsp) {
SolrParams params = req.getParams();
String cname = params.get(CoreAdminParams.CORE);
try {
coreContainer.reload(cname);
return false; // no change on reload
} catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error handling 'reload' action", ex);
}
}
/**
* Handle "SWAP" action
*
* @param req
* @param rsp
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/
protected boolean handleSwapAction(SolrQueryRequest req, SolrQueryResponse rsp) {
final SolrParams params = req.getParams();
final SolrParams required = params.required();
final String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = params.getBool(CoreAdminParams.PERSISTENT, coreContainer.isPersistent());
String other = required.get(CoreAdminParams.OTHER);
coreContainer.swap(cname, other);
return doPersist;
}
protected NamedList<Object> getCoreStatus(CoreContainer cores, String cname) throws IOException {
NamedList<Object> info = new SimpleOrderedMap<Object>();
SolrCore core = cores.getCore(cname);
if (core != null) {
try {
info.add("name", core.getName());
info.add("instanceDir", normalizePath(core.getResourceLoader().getInstanceDir()));
info.add("dataDir", normalizePath(core.getDataDir()));
info.add("startTime", new Date(core.getStartTime()));
info.add("uptime", System.currentTimeMillis() - core.getStartTime());
RefCounted<SolrIndexSearcher> searcher = core.getSearcher();
try {
info.add("index", LukeRequestHandler.getIndexInfo(searcher.get().getReader(), false));
} finally {
searcher.decref();
}
} finally {
core.close();
}
}
return info;
}
protected static String normalizePath(String path) {
if (path == null)
return null;
path = path.replace('/', File.separatorChar);
path = path.replace('\\', File.separatorChar);
return path;
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override
public String getDescription() {
return "Manage Multiple Solr Cores";
}
@Override
public String getVersion() {
return "$Revision: 898152 $";
}
@Override
public String getSourceId() {
return "$Id: CoreAdminHandler.java 898152 2010-01-12 02:19:56Z ryan $";
}
@Override
public String getSource() {
return "$URL: https://svn.apache.org/repos/asf/lucene/dev/trunk/solr/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java $";
}
}