
prompto.code.CodeStoreBootstrapper Maven / Gradle / Ivy
package prompto.code;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import prompto.declaration.AttributeDeclaration;
import prompto.declaration.IDeclaration;
import prompto.error.PromptoError;
import prompto.grammar.Identifier;
import prompto.intrinsic.PromptoVersion;
import prompto.runtime.Context;
import prompto.store.AttributeInfo;
import prompto.store.IStore;
import prompto.type.BlobType;
import prompto.type.BooleanType;
import prompto.type.DateTimeType;
import prompto.type.IType;
import prompto.type.IntegerType;
import prompto.type.ListType;
import prompto.type.TextType;
import prompto.utils.IdentifierList;
import prompto.utils.Logger;
import prompto.utils.TypeUtils;
// use a dedicated bootstrapper to ensure app and code store contexts do not spill
public class CodeStoreBootstrapper {
static final Logger logger = new Logger();
public static Context bootstrap(IStore store, ICodeStore runtime) throws PromptoError {
logger.info(()->"Initializing code store...");
CodeStoreBootstrapper bs = new CodeStoreBootstrapper(store, runtime);
bs.bootstrap();
return bs.context;
}
Context context = Context.newGlobalsContext();
ICodeStore next;
IStore store;
private CodeStoreBootstrapper(IStore store, ICodeStore runtime) {
this.store = store;
URL url = Thread.currentThread().getContextClassLoader().getResource("libraries/CodeStore.pec");
this.next = new ImmutableCodeStore(runtime, ModuleType.LIBRARY, url, PromptoVersion.parse("1.0.0"));
}
private void bootstrap() throws PromptoError {
Map columns = getMinimalColumns(store);
columns = fetchLatestDeclarations(columns);
registerColumnAttributes(columns.values());
if(store!=null) {
Function locator = id -> {
Iterator decls = next.fetchDeclarations(id.toString()).iterator();
return decls.hasNext() ? decls.next() : null;
};
List infos = columns.values().stream().map(c->c.getAttributeInfo(context, locator)).collect(Collectors.toList());
store.createOrUpdateAttributes(infos);
}
}
private void registerColumnAttributes(Collection columns) throws PromptoError {
for(AttributeDeclaration column : columns)
column.register(context);
}
private Map fetchLatestDeclarations(Map decls) throws PromptoError {
try {
Map latest = new HashMap<>();
for(Map.Entry entry : decls.entrySet())
latest.put(entry.getKey(), fetchAttributeDeclaration(entry.getValue()));
return latest;
} catch (RuntimeException e) {
if(e.getCause() instanceof PromptoError)
throw (PromptoError)e.getCause();
else
throw e;
}
}
static final Set reserved = new HashSet<>(Arrays.asList(IStore.dbIdName, "category", "storable", "module"));
private AttributeDeclaration fetchAttributeDeclaration(AttributeDeclaration column) {
try {
// can't write a declaration for a column with a reserved name, so use the hard coded one
if(reserved.contains(column.getName()))
return column;
Iterable decls = next.fetchDeclarations(column.getName());
if(decls==null || !decls.iterator().hasNext())
throw new RuntimeException("Invalid column attribute: " + column.getName());
IDeclaration decl = decls.iterator().next(); // can only get one attribute
if(!(decl instanceof AttributeDeclaration))
throw new RuntimeException("Invalid column attribute: " + column.getName());
return (AttributeDeclaration)decl;
} catch (PromptoError e) {
throw new RuntimeException(e);
}
}
private Map getMinimalColumns(IStore store) {
final IType dbIdIType = store==null ? IntegerType.instance() : TypeUtils.typeToIType(store.getNativeDbIdClass());
return Stream.of(
// attributes with reserved names, the below declarations will be used
new AttributeDeclaration(new Identifier(IStore.dbIdName), dbIdIType),
new AttributeDeclaration(new Identifier("storable"), BooleanType.instance()),
new AttributeDeclaration(new Identifier("category"),
new ListType(TextType.instance()), new IdentifierList(new Identifier("key"))),
// also add 'module' to avoid dependency on DevCenter
new AttributeDeclaration(new Identifier("module"), dbIdIType),
// more required attributes which will be overridden by a prompto declaration
new AttributeDeclaration(new Identifier("author"), TextType.instance()),
new AttributeDeclaration(new Identifier("timeStamp"), DateTimeType.instance()),
new AttributeDeclaration(new Identifier("name"), TextType.instance()),
new AttributeDeclaration(new Identifier("description"), TextType.instance()),
new AttributeDeclaration(new Identifier("version"), TextType.instance()), // TODO add VersionType ?
new AttributeDeclaration(new Identifier("prototype"), TextType.instance()),
new AttributeDeclaration(new Identifier("dialect"), TextType.instance()),
new AttributeDeclaration(new Identifier("body"), TextType.instance()),
new AttributeDeclaration(new Identifier("data"), BlobType.instance()),
new AttributeDeclaration(new Identifier("mimeType"), TextType.instance()),
new AttributeDeclaration(new Identifier("moduleStatus"), TextType.instance()), // for bootstrapping TextType is good enough
new AttributeDeclaration(new Identifier("parked"), BooleanType.instance()))
.map(attr->attr.withStorable(true))
.collect(Collectors.toMap(attr->attr.getName(), Function.identity()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy