summaryrefslogtreecommitdiffstats
path: root/config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java
diff options
context:
space:
mode:
Diffstat (limited to 'config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java')
-rw-r--r--config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java219
1 files changed, 37 insertions, 182 deletions
diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java
index 70da2f2e92e..d0cca38b375 100644
--- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java
+++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/SchemaValidator.java
@@ -6,214 +6,40 @@ import com.thaiopensource.util.PropertyMapBuilder;
import com.thaiopensource.validate.ValidateProperty;
import com.thaiopensource.validate.ValidationDriver;
import com.thaiopensource.validate.rng.CompactSchemaReader;
-import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeployLogger;
-import com.yahoo.io.IOUtils;
import com.yahoo.io.reader.NamedReader;
-import com.yahoo.log.LogLevel;
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
import com.yahoo.yolean.Exceptions;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
+
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.Reader;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
import java.util.logging.Level;
-import java.util.logging.Logger;
/**
- * Validates xml files against one schema.
+ * Validates xml files against a schema.
*
* @author tonytv
*/
public class SchemaValidator {
- public static final String schemaDirBase = System.getProperty("java.io.tmpdir", File.separator + "tmp" + File.separator + "vespa");
- static final String servicesXmlSchemaName = "services.rnc";
- static final String hostsXmlSchemaName = "hosts.rnc";
- static final String deploymentXmlSchemaName = "deployment.rnc";
- static final String validationOverridesXmlSchemaName = "validation-overrides.rnc";
private final CustomErrorHandler errorHandler = new CustomErrorHandler();
private final ValidationDriver driver;
- private DeployLogger deployLogger;
- private static final Logger log = Logger.getLogger(SchemaValidator.class.getName());
-
- /**
- * Initializes the validator by using the given file as schema file
- * @param schema a schema file in RNC format
- * @param logger a logger
- * @param vespaVersion the version of Vespa we should validate against
- */
- public SchemaValidator(String schema, DeployLogger logger, Version vespaVersion) {
- this.deployLogger = logger;
- driver = new ValidationDriver(PropertyMap.EMPTY, instanceProperties(), CompactSchemaReader.getInstance());
- File schemaDir = new File(schemaDirBase);
- try {
- schemaDir = saveSchemasFromJar(new File(SchemaValidator.schemaDirBase), vespaVersion);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- loadSchema(new File(schemaDir + File.separator + "schema" + File.separator + schema));
- IOUtils.recursiveDeleteDir(schemaDir);
- }
+ private final DeployLogger deployLogger;
/**
* Initializes the validator by using the given file as schema file
- * @param schema a schema file in RNC format
- * @param vespaVersion the version we should validate against
- * @throws IOException if it is not possible to read schema files
- */
- public SchemaValidator(String schema, Version vespaVersion) throws IOException {
- this(schema, new BaseDeployLogger(), vespaVersion);
- }
-
- /**
- * Create a validator for services.xml for tests
- * @throws IOException if it is not possible to read schema files
- */
- public static SchemaValidator createTestValidatorServices(Version vespaVersion) throws IOException {
- return new SchemaValidator(servicesXmlSchemaName, vespaVersion);
- }
-
- /**
- * Create a validator for hosts.xml for tests
- * @throws IOException if it is not possible to read schema files
- */
- public static SchemaValidator createTestValidatorHosts(Version vespaVersion) throws IOException {
- return new SchemaValidator(hostsXmlSchemaName, vespaVersion);
- }
-
- /**
- * Create a validator for deployment.xml for tests
*
+ * @param schemaFile schema file
* @throws IOException if it is not possible to read schema files
*/
- public static SchemaValidator createTestValidatorDeployment(Version vespaVersion) throws IOException {
- return new SchemaValidator(deploymentXmlSchemaName, vespaVersion);
- }
-
- private class CustomErrorHandler implements ErrorHandler {
- volatile String fileName;
-
- public void warning(SAXParseException e) throws SAXException {
- deployLogger.log(Level.WARNING, message(e));
- }
-
- public void error(SAXParseException e) throws SAXException {
- throw new IllegalArgumentException(message(e));
- }
-
- public void fatalError(SAXParseException e) throws SAXException {
- throw new IllegalArgumentException(message(e));
- }
-
- private String message(SAXParseException e) {
- return "XML error in " + fileName + ": " +
- Exceptions.toMessageString(e)
- + " [" + e.getLineNumber() + ":" + e.getColumnNumber() + "]";
- }
- }
-
- /**
- * Look for the schema files that should be in vespa-model.jar and saves them on temp dir.
- *
- * @return the directory the schema files are stored in
- * @throws IOException if it is not possible to read schema files
- */
- private File saveSchemasFromJar(File tmpBase, Version vespaVersion) throws IOException {
- final Class<? extends SchemaValidator> schemaValidatorClass = this.getClass();
- final ClassLoader classLoader = schemaValidatorClass.getClassLoader();
- Enumeration<URL> uris = classLoader.getResources("schema");
- if (uris==null) return null;
- File tmpDir = java.nio.file.Files.createTempDirectory(tmpBase.toPath(), "vespa").toFile();
- log.log(LogLevel.DEBUG, "Saving schemas to " + tmpDir);
- while(uris.hasMoreElements()) {
- URL u = uris.nextElement();
- log.log(LogLevel.DEBUG, "uri for resource 'schema'=" + u.toString());
- if ("jar".equals(u.getProtocol())) {
- JarURLConnection jarConnection = (JarURLConnection) u.openConnection();
- JarFile jarFile = jarConnection.getJarFile();
- for (Enumeration<JarEntry> entries = jarFile.entries();
- entries.hasMoreElements();) {
-
- JarEntry je=entries.nextElement();
- if (je.getName().startsWith("schema/") && je.getName().endsWith(".rnc")) {
- writeContentsToFile(tmpDir, je.getName(), jarFile.getInputStream(je));
- }
- }
- jarFile.close();
- } else if ("bundle".equals(u.getProtocol())) {
- Bundle bundle = FrameworkUtil.getBundle(schemaValidatorClass);
- log.log(LogLevel.DEBUG, classLoader.toString());
- log.log(LogLevel.DEBUG, "bundle=" + bundle);
- // TODO: Hack to handle cases where bundle=null
- if (bundle == null) {
- File schemaPath;
- if (vespaVersion.getMajor() == 5) {
- schemaPath = new File(getDefaults().underVespaHome("share/vespa/schema/version/5.x/schema/"));
- } else {
- schemaPath = new File(getDefaults().underVespaHome("share/vespa/schema/"));
- }
- log.log(LogLevel.DEBUG, "Using schemas found in " + schemaPath);
- copySchemas(schemaPath, tmpDir);
- } else {
- log.log(LogLevel.DEBUG, String.format("Saving schemas for model bundle %s:%s", bundle.getSymbolicName(), bundle
- .getVersion()));
- for (Enumeration<URL> entries = bundle.findEntries("schema", "*.rnc", true);
- entries.hasMoreElements(); ) {
-
- URL url = entries.nextElement();
- writeContentsToFile(tmpDir, url.getFile(), url.openStream());
- }
- }
- } else if ("file".equals(u.getProtocol())) {
- File schemaPath = new File(u.getPath());
- copySchemas(schemaPath, tmpDir);
- }
- }
- return tmpDir;
- }
-
- private static void copySchemas(File from, File to) throws IOException {
- // TODO: only copy .rnc files.
- if (! from.exists()) throw new IOException("Could not find schema source directory '" + from + "'");
- if (! from.isDirectory()) throw new IOException("Schema source '" + from + "' is not a directory");
- File sourceFile = new File(from, servicesXmlSchemaName);
- if (! sourceFile.exists()) throw new IOException("Schema source file '" + sourceFile + "' not found");
- IOUtils.copyDirectoryInto(from, to);
- }
-
- private static void writeContentsToFile(File outDir, String outFile, InputStream inputStream) throws IOException {
- String contents = IOUtils.readAll(new InputStreamReader(inputStream));
- File out = new File(outDir, outFile);
- IOUtils.writeFile(out, contents, false);
- }
-
- private void loadSchema(File schemaFile) {
- try {
- driver.loadSchema(ValidationDriver.fileInputSource(schemaFile));
- } catch (SAXException e) {
- throw new RuntimeException("Invalid schema '" + schemaFile + "'", e);
- } catch (IOException e) {
- throw new RuntimeException("IO error reading schema '" + schemaFile + "'", e);
- }
- }
-
- private PropertyMap instanceProperties() {
- PropertyMapBuilder builder = new PropertyMapBuilder();
- builder.put(ValidateProperty.ERROR_HANDLER, errorHandler);
- return builder.toPropertyMap();
+ SchemaValidator(File schemaFile, DeployLogger deployLogger) throws IOException, SAXException {
+ this.deployLogger = deployLogger;
+ this.driver = new ValidationDriver(PropertyMap.EMPTY, instanceProperties(), CompactSchemaReader.getInstance());
+ driver.loadSchema(ValidationDriver.fileInputSource(schemaFile));
}
public void validate(File file) throws IOException {
@@ -246,4 +72,33 @@ public class SchemaValidator {
"XML error in " + (fileName == null ? " input" : fileName) + ": " + Exceptions.toMessageString(e));
}
}
+
+ private PropertyMap instanceProperties() {
+ PropertyMapBuilder builder = new PropertyMapBuilder();
+ builder.put(ValidateProperty.ERROR_HANDLER, errorHandler);
+ return builder.toPropertyMap();
+ }
+
+ private class CustomErrorHandler implements ErrorHandler {
+ volatile String fileName;
+
+ public void warning(SAXParseException e) throws SAXException {
+ deployLogger.log(Level.WARNING, message(e));
+ }
+
+ public void error(SAXParseException e) throws SAXException {
+ throw new IllegalArgumentException(message(e));
+ }
+
+ public void fatalError(SAXParseException e) throws SAXException {
+ throw new IllegalArgumentException(message(e));
+ }
+
+ private String message(SAXParseException e) {
+ return "XML error in " + fileName + ": " +
+ Exceptions.toMessageString(e)
+ + " [" + e.getLineNumber() + ":" + e.getColumnNumber() + "]";
+ }
+ }
+
}