/* * 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.update.processor; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.util.plugin.PluginInfoInitialized; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.SolrException; import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrCore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.ArrayList; /** * Manages a chain of UpdateRequestProcessorFactories. * <p> * Chain can be configured via solrconfig.xml: * </p> * <pre class="prettyprint"> * <updateRequestProcessors name="key" default="true"> * <processor class="PathToClass1" /> * <processor class="PathToClass2" /> * <processor class="solr.LogUpdateProcessorFactory" > * <int name="maxNumToLog">100</int> * </processor> * <processor class="solr.RunUpdateProcessorFactory" /> * </updateRequestProcessors> * </pre> * <p> * Allmost all processor chains should end with an instance of * {@link RunUpdateProcessorFactory} unless the user is explicitly * executing the update commands in an alternative custom * <code>UpdateRequestProcessorFactory</code>. * </p> * * @see UpdateRequestProcessorFactory * @see #init * @see #createProcessor * @since solr 1.3 */ public final class UpdateRequestProcessorChain implements PluginInfoInitialized { public final static Logger log = LoggerFactory.getLogger(UpdateRequestProcessorChain.class); private UpdateRequestProcessorFactory[] chain; private final SolrCore solrCore; public UpdateRequestProcessorChain(SolrCore solrCore) { this.solrCore = solrCore; } /** * Initializes the chain using the factories specified by the <code>PluginInfo</code>. * if the chain includes the <code>RunUpdateProcessorFactory</code>, but * does not include an implementation of the * <code>DistributingUpdateProcessorFactory</code> interface, then an * instance of <code>DistributedUpdateProcessorFactory</code> will be * injected immediately prior to the <code>RunUpdateProcessorFactory</code>. * * @see DistributingUpdateProcessorFactory * @see RunUpdateProcessorFactory * @see DistributedUpdateProcessorFactory */ public void init(PluginInfo info) { final String infomsg = "updateRequestProcessorChain \"" + (null != info.name ? info.name : "") + "\"" + (info.isDefault() ? " (default)" : ""); // wrap in an ArrayList so we know we know we can do fast index lookups // and that add(int,Object) is supported List<UpdateRequestProcessorFactory> list = new ArrayList (solrCore.initPlugins(info.getChildren("processor"),UpdateRequestProcessorFactory.class,null)); if(list.isEmpty()){ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, infomsg + " require at least one processor"); } int numDistrib = 0; int runIndex = -1; // hi->lo incase multiple run instances, add before first one // (no idea why someone might use multiple run instances, but just in case) for (int i = list.size()-1; 0 <= i; i--) { UpdateRequestProcessorFactory factory = list.get(i); if (factory instanceof DistributingUpdateProcessorFactory) { numDistrib++; } if (factory instanceof RunUpdateProcessorFactory) { runIndex = i; } } if (1 < numDistrib) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, infomsg + " may not contain more then one " + "instance of DistributingUpdateProcessorFactory"); } if (0 <= runIndex && 0 == numDistrib) { // by default, add distrib processor immediately before run DistributedUpdateProcessorFactory distrib = new DistributedUpdateProcessorFactory(); distrib.init(new NamedList()); list.add(runIndex, distrib); log.info("inserting DistributedUpdateProcessorFactory into " + infomsg); } chain = list.toArray(new UpdateRequestProcessorFactory[list.size()]); } /** * Creates a chain backed directly by the specified array. Modifications to * the array will affect future calls to <code>createProcessor</code> */ public UpdateRequestProcessorChain( UpdateRequestProcessorFactory[] chain, SolrCore solrCore) { this.chain = chain; this.solrCore = solrCore; } /** * Uses the factories in this chain to creates a new * <code>UpdateRequestProcessor</code> instance specific for this request. * If the <code>DISTRIB_UPDATE_PARAM</code> is present in the request and is * non-blank, then any factory in this chain prior to the instance of * <code>{@link DistributingUpdateProcessorFactory}</code> will be skipped, * and the <code>UpdateRequestProcessor</code> returned will be from that * <code>DistributingUpdateProcessorFactory</code> * * @see UpdateRequestProcessorFactory#getInstance * @see DistributingUpdateProcessorFactory#DISTRIB_UPDATE_PARAM */ public UpdateRequestProcessor createProcessor(SolrQueryRequest req, SolrQueryResponse rsp) { UpdateRequestProcessor processor = null; UpdateRequestProcessor last = null; final String distribPhase = req.getParams().get (DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM, ""); final boolean skipToDistrib = ! distribPhase.trim().isEmpty(); for (int i = chain.length-1; i>=0; i--) { processor = chain[i].getInstance(req, rsp, last); last = processor == null ? last : processor; if (skipToDistrib && chain[i] instanceof DistributingUpdateProcessorFactory) { break; } } return last; } /** * Returns the underlying array of factories used in this chain. * Modifications to the array will affect future calls to * <code>createProcessor</code> */ public UpdateRequestProcessorFactory[] getFactories() { return chain; } }