001/* 002 * (C) Copyright 2014-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo 018 */ 019 020package org.nuxeo.elasticsearch.config; 021 022import static org.nuxeo.elasticsearch.ElasticSearchConstants.ALL_FIELDS; 023import static org.nuxeo.elasticsearch.ElasticSearchConstants.BINARYTEXT_FIELD; 024import static org.nuxeo.elasticsearch.ElasticSearchConstants.DOC_TYPE; 025 026import java.io.File; 027import java.io.FileInputStream; 028import java.io.FileNotFoundException; 029import java.io.IOException; 030import java.io.InputStream; 031 032import org.apache.commons.io.IOUtils; 033import org.apache.commons.lang.StringUtils; 034import org.nuxeo.common.Environment; 035import org.nuxeo.common.xmap.annotation.XNode; 036import org.nuxeo.common.xmap.annotation.XNodeList; 037import org.nuxeo.common.xmap.annotation.XObject; 038import org.nuxeo.elasticsearch.core.IncrementalIndexNameGenerator; 039 040/** 041 * XMap descriptor for configuring an index 042 * 043 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a> 044 */ 045@XObject(value = "elasticSearchIndex") 046public class ElasticSearchIndexConfig { 047 public static final String DEFAULT_SETTING_FILE = "default-doc-settings.json"; 048 049 public static final String DEFAULT_MAPPING_FILE = "default-doc-mapping.json"; 050 051 protected static final String DEFAULT_REPOSITORY_NAME = "default"; 052 053 protected static final String WRITE_SUFFIX = "-write"; 054 055 @XNode("@enabled") 056 protected boolean isEnabled = true; 057 058 @XNode("@name") 059 protected String name; 060 061 // @since 9.3 062 @XNode("@manageAlias") 063 protected boolean manageAlias; 064 065 // @since 9.3 066 @XNode("@writeAlias") 067 protected String writeAlias; 068 069 @XNode("@repository") 070 protected String repositoryName; 071 072 @XNode("@type") 073 protected String type = DOC_TYPE; 074 075 @XNode("@create") 076 protected boolean create = true; 077 078 @XNode("settings") 079 protected String settings; 080 081 @XNode("settings@file") 082 protected String settingsFile; 083 084 @XNode("mapping") 085 protected String mapping; 086 087 @XNode("mapping@file") 088 protected String mappingFile; 089 090 @XNodeList(value = "fetchFromSource/exclude", type = String[].class, componentType = String.class) 091 protected String[] excludes; 092 093 @XNodeList(value = "fetchFromSource/include", type = String[].class, componentType = String.class) 094 protected String[] includes; 095 096 @Override 097 public String toString() { 098 if (isEnabled()) { 099 return String.format("EsIndexConfig(%s, %s, %s)", getName(), getRepositoryName(), getType()); 100 } 101 return "EsIndexConfig disabled"; 102 } 103 104 public String[] getExcludes() { 105 if (excludes == null) { 106 return new String[] { BINARYTEXT_FIELD }; 107 } 108 return excludes; 109 } 110 111 public String[] getIncludes() { 112 if (includes == null || includes.length == 0) { 113 return new String[] { ALL_FIELDS }; 114 } 115 return includes; 116 } 117 118 public String getName() { 119 return name; 120 } 121 122 public String getType() { 123 return type; 124 } 125 126 public String getSettings() { 127 if (settingsFile != null) { 128 return contentOfFile(settingsFile); 129 } else if (settings != null && !settings.isEmpty()) { 130 return settings; 131 } 132 return contentOfFile(DEFAULT_SETTING_FILE); 133 } 134 135 protected String contentOfFile(String filename) { 136 try { 137 return IOUtils.toString(getResourceStream(filename), "UTF-8"); 138 } catch (IOException e) { 139 throw new IllegalArgumentException("Cannot load resource file: " + filename, e); 140 } 141 } 142 143 protected InputStream getResourceStream(String filename) { 144 // First check if the resource is available on the config directory 145 File file = new File(Environment.getDefault().getConfig(), filename); 146 if (file.exists()) { 147 try { 148 return new FileInputStream(file); 149 } catch (FileNotFoundException e) { 150 // try another way 151 } 152 } 153 154 // getResourceAsStream is needed getResource will not work when called from another module 155 InputStream ret = this.getClass().getClassLoader().getResourceAsStream(filename); 156 if (ret == null) { 157 // Then try to get it from jar 158 ret = this.getClass().getClassLoader().getResourceAsStream(filename); 159 } 160 if (ret == null) { 161 throw new IllegalArgumentException( 162 String.format("Resource file cannot be found: %s or %s", file.getAbsolutePath(), filename)); 163 } 164 return ret; 165 } 166 167 public String getMapping() { 168 if (mappingFile != null) { 169 return contentOfFile(mappingFile); 170 } else if (mapping != null && !mapping.isEmpty()) { 171 return mapping; 172 } 173 return contentOfFile(DEFAULT_MAPPING_FILE); 174 } 175 176 public boolean mustCreate() { 177 return create; 178 } 179 180 public String getRepositoryName() { 181 if (isDocumentIndex() && repositoryName == null) { 182 repositoryName = DEFAULT_REPOSITORY_NAME; 183 } 184 return repositoryName; 185 } 186 187 public boolean isEnabled() { 188 return isEnabled; 189 } 190 191 public void setEnabled(boolean isEnabled) { 192 this.isEnabled = isEnabled; 193 } 194 195 /** 196 * Return true if the index/mapping is associated with a Nuxeo document repository 197 * 198 * @since 7.4 199 */ 200 public boolean isDocumentIndex() { 201 return DOC_TYPE.equals(getType()); 202 } 203 204 /** 205 * Use {@code other} mapping and settings if not defined. 206 */ 207 public void merge(final ElasticSearchIndexConfig other) { 208 if (other == null) { 209 return; 210 } 211 if (mapping == null && other.mapping != null) { 212 mapping = other.mapping; 213 } 214 if (settings == null && other.settings != null) { 215 settings = other.settings; 216 } 217 if (mappingFile == null && other.mappingFile != null) { 218 mappingFile = other.mappingFile; 219 } 220 if (settingsFile == null && other.settingsFile != null) { 221 settingsFile = other.settingsFile; 222 } 223 } 224 225 // @since 9.3 226 public boolean hasExplicitWriteIndex() { 227 return StringUtils.isNotBlank(writeAlias); 228 } 229 230 // @since 9.3 231 public String writeIndexOrAlias() { 232 // Custom alias managed outside of Nuxeo 233 if (hasExplicitWriteIndex()) { 234 return writeAlias; 235 } 236 // Nuxeo manages the write alias 237 if (manageAlias) { 238 return name + WRITE_SUFFIX; 239 } 240 // Simple index 241 return name; 242 } 243 244 // @since 9.3 245 public boolean manageAlias() { 246 return manageAlias; 247 } 248 249 // @since 9.3 250 public String newWriteIndexForAlias(String aliasName, String oldIndexName) { 251 // TODO make the alias resolver configurable 252 return new IncrementalIndexNameGenerator().getNextIndexName(aliasName, oldIndexName); 253 } 254}