use of net.morimekta.providence.PMessageBuilder in project providence by morimekta.
the class ProvidenceConfigParser method parseMessage.
@SuppressWarnings("unchecked")
<M extends PMessage<M, F>, F extends PField> M parseMessage(@Nonnull Tokenizer tokenizer, @Nonnull ProvidenceConfigContext context, @Nonnull PMessageBuilder<M, F> builder) throws IOException {
PMessageDescriptor<M, F> descriptor = builder.descriptor();
Token token = tokenizer.expect("object end or field");
while (!token.isSymbol(Token.kMessageEnd)) {
if (!token.isIdentifier()) {
throw new TokenizerException(token, "Invalid field name: " + token.asString()).setLine(tokenizer.getLine());
}
F field = descriptor.findFieldByName(token.asString());
if (field == null) {
if (strict) {
throw new TokenizerException("No such field " + token.asString() + " in " + descriptor.getQualifiedName()).setLine(tokenizer.getLine());
} else {
token = tokenizer.expect("field value sep, message start or reference start");
if (token.isSymbol(DEFINE_REFERENCE)) {
context.setReference(context.initReference(tokenizer.expectIdentifier("reference name"), tokenizer), null);
// Ignore reference.
token = tokenizer.expect("field value sep or message start");
}
if (token.isSymbol(Token.kFieldValueSep)) {
token = tokenizer.expect("value declaration");
} else if (!token.isSymbol(Token.kMessageStart)) {
throw new TokenizerException(token, "Expected field-value separator or inherited message").setLine(tokenizer.getLine());
}
// Non-strict will just consume unknown fields, this way
// we can be forward-compatible when reading config.
consumeValue(context, tokenizer, token);
token = nextNotLineSep(tokenizer, "field or message end");
continue;
}
}
if (field.getType() == PType.MESSAGE) {
// go recursive with optional
String reference = null;
char symbol = tokenizer.expectSymbol("Message assigner or start", Token.kFieldValueSep, Token.kMessageStart, DEFINE_REFERENCE);
if (symbol == DEFINE_REFERENCE) {
Token ref = tokenizer.expectIdentifier("reference name");
if (strict) {
throw tokenizer.failure(ref, "Reusable objects are not allowed in strict mode.");
}
reference = context.initReference(ref, tokenizer);
symbol = tokenizer.expectSymbol("Message assigner or start after " + reference, Token.kFieldValueSep, Token.kMessageStart);
}
PMessageBuilder bld;
if (symbol == Token.kFieldValueSep) {
token = tokenizer.expect("reference or message start");
if (UNDEFINED.equals(token.asString())) {
// unset.
builder.clear(field.getId());
context.setReference(reference, null);
// special casing this, as we don't want to duplicate the parse line below.
token = nextNotLineSep(tokenizer, "field or message end");
continue;
}
// overwrite with new.
bld = ((PMessageDescriptor) field.getDescriptor()).builder();
if (token.isReferenceIdentifier()) {
// Inherit from reference.
try {
PMessage ref = resolve(context, token, tokenizer, field.getDescriptor());
if (ref != null) {
bld.merge(ref);
} else {
if (tokenizer.peek().isSymbol(Token.kMessageStart)) {
throw new TokenizerException(token, "Inherit from unknown reference %s", token.asString()).setLine(tokenizer.getLine());
} else if (strict) {
throw new TokenizerException(token, "Unknown reference %s", token.asString()).setLine(tokenizer.getLine());
}
}
} catch (ProvidenceConfigException e) {
throw new TokenizerException(token, "Unknown inherited reference '%s'", token.asString()).setLine(tokenizer.getLine());
}
token = tokenizer.expect("after message reference");
// we assume a new field or end of current message.
if (!token.isSymbol(Token.kMessageStart)) {
builder.set(field.getId(), context.setReference(reference, bld.build()));
continue;
}
} else if (!token.isSymbol(Token.kMessageStart)) {
throw new TokenizerException(token, "Unexpected token " + token.asString() + ", expected message start").setLine(tokenizer.getLine());
}
} else {
// extend in-line.
bld = builder.mutator(field.getId());
}
builder.set(field.getId(), context.setReference(reference, parseMessage(tokenizer, context, bld)));
} else if (field.getType() == PType.MAP) {
// maps can be extended the same way as
token = tokenizer.expect("field sep or value start");
Map baseValue = new LinkedHashMap<>();
String reference = null;
if (token.isSymbol(DEFINE_REFERENCE)) {
Token ref = tokenizer.expectIdentifier("reference name");
if (strict) {
throw tokenizer.failure(ref, "Reusable objects are not allowed in strict mode.");
}
reference = context.initReference(ref, tokenizer);
token = tokenizer.expect("field sep or value start");
}
if (token.isSymbol(Token.kFieldValueSep)) {
token = tokenizer.expect("field id or start");
if (UNDEFINED.equals(token.asString())) {
builder.clear(field.getId());
context.setReference(reference, null);
token = tokenizer.expect("message end or field");
continue;
} else if (token.isReferenceIdentifier()) {
try {
baseValue = resolve(context, token, tokenizer, field.getDescriptor());
} catch (ProvidenceConfigException e) {
throw new TokenizerException(token, e.getMessage()).setLine(tokenizer.getLine());
}
token = tokenizer.expect("map start or next field");
if (!token.isSymbol(Token.kMessageStart)) {
builder.set(field.getId(), context.setReference(reference, baseValue));
continue;
} else if (baseValue == null) {
baseValue = new LinkedHashMap<>();
}
}
} else {
baseValue.putAll(builder.build().get(field.getId()));
}
if (!token.isSymbol(Token.kMessageStart)) {
throw new TokenizerException(token, "Expected map start, but got '%s'", token.asString()).setLine(tokenizer.getLine());
}
Map map = parseMapValue(tokenizer, context, (PMap) field.getDescriptor(), baseValue);
builder.set(field.getId(), context.setReference(reference, map));
} else {
String reference = null;
// Simple fields *must* have the '=' separation, may have '&' reference.
if (tokenizer.expectSymbol("field value sep", Token.kFieldValueSep, DEFINE_REFERENCE) == DEFINE_REFERENCE) {
Token ref = tokenizer.expectIdentifier("reference name");
if (strict) {
throw tokenizer.failure(ref, "Reusable objects are not allowed in strict mode.");
}
reference = context.initReference(ref, tokenizer);
tokenizer.expectSymbol("field value sep", Token.kFieldValueSep);
}
token = tokenizer.expect("field value");
if (UNDEFINED.equals(token.asString())) {
builder.clear(field.getId());
context.setReference(reference, null);
} else {
Object value = parseFieldValue(token, tokenizer, context, field.getDescriptor(), strict);
builder.set(field.getId(), context.setReference(reference, value));
}
}
token = nextNotLineSep(tokenizer, "field or message end");
}
return builder.build();
}
use of net.morimekta.providence.PMessageBuilder in project providence by morimekta.
the class OverrideConfigSupplier method buildOverrideConfig.
private static <Message extends PMessage<Message, Field>, Field extends PField> Message buildOverrideConfig(Message parent, Map<String, String> overrides, boolean strict) throws ProvidenceConfigException {
PMessageBuilder<Message, Field> builder = parent.mutate();
for (Map.Entry<String, String> override : overrides.entrySet()) {
String[] path = override.getKey().split("[.]");
String fieldName = lastFieldName(path);
PMessageBuilder containedBuilder = builderForField(strict, builder, path);
if (containedBuilder == null) {
continue;
}
PField field = containedBuilder.descriptor().findFieldByName(fieldName);
if (field == null) {
if (strict) {
throw new ProvidenceConfigException("No such field %s in %s [%s]", fieldName, containedBuilder.descriptor().getQualifiedName(), String.join(".", path));
}
continue;
}
if (UNDEFINED.equals(override.getValue())) {
containedBuilder.clear(field.getId());
} else {
containedBuilder.set(field.getId(), readFieldValue(override.getKey(), override.getValue(), field.getDescriptor()));
}
}
return builder.build();
}
use of net.morimekta.providence.PMessageBuilder in project providence by morimekta.
the class ProvidenceConfigParser method parseDefinitionValue.
@SuppressWarnings("unchecked")
Object parseDefinitionValue(ProvidenceConfigContext context, Tokenizer tokenizer) throws IOException {
Token token = tokenizer.expect("Start of def value");
if (token.isReal()) {
return Double.parseDouble(token.asString());
} else if (token.isInteger()) {
return Long.parseLong(token.asString());
} else if (token.isStringLiteral()) {
return token.decodeLiteral(strict);
} else if (TRUE.equalsIgnoreCase(token.asString())) {
return Boolean.TRUE;
} else if (FALSE.equalsIgnoreCase(token.asString())) {
return Boolean.FALSE;
} else if (Token.B64.equals(token.asString())) {
tokenizer.expectSymbol("binary data enclosing start", Token.kParamsStart);
return Binary.fromBase64(tokenizer.readBinary(Token.kParamsEnd));
} else if (Token.HEX.equals(token.asString())) {
tokenizer.expectSymbol("binary data enclosing start", Token.kParamsStart);
return Binary.fromHexString(tokenizer.readBinary(Token.kParamsEnd));
} else if (token.isDoubleQualifiedIdentifier()) {
// this may be an enum reference, must be
// - package.EnumType.IDENTIFIER
String id = token.asString();
int l = id.lastIndexOf(Token.kIdentifierSep);
try {
PEnumDescriptor ed = registry.getEnumType(id.substring(0, l));
PEnumValue val = ed.findByName(id.substring(l + 1));
if (val == null && strict) {
throw new TokenizerException(token, "Unknown %s value: %s", id.substring(0, l), id.substring(l + 1)).setLine(tokenizer.getLine());
}
// Note that unknown enum value results in null. Therefore we don't catch null values here.
return val;
} catch (IllegalArgumentException e) {
// No such declared type.
if (strict) {
throw new TokenizerException(token, "Unknown enum identifier: %s", id.substring(0, l)).setLine(tokenizer.getLine());
}
consumeValue(context, tokenizer, token);
} catch (ClassCastException e) {
// Not an enum.
throw new TokenizerException(token, "Identifier " + id + " does not reference an enum, from " + token.asString()).setLine(tokenizer.getLine());
}
} else if (token.isQualifiedIdentifier()) {
// Message type.
PMessageDescriptor descriptor;
try {
descriptor = registry.getMessageType(token.asString());
} catch (IllegalArgumentException e) {
// - strict mode: all types must be known.
if (strict) {
throw new TokenizerException(token, "Unknown declared type: %s", token.asString()).setLine(tokenizer.getLine());
}
consumeValue(context, tokenizer, token);
return null;
}
PMessageBuilder builder = descriptor.builder();
if (tokenizer.expectSymbol("message start or inherits", '{', ':') == ':') {
token = tokenizer.expect("inherits reference");
PMessage inheritsFrom = resolve(context, token, tokenizer, descriptor);
if (inheritsFrom == null) {
throw new TokenizerException(token, "Inheriting from null reference: %s", token.asString()).setLine(tokenizer.getLine());
}
builder.merge(inheritsFrom);
tokenizer.expectSymbol("message start", '{');
}
return parseMessage(tokenizer, context, builder);
} else {
throw new TokenizerException(token, "Invalid define value " + token.asString()).setLine(tokenizer.getLine());
}
return null;
}
use of net.morimekta.providence.PMessageBuilder in project providence by morimekta.
the class HazelcastMessageBuilderStorage method putAllBuilders.
@Nonnull
@Override
@SuppressWarnings("unchecked")
public <B extends PMessageBuilder<Message, Field>> Map<Key, B> putAllBuilders(@Nonnull Map<Key, B> builders) {
Map<Key, ICompletableFuture<Builder>> futureMap = new HashMap<>();
builders.forEach((key, builder) -> futureMap.put(key, hazelcastMap.putAsync(key, (Builder) builder)));
Map<Key, B> ret = new HashMap<>();
futureMap.forEach((key, future) -> {
try {
Builder value = future.get();
if (value != null) {
ret.put(key, (B) value);
}
} catch (ExecutionException | InterruptedException e) {
// TODO: Figure out if we timed out or were interrupted...
throw new RuntimeException(e.getMessage(), e);
}
});
return ret;
}
Aggregations