/* * Copyright 2014-2017 the original author or authors. * * Licensed 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.springframework.data.solr.core.schema; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** * @author Christoph Strobl * @since 1.3 */ public class SchemaDefinition { private String collectionName; private List<FieldDefinition> fields; private List<CopyFieldDefinition> copyFields; private String name; private Double version; private String uniqueKey; public SchemaDefinition() {} public SchemaDefinition(String collectionName) { this.collectionName = collectionName; this.fields = new ArrayList<>(); } public String getCollectionName() { return collectionName; } public List<FieldDefinition> getFields() { return fields; } public void setFields(List<FieldDefinition> fields) { this.fields = fields != null ? fields : new ArrayList<>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getVersion() { return version; } public void setVersion(Double version) { this.version = version; } public String getUniqueKey() { return uniqueKey; } public void setUniqueKey(String uniqueKey) { this.uniqueKey = uniqueKey; } public boolean containsField(String name) { return getFieldDefinition(name) != null; } public FieldDefinition getFieldDefinition(String name) { if (CollectionUtils.isEmpty(this.fields)) { return null; } for (FieldDefinition fd : this.fields) { if (ObjectUtils.nullSafeEquals(fd.getName(), name)) { return fd; } } return null; } public void addFieldDefinition(FieldDefinition fieldDef) { if (this.fields == null) { this.fields = new ArrayList<>(); } this.fields.add(fieldDef); } public void addCopyField(CopyFieldDefinition copyField) { if (this.copyFields == null) { this.copyFields = new ArrayList<>(); } this.copyFields.add(copyField); } public List<CopyFieldDefinition> getCopyFields() { return this.copyFields; } public void setCollectionName(String collectionName) { this.collectionName = collectionName; } /** * @author Christoph Strobl * @since 1.3 */ public interface SchemaField {} /** * @author Christoph Strobl * @since 1.3 */ @Data @NoArgsConstructor public static class FieldDefinition implements SchemaField { private String name; private String type; private boolean stored; private boolean indexed; private Object defaultValue; private List<String> copyFields; private List<Filter> filters; private List<Tokenizer> tokenizers; private boolean multiValued; private boolean required; public FieldDefinition(String name) { this.name = name; } public void setCopyFields(Collection<String> copyFields) { this.copyFields = new ArrayList<>(copyFields); } /** * @return * @since 2.1 */ public Map<String, Object> asMap() { Map<String, Object> values = new LinkedHashMap<>(); addIfNotNull("name", name, values); addIfNotNull("type", type, values); addIfNotNull("indexed", indexed, values); addIfNotNull("stored", stored, values); addIfNotNull("multiValued", multiValued, values); addIfNotNull("default", defaultValue, values); addIfNotNull("required", required, values); return values; } private void addIfNotNull(String key, Object value, Map<String, Object> dest) { if (value != null) { dest.put(key, value); } } /** * @param source * @return * @since 2.1 */ public static FieldDefinition fromMap(Map<String, Object> source) { FieldDefinition fd = new FieldDefinition(); if (!CollectionUtils.isEmpty(source)) { fd.name = valueFromMap("name", source, null); fd.type = valueFromMap("type", source, null); fd.indexed = valueFromMap("indexed", source, false); fd.stored = valueFromMap("stored", source, false); fd.multiValued = valueFromMap("multiValued", source, false); fd.required = valueFromMap("required", source, false); fd.defaultValue = valueFromMap("default", source, null); } return fd; } private static <T> T valueFromMap(String key, Map<String, Object> source, T defaultValue) { if (source.containsKey(key)) { return (T) source.get(key); } else { return defaultValue; } } /** * @author Christoph Strobl * @since 2.1 */ public static class Builder { FieldDefinition fd; public Builder() { fd = new FieldDefinition(); } public Builder named(String name) { fd.setName(name); return this; } public Builder stored() { fd.setStored(true); return this; } public Builder indexed() { fd.setIndexed(true); return this; } public Builder muliValued() { fd.setMultiValued(true); return this; } public Builder copyTo(String... fields) { fd.setCopyFields(Arrays.asList(fields)); return this; } public Builder required() { fd.setRequired(true); return this; } public Builder typedAs(String type) { fd.setType(type); return this; } public Builder defaultedTo(Object value) { fd.setDefaultValue(value); return this; } public FieldDefinition create() { return fd; } } /** * @return * @since 2.1 */ public static Builder newFieldDefinition() { return new Builder(); } } /** * @author Christoph Strobl * @since 1.3 */ @Data public static class CopyFieldDefinition implements SchemaField { String source; List<String> destination; public static CopyFieldDefinition fromMap(Map<String, Object> fieldValueMap) { CopyFieldDefinition cfd = new CopyFieldDefinition(); cfd.source = (String) fieldValueMap.get("source"); Object dest = fieldValueMap.get("dest"); if (dest instanceof Collection) { cfd.destination = new ArrayList<>((Collection<String>) dest); } else if (fieldValueMap.get("dest") instanceof String) { cfd.destination = Collections.<String> singletonList(dest.toString()); } return cfd; } /** * @return * @since 2.1 */ public static Builder newCopyFieldDefinition() { return new Builder(); } /** * @author Christoph Strobl * @since 2.1 */ public static class Builder { CopyFieldDefinition cf; public Builder() { cf = new CopyFieldDefinition(); } public Builder copyFrom(String source) { cf.setSource(source); return this; } public Builder to(String... destinations) { if (cf.getDestination() == null) { cf.setDestination(Arrays.asList(destinations)); } else { ArrayList<String> values = new ArrayList<>(cf.getDestination()); CollectionUtils.mergeArrayIntoCollection(destinations, values); cf.setDestination(values); } return this; } public CopyFieldDefinition create() { return cf; } } } /** * @author Christoph Strobl * @since 1.3 */ public static class Filter { String clazz; String pattern; String replace; String replacement; } /** * @author Christoph Strobl * @since 1.3 */ public static class Tokenizer { String clazz; } public static class FieldDefinitionBuilder { private FieldDefinition fieldDef; public FieldDefinitionBuilder() { this.fieldDef = new FieldDefinition(); } public FieldDefinition idFieldDefinition(String fieldname, String type) { fieldDef.setName(fieldname); fieldDef.setType(type); fieldDef.setIndexed(true); fieldDef.setStored(true); fieldDef.setMultiValued(false); return fieldDef; } } }