use of org.apache.ignite.configuration.RootKey in project ignite-3 by apache.
the class ConfigurationUtilTest method testFlattenedMapPolymorphicConfig.
@Test
void testFlattenedMapPolymorphicConfig() {
InnerNode polymorphicRootInnerNode = newNodeInstance(PolymorphicRootConfigurationSchema.class);
addDefaults(polymorphicRootInnerNode);
RootKey<?, ?> rootKey = PolymorphicRootConfiguration.KEY;
SuperRoot superRoot = new SuperRoot(key -> null, Map.of(rootKey, polymorphicRootInnerNode));
final Map<String, Serializable> act = flattenedMap(superRoot, rootKey, node -> ((PolymorphicRootChange) node).changePolymorphicSubCfg(c -> c.convert(SecondPolymorphicInstanceChange.class)));
Map<String, Serializable> exp = new HashMap<>();
exp.put("rootPolymorphic.polymorphicSubCfg.typeId", "second");
exp.put("rootPolymorphic.polymorphicSubCfg.longVal", 0L);
exp.put("rootPolymorphic.polymorphicSubCfg.strVal", null);
exp.put("rootPolymorphic.polymorphicSubCfg.intVal", 0);
assertEquals(exp, act);
}
use of org.apache.ignite.configuration.RootKey in project ignite-3 by apache.
the class ConfigurationUtilTest method testFlattenedMapPolymorphicNamedConfig.
@Test
void testFlattenedMapPolymorphicNamedConfig() {
InnerNode polymorphicRootInnerNode = newNodeInstance(PolymorphicRootConfigurationSchema.class);
PolymorphicRootChange polymorphicRootChange = ((PolymorphicRootChange) polymorphicRootInnerNode);
polymorphicRootChange.changePolymorphicNamedCfg(c -> c.create("0", c1 -> {
}));
addDefaults(polymorphicRootInnerNode);
RootKey<?, ?> rootKey = PolymorphicRootConfiguration.KEY;
SuperRoot superRoot = new SuperRoot(key -> null, Map.of(rootKey, polymorphicRootInnerNode));
final Map<String, Serializable> act = flattenedMap(superRoot, rootKey, node -> ((PolymorphicRootChange) node).changePolymorphicNamedCfg(c -> c.createOrUpdate("0", c1 -> c1.convert(SecondPolymorphicInstanceChange.class))));
NamedListNode<?> polymorphicNamedCfgListNode = (NamedListNode<?>) polymorphicRootChange.polymorphicNamedCfg();
UUID internalId = polymorphicNamedCfgListNode.internalId("0");
Map<String, Serializable> exp = new HashMap<>();
exp.put("rootPolymorphic.polymorphicNamedCfg." + internalId + ".typeId", "second");
exp.put("rootPolymorphic.polymorphicNamedCfg." + internalId + ".longVal", 0L);
exp.put("rootPolymorphic.polymorphicNamedCfg." + internalId + ".strVal", null);
exp.put("rootPolymorphic.polymorphicNamedCfg." + internalId + ".intVal", 0);
assertEquals(exp, act);
}
use of org.apache.ignite.configuration.RootKey in project ignite-3 by apache.
the class ConfigurationAsmGenerator method addConfigurationImplConstructor.
/**
* Implements default constructor for the configuration class. It initializes all fields and adds them to members collection.
*
* @param classDef Configuration impl class definition.
* @param schemaClass Configuration schema class.
* @param internalExtensions Internal extensions of the configuration schema.
* @param fieldDefs Field definitions for all fields of configuration impl class.
* @param schemaFields Fields of the schema class.
* @param internalFields Fields of internal extensions of the configuration schema.
* @param polymorphicFields Fields of polymorphic extensions of the configuration schema.
* @param internalIdField Internal id field or {@code null} if it's not present.
* @param internalConfigTypesFieldDef Field definition for {@link DynamicConfiguration#internalConfigTypes},
* {@code null} if there are no internal extensions.
*/
private void addConfigurationImplConstructor(ClassDefinition classDef, Class<?> schemaClass, Set<Class<?>> internalExtensions, Map<String, FieldDefinition> fieldDefs, Collection<Field> schemaFields, Collection<Field> internalFields, Collection<Field> polymorphicFields, @Nullable Field internalIdField, @Nullable FieldDefinition internalConfigTypesFieldDef) {
MethodDefinition ctor = classDef.declareConstructor(of(PUBLIC), arg("prefix", List.class), arg("key", String.class), arg("rootKey", RootKey.class), arg("changer", DynamicConfigurationChanger.class), arg("listenOnly", boolean.class));
Variable rootKeyVar = ctor.getScope().getVariable("rootKey");
Variable changerVar = ctor.getScope().getVariable("changer");
Variable listenOnlyVar = ctor.getScope().getVariable("listenOnly");
SchemaClassesInfo schemaClassInfo = schemasInfo.get(schemaClass);
Variable thisVar = ctor.getThis();
BytecodeBlock ctorBody = ctor.getBody().append(thisVar).append(ctor.getScope().getVariable("prefix")).append(ctor.getScope().getVariable("key")).append(rootKeyVar).append(changerVar).append(listenOnlyVar).invokeConstructor(DYNAMIC_CONFIGURATION_CTOR);
BytecodeExpression thisKeysVar = thisVar.getField("keys", List.class);
// Wrap object into list to reuse the loop below.
List<Field> internalIdFieldAsList = internalIdField == null ? emptyList() : List.of(internalIdField);
int newIdx = 0;
for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields, internalIdFieldAsList)) {
String fieldName = schemaField.getName();
BytecodeExpression newValue;
if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField)) {
// A field with @InjectedName is special (auxiliary), it is not stored in storages as a regular field, and therefore there
// is no direct access to it. It is stored in the InnerNode and does not participate in its traversal, so in order to get
// it we need to get the InnerNode, and only then the value of this field.
// newValue = new DynamicProperty(this.keys, fieldName, rootKey, changer, listenOnly, readOnly);
newValue = newInstance(DynamicProperty.class, thisKeysVar, constantString(isInjectedName(schemaField) ? InnerNode.INJECTED_NAME : isInternalId(schemaField) ? InnerNode.INTERNAL_ID : schemaField.getName()), rootKeyVar, changerVar, listenOnlyVar, constantBoolean(isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField)));
} else {
SchemaClassesInfo fieldInfo = schemasInfo.get(schemaField.getType());
ParameterizedType cfgImplParameterizedType = typeFromJavaClassName(fieldInfo.cfgImplClassName);
if (isConfigValue(schemaField)) {
// newValue = new MyConfigurationImpl(super.keys, fieldName, rootKey, changer, listenOnly);
newValue = newInstance(cfgImplParameterizedType, thisKeysVar, constantString(fieldName), rootKeyVar, changerVar, listenOnlyVar);
} else {
// We have to create method "$new$<idx>" to reference it in lambda expression. That's the way it
// works, it'll invoke constructor with all 5 arguments, not just 2 as in BiFunction.
MethodDefinition newMtd = classDef.declareMethod(of(PRIVATE, STATIC, SYNTHETIC), "$new$" + newIdx++, typeFromJavaClassName(fieldInfo.cfgClassName), arg("rootKey", RootKey.class), arg("changer", DynamicConfigurationChanger.class), arg("listenOnly", boolean.class), arg("prefix", List.class), arg("key", String.class));
// newValue = new NamedListConfiguration(this.keys, fieldName, rootKey, changer, listenOnly,
// (p, k) -> new ValueConfigurationImpl(p, k, rootKey, changer, listenOnly),
// (p, c) -> new ValueDirectProxy(p, c),
// new ValueConfigurationImpl(this.keys, "any", rootKey, changer, true)
// );
newValue = newInstance(NamedListConfiguration.class, thisKeysVar, constantString(fieldName), rootKeyVar, changerVar, listenOnlyVar, invokeDynamic(LAMBDA_METAFACTORY, asList(getMethodType(getType(Object.class), getType(Object.class), getType(Object.class)), new Handle(Opcodes.H_INVOKESTATIC, internalName(schemaClassInfo.cfgImplClassName), newMtd.getName(), newMtd.getMethodDescriptor(), false), getMethodType(typeFromJavaClassName(fieldInfo.cfgClassName).getAsmType(), getType(List.class), getType(String.class))), "apply", BiFunction.class, rootKeyVar, changerVar, listenOnlyVar), newDirectProxyLambda(fieldInfo), newInstance(cfgImplParameterizedType, thisKeysVar, constantString("any"), rootKeyVar, changerVar, constantBoolean(true)).cast(ConfigurationProperty.class));
newMtd.getBody().append(newInstance(cfgImplParameterizedType, newMtd.getScope().getVariable("prefix"), newMtd.getScope().getVariable("key"), newMtd.getScope().getVariable("rootKey"), newMtd.getScope().getVariable("changer"), newMtd.getScope().getVariable("listenOnly"))).retObject();
}
}
FieldDefinition fieldDef = fieldDefs.get(fieldName(schemaField));
// this.field = newValue;
ctorBody.append(thisVar.setField(fieldDef, newValue));
if (!isPolymorphicConfigInstance(schemaField.getDeclaringClass()) && !isInternalId(schemaField)) {
// add(this.field);
ctorBody.append(thisVar.invoke(DYNAMIC_CONFIGURATION_ADD_MTD, thisVar.getField(fieldDef)));
}
}
if (internalConfigTypesFieldDef != null) {
assert !internalExtensions.isEmpty() : classDef;
// Class[] tmp;
Variable tmpVar = ctor.getScope().createTempVariable(Class[].class);
BytecodeBlock initInternalConfigTypesField = new BytecodeBlock();
// tmp = new Class[size];
initInternalConfigTypesField.append(tmpVar.set(newArray(type(Class[].class), internalExtensions.size())));
int i = 0;
for (Class<?> extension : internalExtensions) {
// tmp[i] = InternalTableConfiguration.class;
initInternalConfigTypesField.append(set(tmpVar, constantInt(i++), constantClass(typeFromJavaClassName(configurationClassName(extension)))));
}
// this._internalConfigTypes = tmp;
initInternalConfigTypesField.append(setThisFieldCode(ctor, tmpVar, internalConfigTypesFieldDef));
ctorBody.append(initInternalConfigTypesField);
}
ctorBody.ret();
}
use of org.apache.ignite.configuration.RootKey in project ignite-3 by apache.
the class ConfigurationExtension method cfgValue.
/**
* Instantiates a configuration instance for injection.
*
* @param type Type of the field or parameter. Class name must end with {@code Configuration}.
* @param annotation Annotation present on the field or parameter.
* @param cgen Runtime code generator associated with the extension instance.
* @param pool Single-threaded executor service to perform configuration changes.
* @param revisionListenerHolder Configuration storage revision change listener holder.
* @return Mock configuration instance.
* @throws ClassNotFoundException If corresponding configuration schema class is not found.
*/
private static Object cfgValue(Class<?> type, InjectConfiguration annotation, ConfigurationAsmGenerator cgen, ExecutorService pool, StorageRevisionListenerHolderImpl revisionListenerHolder) throws ClassNotFoundException {
// Trying to find a schema class using configuration naming convention. This code won't work for inner Java
// classes, extension is designed to mock actual configurations from public API to configure Ignite components.
Class<?> schemaClass = Class.forName(type.getCanonicalName() + "Schema");
cgen.compileRootSchema(schemaClass, internalSchemaExtensions(List.of(annotation.internalExtensions())), polymorphicSchemaExtensions(List.of(annotation.polymorphicExtensions())));
// RootKey must be mocked, there's no way to instantiate it using a public constructor.
RootKey rootKey = mock(RootKey.class);
when(rootKey.key()).thenReturn("mock");
when(rootKey.type()).thenReturn(LOCAL);
when(rootKey.schemaClass()).thenReturn(schemaClass);
when(rootKey.internal()).thenReturn(false);
SuperRoot superRoot = new SuperRoot(s -> new RootInnerNode(rootKey, cgen.instantiateNode(schemaClass)));
ConfigObject hoconCfg = ConfigFactory.parseString(annotation.value()).root();
HoconConverter.hoconSource(hoconCfg).descend(superRoot);
ConfigurationUtil.addDefaults(superRoot);
// Reference to the super root is required to make DynamicConfigurationChanger#change method atomic.
var superRootRef = new AtomicReference<>(superRoot);
// Reference that's required for notificator.
var cfgRef = new AtomicReference<DynamicConfiguration<?, ?>>();
cfgRef.set(cgen.instantiateCfg(rootKey, new DynamicConfigurationChanger() {
/**
* {@inheritDoc}
*/
@Override
public CompletableFuture<Void> change(ConfigurationSource change) {
return CompletableFuture.supplyAsync(() -> {
SuperRoot sr = superRootRef.get();
SuperRoot copy = sr.copy();
change.descend(copy);
ConfigurationUtil.dropNulls(copy);
if (superRootRef.compareAndSet(sr, copy)) {
long storageRevision = revisionListenerHolder.storageRev.incrementAndGet();
long notificationNumber = revisionListenerHolder.notificationListenerCnt.incrementAndGet();
List<CompletableFuture<?>> futures = new ArrayList<>();
futures.addAll(notifyListeners(sr.getRoot(rootKey), copy.getRoot(rootKey), (DynamicConfiguration<InnerNode, ?>) cfgRef.get(), storageRevision, notificationNumber));
futures.addAll(revisionListenerHolder.notifyStorageRevisionListeners(storageRevision, notificationNumber));
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}
return change(change);
}, pool).thenCompose(Function.identity());
}
/**
* {@inheritDoc}
*/
@Override
public InnerNode getRootNode(RootKey<?, ?> rk) {
return superRootRef.get().getRoot(rk);
}
/**
* {@inheritDoc}
*/
@Override
public <T> T getLatest(List<KeyPathNode> path) {
return findEx(path, superRootRef.get());
}
/**
* {@inheritDoc}
*/
@Override
public long notificationCount() {
return revisionListenerHolder.notificationListenerCnt.get();
}
}));
touch(cfgRef.get());
return cfgRef.get();
}
Aggregations