From fdeffbb536dc91712ad8572b386c8c9c1b2b7c8d Mon Sep 17 00:00:00 2001 From: Shalin Shekhar Mangar Date: Sat, 20 Jun 2015 16:24:08 +0000 Subject: [PATCH] SOLR-7182: Make the Schema-API a first class citizen of SolrJ git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1686650 13f79535-47bb-0310-9956-ffa450edef68 --- solr/CHANGES.txt | 3 + .../request/schema/AbstractSchemaRequest.java | 49 + .../request/schema/AnalyzerDefinition.java | 63 ++ .../request/schema/FieldTypeDefinition.java | 87 ++ .../solrj/request/schema/SchemaRequest.java | 853 ++++++++++++++++ .../solrj/request/schema/package-info.java | 23 + .../schema/FieldTypeRepresentation.java | 47 + .../response/schema/SchemaRepresentation.java | 128 +++ .../solrj/response/schema/SchemaResponse.java | 508 ++++++++++ .../solrj/response/schema/package-info.java | 23 + .../conf/solrconfig-managed-schema.xml | 32 + .../solr/client/solrj/request/SchemaTest.java | 910 ++++++++++++++++++ 12 files changed, 2726 insertions(+) create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AbstractSchemaRequest.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AnalyzerDefinition.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/FieldTypeDefinition.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/SchemaRequest.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/package-info.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/FieldTypeRepresentation.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaRepresentation.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaResponse.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/package-info.java create mode 100644 solr/solrj/src/test-files/solrj/solr/collection1/conf/solrconfig-managed-schema.xml create mode 100644 solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 9cf0fc21abf..5dbe8eee0cd 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -133,6 +133,9 @@ New Features * SOLR-7639: MoreLikeThis QParser now supports all options provided by the MLT Handler i.e. mintf, mindf, minwl, maxwl, maxqt, and maxntp. +* SOLR-7182: Make the Schema-API a first class citizen of SolrJ. The new SchemaRequest and its inner + classes can be used to make requests to the Schema API. (Sven Windisch, Marius Grama via shalin) + Bug Fixes ---------------------- diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AbstractSchemaRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AbstractSchemaRequest.java new file mode 100644 index 00000000000..661d167d012 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AbstractSchemaRequest.java @@ -0,0 +1,49 @@ +package org.apache.solr.client.solrj.request.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 java.io.IOException; +import java.util.Collection; + +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrResponse; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.ContentStream; + +public abstract class AbstractSchemaRequest extends SolrRequest { + private SolrParams params = null; + + public AbstractSchemaRequest(METHOD m, String path) { + super(m, path); + } + + public AbstractSchemaRequest(METHOD m, String path, SolrParams params) { + this(m, path); + this.params = params; + } + + @Override + public SolrParams getParams() { + return params; + } + + @Override + public Collection getContentStreams() throws IOException { + return null; + } +} diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AnalyzerDefinition.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AnalyzerDefinition.java new file mode 100644 index 00000000000..ed5aeb5878f --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/AnalyzerDefinition.java @@ -0,0 +1,63 @@ +package org.apache.solr.client.solrj.request.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 java.util.List; +import java.util.Map; + +public class AnalyzerDefinition { + private Map attributes; + + private List> charFilters; + + private Map tokenizer; + + private List> filters; + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public List> getCharFilters() { + return charFilters; + } + + public void setCharFilters(List> charFilters) { + this.charFilters = charFilters; + } + + public Map getTokenizer() { + return tokenizer; + } + + public void setTokenizer(Map tokenizer) { + this.tokenizer = tokenizer; + } + + public List> getFilters() { + return filters; + } + + public void setFilters(List> filters) { + this.filters = filters; + } +} \ No newline at end of file diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/FieldTypeDefinition.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/FieldTypeDefinition.java new file mode 100644 index 00000000000..4599f4b0ae1 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/FieldTypeDefinition.java @@ -0,0 +1,87 @@ +package org.apache.solr.client.solrj.request.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 java.util.Map; + +public class FieldTypeDefinition { + private Map attributes; + + private AnalyzerDefinition analyzer; + + private AnalyzerDefinition indexAnalyzer; + + private AnalyzerDefinition queryAnalyzer; + + private AnalyzerDefinition multiTermAnalyzer; + + private Map similarity; + + public FieldTypeDefinition() { + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public Map getSimilarity() { + return similarity; + } + + public void setSimilarity(Map similarity) { + this.similarity = similarity; + } + + public AnalyzerDefinition getAnalyzer() { + return analyzer; + } + + public void setAnalyzer(AnalyzerDefinition analyzer) { + this.analyzer = analyzer; + } + + public AnalyzerDefinition getIndexAnalyzer() { + return indexAnalyzer; + } + + public void setIndexAnalyzer(AnalyzerDefinition indexAnalyzer) { + this.indexAnalyzer = indexAnalyzer; + } + + public AnalyzerDefinition getQueryAnalyzer() { + return queryAnalyzer; + } + + public void setQueryAnalyzer(AnalyzerDefinition queryAnalyzer) { + this.queryAnalyzer = queryAnalyzer; + } + + public AnalyzerDefinition getMultiTermAnalyzer() { + return multiTermAnalyzer; + } + + public void setMultiTermAnalyzer(AnalyzerDefinition multiTermAnalyzer) { + this.multiTermAnalyzer = multiTermAnalyzer; + } +} + + diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/SchemaRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/SchemaRequest.java new file mode 100644 index 00000000000..769e9bd4d6c --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/SchemaRequest.java @@ -0,0 +1,853 @@ +package org.apache.solr.client.solrj.request.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 java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.response.schema.SchemaResponse; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.ContentStream; +import org.apache.solr.common.util.ContentStreamBase; +import org.apache.solr.common.util.NamedList; +import org.noggit.CharArr; +import org.noggit.JSONWriter; + +/** + *

This class offers access to the operations exposed by the Solr Schema API.

+ *

Most of the operations of this class offer a very abstract interface avoiding + * in this manner eventual changes due to Solr Schema API updates. On the other + * hand, the creation of request parameters for creating new fields or field types + * can be tedious because it is not strongly typed (the user has to build on his own + * a {@link NamedList} argument containing the field/field type properties).

+ *

The class does not currently offer explicit support for the Schema API operations exposed + * through Managed Resources, but such operations can be built with little effort manually + * based on this class within the client applications.

+ *

This class is experimental and it is subject to change.

+ * + * @see Solr Schema API + * @see Solr managed resources + * @since solr 5.3 + */ +public class SchemaRequest extends AbstractSchemaRequest { + + /** + * Default constructor. + * It can be used to retrieve the entire schema. + * + * @see #process(SolrClient) + */ + public SchemaRequest() { + this(null); + } + + public SchemaRequest(SolrParams q) { + super(METHOD.GET, "/schema", q); + } + + private static NamedList createAddFieldTypeNamedList(FieldTypeDefinition fieldTypeDefinition) { + final NamedList addFieldTypeNamedList = new NamedList<>(); + addFieldTypeNamedList.addAll(fieldTypeDefinition.getAttributes()); + AnalyzerDefinition analyzerDefinition = fieldTypeDefinition.getAnalyzer(); + if (analyzerDefinition != null) { + NamedList analyzerNamedList = createAnalyzerNamedList(analyzerDefinition); + addFieldTypeNamedList.add("analyzer", analyzerNamedList); + } + AnalyzerDefinition indexAnalyzerDefinition = fieldTypeDefinition.getIndexAnalyzer(); + if (indexAnalyzerDefinition != null) { + NamedList indexAnalyzerNamedList = createAnalyzerNamedList(indexAnalyzerDefinition); + addFieldTypeNamedList.add("indexAnalyzer", indexAnalyzerNamedList); + } + AnalyzerDefinition queryAnalyzerDefinition = fieldTypeDefinition.getQueryAnalyzer(); + if (queryAnalyzerDefinition != null) { + NamedList queryAnalyzerNamedList = createAnalyzerNamedList(queryAnalyzerDefinition); + addFieldTypeNamedList.add("queryAnalyzer", queryAnalyzerNamedList); + } + AnalyzerDefinition multiTermAnalyzerDefinition = fieldTypeDefinition.getMultiTermAnalyzer(); + if (multiTermAnalyzerDefinition != null) { + NamedList multiTermAnalyzerNamedList = createAnalyzerNamedList(multiTermAnalyzerDefinition); + addFieldTypeNamedList.add("multiTermAnalyzer", multiTermAnalyzerNamedList); + } + Map similarityAttributes = fieldTypeDefinition.getSimilarity(); + if (similarityAttributes != null && !similarityAttributes.isEmpty()) { + addFieldTypeNamedList.add("similarity", new NamedList<>(similarityAttributes)); + } + + return addFieldTypeNamedList; + } + + private static NamedList createAnalyzerNamedList(AnalyzerDefinition analyzerDefinition) { + NamedList analyzerNamedList = new NamedList<>(); + Map analyzerAttributes = analyzerDefinition.getAttributes(); + if (analyzerAttributes != null) + analyzerNamedList.addAll(analyzerAttributes); + List> charFiltersAttributes = analyzerDefinition.getCharFilters(); + if (charFiltersAttributes != null) { + List> charFiltersList = new LinkedList<>(); + for (Map charFilterAttributes : charFiltersAttributes) + charFiltersList.add(new NamedList<>(charFilterAttributes)); + analyzerNamedList.add("charFilters", charFiltersList); + } + Map tokenizerAttributes = analyzerDefinition.getTokenizer(); + if (tokenizerAttributes != null) { + analyzerNamedList.add("tokenizer", new NamedList<>(tokenizerAttributes)); + } + List> filtersAttributes = analyzerDefinition.getFilters(); + if (filtersAttributes != null) { + List> filtersList = new LinkedList<>(); + for (Map filterAttributes : filtersAttributes) + filtersList.add(new NamedList<>(filterAttributes)); + analyzerNamedList.add("filters", filtersList); + } + return analyzerNamedList; + } + + private static NamedList createAddFieldNamedList(Map fieldAttributes) { + final NamedList addFieldProps = new NamedList<>(); + if (fieldAttributes != null) addFieldProps.addAll(fieldAttributes); + return addFieldProps; + } + + @Override + protected SchemaResponse createResponse(SolrClient client) { + return new SchemaResponse(); + } + + /** + * Schema API request class that can be used to retrieve the name of the schema. + */ + public static class SchemaName extends AbstractSchemaRequest { + public SchemaName() { + this(null); + } + + public SchemaName(SolrParams q) { + super(METHOD.GET, "/schema/name", q); + } + + @Override + protected SchemaResponse.SchemaNameResponse createResponse(SolrClient client) { + return new SchemaResponse.SchemaNameResponse(); + } + } + + /** + * Schema API request that can be used to retrieve the version + * of the schema for the specified collection. + */ + public static class SchemaVersion extends AbstractSchemaRequest { + public SchemaVersion() { + this(null); + } + + public SchemaVersion(SolrParams q) { + super(METHOD.GET, "/schema/version", q); + } + + @Override + protected SchemaResponse.SchemaVersionResponse createResponse(SolrClient client) { + return new SchemaResponse.SchemaVersionResponse(); + } + } + + /** + * Schema API request class that lists the field definitions contained in the schema. + */ + public static class Fields extends AbstractSchemaRequest { + public Fields() { + this(null); + } + + public Fields(SolrParams q) { + super(METHOD.GET, "/schema/fields", q); + } + + @Override + protected SchemaResponse.FieldsResponse createResponse(SolrClient client) { + return new SchemaResponse.FieldsResponse(); + } + } + + /** + * Schema API request that lists the field definition for the specified field + * contained in the schema. + */ + public static class Field extends AbstractSchemaRequest { + /** + * Creates a new instance of the request. + * + * @param fieldName the name of the field for which the definition is to be retrieved + */ + public Field(String fieldName) { + this(fieldName, null); + } + + public Field(String fieldName, SolrParams q) { + super(METHOD.GET, "/schema/fields/" + fieldName, q); + } + + @Override + protected SchemaResponse.FieldResponse createResponse(SolrClient client) { + return new SchemaResponse.FieldResponse(); + } + } + + /** + * Schema API request that lists the dynamic field definitions contained in the schema. + */ + public static class DynamicFields extends AbstractSchemaRequest { + + public DynamicFields() { + this(null); + } + + public DynamicFields(SolrParams q) { + super(METHOD.GET, "/schema/dynamicfields", q); + } + + @Override + protected SchemaResponse.DynamicFieldsResponse createResponse(SolrClient client) { + return new SchemaResponse.DynamicFieldsResponse(); + } + } + + /** + * Schema API request that lists the dynamic field definition for the specified field + * contained in the schema. + */ + public static class DynamicField extends AbstractSchemaRequest { + /** + * Creates a new instance of the class. + * + * @param dynamicFieldName the name of the dynamic field for which the definition is to be retrieved + */ + public DynamicField(String dynamicFieldName) { + this(dynamicFieldName, null); + } + + public DynamicField(String dynamicFieldName, SolrParams q) { + super(METHOD.GET, "/schema/dynamicfields/" + dynamicFieldName); + } + + @Override + protected SchemaResponse.DynamicFieldResponse createResponse(SolrClient client) { + return new SchemaResponse.DynamicFieldResponse(); + } + } + + /** + * Schema API request that lists the types definitions contained + * in the schema. + */ + public static class FieldTypes extends AbstractSchemaRequest { + public FieldTypes() { + this(null); + } + + public FieldTypes(SolrParams q) { + super(METHOD.GET, "/schema/fieldtypes"); + } + + @Override + protected SchemaResponse.FieldTypesResponse createResponse(SolrClient client) { + return new SchemaResponse.FieldTypesResponse(); + } + } + + /** + * Schema API request that retrieves the type definitions for the specified field + * type contained in the schema. + */ + public static class FieldType extends AbstractSchemaRequest { + /** + * Creates a new instance of the request. + * + * @param fieldTypeName the name of the field type for which the definition is to be retrieved + */ + public FieldType(String fieldTypeName) { + this(fieldTypeName, null); + } + + public FieldType(String fieldTypeName, SolrParams q) { + super(METHOD.GET, "/schema/fieldtypes/" + fieldTypeName, q); + } + + @Override + protected SchemaResponse.FieldTypeResponse createResponse(SolrClient client) { + return new SchemaResponse.FieldTypeResponse(); + } + } + + /** + * Schema API request that retrieves the source and destination of + * each copy field in the schema. + */ + public static class CopyFields extends AbstractSchemaRequest { + public CopyFields() { + this(null); + } + + public CopyFields(SolrParams q) { + super(METHOD.GET, "/schema/copyfields", q); + } + + @Override + protected SchemaResponse.CopyFieldsResponse createResponse(SolrClient client) { + return new SchemaResponse.CopyFieldsResponse(); + } + } + + /** + * Schema API request that retrieves the field name that is defined as + * the uniqueKey for the index of the specified collection. + */ + public static class UniqueKey extends AbstractSchemaRequest { + public UniqueKey() { + this(null); + } + + public UniqueKey(SolrParams q) { + super(METHOD.GET, "/schema/uniquekey", q); + } + + @Override + protected SchemaResponse.UniqueKeyResponse createResponse(SolrClient client) { + return new SchemaResponse.UniqueKeyResponse(); + } + } + + /** + * Retrieves the class name of the global similarity defined (if any) in the schema. + */ + public static class GlobalSimilarity extends AbstractSchemaRequest { + public GlobalSimilarity() { + this(null); + } + + public GlobalSimilarity(SolrParams q) { + super(METHOD.GET, "/schema/similarity", q); + } + + @Override + protected SchemaResponse.GlobalSimilarityResponse createResponse(SolrClient client) { + return new SchemaResponse.GlobalSimilarityResponse(); + } + } + + /** + * Retrieves the default operator if it is defined in the schema. + */ + public static class DefaultQueryOperator extends AbstractSchemaRequest { + public DefaultQueryOperator() { + this(null); + } + + public DefaultQueryOperator(SolrParams q) { + super(METHOD.GET, "/schema/solrqueryparser/defaultoperator", q); + } + + @Override + protected SchemaResponse.DefaultQueryOperatorResponse createResponse(SolrClient client) { + return new SchemaResponse.DefaultQueryOperatorResponse(); + } + } + + + /** + * Adds a new field definition to the schema. + * If the field already exists, the method {@link #process(SolrClient, String)} will fail. + * Note that the request will be translated to json, so please use concrete values (e.g. : true, 1) + * instead of their string representation (e.g. : "true", "1") for the field attributes expecting + * boolean or number values. + */ + public static class AddField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldAttributes field type attributes that can be used to enrich the field definition. + * @see Defining Solr fields + */ + public AddField(Map fieldAttributes) { + this(fieldAttributes, null); + } + + public AddField(Map fieldAttributes, SolrParams q) { + super(createRequestParameters(fieldAttributes), q); + } + + private static NamedList createRequestParameters(Map fieldAttributes) { + final NamedList addFieldParameters = createAddFieldNamedList(fieldAttributes); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("add-field", addFieldParameters); + return requestParameters; + } + } + + /** + * Replaces a field's definition. Note that the full definition for a field must be supplied - this command + * will not partially modify a field's definition. If the field does not exist in the schema the method call + * {@link #process(SolrClient, String)} will fail. + * + * @see Defining Solr fields + */ + public static class ReplaceField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldAttributes field type attributes that can be used to enrich the field definition. + */ + public ReplaceField(Map fieldAttributes) { + this(fieldAttributes, null); + } + + public ReplaceField(Map fieldAttributes, SolrParams q) { + super(createRequestParameters(fieldAttributes), q); + } + + private static NamedList createRequestParameters(Map fieldAttributes) { + final NamedList replaceFieldParameters = createAddFieldNamedList(fieldAttributes); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("replace-field", replaceFieldParameters); + return requestParameters; + } + } + + /** + * Removes a field definition from the schema. If the field does not exist in the schema, + * or if the field is the source or destination of a copy field rule the method call + * {@link #process(SolrClient, String)} will fail. + */ + public static class DeleteField extends SingleUpdate { + + /** + * Creates a new instance of the request. + * + * @param fieldName the name of the new field to be removed + */ + public DeleteField(String fieldName) { + this(fieldName, null); + } + + public DeleteField(String fieldName, SolrParams q) { + super(createRequestParameters(fieldName), q); + } + + private static NamedList createRequestParameters(String fieldName) { + final NamedList deleteFieldParameters = new NamedList<>(); + deleteFieldParameters.add("name", fieldName); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("delete-field", deleteFieldParameters); + return requestParameters; + } + } + + /** + * Adds a new dynamic field rule to the schema of the specified collection. + * + * @see Defining Solr fields + * @see Solr dynamic fields + */ + public static class AddDynamicField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldAttributes field type attributes that can be used to enrich the field definition. + */ + public AddDynamicField(Map fieldAttributes) { + this(fieldAttributes, null); + } + + public AddDynamicField(Map fieldAttributes, SolrParams q) { + super(createRequestParameters(fieldAttributes), q); + } + + private static NamedList createRequestParameters(Map fieldAttributes) { + final NamedList addDynamicFieldParameters = createAddFieldNamedList(fieldAttributes); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("add-dynamic-field", addDynamicFieldParameters); + return requestParameters; + } + } + + /** + * Replaces a dynamic field rule in the schema of the specified collection. + * Note that the full definition for a dynamic field rule must be supplied - this command + * will not partially modify a dynamic field rule's definition. + * If the dynamic field rule does not exist in the schema the method call + * {@link #process(SolrClient, String)} will fail. + */ + public static class ReplaceDynamicField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param dynamicFieldAttributes field type attributes that can be used to enrich the field definition. + * @see Defining Solr fields + * @see Solr dynamic fields + */ + public ReplaceDynamicField(Map dynamicFieldAttributes) { + this(dynamicFieldAttributes, null); + } + + public ReplaceDynamicField(Map dynamicFieldAttributes, SolrParams q) { + super(createRequestParameters(dynamicFieldAttributes), q); + } + + private static NamedList createRequestParameters( + Map dynamicFieldAttributes) { + final NamedList replaceDynamicFieldParameters = createAddFieldNamedList(dynamicFieldAttributes); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("replace-dynamic-field", replaceDynamicFieldParameters); + return requestParameters; + } + } + + /** + * Deletes a dynamic field rule from your schema. If the dynamic field rule does not exist in the schema, + * or if the schema contains a copy field rule with a target or destination that matches only this + * dynamic field rule the method call {@link #process(SolrClient, String)} will fail. + */ + public static class DeleteDynamicField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param dynamicFieldName the name of the dynamic field to be removed + */ + public DeleteDynamicField(String dynamicFieldName) { + this(dynamicFieldName, null); + } + + public DeleteDynamicField(String fieldName, SolrParams q) { + super(createRequestParameters(fieldName), q); + } + + private static NamedList createRequestParameters(String fieldName) { + final NamedList deleteDynamicFieldParameters = new NamedList<>(); + deleteDynamicFieldParameters.add("name", fieldName); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("delete-dynamic-field", deleteDynamicFieldParameters); + return requestParameters; + } + } + + /** + * Update request used to add a new field type to the schema. + */ + public static class AddFieldType extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldTypeDefinition the field type definition + * @see Solr field types + */ + public AddFieldType(FieldTypeDefinition fieldTypeDefinition) { + this(fieldTypeDefinition, null); + } + + public AddFieldType(FieldTypeDefinition fieldTypeDefinition, SolrParams q) { + super(createRequestParameters(fieldTypeDefinition), q); + } + + private static NamedList createRequestParameters(FieldTypeDefinition fieldTypeDefinition) { + final NamedList addFieldTypeParameters = createAddFieldTypeNamedList(fieldTypeDefinition); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("add-field-type", addFieldTypeParameters); + return requestParameters; + } + } + + /** + * Replaces a field type in schema belonging to the schema of the specified collection. + * Note that the full definition for a field type must be supplied- this command will not partially modify + * a field type's definition. If the field type does not exist in the schema the + * method call {@link #process(SolrClient, String)} will fail. + */ + public static class ReplaceFieldType extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldTypeDefinition the field type definition + * @see Solr field types + */ + public ReplaceFieldType(FieldTypeDefinition fieldTypeDefinition) { + this(fieldTypeDefinition, null); + } + + public ReplaceFieldType(FieldTypeDefinition fieldTypeDefinition, SolrParams q) { + super(createRequestParameters(fieldTypeDefinition), q); + } + + private static NamedList createRequestParameters(FieldTypeDefinition fieldTypeDefinition) { + final NamedList replaceFieldTypeParameters = createAddFieldTypeNamedList(fieldTypeDefinition); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("replace-field-type", replaceFieldTypeParameters); + return requestParameters; + } + } + + /** + * Removes a field type from the schema of the specified collection. + * If the field type does not exist in the schema, or if any + * field or dynamic field rule in the schema uses the field type, the + * method call {@link #process(SolrClient, String)} will fail. + */ + public static class DeleteFieldType extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param fieldTypeName the name of the field type to be removed + */ + public DeleteFieldType(String fieldTypeName) { + this(fieldTypeName, null); + } + + public DeleteFieldType(String fieldTypeName, SolrParams q) { + super(createRequestParameters(fieldTypeName), q); + } + + private static NamedList createRequestParameters(String fieldTypeName) { + final NamedList deleteFieldTypeParameters = new NamedList<>(); + deleteFieldTypeParameters.add("name", fieldTypeName); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("delete-field-type", deleteFieldTypeParameters); + return requestParameters; + } + } + + /** + * Adds a new copy field rule to the schema of the specified collection. + */ + public static class AddCopyField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param source the source field name + * @param dest the collection of the destination field names + * @see Copying fields + */ + public AddCopyField(String source, List dest) { + this(source, dest, (SolrParams) null); + } + + /** + * Creates a new instance of the request. + * + * @param source the source field name + * @param dest the collection of the destination field names + * @param maxChars the number of characters to be copied from the source to the dest. Specifying + * 0 as value, means that all the source characters will be copied to the dest. + * @see Copying fields + */ + public AddCopyField(String source, List dest, Integer maxChars) { + this(source, dest, maxChars, null); + } + + public AddCopyField(String source, List dest, SolrParams q) { + super(createRequestParameters(source, dest, null), q); + } + + public AddCopyField(String source, List dest, Integer maxChars, SolrParams q) { + super(createRequestParameters(source, dest, maxChars), q); + } + + private static NamedList createRequestParameters(String source, List dest, Integer maxchars) { + final NamedList addCopyFieldParameters = new NamedList<>(); + addCopyFieldParameters.add("source", source); + addCopyFieldParameters.add("dest", dest); + if (maxchars != null) { + addCopyFieldParameters.add("maxChars", maxchars); + } + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("add-copy-field", addCopyFieldParameters); + return requestParameters; + } + } + + /** + * Deletes a copy field rule from the schema of the specified collection. + * If the copy field rule does not exist in the schema then the + * method call {@link #process(SolrClient, String)} will fail. + */ + public static class DeleteCopyField extends SingleUpdate { + /** + * Creates a new instance of the request. + * + * @param source the source field name + * @param dest the collection of the destination field names + */ + public DeleteCopyField(String source, List dest) { + this(source, dest, null); + } + + public DeleteCopyField(String source, List dest, SolrParams q) { + super(createRequestParameters(source, dest), q); + } + + private static NamedList createRequestParameters(String source, List dest) { + final NamedList addCopyFieldParameters = new NamedList<>(); + addCopyFieldParameters.add("source", source); + addCopyFieldParameters.add("dest", dest); + final NamedList requestParameters = new NamedList<>(); + requestParameters.add("delete-copy-field", addCopyFieldParameters); + return requestParameters; + } + } + + public abstract static class Update extends AbstractSchemaRequest { + + public Update() { + this(null); + } + + public Update(SolrParams q) { + super(METHOD.POST, "/schema", q); + } + + protected abstract NamedList getRequestParameters(); + + @Override + public Collection getContentStreams() throws IOException { + CharArr json = new CharArr(); + new SchemaRequestJSONWriter(json).write(getRequestParameters()); + return Collections.singletonList(new ContentStreamBase.StringStream(json.toString())); + } + + @Override + protected SchemaResponse.UpdateResponse createResponse(SolrClient client) { + return new SchemaResponse.UpdateResponse(); + } + } + + private static abstract class SingleUpdate extends Update { + private final NamedList requestParameters; + + public SingleUpdate(NamedList requestParameters) { + this(requestParameters, null); + } + + public SingleUpdate(NamedList requestParameters, SolrParams q) { + super(q); + this.requestParameters = requestParameters; + } + + @Override + protected NamedList getRequestParameters() { + return requestParameters; + } + } + + /** + *

The Schema API offers the possibility to perform one or more add requests in a single command.

+ *

The API is transactional and all commands in a single {@link #process(SolrClient, String)} call + * either succeed or fail together.

+ */ + public static class MultiUpdate extends Update { + private List updateSchemaRequests = new LinkedList<>(); + + public MultiUpdate(List updateSchemaRequests) { + this(updateSchemaRequests, null); + } + + public MultiUpdate(List updateSchemaRequests, SolrParams q) { + super(q); + if (updateSchemaRequests == null) { + throw new IllegalArgumentException("updateSchemaRequests must be non-null"); + } + for (Update updateSchemaRequest : updateSchemaRequests) { + if (updateSchemaRequest == null) { + throw new IllegalArgumentException("updateSchemaRequests elements must be non-null"); + } + this.updateSchemaRequests.add(updateSchemaRequest); + } + } + + @Override + protected NamedList getRequestParameters() { + NamedList multipleRequestsParameters = new NamedList<>(); + for (Update updateSchemaRequest : updateSchemaRequests) { + multipleRequestsParameters.addAll(updateSchemaRequest.getRequestParameters()); + } + return multipleRequestsParameters; + } + } + + /** + * Simple extension of the noggit JSONWriter used to be write objects + * of type {@link NamedList}. + * Writing of objects of the type {@link NamedList} is done in very much + * the same way as for a map. + *

+ * This writer is particularly useful when doing multiple update requests. + * In update Schema API there can be done multiple add operations of the same + * type (e.g. : add-field-type), they are grouped in an associative array, even though + * this can't be done normally in JSON. For such a use-case, the {@link NamedList} + * objects are particularly useful because they can group key-value mappings + * having the same values for the keys (unlike maps). + */ + private static class SchemaRequestJSONWriter extends JSONWriter { + public SchemaRequestJSONWriter(CharArr out, int indentSize) { + super(out, indentSize); + } + + public SchemaRequestJSONWriter(CharArr out) { + super(out); + } + + public void write(Object o) { + if (o instanceof NamedList) { + write((NamedList) o); + } else super.write(o); + } + + /** + * @see #write(Map) + */ + @SuppressWarnings("unchecked") + public void write(NamedList val) { + this.startObject(); + int sz = val.size(); + boolean first = true; + Iterator i$ = val.iterator(); + + while (i$.hasNext()) { + Map.Entry entry = (Map.Entry) i$.next(); + if (first) { + first = false; + } else { + this.writeValueSeparator(); + } + + if (sz > 1) { + this.indent(); + } + + this.writeString(entry.getKey()); + this.writeNameSeparator(); + this.write(entry.getValue()); + } + + this.endObject(); + } + } +} + diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/package-info.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/package-info.java new file mode 100644 index 00000000000..874d16b1ce9 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/schema/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * Convenience classes for making Schema API requests. + *

