Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.deephacks.tools4j.config.internal.core.admin.AdminCoreContext Maven / Gradle / Ivy
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.deephacks.tools4j.config.internal.core.admin;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.deephacks.tools4j.config.admin.AdminContext;
import org.deephacks.tools4j.config.admin.query.BeanQuery;
import org.deephacks.tools4j.config.internal.core.ConfigCore;
import org.deephacks.tools4j.config.internal.core.DefaultSchemaManager;
import org.deephacks.tools4j.config.internal.core.Lookup;
import org.deephacks.tools4j.config.internal.core.runtime.BeanToObjectConverter;
import org.deephacks.tools4j.config.internal.core.runtime.ClassToSchemaConverter;
import org.deephacks.tools4j.config.internal.core.runtime.DefaultBeanManager;
import org.deephacks.tools4j.config.internal.core.runtime.FieldToSchemaPropertyConverter;
import org.deephacks.tools4j.config.internal.core.runtime.ObjectToBeanConverter;
import org.deephacks.tools4j.config.model.AbortRuntimeException;
import org.deephacks.tools4j.config.model.Bean;
import org.deephacks.tools4j.config.model.Bean.BeanId;
import org.deephacks.tools4j.config.model.BeanUtils;
import org.deephacks.tools4j.config.model.Schema;
import org.deephacks.tools4j.config.model.Schema.SchemaPropertyRef;
import org.deephacks.tools4j.config.spi.BeanManager;
import org.deephacks.tools4j.config.spi.CacheManager;
import org.deephacks.tools4j.config.spi.Conversion;
import org.deephacks.tools4j.config.spi.SchemaManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.deephacks.tools4j.config.internal.core.admin.SchemaValidator.validateSchema;
import static org.deephacks.tools4j.config.model.Events.CFG301_MISSING_RUNTIME_REF;
/**
* AdminCoreContext is responsible for separating the admin and config
* context so that no dependencies (compile nor config) exist between them.
*/
@Singleton
public final class AdminCoreContext extends AdminContext {
/** API class for JSR 303 1.0 bean validation */
public static final String JSR303_1_0_CLASSNAME = "javax.validation.Validation";
private static final Conversion conversion;
static {
conversion = Conversion.get();
conversion.register(new BeanToObjectConverter());
conversion.register(new ObjectToBeanConverter());
conversion.register(new ClassToSchemaConverter());
conversion.register(new FieldToSchemaPropertyConverter());
}
@Inject
private ConfigCore core;
private static final Lookup lookup = Lookup.get();
private BeanManager beanManager = lookup.lookup(BeanManager.class, DefaultBeanManager.class);
private SchemaManager schemaManager = lookup.lookup(SchemaManager.class, DefaultSchemaManager.class);
private Optional validator;
private Optional cacheManager;
@Override
public List list(String schemaName) {
Preconditions.checkNotNull(schemaName);
doLookup();
Map beans = beanManager.list(schemaName);
core.setSchema(schemaManager.getSchemas(), beans);
return new ArrayList<>(beans.values());
}
@Override
public List list(String schemaName, Collection instanceIds) {
Preconditions.checkNotNull(schemaName);
if (instanceIds == null || instanceIds.isEmpty()) {
return new ArrayList<>();
}
doLookup();
Map beans = beanManager.list(schemaName, instanceIds);
Map result = new HashMap<>();
for (String instanceId : instanceIds) {
Bean b = beans.get(BeanId.create(instanceId, schemaName));
result.put(b.getId(), b);
}
Map schemas = schemaManager.getSchemas();
core.setSchema(schemas, result);
return new ArrayList<>(result.values());
}
@Override
public Optional get(BeanId beanId) {
Preconditions.checkNotNull(beanId);
doLookup();
Optional bean = beanManager.getEager(beanId);
if (!bean.isPresent()) {
return bean;
}
Map schemas = schemaManager.getSchemas();
core.setSchema(bean.get(), schemas);
setSingletonReferences(bean.get(), schemas);
return bean;
}
@Override
public void create(Bean bean) {
Preconditions.checkNotNull(bean);
create(Arrays.asList(bean));
core.cache(bean);
}
@Override
public void createObject(Object object) throws AbortRuntimeException {
createObjects(Arrays.asList(object));
}
@Override
public void create(Collection beans) {
if (beans == null || beans.isEmpty()) {
return;
}
doLookup();
core.setSchema(schemaManager.getSchemas(), beans);
validateSchema(beans);
if (validator.isPresent()) {
initReferences(beans);
validator.get().validate(beans);
}
beanManager.create(beans);
core.cache(beans);
}
@Override
public void createObjects(Collection objects) throws AbortRuntimeException {
if (objects == null || objects.isEmpty()) {
return;
}
Collection beans = convertToBeans(objects);
create(beans);
}
@Override
public void set(Bean bean) {
Preconditions.checkNotNull(bean);
set(Arrays.asList(bean));
}
@Override
public void setObject(Object object) throws AbortRuntimeException {
setObjects(Arrays.asList(object));
}
@Override
public void set(Collection beans) {
if (beans == null || beans.isEmpty()) {
return;
}
doLookup();
core.setSchema(schemaManager.getSchemas(), beans);
validateSchema(beans);
if (validator.isPresent()) {
initReferences(beans);
validateSet(beans);
}
beanManager.set(beans);
core.cache(beans);
}
@Override
public void setObjects(Collection objects) throws AbortRuntimeException {
if (objects == null || objects.isEmpty()) {
return;
}
Collection beans = convertToBeans(objects);
set(beans);
}
@Override
public void merge(Bean bean) {
Preconditions.checkNotNull(bean);
merge(Arrays.asList(bean));
}
@Override
public void mergeObject(Object object) throws AbortRuntimeException {
mergeObjects(Arrays.asList(object));
}
@Override
public void merge(Collection beans) {
if (beans == null || beans.isEmpty()) {
return;
}
doLookup();
core.setSchema(schemaManager.getSchemas(), beans);
validateSchema(beans);
// ok to not have validation manager available
if (validator.isPresent()) {
validateMerge(beans);
}
beanManager.merge(beans);
for (Bean bean : beans) {
// must refresh the bean from storage since it is merged.
Optional refreshed = beanManager.getEager(bean.getId());
if (refreshed.isPresent()) {
core.cache(refreshed.get());
}
}
}
@Override
public void mergeObjects(Collection objects) throws AbortRuntimeException {
if (objects == null || objects.isEmpty()) {
return;
}
Collection beans = convertToBeans(objects);
merge(beans);
}
@Override
public void delete(BeanId beanId) {
Preconditions.checkNotNull(beanId);
doLookup();
beanManager.delete(beanId);
core.cacheRemove(beanId);
}
@Override
public void delete(String name, Collection instances) {
Preconditions.checkNotNull(name);
if (instances == null || instances.isEmpty()) {
return;
}
doLookup();
beanManager.delete(name, instances);
core.cacheRemove(name, instances);
}
@Override
public Map getSchemas() {
doLookup();
return schemaManager.getSchemas();
}
@Override
public BeanQuery newQuery(String schemaName) {
doLookup();
Schema schema = schemaManager.getSchema(schemaName);
Preconditions.checkNotNull(schema, "Schema " + schemaName + " does not exist.");
return beanManager.newQuery(schema);
}
private void initReferences(Collection beans) {
Map indexed = BeanUtils.uniqueIndex(beans);
for (Bean bean : beans) {
for (String name : bean.getReferenceNames()) {
List ids = bean.getReference(name);
if (ids == null) {
continue;
}
for (BeanId id : ids) {
Bean ref = indexed.get(id);
if (ref == null) {
// TODO: investigate if eager is really needed
Optional optionalRef = beanManager.getEager(id);
if (optionalRef.isPresent()) {
core.setSchema(optionalRef.get(), schemaManager.getSchemas());
ref = optionalRef.get();
}
}
id.setBean(ref);
}
}
}
}
private void validateMerge(Collection mergebeans) {
Map beansToValidate = beanManager.getBeanToValidate(mergebeans);
core.setSchema(schemaManager.getSchemas(), beansToValidate);
// since we are validating mergebean predecessors, we need to make sure
// that they see a merged reference (not unmerged reference currently in storage)
// before validation can proceed.
for (Bean mergebean : mergebeans) {
ArrayList mergeBeanReferences = new ArrayList<>();
ArrayList checked = new ArrayList<>();
findReferences(mergebean.getId(), beansToValidate.values(), mergeBeanReferences,
checked);
// merge list references
merge(mergeBeanReferences, mergebean);
}
// ready to validate
validator.get().validate(beansToValidate.values());
}
private void validateSet(Collection setbeans) {
Map beansToValidate = beanManager.getBeanToValidate(setbeans);
core.setSchema(schemaManager.getSchemas(), beansToValidate);
// since we are validating setbean predecessors, we need to make sure
// that they see a replaced/set reference (not old reference currently in storage)
// before validation can proceed.
for (Bean setbean : setbeans) {
ArrayList setBeanReferences = new ArrayList<>();
ArrayList checked = new ArrayList<>();
findReferences(setbean.getId(), beansToValidate.values(), setBeanReferences, checked);
for (Bean ref : setBeanReferences) {
// clearing and then merging have same
// effect as a 'set' operation
ref.clear();
}
merge(setBeanReferences, setbean);
}
validator.get().validate(beansToValidate.values());
}
/**
* Does a recursive check if predecessor have a particular reference and if
* so return those predecessor references.
*/
private List findReferences(BeanId reference, Collection predecessors,
ArrayList matches, ArrayList checked) {
for (Bean predecessor : predecessors) {
findReferences(reference, predecessor, matches, checked);
}
return matches;
}
private void findReferences(BeanId reference, Bean predecessor, ArrayList matches,
ArrayList checked) {
if (checked.contains(predecessor)) {
return;
}
checked.add(predecessor);
if (reference.equals(predecessor.getId()) && !matches.contains(predecessor)) {
matches.add(predecessor);
}
for (BeanId ref : predecessor.getReferences()) {
if (ref.getBean() == null) {
continue;
}
if (matches.contains(ref.getBean())) {
continue;
}
if (ref.equals(reference)) {
matches.add(ref.getBean());
}
findReferences(reference, ref.getBean(), matches, checked);
}
}
private void merge(List sources, Bean mergeBean) {
HashMap cache = new HashMap<>();
for (Bean source : sources) {
for (String name : mergeBean.getPropertyNames()) {
List values = mergeBean.getValues(name);
if (values == null || values.size() == 0) {
continue;
}
source.setProperty(name, values);
}
for (String name : mergeBean.getReferenceNames()) {
List refs = mergeBean.getReference(name);
if (refs == null || refs.size() == 0) {
source.setReferences(name, refs);
continue;
}
for (BeanId beanId : refs) {
Bean bean = cache.get(beanId);
if (bean == null) {
Optional optional = beanManager.getLazy(beanId);
if (!optional.isPresent()) {
throw CFG301_MISSING_RUNTIME_REF(beanId);
}
bean = optional.get();
core.setSchema(bean, schemaManager.getSchemas());
cache.put(beanId, bean);
}
beanId.setBean(bean);
}
source.setReferences(name, refs);
}
}
}
/**
* Used for setting or creating a single bean.
*/
@SuppressWarnings("unused")
private void initalizeReferences(Bean bean) {
for (String name : bean.getReferenceNames()) {
List values = bean.getReference(name);
if (values == null) {
continue;
}
for (BeanId beanId : values) {
Optional ref = beanManager.getEager(beanId);
if (ref.isPresent()) {
beanId.setBean(ref.get());
}
core.setSchema(beanId.getBean(), schemaManager.getSchemas());
}
}
}
/**
* Used for setting or creating a multiple beans.
*
* We must consider that the operation may include beans that have
* references betewen eachother. User provided beans are
* prioritized and the storage is secondary for looking up references.
*/
@SuppressWarnings("unused")
private void initalizeReferences(Collection beans) {
Map userProvided = BeanUtils.uniqueIndex(beans);
for (Bean bean : beans) {
for (String name : bean.getReferenceNames()) {
List values = bean.getReference(name);
if (values == null) {
continue;
}
for (BeanId beanId : values) {
// the does not exist in storage, but may exist in the
// set of beans provided by the user.
Bean ref = userProvided.get(beanId);
if (ref == null) {
Optional optional = beanManager.getEager(beanId);
if (optional.isPresent()) {
ref = optional.get();
}
}
beanId.setBean(ref);
core.setSchema(beanId.getBean(), schemaManager.getSchemas());
}
}
}
}
private void setSingletonReferences(Bean bean, Map schemas) {
Schema s = bean.getSchema();
for (SchemaPropertyRef ref : s.get(SchemaPropertyRef.class)) {
if (ref.isSingleton()) {
Schema singletonSchema = schemas.get(ref.getSchemaName());
Optional singleton = beanManager.getSingleton(ref.getSchemaName());
if (singleton.isPresent()) {
singleton.get().set(singletonSchema);
BeanId singletonId = singleton.get().getId();
singletonId.setBean(singleton.get());
// recursive call.
setSingletonReferences(singleton.get(), schemas);
bean.setReference(ref.getName(), singletonId);
}
}
}
}
private void doLookup() {
// core would already be injected in a cdi environment
if (core == null) {
core = new ConfigCore();
}
if (cacheManager == null) {
cacheManager = core.lookupCacheManager();
}
if (validator == null) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
cl.loadClass(JSR303_1_0_CLASSNAME);
validator = Optional.of(new Jsr303Validator());
} catch (Exception e) {
validator = Optional.absent();
}
}
}
private Collection convertToBeans(Collection objects) {
ArrayList beans = new ArrayList<>();
for (Object object : objects) {
if(object instanceof Bean) {
beans.add((Bean) object);
} else {
Bean bean = conversion.convert(object, Bean.class);
beans.add(bean);
}
}
return beans;
}
}