/* * 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.geode.cache.lucene.internal; import org.apache.geode.DataSerializable; import org.apache.geode.DataSerializer; import org.apache.geode.internal.Version; import org.apache.geode.internal.cache.CacheServiceProfile; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.*; public class LuceneIndexCreationProfile implements CacheServiceProfile, DataSerializable { private String indexName; private String[] fieldNames; private String analyzerClass; private Map<String, String> fieldAnalyzers; private String regionPath; /* Used by DataSerializer */ public LuceneIndexCreationProfile() {} public LuceneIndexCreationProfile(String indexName, String regionPath, String[] fieldNames, Analyzer analyzer, Map<String, Analyzer> fieldAnalyzers) { this.indexName = indexName; this.regionPath = regionPath; this.fieldNames = fieldNames; this.analyzerClass = analyzer.getClass().getSimpleName(); initializeFieldAnalyzers(fieldAnalyzers); } public String getIndexName() { return this.indexName; } public String[] getFieldNames() { return this.fieldNames; } public String getAnalyzerClass() { return this.analyzerClass; } public Map<String, String> getFieldAnalyzers() { return this.fieldAnalyzers; } protected void initializeFieldAnalyzers(Map<String, Analyzer> fieldAnalyzers) { this.fieldAnalyzers = new HashMap<>(); for (String field : fieldNames) { if (fieldAnalyzers != null && !fieldAnalyzers.isEmpty()) { this.fieldAnalyzers.put(field, fieldAnalyzers.get(field) == null ? StandardAnalyzer.class.getSimpleName() : fieldAnalyzers.get(field).getClass().getSimpleName()); } else { this.fieldAnalyzers.put(field, StandardAnalyzer.class.getSimpleName()); } } } @Override public String getId() { return "lucene_" + LuceneServiceImpl.getUniqueIndexName(indexName, regionPath); } @Override public String checkCompatibility(String regionPath, CacheServiceProfile profile) { String result = null; LuceneIndexCreationProfile remoteProfile = (LuceneIndexCreationProfile) profile; if (remoteProfile == null) { // TODO This can occur if one member defines no indexes but another one does. Currently this // is caught by the async event id checks. } else { // Verify fields are the same if (!Arrays.equals(remoteProfile.getFieldNames(), getFieldNames())) { return LocalizedStrings.LuceneService_CANNOT_CREATE_INDEX_0_ON_REGION_1_WITH_FIELDS_2_BECAUSE_ANOTHER_MEMBER_DEFINES_THE_SAME_INDEX_WITH_FIELDS_3 .toString(getIndexName(), regionPath, Arrays.toString(getFieldNames()), Arrays.toString(remoteProfile.getFieldNames())); } // Verify the analyzer class is the same // Note: This test will currently only fail if per-field analyzers are used in one member but // not another, // This condition will be caught in the tests below so this test is commented out. If we ever // allow the user // to configure a single analyzer for all fields, then this test will be useful again. /* * if (!remoteLuceneIndexProfile.getAnalyzerClass().isInstance(getAnalyzer())) { result = * LocalizedStrings. * LuceneService_CANNOT_CREATE_INDEX_0_ON_REGION_1_WITH_ANALYZER_2_BECAUSE_ANOTHER_MEMBER_DEFINES_THE_SAME_INDEX_WITH_ANALYZER_3 * .toString(indexName, regionPath, remoteLuceneIndexProfile.getAnalyzerClass().getName(), * analyzer.getClass().getName()); } */ // Iterate the existing analyzers and compare them to the input analyzers // Note: This is currently destructive to the input field analyzers map which should be ok // since its a transient object. if (!getFieldAnalyzers().equals(remoteProfile.getFieldAnalyzers())) { if (getFieldAnalyzers().size() != remoteProfile.getFieldAnalyzers().size()) { return LocalizedStrings.LuceneService_CANNOT_CREATE_INDEX_0_ON_REGION_1_WITH_FIELDS_2_BECAUSE_ANOTHER_MEMBER_DEFINES_THE_SAME_INDEX_WITH_FIELDS_3 .toString(getIndexName(), regionPath, Arrays.toString(getFieldAnalyzers().keySet().toArray()), Arrays.toString(remoteProfile.getFieldAnalyzers().keySet().toArray())); } // now the 2 maps should have the same size for (String field : getFieldAnalyzers().keySet()) { if (!remoteProfile.getFieldAnalyzers().get(field) .equals(getFieldAnalyzers().get(field))) { return LocalizedStrings.LuceneService_CANNOT_CREATE_INDEX_0_ON_REGION_1_WITH_ANALYZER_2_ON_FIELD_3_BECAUSE_ANOTHER_MEMBER_DEFINES_THE_SAME_INDEX_WITH_ANALYZER_4_ON_THAT_FIELD .toString(getIndexName(), regionPath, getFieldAnalyzers().get(field), field, remoteProfile.getFieldAnalyzers().get(field)); } } } } return result; } @Override public void toData(DataOutput out) throws IOException { DataSerializer.writeString(this.indexName, out); DataSerializer.writeString(this.regionPath, out); DataSerializer.writeStringArray(this.fieldNames, out); DataSerializer.writeString(this.analyzerClass, out); DataSerializer.writeHashMap(this.fieldAnalyzers, out); } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { this.indexName = DataSerializer.readString(in); this.regionPath = DataSerializer.readString(in); this.fieldNames = DataSerializer.readStringArray(in); this.analyzerClass = DataSerializer.readString(in); this.fieldAnalyzers = DataSerializer.readHashMap(in); } public String toString() { return new StringBuilder().append(getClass().getSimpleName()).append("[").append("indexName=") .append(this.indexName).append("; fieldNames=").append(Arrays.toString(this.fieldNames)) .append("; analyzerClass=").append(this.analyzerClass).append("; fieldAnalyzers=") .append(this.fieldAnalyzers).append("]").toString(); } public String getRegionPath() { return this.regionPath; } }