// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.federation;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.chain.Chain;
import com.yahoo.component.chain.dependencies.After;
import com.yahoo.prelude.Ping;
import com.yahoo.prelude.Pong;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.cluster.PingableSearcher;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.HitGroup;
import com.yahoo.search.searchchain.Execution;
/**
* A lightweight searcher to forward all incoming requests to a single search
* chain defined in config. An alternative to federation searcher when standard
* semantics are not necessary for the application.
*
* @see FederationSearcher
* @since 5.0.13
* @author Steinar Knutsen
*/
@After("*")
public class ForwardingSearcher extends PingableSearcher {
private final ComponentSpecification target;
public ForwardingSearcher(final SearchchainForwardConfig config) {
if (config.target() == null) {
throw new RuntimeException(
"Configuration value searchchain-forward.target was null.");
}
try {
target = new ComponentSpecification(config.target());
} catch (RuntimeException e) {
throw new RuntimeException(
"Failed constructing the component specification from searchchain-forward.target: "
+ config.target(), e);
}
}
@Override
public Result search(final Query query, final Execution execution) {
Execution next = createForward(execution);
if (next == null) {
return badResult(query);
} else {
return next.search(query);
}
}
private Result badResult(final Query query) {
final ErrorMessage error = noSearchchain();
return new Result(query, error);
}
@Override
public Pong ping(final Ping ping, final Execution execution) {
Execution next = createForward(execution);
if (next == null) {
return badPong();
} else {
return next.ping(ping);
}
}
private Pong badPong() {
final Pong pong = new Pong();
pong.addError(noSearchchain());
return pong;
}
@Override
public void fill(final Result result, final String summaryClass,
final Execution execution) {
Execution next = createForward(execution);
if (next == null) {
badFill(result.hits());
return;
} else {
next.fill(result, summaryClass);
}
}
private void badFill(HitGroup hits) {
hits.addError(noSearchchain());
}
private Execution createForward(Execution execution) {
Chain targetChain = execution.context().searchChainRegistry()
.getComponent(target);
if (targetChain == null) {
return null;
}
return new Execution(targetChain, execution.context());
}
private ErrorMessage noSearchchain() {
return ErrorMessage
.createServerIsMisconfigured("Could not get search chain matching component specification: " + target);
}
}