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.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.rest.GETable;
import org.apache.solr.rest.POSTable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
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.util.ArrayList;
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;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* This class responds to requests at /solr/(corename)/schema/fields
* <p/>
* Two query parameters are supported:
* <ul>
* <li>
* "fl": a comma- and/or space-separated list of fields to send properties
* for in the response, rather than the default: all of them.
* </li>
* <li>
* "includeDynamic": if the "fl" parameter is specified, matching dynamic
* fields are included in the response and identified with the "dynamicBase"
* property. If the "fl" parameter is not specified, the "includeDynamic"
* query parameter is ignored.
* </li>
* </ul>
*/
public class FieldCollectionResource extends BaseFieldResource implements GETable, POSTable {
private static final Logger log = LoggerFactory.getLogger(FieldCollectionResource.class);
private boolean includeDynamic;
public FieldCollectionResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
if (isExisting()) {
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
}
}
@Override
public Representation get() {
try {
final List<SimpleOrderedMap<Object>> props = new ArrayList<>();
if (null == getRequestedFields()) {
SortedSet<String> fieldNames = new TreeSet<>(getSchema().getFields().keySet());
for (String fieldName : fieldNames) {
props.add(getFieldProperties(getSchema().getFields().get(fieldName)));
}
} else {
if (0 == getRequestedFields().size()) {
String message = "Empty " + CommonParams.FL + " parameter value";
throw new SolrException(ErrorCode.BAD_REQUEST, message);
}
// Use the same order as the fl parameter
for (String fieldName : getRequestedFields()) {
final SchemaField field;
if (includeDynamic) {
field = getSchema().getFieldOrNull(fieldName);
} else {
field = getSchema().getFields().get(fieldName);
}
if (null == field) {
log.info("Requested field '" + fieldName + "' not found.");
} else {
props.add(getFieldProperties(field));
}
}
}
getSolrResponse().add(IndexSchema.FIELDS, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
@Override
public Representation post(Representation entity) {
try {
if (!getSchema().isMutable()) {
final String message = "This IndexSchema is not mutable.";
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
if (null == entity.getMediaType()) {
entity.setMediaType(MediaType.APPLICATION_JSON);
}
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(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): [{\"name\":\"foo\",\"type\":\"text_general\", ...}, {...}, ...]";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
List<Map<String, Object>> list = (List<Map<String, Object>>) object;
List<SchemaField> newFields = new ArrayList<>();
IndexSchema oldSchema = getSchema();
Map<String, Collection<String>> copyFields = new HashMap<>();
Set<String> malformed = new HashSet<>();
for (Map<String, Object> map : list) {
String fieldName = (String) map.remove(IndexSchema.NAME);
if (null == fieldName) {
String message = "Missing '" + IndexSchema.NAME + "' mapping.";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
}
String fieldType = (String) map.remove(IndexSchema.TYPE);
if (null == fieldType) {
String message = "Missing '" + IndexSchema.TYPE + "' mapping.";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
}
// copyFields:"comma separated list of destination fields"
Object copies = map.get(IndexSchema.COPY_FIELDS);
List<String> copyTo = null;
if (copies != null) {
if (copies instanceof List){
copyTo = (List<String>) copies;
} else if (copies instanceof String){
copyTo = Collections.singletonList(copies.toString());
} else {
String message = "Invalid '" + IndexSchema.COPY_FIELDS + "' type.";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
}
}
if (copyTo != null) {
map.remove(IndexSchema.COPY_FIELDS);
copyFields.put(fieldName, copyTo);
}
newFields.add(oldSchema.newField(fieldName, fieldType, map));
}
IndexSchema newSchema = oldSchema.addFields(newFields, copyFields);
getSolrCore().setLatestSchema(newSchema);
}
}
}
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}