diff options
author | Jon Bratseth <bratseth@verizonmedia.com> | 2020-03-13 15:03:16 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@verizonmedia.com> | 2020-03-13 15:03:16 +0100 |
commit | d1dc33f47cb35a0542f10f60309a3d24b7a85a29 (patch) | |
tree | a9076d1c5d0aa699e7f5a9131cb0d0c90646ef39 | |
parent | 8afe53c8d43910621ce19ad7d278b601dd85eaa1 (diff) |
searchdefinitions -> schemas
15 files changed, 181 insertions, 217 deletions
diff --git a/application/src/main/java/com/yahoo/application/Application.java b/application/src/main/java/com/yahoo/application/Application.java index b200244a21c..87e82a3fdeb 100644 --- a/application/src/main/java/com/yahoo/application/Application.java +++ b/application/src/main/java/com/yahoo/application/Application.java @@ -254,13 +254,13 @@ public final class Application implements AutoCloseable { * @throws java.io.IOException e.g.if file not found */ public Builder documentType(String name, String searchDefinition) throws IOException { - Path path = nestedResource(ApplicationPackage.SEARCH_DEFINITIONS_DIR, name, ApplicationPackage.SD_NAME_SUFFIX); + Path path = nestedResource(ApplicationPackage.SCHEMAS_DIR, name, ApplicationPackage.SD_NAME_SUFFIX); createFile(path, searchDefinition); return this; } public Builder expressionInclude(String name, String searchDefinition) throws IOException { - Path path = nestedResource(ApplicationPackage.SEARCH_DEFINITIONS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); + Path path = nestedResource(ApplicationPackage.SCHEMAS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); createFile(path, searchDefinition); return this; } @@ -271,7 +271,7 @@ public final class Application implements AutoCloseable { * @throws java.io.IOException e.g.if file not found */ public Builder rankExpression(String name, String rankExpressionContent) throws IOException { - Path path = nestedResource(ApplicationPackage.SEARCH_DEFINITIONS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); + Path path = nestedResource(ApplicationPackage.SCHEMAS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); createFile(path, rankExpressionContent); return this; } diff --git a/application/src/main/java/com/yahoo/application/ApplicationBuilder.java b/application/src/main/java/com/yahoo/application/ApplicationBuilder.java index 9d7cf2c8673..ac64ae188e5 100644 --- a/application/src/main/java/com/yahoo/application/ApplicationBuilder.java +++ b/application/src/main/java/com/yahoo/application/ApplicationBuilder.java @@ -37,13 +37,13 @@ public class ApplicationBuilder { } public ApplicationBuilder documentType(String name, String searchDefinition) throws IOException { - Path path = nestedResource(ApplicationPackage.SEARCH_DEFINITIONS_DIR, name, ApplicationPackage.SD_NAME_SUFFIX); + Path path = nestedResource(ApplicationPackage.SCHEMAS_DIR, name, ApplicationPackage.SD_NAME_SUFFIX); createFile(path, searchDefinition); return this; } public ApplicationBuilder rankExpression(String name, String rankExpressionContent) throws IOException { - Path path = nestedResource(ApplicationPackage.SEARCH_DEFINITIONS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); + Path path = nestedResource(ApplicationPackage.SCHEMAS_DIR, name, ApplicationPackage.RANKEXPRESSION_NAME_SUFFIX); createFile(path, rankExpressionContent); return this; } diff --git a/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java b/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java index a4f566e2a71..a0c2ec9983b 100644 --- a/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java +++ b/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java @@ -32,9 +32,10 @@ public class ApplicationBuilderTest { @Test public void query_profile_can_be_added() throws Exception { withApplicationBuilder(builder -> { - builder.queryProfile("MyProfile", "<query-profile id=\"MyProfile\">" + // - "<field name=\"message\">Hello world!</field>" + // - "</query-profile>"); + builder.queryProfile("MyProfile", + "<query-profile id=\"MyProfile\">" + + "<field name=\"message\">Hello world!</field>" + + "</query-profile>"); assertTrue(Files.exists(builder.getPath().resolve("search/query-profiles/MyProfile.xml"))); }); @@ -44,7 +45,7 @@ public class ApplicationBuilderTest { public void rank_expression_can_be_added() throws Exception { withApplicationBuilder(builder -> { builder.rankExpression("myExpression", "content"); - assertTrue(Files.exists(builder.getPath().resolve("searchdefinitions/myExpression.expression"))); + assertTrue(Files.exists(builder.getPath().resolve("schemas/myExpression.expression"))); }); } diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/AppSubDirs.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/AppSubDirs.java index 32054b1ad9a..2b7aa5ab6e1 100644 --- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/AppSubDirs.java +++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/AppSubDirs.java @@ -59,8 +59,7 @@ public class AppSubDirs { return configDefs.first; } - public File searchdefinitions() { - return searchdefinitions.first; - } + @Deprecated // Remove after March 2020 + public File searchdefinitions() { return searchdefinitions.first; } } diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/ApplicationPackageXmlFilesValidator.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/ApplicationPackageXmlFilesValidator.java index 74ade9d8e14..b0c4f74f9f6 100644 --- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/ApplicationPackageXmlFilesValidator.java +++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/ApplicationPackageXmlFilesValidator.java @@ -35,20 +35,11 @@ public class ApplicationPackageXmlFilesValidator { return new ApplicationPackageXmlFilesValidator(new AppSubDirs(appDir), vespaVersion); } - @SuppressWarnings("deprecation") public void checkApplication() throws IOException { validate(validators.servicesXmlValidator(), servicesFileName()); validateOptional(validators.hostsXmlValidator(), FilesApplicationPackage.HOSTS); validateOptional(validators.deploymentXmlValidator(), FilesApplicationPackage.DEPLOYMENT_FILE.getName()); validateOptional(validators.validationOverridesXmlValidator(), FilesApplicationPackage.VALIDATION_OVERRIDES.getName()); - - if (appDirs.searchdefinitions().exists()) { - if (FilesApplicationPackage.getSearchDefinitionFiles(appDirs.root()).isEmpty()) { - throw new IllegalArgumentException("Application package in " + appDirs.root() + - " must contain at least one search definition (.sd) file when directory searchdefinitions/ exists."); - } - } - validateRouting(appDirs.routingtables); } @@ -71,7 +62,6 @@ public class ApplicationPackageXmlFilesValidator { validator.validate(appDirs.file(filename)); } - @SuppressWarnings("deprecation") private String servicesFileName() { String servicesFile = FilesApplicationPackage.SERVICES; if ( ! appDirs.file(servicesFile).exists()) { diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java index 8c3ccdc4c0b..5860c365947 100644 --- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java +++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java @@ -49,6 +49,7 @@ import java.security.MessageDigest; import java.util.*; import java.util.jar.JarFile; import java.util.logging.Logger; +import java.util.stream.Stream; import static com.yahoo.text.Lowercase.toLowerCase; @@ -336,77 +337,73 @@ public class FilesApplicationPackage implements ApplicationPackage { public static Map<String, String> allSdsFromDocprocBundlesAndClasspath(File appDir) throws IOException { File dpChains = new File(appDir, ApplicationPackage.COMPONENT_DIR); if (!dpChains.exists() || !dpChains.isDirectory()) return Collections.emptyMap(); - List<String> usedNames = new ArrayList<>(); - Map<String, String> ret = new LinkedHashMap<>(); + Set<String> usedNames = new HashSet<>(); + Map<String, String> schemas = new LinkedHashMap<>(); // try classpath first - allSdsOnClassPath(usedNames, ret); + allSdsOnClassPath(usedNames, schemas); - for (File bundle : dpChains.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".jar"); - }})) { + for (File bundle : dpChains.listFiles((File dir, String name) -> name.endsWith(".jar"))) { for(Map.Entry<String, String> entry : ApplicationPackage.getBundleSdFiles("", new JarFile(bundle)).entrySet()) { String sdName = entry.getKey(); if (usedNames.contains(sdName)) { - throw new IllegalArgumentException("The search definition name '"+sdName+"' used in bundle '"+ - bundle.getName()+"' is already used in classpath or previous bundle."); + throw new IllegalArgumentException("The search definition name '" + sdName + "' used in bundle '"+ + bundle.getName()+ "' is already used in classpath or previous bundle."); } usedNames.add(sdName); String sdPayload = entry.getValue(); - ret.put(sdName, sdPayload); + schemas.put(sdName, sdPayload); } } - return ret; + return schemas; } - private static void allSdsOnClassPath(List<String> usedNames, Map<String, String> ret) throws IOException { - Enumeration<java.net.URL> resources = FilesApplicationPackage.class.getClassLoader().getResources(ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()); - - while(resources.hasMoreElements()) { - URL resource = resources.nextElement(); - - String protocol = resource.getProtocol(); + private static void allSdsOnClassPath(Set<String> usedNames, Map<String, String> schemas) { + ClassLoader cl = FilesApplicationPackage.class.getClassLoader(); + Stream<URL> resources = Stream.concat(cl.resources(ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()), + cl.resources(ApplicationPackage.SCHEMAS_DIR.getRelative())); + resources.forEach(resource -> addSchemaFrom(resource, schemas, usedNames)); + } - if ("file".equals(protocol)) { - File file; - try { - file = new File(resource.toURI()); - } catch (URISyntaxException e) { - continue; - } - // only interested in directories - if (file.isDirectory()) { - List<File> sdFiles = getSearchDefinitionFiles(file); - for (File sdFile : sdFiles) { - String sdName = sdFile.getName(); + private static void addSchemaFrom(URL resource, Map<String, String> schemas, Set<String> usedNames) { + try { + switch (resource.getProtocol()) { + case "file": + File file = new File(resource.toURI()); + if (file.isDirectory()) { + List<File> sdFiles = getSearchDefinitionFiles(file); + for (File sdFile : sdFiles) { + String sdName = sdFile.getName(); + if (usedNames.contains(sdName)) { + throw new IllegalArgumentException("The search definition name '" + sdName + + "' found in classpath already used earlier in classpath."); + } + usedNames.add(sdName); + String contents = IOUtils.readAll(new FileReader(sdFile)); + schemas.put(sdFile.getName(), contents); + } + } + break; + case "jar": + JarURLConnection jarConnection = (JarURLConnection) resource.openConnection(); + JarFile jarFile = jarConnection.getJarFile(); + for (Map.Entry<String, String> entry : ApplicationPackage.getBundleSdFiles("", jarFile).entrySet()) { + String sdName = entry.getKey(); if (usedNames.contains(sdName)) { - throw new IllegalArgumentException("The search definition name '"+sdName+ - "' found in classpath already used earlier in classpath."); + throw new IllegalArgumentException("The search definitions name '" + sdName + + "' used in bundle '" + jarFile.getName() + "' " + + "is already used in classpath or previous bundle."); } usedNames.add(sdName); - String contents = IOUtils.readAll(new FileReader(sdFile)); - ret.put(sdFile.getName(), contents); - } - } - } - else if ("jar".equals(protocol)) { - JarURLConnection jarConnection = (JarURLConnection) resource.openConnection(); - JarFile jarFile = jarConnection.getJarFile(); - for(Map.Entry<String, String> entry : ApplicationPackage.getBundleSdFiles("", jarFile).entrySet()) { - String sdName = entry.getKey(); - if (usedNames.contains(sdName)) { - throw new IllegalArgumentException("The search definitions name '"+sdName+ - "' used in bundle '"+jarFile.getName()+"' " + - "is already used in classpath or previous bundle."); + String sdPayload = entry.getValue(); + schemas.put(sdName, sdPayload); } - usedNames.add(sdName); - String sdPayload = entry.getValue(); - ret.put(sdName, sdPayload); - } + break; } } + catch (IOException | URISyntaxException e) { + throw new IllegalArgumentException("Could not read schema from '" + resource + "'", e); + } } /** @@ -462,11 +459,7 @@ public class FilesApplicationPackage implements ApplicationPackage { if (! configDefsDir.isDirectory()) return; log.log(LogLevel.DEBUG, "Getting all config definitions from '" + configDefsDir + "'"); - for (File def : configDefsDir.listFiles( - new FilenameFilter() { @Override public boolean accept(File dir, String name) { // TODO: Fix - return name.matches(".*\\.def");}})) { - - log.log(LogLevel.DEBUG, "Processing config definition '" + def + "'"); + for (File def : configDefsDir.listFiles((File dir, String name) -> name.matches(".*\\.def"))) { String[] nv = def.getName().split("\\.def"); ConfigDefinitionKey key; try { @@ -521,30 +514,25 @@ public class FilesApplicationPackage implements ApplicationPackage { } } - //Only intended for DeployProcessor, others should use the member version static List<File> getSearchDefinitionFiles(File appDir) { - //The dot is escaped later in this method: - assert (ApplicationPackage.SD_NAME_SUFFIX.charAt(0) == '.'); + List<File> schemaFiles = new ArrayList<>(); + + File sdDir = new File(appDir, ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()); + if (sdDir.isDirectory()) + schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> name.matches(".*\\" + ApplicationPackage.SD_NAME_SUFFIX)))); - List<File> ret = new ArrayList<>(); - File sdDir; + sdDir = new File(appDir, ApplicationPackage.SCHEMAS_DIR.getRelative()); + if (sdDir.isDirectory()) + schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> name.matches(".*\\" + ApplicationPackage.SD_NAME_SUFFIX)))); - sdDir = new File(appDir, ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()); - if (!sdDir.isDirectory()) { - return ret; - } - ret.addAll(Arrays.asList( - sdDir.listFiles( - new FilenameFilter() { @Override public boolean accept(File dir, String name) { - return name.matches(".*\\" + ApplicationPackage.SD_NAME_SUFFIX);}}))); - return ret; + return schemaFiles; } public List<File> getSearchDefinitionFiles() { return getSearchDefinitionFiles(appDir); } - //Only for use by deploy processor + // Only for use by deploy processor public static List<Component> getComponents(File appDir) { List<Component> components = new ArrayList<>(); for (Bundle bundle : Bundle.getBundles(new File(appDir, ApplicationPackage.COMPONENT_DIR))) { @@ -622,6 +610,7 @@ public class FilesApplicationPackage implements ApplicationPackage { public Bundle getBundle() { return bundle; } + } // class Component /** @@ -643,12 +632,14 @@ public class FilesApplicationPackage implements ApplicationPackage { } private File expressionFileNameToFile(String name) { - File expressionFile = new File(name); - if (expressionFile.isAbsolute()) { + if (new File(name).isAbsolute()) throw new IllegalArgumentException("Absolute path to ranking expression file is not allowed: " + name); - } - File sdDir = new File(appDir, ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()); - return new File(sdDir, name); + + File sdDir = new File(appDir, ApplicationPackage.SCHEMAS_DIR.getRelative()); + File expressionFile = new File(sdDir, name); + if ( !expressionFile.exists()) + expressionFile = new File(appDir, ApplicationPackage.SEARCH_DEFINITIONS_DIR.getRelative()); + return expressionFile; } @Override @@ -700,9 +691,8 @@ public class FilesApplicationPackage implements ApplicationPackage { ! name.equals(HOSTS) && ! name.equals(CONFIG_DEFINITIONS_DIR)); preprocessXML(new File(preprocessedDir, SERVICES), getServicesFile(), zone); - if (getHostsFile().exists()) { + if (getHostsFile().exists()) preprocessXML(new File(preprocessedDir, HOSTS), getHostsFile(), zone); - } FilesApplicationPackage preprocessed = FilesApplicationPackage.fromFile(preprocessedDir, includeSourceFiles); preprocessed.copyUserDefsIntoApplication(); return preprocessed; @@ -742,11 +732,12 @@ public class FilesApplicationPackage implements ApplicationPackage { /** * Adds the given path to the digest, or does nothing if path is neither file nor dir + * * @param path path to add to message digest * @param suffix only files with this suffix are considered * @param digest the {link @MessageDigest} to add the file paths to * @param recursive whether to recursively find children in the paths - * @param fullPathNames Whether to include the full paths in checksum or only the names + * @param fullPathNames whether to include the full paths in checksum or only the names * @throws java.io.IOException if adding path to digest fails when reading files from path */ private static void addPathToDigest(File path, String suffix, MessageDigest digest, boolean recursive, boolean fullPathNames) throws IOException { @@ -773,16 +764,17 @@ public class FilesApplicationPackage implements ApplicationPackage { } private static final int MD5_BUFFER_SIZE = 65536; + private static void addToDigest(InputStream is, MessageDigest digest) throws IOException { - if (is==null) return; + if (is == null) return; byte[] buffer = new byte[MD5_BUFFER_SIZE]; int i; do { - i=is.read(buffer); + i = is.read(buffer); if (i > 0) { digest.update(buffer, 0, i); } - } while(i!=-1); + } while(i != -1); } /** diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 8556fd4a40b..4a7d929fd3e 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -137,6 +137,7 @@ "fields": [ "public static final java.lang.String HOSTS", "public static final java.lang.String SERVICES", + "public static final com.yahoo.path.Path SCHEMAS_DIR", "public static final com.yahoo.path.Path SEARCH_DEFINITIONS_DIR", "public static final java.lang.String COMPONENT_DIR", "public static final java.lang.String SEARCHCHAINS_DIR", diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java index db3d391d19b..174f9bb54d7 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java @@ -36,8 +36,6 @@ import java.util.jar.JarFile; * The class hides detail as to whether the source is local files or ZooKeeper * data in config server. * - * Anyone wanting to access application data should use this interface. - * * @author Vegard Havdal */ public interface ApplicationPackage { @@ -47,7 +45,8 @@ public interface ApplicationPackage { String HOSTS = "hosts.xml"; String SERVICES = "services.xml"; - Path SEARCH_DEFINITIONS_DIR = Path.fromString("searchdefinitions"); + Path SCHEMAS_DIR = Path.fromString("schemas"); + Path SEARCH_DEFINITIONS_DIR = Path.fromString("searchdefinitions"); // Legacy addition to schemas String COMPONENT_DIR = "components"; String SEARCHCHAINS_DIR = "search/chains"; String DOCPROCCHAINS_DIR = "docproc/chains"; @@ -168,7 +167,7 @@ public interface ApplicationPackage { } /** - * Returns inforamtion about a file + * Returns information about a file * * @param relativePath the relative path of the file within this application package. * @return information abut the file, returned whether or not the file exists @@ -206,23 +205,26 @@ public interface ApplicationPackage { Reader getRankingExpression(String name); /** - * Returns the name-payload pairs of any sd files under path/searchdefinitions/ in the given jar bundle - * @param bundle The jar file, which will be closed afterwards by this method. - * @param path For example 'complex/' + * Returns the name-payload pairs of any sd files under path/schemas and path/searchdefinitions/ + * in the given jar bundle. + * + * @param bundle the jar file, which will be closed afterwards by this method + * @param path for example 'complex/' * @return map of the SD payloads * @throws IOException if it is reading sd files fails */ static Map<String, String> getBundleSdFiles(String path, JarFile bundle) throws IOException { - Map<String,String> ret = new LinkedHashMap<>(); + Map<String, String> schemas = new LinkedHashMap<>(); for (Enumeration<JarEntry> e = bundle.entries(); e.hasMoreElements();) { - JarEntry je=e.nextElement(); - if (je.getName().startsWith(path+SEARCH_DEFINITIONS_DIR+"/") && je.getName().endsWith(SD_NAME_SUFFIX)) { - String contents = IOUtils.readAll(new InputStreamReader(bundle.getInputStream(je))); - ret.put(getFileName(je), contents); + JarEntry entry = e.nextElement(); + if ((entry.getName().startsWith(path + SCHEMAS_DIR + "/") || entry.getName().startsWith(path + SEARCH_DEFINITIONS_DIR + "/")) + && entry.getName().endsWith(SD_NAME_SUFFIX)) { + String contents = IOUtils.readAll(new InputStreamReader(bundle.getInputStream(entry))); + schemas.put(getFileName(entry), contents); } } bundle.close(); - return ret; + return schemas; } /** diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java index e66a7e1ef7e..930c3c94907 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java @@ -7,6 +7,7 @@ import com.yahoo.config.provision.ApplicationId; * Interface for those wanting to be notified about changes to the SuperModel. */ public interface SuperModelListener { + /** * Application has been activated: Either deployed the first time, * internally redeployed, or externally triggered redeploy. @@ -22,7 +23,7 @@ public interface SuperModelListener { * Invoked once all applications that were supposed to be deployed on bootstrap * have been activated (and the respective {@link #applicationActivated(SuperModel, ApplicationInfo) * applicationActivated} have been invoked). The SuperModel is then said to be "complete". - * @param superModel */ void notifyOfCompleteness(SuperModel superModel); + } diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java index a9b4e06ae1b..23983fda413 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java @@ -417,20 +417,18 @@ public class DeployState implements ConfigDefinitionStore { for (NamedReader reader : readers) { try { String readerName = reader.getName(); - String searchName = builder.importReader(reader, readerName, logger); + String topLevelName = builder.importReader(reader, readerName, logger); String sdName = stripSuffix(readerName, ApplicationPackage.SD_NAME_SUFFIX); - names.put(searchName, sdName); - if ( ! sdName.equals(searchName)) { - throw new IllegalArgumentException("Search definition file name ('" + sdName + "') and name of " + - "search element ('" + searchName + + names.put(topLevelName, sdName); + if ( ! sdName.equals(topLevelName)) { + throw new IllegalArgumentException("Schema definition file name ('" + sdName + "') and name of " + + "top level element ('" + topLevelName + "') are not equal for file '" + readerName + "'"); } } catch (ParseException e) { - throw new IllegalArgumentException("Could not parse search definition file '" + - getSearchDefinitionRelativePath(reader.getName()) + "': " + e.getMessage(), e); + throw new IllegalArgumentException("Could not parse sd file '" + reader.getName(), e); } catch (IOException e) { - throw new IllegalArgumentException("Could not read search definition file '" + - getSearchDefinitionRelativePath(reader.getName()) + "': " + e.getMessage(), e); + throw new IllegalArgumentException("Could not read sd file '" + reader.getName(), e); } finally { closeIgnoreException(reader.getReader()); } @@ -439,10 +437,6 @@ public class DeployState implements ConfigDefinitionStore { return SearchDocumentModel.fromBuilderAndNames(builder, names); } - private String getSearchDefinitionRelativePath(String name) { - return ApplicationPackage.SEARCH_DEFINITIONS_DIR + File.separator + name; - } - private static String stripSuffix(String nodeName, String postfix) { assert (nodeName.endsWith(postfix)); return nodeName.substring(0, nodeName.length() - postfix.length()); diff --git a/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java b/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java index cb1577417b4..099ff83774f 100644 --- a/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java +++ b/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java @@ -72,21 +72,18 @@ public class ApplicationDeployTest { break; case "product": assertTrue(s instanceof DocumentOnlySearch); - assertEquals(s.getDocument().getField("title").getDataType(), DataType.STRING); + assertEquals(DataType.STRING, s.getDocument().getField("title").getDataType()); break; default: fail(); } } - File[] truth = new File[]{new File(TESTSDDIR + "laptop.sd"), - new File(TESTSDDIR + "music.sd"), - new File(TESTSDDIR + "pc.sd"), - new File(TESTSDDIR + "product.sd"), - new File(TESTSDDIR + "sock.sd")}; - Arrays.sort(truth); - List<File> appSdFiles = tester.app().getSearchDefinitionFiles(); - Collections.sort(appSdFiles); - assertEquals(appSdFiles, Arrays.asList(truth)); + assertEquals(Set.of(new File(TESTSDDIR + "laptop.sd"), + new File(TESTSDDIR + "music.sd"), + new File(TESTSDDIR + "pc.sd"), + new File(TESTSDDIR + "product.sd"), + new File(TESTSDDIR + "sock.sd")), + new HashSet<>(tester.app().getSearchDefinitionFiles())); List<FilesApplicationPackage.Component> components = tester.app().getComponents(); assertEquals(1, components.size()); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java index 13ef19f5f5d..9cb97b9cfb5 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java @@ -87,17 +87,16 @@ public class ZooKeeperClient { /** Sets the app id and attempts to set up zookeeper. The app id must be ordered for purge to work OK. */ private void createZooKeeperNodes() { - if (!configCurator.exists(rootPath.getAbsolute())) { + if ( ! configCurator.exists(rootPath.getAbsolute())) configCurator.createNode(rootPath.getAbsolute()); - } - for (String subPath : Arrays.asList( - ConfigCurator.DEFCONFIGS_ZK_SUBPATH, - ConfigCurator.USER_DEFCONFIGS_ZK_SUBPATH, - ConfigCurator.USERAPP_ZK_SUBPATH, - ZKApplicationPackage.fileRegistryNode)) { - // TODO The replaceFirst below is hackish. - configCurator.createNode(getZooKeeperAppPath(null).getAbsolute(), subPath.replaceFirst("/", "")); + for (String subPath : Arrays.asList(ConfigCurator.DEFCONFIGS_ZK_SUBPATH, + ConfigCurator.USER_DEFCONFIGS_ZK_SUBPATH, + ConfigCurator.USERAPP_ZK_SUBPATH, + ZKApplicationPackage.fileRegistryNode)) { + // TODO: The replaceFirst below is hackish. + configCurator.createNode(getZooKeeperAppPath(null).getAbsolute(), + subPath.replaceFirst("/", "")); } } @@ -108,7 +107,6 @@ public class ZooKeeperClient { */ void write(ApplicationPackage app) { logFine("Feeding application config into ZooKeeper"); - // gives lots and lots of debug output: // BasicConfigurator.configure(); try { logFine("Feeding user def files into ZooKeeper"); writeUserDefs(app); @@ -121,43 +119,33 @@ public class ZooKeeperClient { write(app.getMetaData()); } catch (Exception e) { throw new IllegalStateException("Unable to write vespa model to config server(s) " + System.getProperty("configsources") + "\n" + - "Please ensure that cloudconfig_server is started on the config server node(s), " + - "and check the vespa log for configserver errors. ", e); + "Please ensure that cloudconfig_server is started on the config server node(s), " + + "and check the vespa log for configserver errors. ", e); } } private void writeSearchDefinitions(ApplicationPackage app) throws IOException { Collection<NamedReader> sds = app.getSearchDefinitions(); - if (sds.isEmpty()) { - return; - } - Path zkPath = getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.SEARCH_DEFINITIONS_DIR); + if (sds.isEmpty()) return; + + Path zkPath = getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.SCHEMAS_DIR); configCurator.createNode(zkPath.getAbsolute()); - // Ensures that ranking expressions and other files are also fed. + // Ensures that ranking expressions and other files are also written writeDir(app.getFile(ApplicationPackage.SEARCH_DEFINITIONS_DIR), zkPath, false); + writeDir(app.getFile(ApplicationPackage.SCHEMAS_DIR), zkPath, false); for (NamedReader sd : sds) { - String name = sd.getName(); - Reader reader = sd.getReader(); - String data = com.yahoo.io.IOUtils.readAll(reader); - reader.close(); - configCurator.putData(zkPath.getAbsolute(), name, data); + configCurator.putData(zkPath.getAbsolute(), sd.getName(), com.yahoo.io.IOUtils.readAll(sd.getReader())); + sd.getReader().close(); } } /** * Puts some of the application package files into ZK - see write(app). * - * @param app The application package to use as input. - * @throws java.io.IOException if not able to write to Zookeeper + * @param app the application package to use as input. + * @throws java.io.IOException if not able to write to Zookeeper */ private void writeSomeOf(ApplicationPackage app) throws IOException { - ApplicationFile.PathFilter srFilter = new ApplicationFile.PathFilter() { - @Override - public boolean accept(Path path) { - return path.getName().endsWith(ApplicationPackage.RULES_NAME_SUFFIX); - } - }; - // Copy app package files and subdirs into zk // TODO: We should have a way of doing this which doesn't require repeating all the content writeFile(app.getFile(Path.fromString(ApplicationPackage.SERVICES)), getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH)); @@ -169,7 +157,8 @@ public class ZooKeeperClient { getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH)); writeDir(app.getFile(ApplicationPackage.RULES_DIR), getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.RULES_DIR), - srFilter, true); + (path) -> path.getName().endsWith(ApplicationPackage.RULES_NAME_SUFFIX), + true); writeDir(app.getFile(ApplicationPackage.QUERY_PROFILES_DIR), getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.QUERY_PROFILES_DIR), xmlFilter, true); @@ -194,20 +183,12 @@ public class ZooKeeperClient { } private void writeDir(ApplicationFile file, Path zooKeeperAppPath, boolean recurse) throws IOException { - writeDir(file, zooKeeperAppPath, new ApplicationFile.PathFilter() { - @Override - public boolean accept(Path path) { - return true; - } - }, recurse); + writeDir(file, zooKeeperAppPath, (__) -> true, recurse); } private void writeDir(ApplicationFile dir, Path path, ApplicationFile.PathFilter filenameFilter, boolean recurse) throws IOException { - if (!dir.isDirectory()) { - logger.log(LogLevel.FINE, dir.getPath().getAbsolute()+" is not a directory. Not feeding the files into ZooKeeper."); - return; - } - for (ApplicationFile file: listFiles(dir, filenameFilter)) { + if ( ! dir.isDirectory()) return; + for (ApplicationFile file : listFiles(dir, filenameFilter)) { String name = file.getPath().getName(); if (name.startsWith(".")) continue; //.svn , .git ... if ("CVS".equals(name)) continue; @@ -223,7 +204,8 @@ public class ZooKeeperClient { } /** - * Like {@link ApplicationFile#listFiles(com.yahoo.config.application.api.ApplicationFile.PathFilter)} with a slightly different semantic. Never filter out directories. + * Like {@link ApplicationFile#listFiles(com.yahoo.config.application.api.ApplicationFile.PathFilter)} + * with slightly different semantics: Never filter out directories. */ private List<ApplicationFile> listFiles(ApplicationFile dir, ApplicationFile.PathFilter filter) { List<ApplicationFile> rawList = dir.listFiles(); @@ -243,9 +225,8 @@ public class ZooKeeperClient { } private void writeFile(ApplicationFile file, Path zkPath) throws IOException { - if (!file.exists()) { - return; - } + if ( ! file.exists()) return; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (InputStream inputStream = file.createInputStream()) { inputStream.transferTo(baos); @@ -292,8 +273,8 @@ public class ZooKeeperClient { String exportedRegistry = PreGeneratedFileRegistry.exportRegistry(fileRegistry); configCurator.putData(getZooKeeperAppPath(null).append(ZKApplicationPackage.fileRegistryNode).getAbsolute(), - vespaVersion.toFullString(), - exportedRegistry); + vespaVersion.toFullString(), + exportedRegistry); } /** @@ -343,9 +324,8 @@ public class ZooKeeperClient { } public void write(AllocatedHosts hosts) throws IOException { - configCurator.putData( - rootPath.append(ZKApplicationPackage.allocatedHostsNode).getAbsolute(), - AllocatedHostsSerializer.toJson(hosts)); + configCurator.putData(rootPath.append(ZKApplicationPackage.allocatedHostsNode).getAbsolute(), + AllocatedHostsSerializer.toJson(hosts)); } public void write(Map<Version, FileRegistry> fileRegistryMap) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java index 3ae678969eb..5f180bdaee1 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java @@ -9,14 +9,12 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Responsible for providing data from an application subtree in zookeeper. * (i.e. /config/v2/tenants/x/session/<session id for an application>/). * - * Takes care of - * - * * @author Tony Vaagenes */ public class ZKApplication { @@ -84,6 +82,10 @@ public class ZKApplication { return reader(data); } + Optional<Reader> getOptionalDataReader(String path, String node) { + return Optional.ofNullable(getData(path, node)).map(data -> reader(data)); + } + public String getData(String path, String node) { try { return zk.getData(getFullPath(path), node); @@ -181,10 +183,9 @@ public class ZKApplication { } Reader getDataReader(String path) { - final String data = getData(path); - if (data == null) { + String data = getData(path); + if (data == null) throw new IllegalArgumentException("No node for " + getFullPath(path) + " exists"); - } return reader(data); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java index bcb958c4b58..c7ec2657996 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java @@ -139,13 +139,16 @@ public class ZKApplicationPackage implements ApplicationPackage { @Override public List<NamedReader> searchDefinitionContents() { - List<NamedReader> ret = new ArrayList<>(); - for (String sd : zkApplication.getChildren(ConfigCurator.USERAPP_ZK_SUBPATH+"/"+SEARCH_DEFINITIONS_DIR)) { - if (sd.endsWith(ApplicationPackage.SD_NAME_SUFFIX)) { - ret.add(new NamedReader(sd, new StringReader(zkApplication.getData(ConfigCurator.USERAPP_ZK_SUBPATH+"/"+SEARCH_DEFINITIONS_DIR, sd)))); - } + List<NamedReader> schemas = new ArrayList<>(); + for (String sd : zkApplication.getChildren(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SEARCH_DEFINITIONS_DIR)) { + if (sd.endsWith(ApplicationPackage.SD_NAME_SUFFIX)) + schemas.add(new NamedReader(sd, new StringReader(zkApplication.getData(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SEARCH_DEFINITIONS_DIR, sd)))); } - return ret; + for (String sd : zkApplication.getChildren(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SCHEMAS_DIR)) { + if (sd.endsWith(ApplicationPackage.SD_NAME_SUFFIX)) + schemas.add(new NamedReader(sd, new StringReader(zkApplication.getData(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SCHEMAS_DIR, sd)))); + } + return schemas; } @Override @@ -176,7 +179,7 @@ public class ZKApplicationPackage implements ApplicationPackage { try { return zkApplication.getDataReader(ConfigCurator.DEFCONFIGS_ZK_SUBPATH, def); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Could not retrieve config definition " + def + ".", e); + throw new IllegalArgumentException("Could not retrieve config definition " + def, e); } } @@ -264,7 +267,10 @@ public class ZKApplicationPackage implements ApplicationPackage { @Override public Reader getRankingExpression(String name) { - return zkApplication.getDataReader(ConfigCurator.USERAPP_ZK_SUBPATH+"/"+SEARCH_DEFINITIONS_DIR, name); + Optional<Reader> reader = zkApplication.getOptionalDataReader(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SCHEMAS_DIR, name); + if (reader.isPresent()) + return reader.get(); + return zkApplication.getDataReader(ConfigCurator.USERAPP_ZK_SUBPATH + "/" + SEARCH_DEFINITIONS_DIR, name); } @Override diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java index 14fa0cb2dbe..91d59bbeb4e 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java @@ -170,16 +170,16 @@ public class ZooKeeperClientTest { @Test public void search_definitions_written_to_ZK() { - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("music.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("base.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("video.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("book.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("pc.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("laptop.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("product.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("sock.sd").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("foo.expression").getAbsolute())); - assertTrue(zk.exists(appPath().append(ApplicationPackage.SEARCH_DEFINITIONS_DIR).append("bar.expression").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("music.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("base.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("video.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("book.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("pc.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("laptop.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("product.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("sock.sd").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("foo.expression").getAbsolute())); + assertTrue(zk.exists(appPath().append(ApplicationPackage.SCHEMAS_DIR).append("bar.expression").getAbsolute())); } private Path appPath() { |