| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.solr.schema; |
| import org.apache.solr.common.SolrException; |
| import org.apache.solr.common.params.MapSolrParams; |
| import org.apache.solr.common.params.SolrParams; |
| import org.apache.solr.search.QParser; |
| import org.apache.lucene.search.Query; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| |
| /** |
| * An abstract base class for FieldTypes that delegate work to another {@link org.apache.solr.schema.FieldType}. |
| * The sub type can be obtained by either specifying the subFieldType attribute or the subFieldSuffix. In the former |
| * case, a new dynamic field will be injected into the schema automatically with the name of {@link #POLY_FIELD_SEPARATOR}. |
| * In the latter case, it will use an existing dynamic field definition to get the type. See the example schema and the |
| * use of the {@link org.apache.solr.schema.PointType} for more details. |
| * |
| **/ |
| public abstract class AbstractSubTypeFieldType extends FieldType implements SchemaAware { |
| protected FieldType subType; |
| public static final String SUB_FIELD_SUFFIX = "subFieldSuffix"; |
| public static final String SUB_FIELD_TYPE = "subFieldType"; |
| protected String suffix; |
| protected int dynFieldProps; |
| protected String[] suffixes; |
| protected String subFieldType = null; |
| protected String subSuffix = null; |
| protected IndexSchema schema; // needed for retrieving SchemaFields |
| |
| public FieldType getSubType() { |
| return subType; |
| } |
| |
| @Override |
| protected void init(IndexSchema schema, Map<String, String> args) { |
| super.init(schema, args); |
| this.schema = schema; |
| //it's not a first class citizen for the IndexSchema |
| SolrParams p = new MapSolrParams(args); |
| subFieldType = p.get(SUB_FIELD_TYPE); |
| subSuffix = p.get(SUB_FIELD_SUFFIX); |
| if (subFieldType != null) { |
| args.remove(SUB_FIELD_TYPE); |
| subType = schema.getFieldTypeByName(subFieldType.trim()); |
| suffix = POLY_FIELD_SEPARATOR + subType.typeName; |
| } else if (subSuffix != null) { |
| args.remove(SUB_FIELD_SUFFIX); |
| suffix = subSuffix; |
| } else { |
| throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "The field type: " + typeName |
| + " must specify the " + |
| SUB_FIELD_TYPE + " attribute or the " + SUB_FIELD_SUFFIX + " attribute."); |
| } |
| } |
| |
| /** |
| * Helper method for creating a dynamic field SchemaField prototype. Returns a {@link SchemaField} with |
| * the {@link FieldType} given and a name of "*" + {@link FieldType#POLY_FIELD_SEPARATOR} + {@link FieldType#typeName} |
| * and props of indexed=true, stored=false. |
| * |
| * @param schema the IndexSchema |
| * @param subType The {@link FieldType} of the prototype. |
| * @param polyField The poly {@link FieldType}. |
| * @return The {@link SchemaField} |
| */ |
| |
| static SchemaField registerPolyFieldDynamicPrototype(IndexSchema schema, FieldType subType, FieldType polyField) { |
| String name = "*" + FieldType.POLY_FIELD_SEPARATOR + subType.typeName; |
| Map<String, String> props = new HashMap<>(); |
| //Just set these, delegate everything else to the field type |
| props.put("indexed", "true"); |
| props.put("stored", "false"); |
| props.put("multiValued", "false"); |
| // if polyField enables dv, add them to the subtypes |
| if (polyField.hasProperty(DOC_VALUES)) { |
| props.put("docValues", "true"); |
| } |
| int p = SchemaField.calcProps(name, subType, props); |
| SchemaField proto = SchemaField.create(name, |
| subType, p, null); |
| schema.registerDynamicFields(proto); |
| return proto; |
| } |
| |
| /** |
| * Registers the polyfield dynamic prototype for this field type: : "*___(field type name)" |
| * |
| * {@inheritDoc} |
| * |
| * @param schema {@inheritDoc} |
| * |
| */ |
| @Override |
| public void inform(IndexSchema schema) { |
| this.schema = schema; |
| //Can't do this until here b/c the Dynamic Fields are not initialized until here. |
| if (subType != null) { |
| SchemaField proto = registerPolyFieldDynamicPrototype(schema, subType, this); |
| dynFieldProps = proto.getProperties(); |
| } |
| } |
| |
| /** |
| * Throws UnsupportedOperationException() |
| */ |
| @Override |
| public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| protected void createSuffixCache(int size) { |
| suffixes = new String[size]; |
| for (int i=0; i<size; i++) { |
| suffixes[i] = "_" + i + suffix; |
| } |
| } |
| |
| protected SchemaField subField(SchemaField base, int i, IndexSchema schema) { |
| return schema.getField(base.getName() + suffixes[i]); |
| } |
| } |