use of net.morimekta.util.Pair in project providence by morimekta.
the class ProvidenceConfigParser method parseConfigRecursively.
@SuppressWarnings("unchecked")
<M extends PMessage<M, F>, F extends PField> Pair<M, Set<String>> parseConfigRecursively(@Nonnull Path file, M parent, String[] stack) throws IOException {
Tokenizer tokenizer;
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file.toFile()))) {
// Non-enclosed content, meaning we should read the whole file immediately.
tokenizer = new Tokenizer(new Utf8StreamReader(in), Tokenizer.DEFAULT_BUFFER_SIZE, true);
}
ProvidenceConfigContext context = new ProvidenceConfigContext();
Set<String> includedFilePaths = new TreeSet<>();
includedFilePaths.add(canonicalFileLocation(file).toString());
Stage lastStage = Stage.INCLUDES;
M result = null;
Token token = tokenizer.peek();
while (token != null) {
tokenizer.next();
if (lastStage == Stage.MESSAGE) {
throw new TokenizerException(token, "Unexpected token '" + token.asString() + "', expected end of file.").setLine(tokenizer.getLine());
} else if (INCLUDE.equals(token.asString())) {
// if include && stage == INCLUDES --> INCLUDES
if (lastStage != Stage.INCLUDES) {
throw new TokenizerException(token, "Include added after defines or message. Only one def block allowed.").setLine(tokenizer.getLine());
}
token = tokenizer.expectLiteral("file to be included");
String includedFilePath = token.decodeLiteral(strict);
PMessage included;
Path includedFile;
try {
includedFile = resolveFile(file, includedFilePath);
Pair<PMessage, Set<String>> tmp = checkAndParseInternal(includedFile, null, stack);
if (tmp != null) {
includedFilePaths.add(includedFile.toString());
includedFilePaths.addAll(tmp.second);
included = tmp.first;
} else {
included = null;
}
} catch (FileNotFoundException e) {
throw new TokenizerException(token, "Included file \"%s\" not found.", includedFilePath).setLine(tokenizer.getLine());
}
token = tokenizer.expectIdentifier("the token 'as'");
if (!AS.equals(token.asString())) {
throw new TokenizerException(token, "Expected token 'as' after included file \"%s\".", includedFilePath).setLine(tokenizer.getLine());
}
token = tokenizer.expectIdentifier("Include alias");
String alias = token.asString();
if (RESERVED_WORDS.contains(alias)) {
throw new TokenizerException(token, "Alias \"%s\" is a reserved word.", alias).setLine(tokenizer.getLine());
}
if (context.containsReference(alias)) {
throw new TokenizerException(token, "Alias \"%s\" is already used.", alias).setLine(tokenizer.getLine());
}
context.setInclude(alias, included);
} else if (DEF.equals(token.asString())) {
// if params && stage == DEF --> DEF
lastStage = Stage.DEFINES;
parseDefinitions(context, tokenizer);
} else if (token.isQualifiedIdentifier()) {
// if a.b (type identifier) --> MESSAGE
lastStage = Stage.MESSAGE;
PMessageDescriptor<M, F> descriptor;
try {
descriptor = (PMessageDescriptor) registry.getDeclaredType(token.asString());
} catch (IllegalArgumentException e) {
// even in non-strict mode.
if (strict || stack.length == 1) {
throw new TokenizerException(token, "Unknown declared type: %s", token.asString()).setLine(tokenizer.getLine());
}
return null;
}
result = parseConfigMessage(tokenizer, context, descriptor.builder(), parent, file);
} else {
throw new TokenizerException(token, "Unexpected token '" + token.asString() + "'. Expected include, defines or message type").setLine(tokenizer.getLine());
}
token = tokenizer.peek();
}
if (result == null) {
throw new TokenizerException("No message in config: " + file.getFileName().toString());
}
return Pair.create(result, includedFilePaths);
}
use of net.morimekta.util.Pair in project providence by morimekta.
the class ProvidenceConfigSupplierTest method testWatchedSupplier.
@Test
public void testWatchedSupplier() throws IOException {
Database first = Database.builder().setDriver("com.mysql.Driver").build();
Database second = Database.builder().setDriver("org.h2.Driver").build();
File file = tmp.newFile().getAbsoluteFile().getCanonicalFile();
when((Pair) parser.parseConfig(file.toPath(), null)).thenReturn(Pair.create(first, ImmutableSet.of(file.toString())));
ArgumentCaptor<FileWatcher.Watcher> watcherCapture = ArgumentCaptor.forClass(FileWatcher.Watcher.class);
doNothing().when(watcher).weakAddWatcher(watcherCapture.capture());
ProvidenceConfigSupplier<Database, Database._Field> supplier = new ProvidenceConfigSupplier<>(file, null, watcher, parser, clock);
assertThat(supplier.get(), is(sameInstance(first)));
assertThat(supplier.get(), is(sameInstance(first)));
assertThat(supplier.get(), is(sameInstance(first)));
verify(parser).parseConfig(file.toPath(), null);
verify(watcher).weakAddWatcher(any(FileWatcher.Watcher.class));
verify(watcher, atMost(4)).startWatching(file);
verifyNoMoreInteractions(watcher, parser);
reset(parser, watcher);
when((Pair) parser.parseConfig(file.toPath(), null)).thenReturn(Pair.create(second, ImmutableSet.of(file.toString())));
doNothing().when(watcher).weakAddWatcher(watcherCapture.capture());
watcherCapture.getValue().onFileUpdate(file);
assertThat(supplier.get(), is(sameInstance(second)));
assertThat(supplier.get(), is(sameInstance(second)));
assertThat(supplier.get(), is(sameInstance(second)));
verify(parser).parseConfig(file.toPath(), null);
verifyNoMoreInteractions(parser, watcher);
}
use of net.morimekta.util.Pair in project providence by morimekta.
the class ProvidenceConfigSupplierTest method testSupplier.
@Test
public void testSupplier() throws IOException {
Database first = Database.builder().setDriver("com.mysql.Driver").build();
Database second = Database.builder().setDriver("org.h2.Driver").build();
File file = tmp.newFile().getAbsoluteFile().getCanonicalFile();
when((Pair) parser.parseConfig(file.toPath(), null)).thenReturn(Pair.create(first, ImmutableSet.of(file.toString())));
ArgumentCaptor<FileWatcher.Watcher> watcherCapture = ArgumentCaptor.forClass(FileWatcher.Watcher.class);
doNothing().when(watcher).weakAddWatcher(watcherCapture.capture());
ProvidenceConfigSupplier<Database, Database._Field> supplier = new ProvidenceConfigSupplier<>(file, null, watcher, parser, clock);
assertThat(supplier.get(), is(sameInstance(first)));
assertThat(supplier.get(), is(sameInstance(first)));
assertThat(supplier.get(), is(sameInstance(first)));
verify(parser).parseConfig(file.toPath(), null);
verify(watcher).weakAddWatcher(any(FileWatcher.Watcher.class));
verify(watcher, atLeast(1)).startWatching(any(File.class));
verifyNoMoreInteractions(watcher, parser);
reset(parser, watcher);
when((Pair) parser.parseConfig(file.toPath(), null)).thenReturn(Pair.create(second, ImmutableSet.of(file.toString())));
doNothing().when(watcher).weakAddWatcher(watcherCapture.capture());
watcherCapture.getValue().onFileUpdate(file);
assertThat(supplier.get(), is(sameInstance(second)));
assertThat(supplier.get(), is(sameInstance(second)));
assertThat(supplier.get(), is(sameInstance(second)));
verify(parser).parseConfig(file.toPath(), null);
verifyNoMoreInteractions(parser, watcher);
}
use of net.morimekta.util.Pair in project providence by morimekta.
the class ProvidenceConfigSupplierTest method testSupplierKeepInstanceOnFailedReload.
@Test
public void testSupplierKeepInstanceOnFailedReload() throws IOException {
Database first = Database.builder().build();
File file = tmp.newFile().getAbsoluteFile().getCanonicalFile();
when((Pair) parser.parseConfig(file.toPath(), null)).thenReturn(Pair.create(first, ImmutableSet.of(file.toString())));
ArgumentCaptor<FileWatcher.Watcher> watcherCapture = ArgumentCaptor.forClass(FileWatcher.Watcher.class);
doNothing().when(watcher).weakAddWatcher(watcherCapture.capture());
ProvidenceConfigSupplier<Database, Database._Field> supplier = new ProvidenceConfigSupplier<>(file, null, watcher, parser, clock);
assertThat(supplier.get(), is(first));
verify(watcher).weakAddWatcher(any(FileWatcher.Watcher.class));
reset(parser, watcher);
when(parser.parseConfig(file.toPath(), null)).thenThrow(new ProvidenceConfigException("test"));
watcherCapture.getValue().onFileUpdate(file);
verify(parser).parseConfig(file.toPath(), null);
verifyNoMoreInteractions(parser);
assertThat(supplier.get(), is(first));
}
Aggregations