/* * 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 java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.lucene.index.Term; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.update.AddUpdateCommand; import org.apache.solr.core.SolrCore; import org.apache.solr.schema.SchemaField; import org.apache.solr.util.plugin.SolrCoreAware; public class SignatureUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware { private List<String> sigFields; private String signatureField; private Term signatureTerm; private boolean enabled = true; private String signatureClass; private boolean overwriteDupes; private SolrParams params; @Override public void init(final NamedList args) { if (args != null) { SolrParams params = SolrParams.toSolrParams(args); boolean enabled = params.getBool("enabled", true); this.enabled = enabled; overwriteDupes = params.getBool("overwriteDupes", true); signatureField = params.get("signatureField", "signatureField"); signatureClass = params.get("signatureClass", "org.apache.solr.update.processor.Lookup3Signature"); this.params = params; Object fields = args.get("fields"); sigFields = fields == null ? null: StrUtils.splitSmart((String)fields, ",", true); if (sigFields != null) { Collections.sort(sigFields); } } } @Override public void inform(SolrCore core) { final SchemaField field = core.getLatestSchema().getFieldOrNull(getSignatureField()); if (null == field) { throw new SolrException (ErrorCode.SERVER_ERROR, "Can't use signatureField which does not exist in schema: " + getSignatureField()); } if (getOverwriteDupes() && ( ! field.indexed() ) ) { throw new SolrException (ErrorCode.SERVER_ERROR, "Can't set overwriteDupes when signatureField is not indexed: " + getSignatureField()); } } public List<String> getSigFields() { return sigFields; } public String getSignatureField() { return signatureField; } public boolean isEnabled() { return enabled; } public String getSignatureClass() { return signatureClass; } public boolean getOverwriteDupes() { return overwriteDupes; } @Override public UpdateRequestProcessor getInstance(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next) { return new SignatureUpdateProcessor(req, rsp, this, next); } class SignatureUpdateProcessor extends UpdateRequestProcessor { private final SolrQueryRequest req; public SignatureUpdateProcessor(SolrQueryRequest req, SolrQueryResponse rsp, SignatureUpdateProcessorFactory factory, UpdateRequestProcessor next) { super(next); this.req = req; } @Override public void processAdd(AddUpdateCommand cmd) throws IOException { if (enabled) { SolrInputDocument doc = cmd.getSolrInputDocument(); List<String> currDocSigFields = null; boolean isPartialUpdate = AtomicUpdateDocumentMerger.isAtomicUpdate(cmd); if (sigFields == null || sigFields.size() == 0) { if (isPartialUpdate) { throw new SolrException (ErrorCode.SERVER_ERROR, "Can't use SignatureUpdateProcessor with partial updates on signature fields"); } Collection<String> docFields = doc.getFieldNames(); currDocSigFields = new ArrayList<>(docFields.size()); currDocSigFields.addAll(docFields); Collections.sort(currDocSigFields); } else { currDocSigFields = sigFields; } Signature sig = req.getCore().getResourceLoader().newInstance(signatureClass, Signature.class); sig.init(params); for (String field : currDocSigFields) { SolrInputField f = doc.getField(field); if (f != null) { if (isPartialUpdate) { throw new SolrException (ErrorCode.SERVER_ERROR, "Can't use SignatureUpdateProcessor with partial update request " + "containing signature field: " + field); } sig.add(field); Object o = f.getValue(); if (o instanceof Collection) { for (Object oo : (Collection)o) { sig.add(String.valueOf(oo)); } } else { sig.add(String.valueOf(o)); } } } byte[] signature = sig.getSignature(); char[] arr = new char[signature.length<<1]; for (int i=0; i<signature.length; i++) { int b = signature[i]; int idx = i<<1; arr[idx]= StrUtils.HEX_DIGITS[(b >> 4) & 0xf]; arr[idx+1]= StrUtils.HEX_DIGITS[b & 0xf]; } String sigString = new String(arr); doc.addField(signatureField, sigString); if (overwriteDupes) { cmd.updateTerm = new Term(signatureField, sigString); } } if (next != null) next.processAdd(cmd); } } // for testing void setEnabled(boolean enabled) { this.enabled = enabled; } }