+ * See <a href="https://cwiki.apache.org/confluence/display/solr/Schema+API">Schema API</a> + */ +package org.apache.solr.client.solrj.request.schema; \ No newline at end of file diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/FieldTypeRepresentation.java b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/FieldTypeRepresentation.java new file mode 100644 index 00000000000..36d31d8f55b --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/FieldTypeRepresentation.java @@ -0,0 +1,47 @@ +package org.apache.solr.client.solrj.response.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 java.util.List; + +import org.apache.solr.client.solrj.request.schema.FieldTypeDefinition; + +public class FieldTypeRepresentation extends FieldTypeDefinition { + private List fields; + + private List dynamicFields; + + public FieldTypeRepresentation() { + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public List getDynamicFields() { + return dynamicFields; + } + + public void setDynamicFields(List dynamicFields) { + this.dynamicFields = dynamicFields; + } +} diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaRepresentation.java b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaRepresentation.java new file mode 100644 index 00000000000..7e6df8b1dfd --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaRepresentation.java @@ -0,0 +1,128 @@ +package org.apache.solr.client.solrj.response.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 java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.request.schema.FieldTypeDefinition; + +public class SchemaRepresentation { + + private String name; + + private float version; + + private String uniqueKey; + + private String defaultSearchField; + + private String defaultOperator; + + private Map similarity; + + private List> fields; + + private List> dynamicFields; + + private List fieldTypes; + + private List> copyFields; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public float getVersion() { + return version; + } + + public void setVersion(float version) { + this.version = version; + } + + public String getUniqueKey() { + return uniqueKey; + } + + public void setUniqueKey(String uniqueKey) { + this.uniqueKey = uniqueKey; + } + + public String getDefaultSearchField() { + return defaultSearchField; + } + + public void setDefaultSearchField(String defaultSearchField) { + this.defaultSearchField = defaultSearchField; + } + + public String getDefaultOperator() { + return defaultOperator; + } + + public void setDefaultOperator(String defaultOperator) { + this.defaultOperator = defaultOperator; + } + + public Map getSimilarity() { + return similarity; + } + + public void setSimilarity(Map similarity) { + this.similarity = similarity; + } + + public List> getFields() { + return fields; + } + + public void setFields(List> fields) { + this.fields = fields; + } + + public List> getDynamicFields() { + return dynamicFields; + } + + public void setDynamicFields(List> dynamicFields) { + this.dynamicFields = dynamicFields; + } + + public List getFieldTypes() { + return fieldTypes; + } + + public void setFieldTypes(List fieldTypes) { + this.fieldTypes = fieldTypes; + } + + public List> getCopyFields() { + return copyFields; + } + + public void setCopyFields(List> copyFields) { + this.copyFields = copyFields; + } + +} diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaResponse.java b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaResponse.java new file mode 100644 index 00000000000..5a4bdb7396d --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/SchemaResponse.java @@ -0,0 +1,508 @@ +package org.apache.solr.client.solrj.response.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 java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.request.schema.AnalyzerDefinition; +import org.apache.solr.client.solrj.request.schema.FieldTypeDefinition; +import org.apache.solr.client.solrj.response.SolrResponseBase; +import org.apache.solr.common.util.NamedList; + +/** + * This class is used to wrap the response messages retrieved from Solr Schema API. + * + * @see Solr Schema API + * @since solr 5.3 + */ +public class SchemaResponse extends SolrResponseBase { + private SchemaRepresentation schemaRepresentation; + + private static Map extractAttributeMap(NamedList namedList) { + if (namedList == null) return null; + LinkedHashMap result = new LinkedHashMap<>(); + for (int i = 0; i < namedList.size(); i++) { + T val = namedList.getVal(i); + String name = namedList.getName(i); + if (!(val instanceof NamedList) && !(val instanceof List)) { + result.put(name, val); + } + } + + return result; + } + + @SuppressWarnings("unchecked") + private static AnalyzerDefinition createAnalyzerDefinition(NamedList analyzerNamedList) { + AnalyzerDefinition analyzerDefinition = new AnalyzerDefinition(); + Map analyzerAttributes = extractAttributeMap(analyzerNamedList); + analyzerDefinition.setAttributes(analyzerAttributes); + List> charFiltersList = (List>) analyzerNamedList.get("charFilters"); + if (charFiltersList != null) { + List> charFiltersAttributesList = new LinkedList<>(); + for (NamedList charFilterNamedList : charFiltersList) { + Map charFilterAttributes = extractAttributeMap(charFilterNamedList); + charFiltersAttributesList.add(charFilterAttributes); + } + analyzerDefinition.setCharFilters(charFiltersAttributesList); + } + NamedList tokenizerNamedList = (NamedList) analyzerNamedList.get("tokenizer"); + if (tokenizerNamedList != null) { + Map tokenizerAttributes = extractAttributeMap(tokenizerNamedList); + analyzerDefinition.setTokenizer(tokenizerAttributes); + } + List> filtersList = (List>) analyzerNamedList.get("filters"); + List> filtersAttributesList = new LinkedList<>(); + if (filtersList != null) { + for (NamedList filterNamedList : filtersList) { + Map filterAttributes = extractAttributeMap(filterNamedList); + filtersAttributesList.add(filterAttributes); + } + analyzerDefinition.setFilters(filtersAttributesList); + } + + return analyzerDefinition; + } + + @SuppressWarnings("unchecked") + private static FieldTypeDefinition createFieldTypeDefinition(NamedList fieldTypeNamedList) { + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + fillFieldTypeDefinition(fieldTypeDefinition, fieldTypeNamedList); + return fieldTypeDefinition; + } + + @SuppressWarnings("unchecked") + private static FieldTypeRepresentation createFieldTypeRepresentation(NamedList fieldTypeNamedList) { + FieldTypeRepresentation fieldTypeRepresentation = new FieldTypeRepresentation(); + fillFieldTypeDefinition(fieldTypeRepresentation, fieldTypeNamedList); + List fields = (List) fieldTypeNamedList.get("fields"); + if (fields != null) fieldTypeRepresentation.setFields(fields); + List dynamicFields = (List) fieldTypeNamedList.get("dynamicFields"); + if (dynamicFields != null) fieldTypeRepresentation.setDynamicFields(dynamicFields); + return fieldTypeRepresentation; + } + + @SuppressWarnings("unchecked") + private static void fillFieldTypeDefinition(FieldTypeDefinition fieldTypeDefinition, NamedList fieldTypeNamedList) { + Map fieldTypeAttributes = extractAttributeMap(fieldTypeNamedList); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + NamedList analyzerNamedList = (NamedList) fieldTypeNamedList.get("analyzer"); + if (analyzerNamedList != null) { + AnalyzerDefinition analyzerDefinition = createAnalyzerDefinition(analyzerNamedList); + fieldTypeDefinition.setAnalyzer(analyzerDefinition); + } + NamedList indexAnalyzerNamedList = (NamedList) fieldTypeNamedList.get("indexAnalyzer"); + if (indexAnalyzerNamedList != null) { + AnalyzerDefinition indexAnalyzerDefinition = + createAnalyzerDefinition(indexAnalyzerNamedList); + fieldTypeDefinition.setIndexAnalyzer(indexAnalyzerDefinition); + } + NamedList queryAnalyzerNamedList = (NamedList) fieldTypeNamedList.get("queryAnalyzer"); + if (queryAnalyzerNamedList != null) { + AnalyzerDefinition queryAnalyzerDefinition = createAnalyzerDefinition(queryAnalyzerNamedList); + fieldTypeDefinition.setQueryAnalyzer(queryAnalyzerDefinition); + } + NamedList multiTermAnalyzerNamedList = (NamedList) fieldTypeNamedList.get("multiTermAnalyzer"); + if (multiTermAnalyzerNamedList != null) { + AnalyzerDefinition multiTermAnalyzerDefinition = + createAnalyzerDefinition(multiTermAnalyzerNamedList); + fieldTypeDefinition.setMultiTermAnalyzer(multiTermAnalyzerDefinition); + } + NamedList similarityNamedList = (NamedList) fieldTypeNamedList.get("similarity"); + if (similarityNamedList != null) { + Map similarityAttributes = extractAttributeMap(similarityNamedList); + fieldTypeDefinition.setSimilarity(similarityAttributes); + } + } + + private static SchemaRepresentation createSchemaConfiguration(NamedList schemaNamedList) { + SchemaRepresentation schemaRepresentation = new SchemaRepresentation(); + schemaRepresentation.setName(getSchemaName(schemaNamedList)); + schemaRepresentation.setVersion(getSchemaVersion(schemaNamedList)); + schemaRepresentation.setUniqueKey(getSchemaUniqueKey(schemaNamedList)); + schemaRepresentation.setDefaultSearchField(getDefaultSearchField(schemaNamedList)); + schemaRepresentation.setDefaultOperator(getDefaultOperator(schemaNamedList)); + schemaRepresentation.setSimilarity(getSimilarity(schemaNamedList)); + schemaRepresentation.setFields(getFields(schemaNamedList)); + schemaRepresentation.setDynamicFields(getDynamicFields(schemaNamedList)); + schemaRepresentation.setFieldTypes(getFieldTypeDefinitions(schemaNamedList)); + schemaRepresentation.setCopyFields(getCopyFields(schemaNamedList)); + return schemaRepresentation; + } + + private static String getSchemaName(NamedList schemaNamedList) { + return (String) schemaNamedList.get("name"); + } + + private static Float getSchemaVersion(NamedList schemaNamedList) { + return (Float) schemaNamedList.get("version"); + } + + private static String getSchemaUniqueKey(NamedList schemaNamedList) { + return (String) schemaNamedList.get("uniqueKey"); + } + + private static String getDefaultSearchField(NamedList schemaNamedList) { + return (String) schemaNamedList.get("defaultSearchField"); + } + + private static Map getSimilarity(NamedList schemaNamedList) { + NamedList similarityNamedList = (NamedList) schemaNamedList.get("similarity"); + Map similarity = null; + if (similarityNamedList != null) similarity = extractAttributeMap(similarityNamedList); + return similarity; + } + + @SuppressWarnings("unchecked") + private static String getDefaultOperator(NamedList schemaNamedList) { + String defaultOperator = null; + NamedList solrQueryParserProperties = (NamedList) schemaNamedList.get("solrQueryParser"); + if (solrQueryParserProperties != null) defaultOperator = (String) solrQueryParserProperties.get("defaultOperator"); + return defaultOperator; + } + + @SuppressWarnings("unchecked") + private static List> getFields(NamedList schemaNamedList) { + List> fieldsAttributes = new LinkedList<>(); + List> fieldsResponse = (List>) schemaNamedList.get("fields"); + for (NamedList fieldNamedList : fieldsResponse) { + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.putAll(extractAttributeMap(fieldNamedList)); + fieldsAttributes.add(fieldAttributes); + } + + return fieldsAttributes; + } + + @SuppressWarnings("unchecked") + private static List> getDynamicFields(NamedList schemaNamedList) { + List> dynamicFieldsAttributes = new LinkedList<>(); + List> dynamicFieldsResponse = (List>) schemaNamedList.get("dynamicFields"); + for (NamedList fieldNamedList : dynamicFieldsResponse) { + Map dynamicFieldAttributes = new LinkedHashMap<>(); + dynamicFieldAttributes.putAll(extractAttributeMap(fieldNamedList)); + dynamicFieldsAttributes.add(dynamicFieldAttributes); + } + + return dynamicFieldsAttributes; + } + + @SuppressWarnings("unchecked") + private static List> getCopyFields(NamedList schemaNamedList) { + List> copyFieldsAttributes = new LinkedList<>(); + List> copyFieldsResponse = (List>) schemaNamedList.get("copyFields"); + for (NamedList copyFieldNamedList : copyFieldsResponse) { + Map copyFieldAttributes = new LinkedHashMap<>(); + copyFieldAttributes.putAll(extractAttributeMap(copyFieldNamedList)); + copyFieldsAttributes.add(copyFieldAttributes); + } + + return copyFieldsAttributes; + } + + @SuppressWarnings("unchecked") + private static List getFieldTypeDefinitions(NamedList schemaNamedList) { + List fieldTypeDefinitions = new LinkedList<>(); + List> fieldsResponse = (List>) schemaNamedList.get("fieldTypes"); + for (NamedList fieldNamedList : fieldsResponse) { + FieldTypeDefinition fieldTypeDefinition = createFieldTypeDefinition(fieldNamedList); + fieldTypeDefinitions.add(fieldTypeDefinition); + } + + return fieldTypeDefinitions; + } + + @SuppressWarnings("unchecked") + private static List getFieldTypeRepresentations(NamedList schemaNamedList) { + List fieldTypeRepresentations = new LinkedList<>(); + List> fieldsResponse = (List>) schemaNamedList.get("fieldTypes"); + for (NamedList fieldNamedList : fieldsResponse) { + FieldTypeRepresentation fieldTypeRepresentation = createFieldTypeRepresentation(fieldNamedList); + fieldTypeRepresentations.add(fieldTypeRepresentation); + } + + return fieldTypeRepresentations; + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + NamedList schemaNamedList = (NamedList) response.get("schema"); + schemaRepresentation = createSchemaConfiguration(schemaNamedList); + } + + public SchemaRepresentation getSchemaRepresentation() { + return schemaRepresentation; + } + + public static class SchemaNameResponse extends SolrResponseBase { + private String schemaName; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + schemaName = SchemaResponse.getSchemaName(response); + } + + public String getSchemaName() { + return schemaName; + } + + } + + public static class SchemaVersionResponse extends SolrResponseBase { + private float schemaVersion; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + schemaVersion = SchemaResponse.getSchemaVersion(response); + } + + public float getSchemaVersion() { + return schemaVersion; + } + + } + + public static class FieldResponse extends SolrResponseBase { + Map field = new LinkedHashMap<>(); + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + NamedList fieldResponse = (NamedList) response.get("field"); + field.putAll(extractAttributeMap(fieldResponse)); + } + + public Map getField() { + return field; + } + + } + + public static class FieldsResponse extends SolrResponseBase { + List> fields; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + fields = SchemaResponse.getFields(response); + } + + public List> getFields() { + return fields; + } + } + + public static class DynamicFieldResponse extends SolrResponseBase { + Map dynamicField = new LinkedHashMap<>(); + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + NamedList dynamicFieldResponse = (NamedList) response.get("dynamicField"); + dynamicField.putAll(extractAttributeMap(dynamicFieldResponse)); + } + + public Map getDynamicField() { + return dynamicField; + } + + } + + public static class DynamicFieldsResponse extends SolrResponseBase { + List> dynamicFields; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + dynamicFields = SchemaResponse.getDynamicFields(response); + } + + public List> getDynamicFields() { + return dynamicFields; + } + } + + public static class UniqueKeyResponse extends SolrResponseBase { + private String uniqueKey; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + uniqueKey = SchemaResponse.getSchemaUniqueKey(response); + } + + public String getUniqueKey() { + return uniqueKey; + } + } + + public static class GlobalSimilarityResponse extends SolrResponseBase { + Map similarity; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + similarity = SchemaResponse.getSimilarity(response); + } + + public Map getSimilarity() { + return similarity; + } + + } + + public static class DefaultQueryOperatorResponse extends SolrResponseBase { + private String defaultOperator; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + defaultOperator = (String) response.get("defaultOperator"); + } + + public String getDefaultOperator() { + return defaultOperator; + } + } + + public static class CopyFieldsResponse extends SolrResponseBase { + List> copyFields; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + copyFields = SchemaResponse.getCopyFields(response); + } + + public List> getCopyFields() { + return copyFields; + } + } + + public static class FieldTypeResponse extends SolrResponseBase { + private FieldTypeRepresentation fieldType; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + NamedList fieldTypeNamedList = (NamedList) response.get("fieldType"); + fieldType = createFieldTypeRepresentation(fieldTypeNamedList); + } + + public FieldTypeRepresentation getFieldType() { + return fieldType; + } + } + + + public static class FieldTypesResponse extends SolrResponseBase { + List fieldTypes; + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + + fieldTypes = SchemaResponse.getFieldTypeRepresentations(response); + } + + public List getFieldTypes() { + return fieldTypes; + } + } + + public static class UpdateResponse extends SolrResponseBase { + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public void setResponse(NamedList response) { + super.setResponse(response); + } + } +} diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/package-info.java b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/package-info.java new file mode 100644 index 00000000000..fe55e040fd2 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/response/schema/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * Convenience classes for dealing with Schema API responses. + *

