
org.usf.jquery.web.ContextEnvironment Maven / Gradle / Ivy
package org.usf.jquery.web;
import static java.lang.reflect.Modifier.isStatic;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static org.usf.jquery.core.Validation.requireLegalVariable;
import static org.usf.jquery.core.Validation.requireNonEmpty;
import static org.usf.jquery.web.ResourceAccessException.resourceAlreadyExistsException;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;
import javax.sql.DataSource;
import org.usf.jquery.core.JQueryException;
import org.usf.jquery.core.NamedColumn;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
*
* @author u$f
*
*/
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ContextEnvironment {
private static final Set RESERVED_WORDS = Stream.of(Parameters.class.getDeclaredFields())
.filter(f-> isStatic(f.getModifiers()))
.map(Field::getName)
.collect(toSet());
private final DatabaseDecorator database;
private final Map views;
private final Map columns;
private final DataSource dataSource; //optional
private final String schema; //optional
private final DatabaseMetadata metadata;
private Map declaredColumns = new HashMap<>();
ContextEnvironment(ContextEnvironment ctx) {
this.database = ctx.database;
this.views = new HashMap<>(ctx.views); //modifiable
this.columns = ctx.columns;
this.dataSource = ctx.dataSource;
this.schema = ctx.schema;
this.metadata = ctx.metadata;
}
public Optional lookupRegisteredView(String name) { //+ declared
return ofNullable(views.get(name));
}
public Optional lookupRegisteredColumn(String name) {
return ofNullable(columns.get(name));
}
Optional lookupDeclaredColumn(String name) {
return ofNullable(declaredColumns.get(name));
}
ViewDecorator declareView(ViewDecorator view) { //additional request views
return views.compute(view.identity(), (k,v)-> {
if(isNull(v)){
return view;
}
throw resourceAlreadyExistsException(k);
});
}
NamedColumn declareColumn(NamedColumn col) {
views.computeIfPresent(col.getTag(), (k,v)-> { //cannot overwrite registered views
throw resourceAlreadyExistsException(k);
}); //but can overwrite registered columns
return declaredColumns.compute(col.getTag(), (k,v)-> {
if(isNull(v)){
return col;
} //cannot overwrite declared column
throw resourceAlreadyExistsException(k);
});
}
ViewMetadata computeTableMetadata(ViewDecorator vd, Function, ViewMetadata> fn) {
return metadata.getTables().computeIfAbsent(vd.identity(), key-> fn.apply(columns.values()));
}
ContextEnvironment bind() {
if(nonNull(dataSource)) {
try(var cnx = dataSource.getConnection()) {
var cm = cnx.getMetaData();
metadata.fetch(cm);
for(var v : views.values()) {
var meta = requireNonNull(v.metadata(), v.identity() + ".metadata");
synchronized(meta) {
meta.fetch(cm, schema);
}
}
}
catch (SQLException e) {
throw new JQueryException(e);
}
}
return this;
}
public static ContextEnvironment of(DatabaseDecorator database,
Collection views, Collection columns) {
return of(database, views, columns, null, null);
}
public static ContextEnvironment of(DatabaseDecorator database,
Collection views, Collection columns, DataSource ds) {
return of(database, views, columns, ds, null);
}
public static ContextEnvironment of(DatabaseDecorator database,
Collection views, Collection columns, DataSource ds, String schema) {
assertIdentity(requireNonNull(database, "configuration.database").identity());
return new ContextEnvironment(database,
unmodifiableIdentityMap(views, ViewDecorator::identity, database.identity() + ".views"), //preserve views order
unmodifiableIdentityMap(columns, ColumnDecorator::identity, database.identity() + ".columns"),
ds, schema, new DatabaseMetadata());
}
static Map unmodifiableIdentityMap(Collection c, Function fn, String msg){
return unmodifiableMap(requireNonEmpty(c, msg).stream()
.collect(toLinkedMap(fn.andThen(ContextEnvironment::assertIdentity), identity())));
}
static Collector> toLinkedMap(
Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper,
(v1, v2) -> {throw new IllegalStateException("!parallel");},
LinkedHashMap::new);
}
static String assertIdentity(String id) {
if(!RESERVED_WORDS.contains(requireLegalVariable(id))){
return id;
}
throw new IllegalArgumentException("reserved word cannot be used as an identifier: " + id);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy