package org.apache.solr.rest.schema; /* * 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. */ import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.rest.GETable; import org.apache.solr.rest.POSTable; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.ManagedIndexSchema; import org.noggit.ObjectBuilder; import org.restlet.data.MediaType; import org.restlet.representation.Representation; import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * This class responds to requests at /solr/(corename)/schema/copyfields * <p/> * * To restrict the set of copyFields in the response, specify one or both * of the following as query parameters, with values as space and/or comma * separated dynamic or explicit field names: * * <ul> * <li>dest.fl: include copyFields that have one of these as a destination</li> * <li>source.fl: include copyFields that have one of these as a source</li> * </ul> * * If both dest.fl and source.fl are given as query parameters, the copyfields * in the response will be restricted to those that match any of the destinations * in dest.fl and also match any of the sources in source.fl. */ public class CopyFieldCollectionResource extends BaseFieldResource implements GETable, POSTable { private static final Logger log = LoggerFactory.getLogger(CopyFieldCollectionResource.class); private static final String SOURCE_FIELD_LIST = IndexSchema.SOURCE + "." + CommonParams.FL; private static final String DESTINATION_FIELD_LIST = IndexSchema.DESTINATION + "." + CommonParams.FL; private Set<String> requestedSourceFields; private Set<String> requestedDestinationFields; public CopyFieldCollectionResource() { super(); } @Override public void doInit() throws ResourceException { super.doInit(); if (isExisting()) { String sourceFieldListParam = getSolrRequest().getParams().get(SOURCE_FIELD_LIST); if (null != sourceFieldListParam) { String[] fields = sourceFieldListParam.trim().split("[,\\s]+"); if (fields.length > 0) { requestedSourceFields = new HashSet<>(Arrays.asList(fields)); requestedSourceFields.remove(""); // Remove empty values, if any } } String destinationFieldListParam = getSolrRequest().getParams().get(DESTINATION_FIELD_LIST); if (null != destinationFieldListParam) { String[] fields = destinationFieldListParam.trim().split("[,\\s]+"); if (fields.length > 0) { requestedDestinationFields = new HashSet<>(Arrays.asList(fields)); requestedDestinationFields.remove(""); // Remove empty values, if any } } } } @Override public Representation get() { try { getSolrResponse().add(IndexSchema.COPY_FIELDS, getSchema().getCopyFieldProperties(true, requestedSourceFields, requestedDestinationFields)); } catch (Exception e) { getSolrResponse().setException(e); } handlePostExecution(log); return new SolrOutputRepresentation(); } @Override public Representation post(Representation entity) throws ResourceException { try { if (!getSchema().isMutable()) { final String message = "This IndexSchema is not mutable."; throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message); } else { if (!entity.getMediaType().equals(MediaType.APPLICATION_JSON, true)) { String message = "Only media type " + MediaType.APPLICATION_JSON.toString() + " is accepted." + " Request has media type " + entity.getMediaType().toString() + "."; log.error(message); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message); } else { Object object = ObjectBuilder.fromJSON(entity.getText()); if (!(object instanceof List)) { String message = "Invalid JSON type " + object.getClass().getName() + ", expected List of the form" + " (ignore the backslashes): [{\"source\":\"foo\",\"dest\":\"comma-separated list of targets\"}, {...}, ...]"; log.error(message); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message); } else { List<Map<String, Object>> list = (List<Map<String, Object>>) object; Map<String, Collection<String>> fieldsToCopy = new HashMap<>(); ManagedIndexSchema oldSchema = (ManagedIndexSchema) getSchema(); Set<String> malformed = new HashSet<>(); for (Map<String,Object> map : list) { String fieldName = (String)map.get(IndexSchema.SOURCE); if (null == fieldName) { String message = "Missing '" + IndexSchema.SOURCE + "' mapping."; log.error(message); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message); } Object dest = map.get(IndexSchema.DESTINATION); List<String> destinations = null; if (dest != null) { if (dest instanceof List){ destinations = (List<String>)dest; } else if (dest instanceof String){ destinations = Collections.singletonList(dest.toString()); } else { String message = "Invalid '" + IndexSchema.DESTINATION + "' type."; log.error(message); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message); } } if (destinations == null) { malformed.add(fieldName); } else { fieldsToCopy.put(fieldName, destinations); } } if (malformed.size() > 0){ StringBuilder message = new StringBuilder("Malformed destination(s) for: "); for (String s : malformed) { message.append(s).append(", "); } if (message.length() > 2) { message.setLength(message.length() - 2);//drop the last , } log.error(message.toString().trim()); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message.toString().trim()); } IndexSchema newSchema = oldSchema.addCopyFields(fieldsToCopy); if (newSchema != null) { getSolrCore().setLatestSchema(newSchema); } } } } } catch (Exception e) { getSolrResponse().setException(e); } handlePostExecution(log); return new SolrOutputRepresentation(); } }