+ * See <a href="https://cwiki.apache.org/confluence/display/solr/Schema+API">Schema API</a> + */ +package org.apache.solr.client.solrj.response.schema; \ No newline at end of file diff --git a/solr/solrj/src/test-files/solrj/solr/collection1/conf/solrconfig-managed-schema.xml b/solr/solrj/src/test-files/solrj/solr/collection1/conf/solrconfig-managed-schema.xml new file mode 100644 index 00000000000..9db6a577f20 --- /dev/null +++ b/solr/solrj/src/test-files/solrj/solr/collection1/conf/solrconfig-managed-schema.xml @@ -0,0 +1,32 @@ + + + + + + ${tests.luceneMatchVersion:LATEST} + + + true + managed-schema + + + + diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java new file mode 100644 index 00000000000..2ea061104d9 --- /dev/null +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java @@ -0,0 +1,910 @@ +package org.apache.solr.client.solrj.request; + +/* + * 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 java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.io.FileUtils; +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.request.schema.AnalyzerDefinition; +import org.apache.solr.client.solrj.request.schema.FieldTypeDefinition; +import org.apache.solr.client.solrj.request.schema.SchemaRequest; +import org.apache.solr.client.solrj.response.SolrResponseBase; +import org.apache.solr.client.solrj.response.schema.FieldTypeRepresentation; +import org.apache.solr.client.solrj.response.schema.SchemaRepresentation; +import org.apache.solr.client.solrj.response.schema.SchemaResponse; +import org.apache.solr.common.SolrException; +import org.apache.solr.util.RestTestBase; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restlet.ext.servlet.ServerServlet; + +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; + +/** + * Test the functionality (accuracy and failure) of the methods exposed by the classes + * {@link SchemaRequest} and {@link SchemaResponse}. + */ +public class SchemaTest extends RestTestBase { + private static void assertValidSchemaResponse(SolrResponseBase schemaResponse) { + assertEquals(0, schemaResponse.getStatus()); + assertNull(schemaResponse.getResponse().get("errors")); + } + + private static void createStoredStringField(String fieldName, SolrClient solrClient) throws Exception { + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", fieldName); + fieldAttributes.put("type", "string"); + fieldAttributes.put("stored", true); + SchemaRequest.AddField addFieldRequest = new SchemaRequest.AddField(fieldAttributes); + addFieldRequest.process(solrClient); + } + + private static SchemaRequest.AddFieldType createFieldTypeRequest(String fieldTypeName) { + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + Map fieldTypeAttributes = new LinkedHashMap<>(); + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "solr.TextField"); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + AnalyzerDefinition indexAnalyzerDefinition = new AnalyzerDefinition(); + Map iTokenizerAttributes = new LinkedHashMap<>(); + iTokenizerAttributes.put("class", "solr.PathHierarchyTokenizerFactory"); + iTokenizerAttributes.put("delimiter", "/"); + indexAnalyzerDefinition.setTokenizer(iTokenizerAttributes); + fieldTypeDefinition.setIndexAnalyzer(indexAnalyzerDefinition); + AnalyzerDefinition queryAnalyzerDefinition = new AnalyzerDefinition(); + Map qTokenizerAttributes = new LinkedHashMap<>(); + qTokenizerAttributes.put("class", "solr.KeywordTokenizerFactory"); + queryAnalyzerDefinition.setTokenizer(qTokenizerAttributes); + fieldTypeDefinition.setQueryAnalyzer(queryAnalyzerDefinition); + return new SchemaRequest.AddFieldType(fieldTypeDefinition); + } + + @Before + public void init() throws Exception { + File tmpSolrHome = createTempDir().toFile(); + FileUtils.copyDirectory(new File(getFile("solrj/solr/collection1").getParent()), tmpSolrHome.getAbsoluteFile()); + + final SortedMap extraServlets = new TreeMap<>(); + final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); + solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); + extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' + + System.setProperty("managed.schema.mutable", "true"); + System.setProperty("enable.update.log", "false"); + + createJettyAndHarness(tmpSolrHome.getAbsolutePath(), "solrconfig-managed-schema.xml", "schema.xml", + "/solr", true, extraServlets); + } + + @After + public void cleanup() throws Exception { + if (jetty != null) { + jetty.stop(); + jetty = null; + } + client = null; + if (restTestHarness != null) { + restTestHarness.close(); + } + restTestHarness = null; + + } + + @Test + public void testSchemaRequestAccuracy() throws Exception { + SchemaRequest schemaRequest = new SchemaRequest(); + SchemaResponse schemaResponse = schemaRequest.process(getSolrClient()); + assertValidSchemaResponse(schemaResponse); + SchemaRepresentation schemaRepresentation = schemaResponse.getSchemaRepresentation(); + assertNotNull(schemaRepresentation); + assertEquals("test", schemaRepresentation.getName()); + assertTrue(1.5 == schemaRepresentation.getVersion()); + assertEquals("id", schemaRepresentation.getUniqueKey()); + assertFalse(schemaRepresentation.getFields().isEmpty()); + assertFalse(schemaRepresentation.getDynamicFields().isEmpty()); + assertFalse(schemaRepresentation.getFieldTypes().isEmpty()); + assertFalse(schemaRepresentation.getCopyFields().isEmpty()); + } + + @Test + public void testSchemaNameRequestAccuracy() throws Exception { + SchemaRequest.SchemaName schemaNameRequest = new SchemaRequest.SchemaName(); + SchemaResponse.SchemaNameResponse schemaNameResponse = schemaNameRequest.process(getSolrClient()); + assertValidSchemaResponse(schemaNameResponse); + assertEquals("test", schemaNameResponse.getSchemaName()); + } + + @Test + public void testSchemaVersionRequestAccuracy() throws Exception { + SchemaRequest.SchemaVersion schemaVersionRequest = new SchemaRequest.SchemaVersion(); + SchemaResponse.SchemaVersionResponse schemaVersionResponse = schemaVersionRequest.process(getSolrClient()); + assertValidSchemaResponse(schemaVersionResponse); + assertTrue(1.5 == schemaVersionResponse.getSchemaVersion()); + } + + @Test + public void testGetFieldsAccuracy() throws Exception { + SchemaRequest.Fields fieldsSchemaRequest = new SchemaRequest.Fields(); + SchemaResponse.FieldsResponse fieldsResponse = fieldsSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(fieldsResponse); + List> fields = fieldsResponse.getFields(); + assertThat(fields.isEmpty(), is(false)); + } + + @Test + public void testGetFieldAccuracy() throws Exception { + String fieldName = "signatureField"; + SchemaRequest.Field fieldSchemaRequest = new SchemaRequest.Field(fieldName); + SchemaResponse.FieldResponse fieldResponse = fieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(fieldResponse); + Map fieldAttributes = fieldResponse.getField(); + assertThat(fieldName, is(equalTo(fieldAttributes.get("name")))); + assertThat("string", is(equalTo(fieldAttributes.get("type")))); + } + + @Test + public void testGetDynamicFieldsAccuracy() throws Exception { + SchemaRequest.DynamicFields dynamicFieldsSchemaRequest = + new SchemaRequest.DynamicFields(); + SchemaResponse.DynamicFieldsResponse dynamicFieldsResponse = dynamicFieldsSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(dynamicFieldsResponse); + List> fields = dynamicFieldsResponse.getDynamicFields(); + assertThat(fields.isEmpty(), is(false)); + } + + @Test + public void testGetDynamicFieldAccuracy() throws Exception { + String dynamicFieldName = "*_i"; + SchemaRequest.DynamicField dynamicFieldSchemaRequest = + new SchemaRequest.DynamicField(dynamicFieldName); + SchemaResponse.DynamicFieldResponse dynamicFieldResponse = dynamicFieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(dynamicFieldResponse); + Map dynamicFieldAttributes = dynamicFieldResponse.getDynamicField(); + assertThat(dynamicFieldName, is(equalTo(dynamicFieldAttributes.get("name")))); + assertThat("int", is(equalTo(dynamicFieldAttributes.get("type")))); + } + + @Test + public void testGetFieldTypesAccuracy() throws Exception { + SchemaRequest.FieldTypes fieldTypesRequest = + new SchemaRequest.FieldTypes(); + SchemaResponse.FieldTypesResponse fieldTypesResponse = fieldTypesRequest.process(getSolrClient()); + assertValidSchemaResponse(fieldTypesResponse); + List fieldTypes = fieldTypesResponse.getFieldTypes(); + assertThat(fieldTypes.isEmpty(), is(false)); + } + + @Test + public void testGetFieldTypeAccuracy() throws Exception { + String fieldType = "string"; + SchemaRequest.FieldType fieldTypeSchemaRequest = + new SchemaRequest.FieldType(fieldType); + SchemaResponse.FieldTypeResponse fieldTypeResponse = fieldTypeSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(fieldTypeResponse); + FieldTypeRepresentation fieldTypeDefinition = fieldTypeResponse.getFieldType(); + assertThat(fieldType, is(equalTo(fieldTypeDefinition.getAttributes().get("name")))); + assertThat("solr.StrField", is(equalTo(fieldTypeDefinition.getAttributes().get("class")))); + } + + @Test + public void testGetCopyFieldsAccuracy() throws Exception { + SchemaRequest.CopyFields copyFieldsRequest = + new SchemaRequest.CopyFields(); + SchemaResponse.CopyFieldsResponse copyFieldsResponse = copyFieldsRequest.process(getSolrClient()); + assertValidSchemaResponse(copyFieldsResponse); + List> copyFieldsAttributes = copyFieldsResponse.getCopyFields(); + assertThat(copyFieldsAttributes.isEmpty(), is(false)); + } + + @Test + public void testGetUniqueKeyAccuracy() throws Exception { + SchemaRequest.UniqueKey uniqueKeyRequest = + new SchemaRequest.UniqueKey(); + SchemaResponse.UniqueKeyResponse uniqueKeyResponse = uniqueKeyRequest.process(getSolrClient()); + assertValidSchemaResponse(uniqueKeyResponse); + assertEquals("id", uniqueKeyResponse.getUniqueKey()); + } + + @Test + public void testGetGlobalSimilarityAccuracy() throws Exception { + SchemaRequest.GlobalSimilarity globalSimilarityRequest = + new SchemaRequest.GlobalSimilarity(); + SchemaResponse.GlobalSimilarityResponse globalSimilarityResponse = globalSimilarityRequest.process(getSolrClient()); + assertValidSchemaResponse(globalSimilarityResponse); + assertEquals("org.apache.solr.search.similarities.DefaultSimilarityFactory", + globalSimilarityResponse.getSimilarity().get("class")); + } + + @Test + public void testGetDefaultQueryOperatorAccuracy() throws Exception { + SchemaRequest.DefaultQueryOperator defaultQueryOperatorRequest = + new SchemaRequest.DefaultQueryOperator(); + SchemaResponse.DefaultQueryOperatorResponse defaultQueryOperatorResponse = + defaultQueryOperatorRequest.process(getSolrClient()); + assertValidSchemaResponse(defaultQueryOperatorResponse); + assertEquals("OR", defaultQueryOperatorResponse.getDefaultOperator()); + } + + @Test + public void testAddFieldAccuracy() throws Exception { + SchemaRequest.Fields fieldsSchemaRequest = new SchemaRequest.Fields(); + SchemaResponse.FieldsResponse initialFieldsResponse = fieldsSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(initialFieldsResponse); + List> initialFields = initialFieldsResponse.getFields(); + + String fieldName = "accuracyField"; + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", fieldName); + fieldAttributes.put("type", "string"); + fieldAttributes.put("stored", false); + fieldAttributes.put("indexed", true); + fieldAttributes.put("default", "accuracy"); + fieldAttributes.put("required", true); + SchemaRequest.AddField addFieldUpdateSchemaRequest = + new SchemaRequest.AddField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + SchemaResponse.FieldsResponse currentFieldsResponse = fieldsSchemaRequest.process(getSolrClient()); + assertEquals(0, currentFieldsResponse.getStatus()); + List> currentFields = currentFieldsResponse.getFields(); + assertEquals(initialFields.size() + 1, currentFields.size()); + + + SchemaRequest.Field fieldSchemaRequest = new SchemaRequest.Field(fieldName); + SchemaResponse.FieldResponse newFieldResponse = fieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldResponse); + Map newFieldAttributes = newFieldResponse.getField(); + assertThat(fieldName, is(equalTo(newFieldAttributes.get("name")))); + assertThat("string", is(equalTo(newFieldAttributes.get("type")))); + assertThat(false, is(equalTo(newFieldAttributes.get("stored")))); + assertThat(true, is(equalTo(newFieldAttributes.get("indexed")))); + assertThat("accuracy", is(equalTo(newFieldAttributes.get("default")))); + assertThat(true, is(equalTo(newFieldAttributes.get("required")))); + } + + @Test + public void addFieldShouldntBeCalledTwiceWithTheSameName() throws Exception { + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", "failureField"); + fieldAttributes.put("type", "string"); + SchemaRequest.AddField addFieldUpdateSchemaRequest = + new SchemaRequest.AddField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldFirstResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldFirstResponse); + + SchemaResponse.UpdateResponse addFieldSecondResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertEquals(0, addFieldSecondResponse.getStatus()); + assertNotNull(addFieldSecondResponse.getResponse().get("errors")); + } + + @Test + public void testDeleteFieldAccuracy() throws Exception { + String fieldName = "fieldToBeDeleted"; + Map fieldAttributesRequest = new LinkedHashMap<>(); + fieldAttributesRequest.put("name", fieldName); + fieldAttributesRequest.put("type", "string"); + SchemaRequest.AddField addFieldUpdateSchemaRequest = + new SchemaRequest.AddField(fieldAttributesRequest); + SchemaResponse.UpdateResponse addFieldResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + SchemaRequest.Field fieldSchemaRequest = new SchemaRequest.Field(fieldName); + SchemaResponse.FieldResponse initialFieldResponse = fieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(initialFieldResponse); + Map fieldAttributesResponse = initialFieldResponse.getField(); + assertThat(fieldName, is(equalTo(fieldAttributesResponse.get("name")))); + + SchemaRequest.DeleteField deleteFieldRequest = + new SchemaRequest.DeleteField(fieldName); + SchemaResponse.UpdateResponse deleteFieldResponse = deleteFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(deleteFieldResponse); + + try { + fieldSchemaRequest.process(getSolrClient()); + fail(String.format(Locale.ROOT, "after removal, the field %s shouldn't be anymore available over Schema API", fieldName)); + } catch (SolrException e) { + //success + } + } + + @Test + public void deletingAFieldThatDoesntExistInTheSchemaShouldFail() throws Exception { + SchemaRequest.DeleteField deleteFieldRequest = + new SchemaRequest.DeleteField("fieldToBeDeleted"); + SchemaResponse.UpdateResponse deleteFieldResponse = deleteFieldRequest.process(getSolrClient()); + assertNotNull(deleteFieldResponse.getResponse().get("errors")); + } + + @Test + public void testReplaceFieldAccuracy() throws Exception { + // Given + Map fieldAttributes = new LinkedHashMap<>(); + String fieldName = "accuracyField"; + fieldAttributes.put("name", fieldName); + fieldAttributes.put("type", "string"); + fieldAttributes.put("stored", false); + fieldAttributes.put("indexed", true); + fieldAttributes.put("required", true); + SchemaRequest.AddField addFieldUpdateSchemaRequest = + new SchemaRequest.AddField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + // When : update the field definition + fieldAttributes.put("stored", true); + fieldAttributes.put("indexed", false); + SchemaRequest.ReplaceField replaceFieldRequest = new SchemaRequest.ReplaceField(fieldAttributes); + SchemaResponse.UpdateResponse replaceFieldResponse = replaceFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(replaceFieldResponse); + + // Then + SchemaRequest.Field fieldSchemaRequest = new SchemaRequest.Field(fieldName); + SchemaResponse.FieldResponse newFieldResponse = fieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldResponse); + Map newFieldAttributes = newFieldResponse.getField(); + assertThat(fieldName, is(equalTo(newFieldAttributes.get("name")))); + assertThat("string", is(equalTo(newFieldAttributes.get("type")))); + assertThat(true, is(equalTo(newFieldAttributes.get("stored")))); + assertThat(false, is(equalTo(newFieldAttributes.get("indexed")))); + assertThat(true, is(equalTo(newFieldAttributes.get("required")))); + } + + @Test + public void testAddDynamicFieldAccuracy() throws Exception { + SchemaRequest.DynamicFields dynamicFieldsSchemaRequest = + new SchemaRequest.DynamicFields(); + SchemaResponse.DynamicFieldsResponse initialDFieldsResponse = dynamicFieldsSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(initialDFieldsResponse); + List> initialDFields = initialDFieldsResponse.getDynamicFields(); + + String dFieldName = "*_acc"; + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", dFieldName); + fieldAttributes.put("type", "string"); + fieldAttributes.put("stored", false); + fieldAttributes.put("indexed", true); + fieldAttributes.put("default", "accuracy"); + fieldAttributes.put("required", true); + SchemaRequest.AddDynamicField addFieldUpdateSchemaRequest = + new SchemaRequest.AddDynamicField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + SchemaResponse.DynamicFieldsResponse currentDFieldsResponse = dynamicFieldsSchemaRequest.process(getSolrClient()); + assertEquals(0, currentDFieldsResponse.getStatus()); + List> currentFields = currentDFieldsResponse.getDynamicFields(); + assertEquals(initialDFields.size() + 1, currentFields.size()); + + + SchemaRequest.DynamicField dFieldRequest = new SchemaRequest.DynamicField(dFieldName); + SchemaResponse.DynamicFieldResponse newFieldResponse = dFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldResponse); + Map newFieldAttributes = newFieldResponse.getDynamicField(); + assertThat(dFieldName, is(equalTo(newFieldAttributes.get("name")))); + assertThat("string", is(equalTo(newFieldAttributes.get("type")))); + assertThat(false, is(equalTo(newFieldAttributes.get("stored")))); + assertThat(true, is(equalTo(newFieldAttributes.get("indexed")))); + assertThat("accuracy", is(equalTo(newFieldAttributes.get("default")))); + assertThat(true, is(equalTo(newFieldAttributes.get("required")))); + } + + @Test + public void addDynamicFieldShouldntBeCalledTwiceWithTheSameName() throws Exception { + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", "*_failure"); + fieldAttributes.put("type", "string"); + SchemaRequest.AddDynamicField addDFieldUpdateSchemaRequest = + new SchemaRequest.AddDynamicField(fieldAttributes); + SchemaResponse.UpdateResponse addDFieldFirstResponse = addDFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addDFieldFirstResponse); + + SchemaResponse.UpdateResponse addDFieldSecondResponse = addDFieldUpdateSchemaRequest.process(getSolrClient()); + assertEquals(0, addDFieldSecondResponse.getStatus()); + assertNotNull(addDFieldSecondResponse.getResponse().get("errors")); + } + + @Test + public void testDeleteDynamicFieldAccuracy() throws Exception { + String dynamicFieldName = "*_del"; + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", dynamicFieldName); + fieldAttributes.put("type", "string"); + SchemaRequest.AddDynamicField addFieldUpdateSchemaRequest = + new SchemaRequest.AddDynamicField(fieldAttributes); + SchemaResponse.UpdateResponse addDynamicFieldResponse = addFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addDynamicFieldResponse); + + SchemaRequest.DynamicField dynamicFieldSchemaRequest = + new SchemaRequest.DynamicField(dynamicFieldName); + SchemaResponse.DynamicFieldResponse initialDFieldResponse = dynamicFieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(initialDFieldResponse); + Map fieldAttributesResponse = initialDFieldResponse.getDynamicField(); + assertThat(dynamicFieldName, is(equalTo(fieldAttributesResponse.get("name")))); + + SchemaRequest.DeleteDynamicField deleteFieldRequest = + new SchemaRequest.DeleteDynamicField(dynamicFieldName); + SchemaResponse.UpdateResponse deleteDynamicFieldResponse = deleteFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(deleteDynamicFieldResponse); + + try { + dynamicFieldSchemaRequest.process(getSolrClient()); + fail(String.format(Locale.ROOT, "after removal, the dynamic field %s shouldn't be anymore available over Schema API", + dynamicFieldName)); + } catch (SolrException e) { + //success + } + } + + @Test + public void deletingADynamicFieldThatDoesntExistInTheSchemaShouldFail() throws Exception { + SchemaRequest.DeleteDynamicField deleteDynamicFieldRequest = + new SchemaRequest.DeleteDynamicField("*_notexists"); + SchemaResponse.UpdateResponse deleteDynamicFieldResponse = deleteDynamicFieldRequest.process(getSolrClient()); + assertNotNull(deleteDynamicFieldResponse.getResponse().get("errors")); + } + + @Test + public void testReplaceDynamicFieldAccuracy() throws Exception { + // Given + String fieldName = "*_replace"; + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", fieldName); + fieldAttributes.put("type", "string"); + fieldAttributes.put("stored", false); + fieldAttributes.put("indexed", true); + fieldAttributes.put("required", true); + SchemaRequest.AddDynamicField addDFieldUpdateSchemaRequest = + new SchemaRequest.AddDynamicField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldResponse = addDFieldUpdateSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + // When : update the field definition + Map replaceFieldAttributes = new LinkedHashMap<>(fieldAttributes); + replaceFieldAttributes.put("stored", true); + replaceFieldAttributes.put("indexed", false); + SchemaRequest.ReplaceDynamicField replaceFieldRequest = + new SchemaRequest.ReplaceDynamicField(replaceFieldAttributes); + SchemaResponse.UpdateResponse replaceFieldResponse = replaceFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(replaceFieldResponse); + + // Then + SchemaRequest.DynamicField dynamicFieldSchemaRequest = + new SchemaRequest.DynamicField(fieldName); + SchemaResponse.DynamicFieldResponse newFieldResponse = dynamicFieldSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldResponse); + Map newFieldAttributes = newFieldResponse.getDynamicField(); + assertThat(fieldName, is(equalTo(newFieldAttributes.get("name")))); + assertThat("string", is(equalTo(newFieldAttributes.get("type")))); + assertThat(true, is(equalTo(newFieldAttributes.get("stored")))); + assertThat(false, is(equalTo(newFieldAttributes.get("indexed")))); + assertThat(true, is(equalTo(newFieldAttributes.get("required")))); + } + + @Test + public void testAddFieldTypeAccuracy() throws Exception { + SchemaRequest.FieldTypes fieldTypesRequest = new SchemaRequest.FieldTypes(); + SchemaResponse.FieldTypesResponse initialFieldTypesResponse = fieldTypesRequest.process(getSolrClient()); + assertValidSchemaResponse(initialFieldTypesResponse); + List initialFieldTypes = initialFieldTypesResponse.getFieldTypes(); + + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + Map fieldTypeAttributes = new LinkedHashMap<>(); + String fieldTypeName = "accuracyTextField"; + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "solr.TextField"); + fieldTypeAttributes.put("positionIncrementGap", "100"); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + + AnalyzerDefinition analyzerDefinition = new AnalyzerDefinition(); + Map charFilterAttributes = new LinkedHashMap<>(); + charFilterAttributes.put("class", "solr.PatternReplaceCharFilterFactory"); + charFilterAttributes.put("replacement", "$1$1"); + charFilterAttributes.put("pattern", "([a-zA-Z])\\\\1+"); + analyzerDefinition.setCharFilters(Collections.singletonList(charFilterAttributes)); + Map tokenizerAttributes = new LinkedHashMap<>(); + tokenizerAttributes.put("class", "solr.WhitespaceTokenizerFactory"); + analyzerDefinition.setTokenizer(tokenizerAttributes); + Map filterAttributes = new LinkedHashMap<>(); + filterAttributes.put("class", "solr.WordDelimiterFilterFactory"); + filterAttributes.put("preserveOriginal", "0"); + analyzerDefinition.setFilters(Collections.singletonList(filterAttributes)); + fieldTypeDefinition.setAnalyzer(analyzerDefinition); + + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeResponse); + + SchemaResponse.FieldTypesResponse currentFieldTypesResponse = fieldTypesRequest.process(getSolrClient()); + assertEquals(0, currentFieldTypesResponse.getStatus()); + List currentFieldTypes = currentFieldTypesResponse.getFieldTypes(); + assertEquals(initialFieldTypes.size() + 1, currentFieldTypes.size()); + + Map fieldAttributes = new LinkedHashMap<>(); + String fieldName = "accuracyField"; + fieldAttributes.put("name", fieldName); + fieldAttributes.put("type", fieldTypeName); + SchemaRequest.AddField addFieldRequest = + new SchemaRequest.AddField(fieldAttributes); + SchemaResponse.UpdateResponse addFieldResponse = addFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldResponse); + + Map dynamicFieldAttributes = new LinkedHashMap<>(); + String dynamicFieldName = "*_accuracy"; + dynamicFieldAttributes.put("name", dynamicFieldName); + dynamicFieldAttributes.put("type", fieldTypeName); + SchemaRequest.AddDynamicField addDynamicFieldRequest = + new SchemaRequest.AddDynamicField(dynamicFieldAttributes); + SchemaResponse.UpdateResponse addDynamicFieldResponse = addDynamicFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(addDynamicFieldResponse); + + SchemaRequest.FieldType fieldTypeRequest = new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse newFieldTypeResponse = fieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldTypeResponse); + FieldTypeRepresentation newFieldTypeRepresentation = newFieldTypeResponse.getFieldType(); + assertThat(fieldTypeName, is(equalTo(newFieldTypeRepresentation.getAttributes().get("name")))); + assertThat("solr.TextField", is(equalTo(newFieldTypeRepresentation.getAttributes().get("class")))); + assertThat(analyzerDefinition.getTokenizer().get("class"), + is(equalTo(newFieldTypeRepresentation.getAnalyzer().getTokenizer().get("class")))); + assertTrue(newFieldTypeRepresentation.getFields().size() == 1); + assertTrue(newFieldTypeRepresentation.getFields().contains(fieldName)); + assertTrue(newFieldTypeRepresentation.getDynamicFields().size() == 1); + assertTrue(newFieldTypeRepresentation.getDynamicFields().contains(dynamicFieldName)); + } + + @Test + public void addFieldTypeWithSimilarityAccuracy() throws Exception { + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + Map fieldTypeAttributes = new LinkedHashMap<>(); + String fieldTypeName = "fullClassNames"; + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "org.apache.solr.schema.TextField"); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + + AnalyzerDefinition analyzerDefinition = new AnalyzerDefinition(); + Map charFilterAttributes = new LinkedHashMap<>(); + charFilterAttributes.put("class", "solr.PatternReplaceCharFilterFactory"); + charFilterAttributes.put("replacement", "$1$1"); + charFilterAttributes.put("pattern", "([a-zA-Z])\\\\1+"); + analyzerDefinition.setCharFilters(Collections.singletonList(charFilterAttributes)); + Map tokenizerAttributes = new LinkedHashMap<>(); + tokenizerAttributes.put("class", "solr.WhitespaceTokenizerFactory"); + analyzerDefinition.setTokenizer(tokenizerAttributes); + fieldTypeDefinition.setAnalyzer(analyzerDefinition); + Map similarityAttributes = new LinkedHashMap<>(); + similarityAttributes.put("class", "org.apache.lucene.misc.SweetSpotSimilarity"); + fieldTypeDefinition.setSimilarity(similarityAttributes); + + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeResponse); + + // similarity is not shown by default for the fieldType + SchemaRequest.FieldType fieldTypeRequest = new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse newFieldTypeResponse = fieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldTypeResponse); + FieldTypeRepresentation newFieldTypeRepresentation = newFieldTypeResponse.getFieldType(); + assertThat(fieldTypeName, is(equalTo(newFieldTypeRepresentation.getAttributes().get("name")))); + assertThat(similarityAttributes.get("class"), is(equalTo(newFieldTypeRepresentation.getSimilarity().get("class")))); + } + + @Test + public void addFieldTypeWithAnalyzerClassAccuracy() throws Exception { + Map fieldTypeAttributes = new LinkedHashMap<>(); + String fieldTypeName = "nameText"; + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "solr.TextField"); + + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + Map analyzerAttributes = new LinkedHashMap<>(); + analyzerAttributes.put("class", "org.apache.lucene.analysis.core.WhitespaceAnalyzer"); + analyzerAttributes.put("luceneMatchVersion", "5.0.0"); + AnalyzerDefinition analyzerDefinition = new AnalyzerDefinition(); + analyzerDefinition.setAttributes(analyzerAttributes); + fieldTypeDefinition.setAnalyzer(analyzerDefinition); + + + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeResponse); + + SchemaRequest.FieldType fieldTypeRequest = new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse newFieldTypeResponse = fieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldTypeResponse); + FieldTypeRepresentation newFieldTypeRepresentation = newFieldTypeResponse.getFieldType(); + assertThat(fieldTypeName, is(equalTo(newFieldTypeRepresentation.getAttributes().get("name")))); + assertThat(analyzerAttributes.get("class"), + is(equalTo(newFieldTypeRepresentation.getAnalyzer().getAttributes().get("class")))); + assertThat(analyzerAttributes.get("luceneMatchVersion"), + is(equalTo(newFieldTypeRepresentation.getAnalyzer().getAttributes().get("luceneMatchVersion")))); + } + + @Test + public void addFieldTypeShouldntBeCalledTwiceWithTheSameName() throws Exception { + Map fieldTypeAttributes = new LinkedHashMap<>(); + fieldTypeAttributes.put("name", "failureInt"); + fieldTypeAttributes.put("class", "solr.TrieIntField"); + fieldTypeAttributes.put("precisionStep", 0); + fieldTypeAttributes.put("omitNorms", true); + fieldTypeAttributes.put("positionIncrementGap", 0); + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeFirstResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeFirstResponse); + + SchemaResponse.UpdateResponse addFieldTypeSecondResponse = addFieldTypeRequest.process(getSolrClient()); + assertEquals(0, addFieldTypeSecondResponse.getStatus()); + assertNotNull(addFieldTypeSecondResponse.getResponse().get("errors")); + } + + @Test + public void testDeleteFieldTypeAccuracy() throws Exception { + Map fieldTypeAttributes = new LinkedHashMap<>(); + String fieldTypeName = "delInt"; + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "solr.TrieIntField"); + fieldTypeAttributes.put("precisionStep", 0); + fieldTypeAttributes.put("omitNorms", true); + fieldTypeAttributes.put("positionIncrementGap", 0); + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeResponse); + + SchemaRequest.FieldType fieldTypeRequest = new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse initialFieldTypeResponse = fieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(initialFieldTypeResponse); + FieldTypeRepresentation responseFieldTypeRepresentation = initialFieldTypeResponse.getFieldType(); + assertThat(fieldTypeName, is(equalTo(responseFieldTypeRepresentation.getAttributes().get("name")))); + + SchemaRequest.DeleteFieldType deleteFieldTypeRequest = + new SchemaRequest.DeleteFieldType(fieldTypeName); + SchemaResponse.UpdateResponse deleteFieldTypeResponse = deleteFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(deleteFieldTypeResponse); + + try { + fieldTypeRequest.process(getSolrClient()); + fail(String.format(Locale.ROOT, "after removal, the field type %s shouldn't be anymore available over Schema API", + fieldTypeName)); + } catch (SolrException e) { + //success + } + } + + @Test + public void deletingAFieldTypeThatDoesntExistInTheSchemaShouldFail() throws Exception { + SchemaRequest.DeleteFieldType deleteFieldTypeRequest = + new SchemaRequest.DeleteFieldType("fieldTypeToBeDeleted"); + SchemaResponse.UpdateResponse deleteFieldResponse = deleteFieldTypeRequest.process(getSolrClient()); + assertNotNull(deleteFieldResponse.getResponse().get("errors")); + } + + @Test + public void testReplaceFieldTypeAccuracy() throws Exception { + // Given + Map fieldTypeAttributes = new LinkedHashMap<>(); + String fieldTypeName = "replaceInt"; + fieldTypeAttributes.put("name", fieldTypeName); + fieldTypeAttributes.put("class", "solr.TrieIntField"); + fieldTypeAttributes.put("precisionStep", 0); + fieldTypeAttributes.put("omitNorms", true); + fieldTypeAttributes.put("positionIncrementGap", 0); + FieldTypeDefinition fieldTypeDefinition = new FieldTypeDefinition(); + fieldTypeDefinition.setAttributes(fieldTypeAttributes); + SchemaRequest.AddFieldType addFieldTypeRequest = + new SchemaRequest.AddFieldType(fieldTypeDefinition); + SchemaResponse.UpdateResponse addFieldTypeResponse = addFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(addFieldTypeResponse); + + // When : update the field definition + fieldTypeAttributes.put("precisionStep", 1); + fieldTypeAttributes.put("omitNorms", false); + FieldTypeDefinition replaceFieldTypeDefinition = new FieldTypeDefinition(); + replaceFieldTypeDefinition.setAttributes(fieldTypeAttributes); + SchemaRequest.ReplaceFieldType replaceFieldTypeRequest = + new SchemaRequest.ReplaceFieldType(replaceFieldTypeDefinition); + SchemaResponse.UpdateResponse replaceFieldTypeResponse = replaceFieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(replaceFieldTypeResponse); + + // Then + SchemaRequest.FieldType fieldTypeRequest = new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse newFieldTypeResponse = fieldTypeRequest.process(getSolrClient()); + assertValidSchemaResponse(newFieldTypeResponse); + FieldTypeRepresentation replacedFieldTypeRepresentation = newFieldTypeResponse.getFieldType(); + Map replacedFieldTypeAttributes = replacedFieldTypeRepresentation.getAttributes(); + assertThat(fieldTypeName, is(equalTo(replacedFieldTypeAttributes.get("name")))); + assertThat("solr.TrieIntField", is(equalTo(replacedFieldTypeAttributes.get("class")))); + assertThat(false, is(equalTo(replacedFieldTypeAttributes.get("omitNorms")))); + assertThat("1", is(equalTo(replacedFieldTypeAttributes.get("precisionStep")))); + assertThat("0", is(equalTo(replacedFieldTypeAttributes.get("positionIncrementGap")))); + } + + @Test + public void testCopyFieldAccuracy() throws Exception { + SchemaRequest.CopyFields copyFieldsSchemaRequest = new SchemaRequest.CopyFields(); + SchemaResponse.CopyFieldsResponse initialCopyFieldsResponse = copyFieldsSchemaRequest.process(getSolrClient()); + List> initialCopyFieldsAttributes = initialCopyFieldsResponse.getCopyFields(); + + String srcFieldName = "copyfield"; + String destFieldName1 = "destField1", destFieldName2 = "destField2"; + createStoredStringField(srcFieldName, getSolrClient()); + createStoredStringField(destFieldName1, getSolrClient()); + createStoredStringField(destFieldName2, getSolrClient()); + + SchemaRequest.AddCopyField addCopyFieldRequest = + new SchemaRequest.AddCopyField(srcFieldName, + Arrays.asList(destFieldName1, destFieldName2)); + SchemaResponse.UpdateResponse addCopyFieldResponse = addCopyFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(addCopyFieldResponse); + + SchemaResponse.CopyFieldsResponse currentCopyFieldsResponse = copyFieldsSchemaRequest.process(getSolrClient()); + List> currentCopyFields = currentCopyFieldsResponse.getCopyFields(); + assertEquals(initialCopyFieldsAttributes.size() + 2, currentCopyFields.size()); + } + + @Test + public void testCopyFieldWithMaxCharsAccuracy() throws Exception { + SchemaRequest.CopyFields copyFieldsSchemaRequest = new SchemaRequest.CopyFields(); + SchemaResponse.CopyFieldsResponse initialCopyFieldsResponse = copyFieldsSchemaRequest.process(getSolrClient()); + List> initialCopyFieldsAttributes = initialCopyFieldsResponse.getCopyFields(); + + String srcFieldName = "copyfield"; + String destFieldName1 = "destField1", destFieldName2 = "destField2"; + createStoredStringField(srcFieldName, getSolrClient()); + createStoredStringField(destFieldName1, getSolrClient()); + createStoredStringField(destFieldName2, getSolrClient()); + + Integer maxChars = 200; + SchemaRequest.AddCopyField addCopyFieldRequest = + new SchemaRequest.AddCopyField(srcFieldName, + Arrays.asList(destFieldName1, destFieldName2), maxChars); + SchemaResponse.UpdateResponse addCopyFieldResponse = addCopyFieldRequest.process(getSolrClient()); + assertValidSchemaResponse(addCopyFieldResponse); + + SchemaResponse.CopyFieldsResponse currentCopyFieldsResponse = copyFieldsSchemaRequest.process(getSolrClient()); + List> currentCopyFields = currentCopyFieldsResponse.getCopyFields(); + assertEquals(initialCopyFieldsAttributes.size() + 2, currentCopyFields.size()); + for (Map currentCopyField : currentCopyFields) { + if (srcFieldName.equals(currentCopyField.get("source"))) { + String currentDestFieldName = (String) currentCopyField.get("dest"); + int currentMaxChars = (Integer) currentCopyField.get("maxChars"); + assertThat(currentDestFieldName, anyOf(is(equalTo(destFieldName1)), is(equalTo(destFieldName2)))); + assertTrue(maxChars == currentMaxChars); + } + } + } + + @Test + public void copyFieldsShouldFailWhenOneOfTheFieldsDoesntExistInTheSchema() throws Exception { + String srcFieldName = "srcnotexist"; + String destFieldName1 = "destNotExist1", destFieldName2 = "destNotExist2"; + + SchemaRequest.AddCopyField addCopyFieldRequest = + new SchemaRequest.AddCopyField(srcFieldName, + Arrays.asList(destFieldName1, destFieldName2)); + SchemaResponse.UpdateResponse addCopyFieldResponse = addCopyFieldRequest.process(getSolrClient()); + assertNotNull(addCopyFieldResponse.getResponse().get("errors")); + } + + @Test + public void testDeleteCopyFieldAccuracy() throws Exception { + String srcFieldName = "copyfield"; + String destFieldName1 = "destField1", destFieldName2 = "destField2"; + createStoredStringField(srcFieldName, getSolrClient()); + createStoredStringField(destFieldName1, getSolrClient()); + createStoredStringField(destFieldName2, getSolrClient()); + + SchemaRequest.AddCopyField addCopyFieldRequest = + new SchemaRequest.AddCopyField(srcFieldName, + Arrays.asList(destFieldName1, destFieldName2)); + SchemaResponse.UpdateResponse addCopyFieldResponse = addCopyFieldRequest.process(getSolrClient()); + System.out.println(addCopyFieldResponse); + assertValidSchemaResponse(addCopyFieldResponse); + + SchemaRequest.DeleteCopyField deleteCopyFieldRequest1 = + new SchemaRequest.DeleteCopyField(srcFieldName, Arrays.asList(destFieldName1)); + assertValidSchemaResponse(deleteCopyFieldRequest1.process(getSolrClient())); + + SchemaRequest.DeleteCopyField deleteCopyFieldRequest2 = + new SchemaRequest.DeleteCopyField(srcFieldName, Arrays.asList(destFieldName2)); + assertValidSchemaResponse(deleteCopyFieldRequest2.process(getSolrClient())); + } + + @Test + public void deleteCopyFieldShouldFailWhenOneOfTheFieldsDoesntExistInTheSchema() throws Exception { + String srcFieldName = "copyfield"; + String destFieldName1 = "destField1", destFieldName2 = "destField2"; + SchemaRequest.DeleteCopyField deleteCopyFieldsRequest = + new SchemaRequest.DeleteCopyField(srcFieldName, + Arrays.asList(destFieldName1, destFieldName2)); + SchemaResponse.UpdateResponse deleteCopyFieldResponse = deleteCopyFieldsRequest.process(getSolrClient()); + assertNotNull(deleteCopyFieldResponse.getResponse().get("errors")); + } + + @Test + public void testMultipleUpdateRequestAccuracy() throws Exception { + String fieldTypeName = "accuracyTextField"; + SchemaRequest.AddFieldType addFieldTypeRequest = createFieldTypeRequest(fieldTypeName); + + String field1Name = "accuracyField1"; + String field2Name = "accuracyField2"; + Map fieldAttributes = new LinkedHashMap<>(); + fieldAttributes.put("name", field1Name); + fieldAttributes.put("type", fieldTypeName); + fieldAttributes.put("stored", true); + fieldAttributes.put("indexed", true); + SchemaRequest.AddField addFieldName1Request = new SchemaRequest.AddField(fieldAttributes); + fieldAttributes.put("name", field2Name); + SchemaRequest.AddField addFieldName2Request = new SchemaRequest.AddField(fieldAttributes); + + List list = new ArrayList<>(3); + list.add(addFieldTypeRequest); + list.add(addFieldName1Request); + list.add(addFieldName2Request); + SchemaRequest.MultiUpdate multiUpdateRequest = new SchemaRequest.MultiUpdate(list); + SchemaResponse.UpdateResponse multipleUpdatesResponse = multiUpdateRequest.process(getSolrClient()); + assertValidSchemaResponse(multipleUpdatesResponse); + + SchemaRequest.FieldType fieldTypeSchemaRequest = + new SchemaRequest.FieldType(fieldTypeName); + SchemaResponse.FieldTypeResponse fieldTypeResponse = fieldTypeSchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(fieldTypeResponse); + FieldTypeRepresentation fieldTypeRepresentation = fieldTypeResponse.getFieldType(); + assertThat(fieldTypeName, is(equalTo(fieldTypeRepresentation.getAttributes().get("name")))); + + SchemaRequest.Field field1SchemaRequest = new SchemaRequest.Field(field1Name); + SchemaResponse.FieldResponse field1Response = field1SchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(field1Response); + Map field1Attributes = field1Response.getField(); + assertThat(field1Name, is(equalTo(field1Attributes.get("name")))); + assertThat(fieldTypeName, is(equalTo(field1Attributes.get("type")))); + assertThat(true, is(equalTo(field1Attributes.get("stored")))); + assertThat(true, is(equalTo(field1Attributes.get("indexed")))); + + SchemaRequest.Field field2SchemaRequest = new SchemaRequest.Field(field1Name); + SchemaResponse.FieldResponse field2Response = field2SchemaRequest.process(getSolrClient()); + assertValidSchemaResponse(field2Response); + Map field2Attributes = field2Response.getField(); + assertThat(field1Name, is(equalTo(field2Attributes.get("name")))); + assertThat(fieldTypeName, is(equalTo(field2Attributes.get("type")))); + assertThat(true, is(equalTo(field2Attributes.get("stored")))); + assertThat(true, is(equalTo(field2Attributes.get("indexed")))); + } +}