com.yahoo.schema.parser.ConvertSchemaCollection Maven / Gradle / Ivy
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.schema.parser;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.application.provider.BaseDeployLogger;
import com.yahoo.config.model.application.provider.MockFileRegistry;
import com.yahoo.config.model.deploy.TestProperties;
import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.document.DocumentTypeManager;
import com.yahoo.schema.RankProfileRegistry;
import com.yahoo.schema.Schema;
import java.util.ArrayList;
import java.util.List;
/**
* Class converting a collection of schemas from the intermediate format.
*
* @author arnej27959
*/
public class ConvertSchemaCollection {
private final IntermediateCollection input;
private final List orderedInput = new ArrayList<>();
private final DocumentTypeManager docMan;
private final ApplicationPackage applicationPackage;
private final FileRegistry fileRegistry;
private final DeployLogger deployLogger;
private final ModelContext.Properties properties;
private final RankProfileRegistry rankProfileRegistry;
private final boolean documentsOnly;
// for unit test
ConvertSchemaCollection(IntermediateCollection input,
DocumentTypeManager documentTypeManager)
{
this(input, documentTypeManager,
MockApplicationPackage.createEmpty(),
new MockFileRegistry(),
new BaseDeployLogger(),
new TestProperties(),
new RankProfileRegistry(),
true);
}
public ConvertSchemaCollection(IntermediateCollection input,
DocumentTypeManager documentTypeManager,
ApplicationPackage applicationPackage,
FileRegistry fileRegistry,
DeployLogger deployLogger,
ModelContext.Properties properties,
RankProfileRegistry rankProfileRegistry,
boolean documentsOnly)
{
this.input = input;
this.docMan = documentTypeManager;
this.applicationPackage = applicationPackage;
this.fileRegistry = fileRegistry;
this.deployLogger = deployLogger;
this.properties = properties;
this.rankProfileRegistry = rankProfileRegistry;
this.documentsOnly = documentsOnly;
input.resolveInternalConnections();
order();
pushTypesToDocuments();
}
void order() {
var map = input.getParsedSchemas();
for (var schema : map.values()) {
findOrdering(schema);
}
}
void findOrdering(ParsedSchema schema) {
if (orderedInput.contains(schema)) return;
for (var parent : schema.getAllResolvedInherits()) {
findOrdering(parent);
}
orderedInput.add(schema);
}
void pushTypesToDocuments() {
for (var schema : orderedInput) {
for (var struct : schema.getStructs()) {
schema.getDocument().addStruct(struct);
}
for (var annotation : schema.getAnnotations()) {
schema.getDocument().addAnnotation(annotation);
}
}
}
private ConvertParsedTypes typeConverter;
public void convertTypes() {
typeConverter = new ConvertParsedTypes(orderedInput, docMan);
typeConverter.convert(true);
}
public List convertToSchemas() {
resolveStructInheritance();
resolveAnnotationInheritance();
addMissingAnnotationStructs();
var converter = new ConvertParsedSchemas(orderedInput,
docMan,
applicationPackage,
fileRegistry,
deployLogger,
properties,
rankProfileRegistry,
documentsOnly);
return converter.convertToSchemas();
}
private void resolveStructInheritance() {
List all = new ArrayList<>();
for (var schema : orderedInput) {
var doc = schema.getDocument();
for (var struct : doc.getStructs()) {
for (String inherit : struct.getInherited()) {
var parent = doc.findParsedStruct(inherit);
if (parent == null) {
throw new IllegalArgumentException("Can not find parent for "+struct+" in "+doc);
}
struct.resolveInherit(inherit, parent);
}
all.add(struct);
}
}
List seen = new ArrayList<>();
for (ParsedStruct struct : all) {
inheritanceCycleCheck(struct, seen);
}
}
private void resolveAnnotationInheritance() {
List all = new ArrayList();
for (var schema : orderedInput) {
var doc = schema.getDocument();
for (var annotation : doc.getAnnotations()) {
for (String inherit : annotation.getInherited()) {
var parent = doc.findParsedAnnotation(inherit);
if (parent == null) {
throw new IllegalArgumentException("Can not find parent for "+annotation+" in "+doc);
}
annotation.resolveInherit(inherit, parent);
}
all.add(annotation);
}
}
List seen = new ArrayList<>();
for (ParsedAnnotation annotation : all) {
inheritanceCycleCheck(annotation, seen);
}
}
private void fixupAnnotationStruct(ParsedAnnotation parsed) {
for (var parent : parsed.getResolvedInherits()) {
fixupAnnotationStruct(parent);
parent.getStruct().ifPresent(ps -> {
var myStruct = parsed.ensureStruct();
if (! myStruct.getInherited().contains(ps.name())) {
myStruct.inherit(ps.name());
myStruct.resolveInherit(ps.name(), ps);
}
});
}
}
private void addMissingAnnotationStructs() {
for (var schema : orderedInput) {
var doc = schema.getDocument();
for (var annotation : doc.getAnnotations()) {
fixupAnnotationStruct(annotation);
}
}
}
private void inheritanceCycleCheck(ParsedStruct struct, List seen) {
String name = struct.name();
if (seen.contains(name)) {
seen.add(name);
throw new IllegalArgumentException("Inheritance/reference cycle for structs: " +
String.join(" -> ", seen));
}
seen.add(name);
for (ParsedStruct parent : struct.getResolvedInherits()) {
inheritanceCycleCheck(parent, seen);
}
seen.remove(name);
}
private void inheritanceCycleCheck(ParsedAnnotation annotation, List seen) {
String name = annotation.name();
if (seen.contains(name)) {
seen.add(name);
throw new IllegalArgumentException("Inheritance/reference cycle for annotations: " +
String.join(" -> ", seen));
}
seen.add(name);
for (ParsedAnnotation parent : annotation.getResolvedInherits()) {
inheritanceCycleCheck(parent, seen);
}
seen.remove(name);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy