/* ********************************************************************
Licensed to Jasig under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Jasig 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.bedework.indexer;
import org.bedework.calfacade.configs.IndexProperties;
import org.bedework.calfacade.indexing.BwIndexer.IndexInfo;
import org.bedework.sysevents.NotificationException;
import org.bedework.util.jmx.ConfBase;
import org.bedework.util.misc.AbstractProcessorThread;
import org.bedework.util.misc.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.naming.NameNotFoundException;
/**
* @author douglm
*
*/
public class BwIndexCtl extends ConfBase<IndexPropertiesImpl>
implements BwIndexCtlMBean {
/* Name of the property holding the location of the config data */
public static final String confuriPname = "org.bedework.bwengine.confuri";
private class ProcessorThread extends AbstractProcessorThread {
/**
* @param name - for the thread
*/
public ProcessorThread(final String name) {
super(name);
}
@Override
public void runInit() {
/* List the indexes in use - ensures we have an indexer early on */
info(" * Current indexes: ");
Set<IndexInfo> is = null;
try {
is = getIndexApp().getIndexInfo();
} catch (Throwable t) {
info(" * Exception getting index info:");
info(" * " + t.getLocalizedMessage());
}
info(listIndexes(is));
}
@Override
public void runProcess() throws Throwable {
getIndexApp().listen();
}
@Override
public void close() {
getIndexApp().close();
}
@Override
public boolean handleException(final Throwable val) {
if (!(val instanceof NotificationException)) {
return false;
}
Throwable t = val.getCause();
if (t instanceof NameNotFoundException) {
// jmx shutting down?
error("Looks like JMX shut down.");
error(t);
running = false;
return true;
}
return false;
}
}
private ProcessorThread processor;
private class CrawlThread extends Thread {
boolean showedTrace;
/**
* @param name - for the thread
*/
public CrawlThread(final String name) {
super(name);
}
@Override
public void run() {
try {
getIndexApp().crawl();
} catch (InterruptedException ie) {
} catch (Throwable t) {
if (!showedTrace) {
error(t);
// showedTrace = true;
} else {
error(t.getMessage());
}
}
}
}
private CrawlThread crawler;
private final static String nm = "indexing";
private BwIndexApp indexApp;
/**
*/
public BwIndexCtl() {
super(getServiceName(nm));
setConfigName(nm);
setConfigPname(confuriPname);
}
/**
* @param name
* @return object name value for the mbean with this name
*/
public static String getServiceName(final String name) {
return "org.bedework.bwengine:service=" + name;
}
@Override
public void setIndexerURL(final String val) {
getConfig().setIndexerURL(val);
}
@Override
public String getIndexerURL() {
return getConfig().getIndexerURL();
}
@Override
public void setEmbeddedIndexer(final boolean val) {
getConfig().setEmbeddedIndexer(val);
}
@Override
public boolean getEmbeddedIndexer() {
return getConfig().getEmbeddedIndexer();
}
@Override
public void setHttpEnabled(final boolean val) {
getConfig().setHttpEnabled(val);
}
@Override
public boolean getHttpEnabled() {
return getConfig().getHttpEnabled();
}
@Override
public void setClusterName(final String val) {
getConfig().setClusterName(val);
}
@Override
public String getClusterName() {
return getConfig().getClusterName();
}
@Override
public void setNodeName(final String val) {
getConfig().setNodeName(val);
}
@Override
public String getNodeName() {
return getConfig().getNodeName();
}
@Override
public void setDataDir(final String val) {
getConfig().setDataDir(val);
}
@Override
public String getDataDir() {
return getConfig().getDataDir();
}
@Override
public void setIndexerConfig(final String val) {
getConfig().setIndexerConfig(val);
}
@Override
public String getIndexerConfig() {
return getConfig().getIndexerConfig();
}
@Override
public void setPublicIndexName(final String val) {
getConfig().setPublicIndexName(val);
}
@Override
public String getPublicIndexName() {
return getConfig().getPublicIndexName();
}
@Override
public void setUserIndexName(final String val) {
getConfig().setUserIndexName(val);
}
@Override
public String getUserIndexName() {
return getConfig().getUserIndexName();
}
@Override
public void setAccount(final String val) {
getConfig().setAccount(val);
}
@Override
public String getAccount() {
return getConfig().getAccount();
}
@Override
public void setMaxEntityThreads(final int val) {
getConfig().setMaxEntityThreads(val);
}
@Override
public int getMaxEntityThreads() {
return getConfig().getMaxEntityThreads();
}
@Override
public void setMaxPrincipalThreads(final int val) {
getConfig().setMaxPrincipalThreads(val);
}
@Override
public int getMaxPrincipalThreads() {
return getConfig().getMaxPrincipalThreads();
}
@Override
public void setIndexPublic(final boolean val) {
getConfig().setIndexPublic(val);
}
@Override
public boolean getIndexPublic() {
return getConfig().getIndexPublic();
}
@Override
public void setIndexUsers(final boolean val) {
getConfig().setIndexUsers(val);
}
@Override
public boolean getIndexUsers() {
return getConfig().getIndexUsers();
}
@Override
public void setDiscardMessages(final boolean val) {
getConfig().setDiscardMessages(val);
}
@Override
public boolean getDiscardMessages() {
return getConfig().getDiscardMessages();
}
@Override
public void setSkipPaths(final String val) {
getConfig().setSkipPaths(val);
}
@Override
public String getSkipPaths() {
return getConfig().getSkipPaths();
}
@Override
public void setSkipPathsList(final List<String> val) {
getConfig().setSkipPathsList(val);
}
@Override
public List<String> getSkipPathsList() {
return getConfig().getSkipPathsList();
}
@Override
public IndexProperties cloneIt() {
return null;
}
@Override
public long getMessageCount() {
return getIndexApp().getMessageCount();
}
@Override
public String listIndexes() {
try {
return listIndexes(getIndexApp().getIndexInfo());
} catch (Throwable t) {
return t.getLocalizedMessage();
}
}
@Override
public String purgeIndexes() {
return getIndexApp().purgeIndexes();
}
public long getEntitiesUpdated() {
return getIndexApp().getEntitiesUpdated();
}
public long getEntitiesDeleted() {
return getIndexApp().getEntitiesDeleted();
}
public long getCollectionsUpdated() {
return getIndexApp().getCollectionsUpdated();
}
public long getCollectionsDeleted() {
return getIndexApp().getCollectionsDeleted();
}
/* ========================================================================
* Operations
* ======================================================================== */
@Override
public List<String> rebuildStatus() {
List<String> res = new ArrayList<>();
if (crawler == null) {
outLine(res, "No rebuild appears to have taken place");
return res;
}
List<CrawlStatus> sts = getIndexApp().getStatus();
if (sts != null) {
for (CrawlStatus st: sts) {
outputStatus(st, res);
}
}
return res;
}
/* (non-Javadoc)
* @see org.bedework.indexer.BwIndexCtlMBean#rebuildIndex()
*/
@Override
public String rebuildIndex() {
try {
if ((crawler != null) && crawler.isAlive()) {
error("Reindexer already started");
return "Reindexer already started";
}
crawler = new CrawlThread(getServiceName());
crawler.start();
return "Started";
} catch (Throwable t) {
List<String> infoLines = new ArrayList<String>();
infoLines.add("***********************************\n");
infoLines.add("Error rebuilding indexes.\n");
infoLines.add("***********************************\n");
error("Error rebuilding indexes.");
error(t);
return t.getLocalizedMessage();
}
}
/* (non-Javadoc)
* @see org.bedework.indexer.BwIndexCtlMBean#isStarted()
*/
@Override
public boolean isStarted() {
return (processor != null) && processor.isAlive();
}
/* (non-Javadoc)
* @see org.bedework.indexer.BwIndexCtlMBean#start()
*/
@Override
public synchronized void start() {
if (processor != null) {
error("Already started");
return;
}
processor = new ProcessorThread(getServiceName());
processor.setRunning(true);
processor.start();
}
/* (non-Javadoc)
* @see org.bedework.indexer.BwIndexCtlMBean#stop()
*/
@Override
public synchronized void stop() {
if (processor == null) {
error("Already stopped");
return;
}
ProcessorThread.stopProcess(processor);
processor = null;
}
@Override
public String loadConfig() {
return loadConfig(IndexPropertiesImpl.class);
}
/* ========================================================================
* Private methods
* ======================================================================== */
private String listIndexes(Set<IndexInfo> is) {
if (Util.isEmpty(is)) {
return "No indexes found";
}
StringBuilder res = new StringBuilder("Indexes");
res.append("------------------------\n");
for (IndexInfo ii: is) {
res.append(ii.getIndexName());
if (!Util.isEmpty(ii.getAliases())) {
String delim = "<----";
for (String a: ii.getAliases()) {
res.append(delim);
res.append(a);
delim = ", ";
}
}
res.append("\n");
}
return res.toString();
}
private void outputStatus(final CrawlStatus status,
final List<String> res) {
outLine(res, "--------------------------------------");
outLine(res, status.name);
outLine(res, "current status: " + status.currentStatus);
if (status.stats != null) {
res.addAll(status.stats.statsList());
}
outLine(res, "");
if (!status.infoLines.isEmpty()) {
res.addAll(status.infoLines);
}
}
private void outLine(final List<String> res,
final String msg) {
res.add(msg + "\n");
}
private BwIndexApp getIndexApp() {
if (indexApp != null) {
return indexApp;
}
indexApp = new BwIndexApp(getConfig());
return indexApp;
}
}