All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.deephacks.tools4j.config.internal.core.runtime.ConfigCoreContext Maven / Gradle / Ivy

There is a newer version: 0.15.0
Show newest version
/**
 * 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.runtime;

import com.google.common.base.Optional;
import org.deephacks.tools4j.config.Config;
import org.deephacks.tools4j.config.ConfigContext;
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.SystemProperties;
import org.deephacks.tools4j.config.internal.core.query.ConfigIndexedCollection;
import org.deephacks.tools4j.config.internal.core.query.ConfigQuery;
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.Events;
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.HashMap;
import java.util.List;
import java.util.Map;

import static org.deephacks.tools4j.config.model.Events.CFG102_NOT_CONFIGURABLE;
import static org.deephacks.tools4j.config.model.Events.CFG303;

/**
 * ConfigCoreContext is responsible for separating the admin, config and spi
 * context so that no dependencies (compile nor config) exist between them.
 */
@Singleton
public final class ConfigCoreContext extends ConfigContext {
    private Conversion conversion;
    private static final Lookup lookup = Lookup.get();
    private SchemaManager schemaManager = lookup.lookup(SchemaManager.class, DefaultSchemaManager.class);
    private BeanManager beanManager = lookup.lookup(BeanManager.class, DefaultBeanManager.class);
    private Optional cacheManager;
    private HashMap schemas = new HashMap<>();
    private SystemProperties properties = SystemProperties.instance();
    private static HashMap FILE_CONFIG;
    private static HashMap, Class> initalized = new HashMap<>();

    @Inject
    private ConfigCore core;

    @Override
    public void register(Class... configurable) {
        doLookup();
        for (Class clazz : configurable) {
            getSchema(clazz);
        }
    }

    @Override
    public void unregister(Class... configurable) {
        doLookup();
        for (Class clazz : configurable) {
            Schema schema = conversion.convert(clazz, Schema.class);
            schemaManager.removeSchema(schema.getName());
            core.removeIndex(schema);
        }
    }

    @Override
    public void registerDefault(Object... instances) {
        doLookup();
        for (Object instance : instances) {
            Bean bean = conversion.convert(instance, Bean.class);
            bean.setDefault();
            try {
                beanManager.create(bean);
            } catch (AbortRuntimeException e) {
                // ignore if bean already exist
                if (e.getEvent().getCode() != CFG303) {
                    throw e;
                }
            }
        }
    }

    @Override
    public  T get(Class configurable) {
        doLookup();
        Schema schema = getSchema(configurable);
        BeanId singleton = getSingletonId(schema, configurable);
        Optional bean = beanManager.getEager(singleton);
        if (!bean.isPresent()) {
            initFile(configurable);
            Bean fileBean = FILE_CONFIG.get(singleton);
            if (fileBean != null) {
                fileBean.set(schema);
                bean = Optional.of(fileBean);
            }
            if (bean.isPresent()) {
                T object = conversion.convert(bean.get(), configurable);
                core.cache(bean.get());
                return object;
            }
        }
        if (!bean.isPresent()) {
            bean = Optional.of(Bean.create(BeanId.createSingleton(schema.getName())));
        }
        core.setSchema(bean.get(), schemas);
        setSingletonReferences(bean.get(), schemas);
        T object = conversion.convert(bean.get(), configurable);
        core.cache(bean.get());
        return object;
    }

    @Override
    public  List list(Class configurable) {
        doLookup();
        Schema s = getSchema(configurable);
        initFile(configurable);
        Map beans = new HashMap<>();
        Map schemas = schemaManager.getSchemas();
        Map found = beanManager.list(s.getName());
        // only fallback to file if no beans were found.
        // maybe good if file and storage beans were merged?
        // on the other hand, that would mean that file bean instances
        // never can be removed, which may be annoying?
        if (found.isEmpty()) {
            for (Bean bean : FILE_CONFIG.values()) {
                if (bean.getId().getSchemaName().equals(s.getName())) {
                    beans.put(bean.getId(), bean);
                }
            }
        }
        for (Bean foundBean : found.values()) {
            beans.put(foundBean.getId(), foundBean);
        }
        core.setSchema(schemas, beans);
        for (Bean bean : beans.values()) {
            setSingletonReferences(bean, schemas);
            core.cache(bean);
        }
        ArrayList objects = new ArrayList<>();
        for(T object : conversion.convert(beans.values(), configurable)) {
            objects.add(object);

        }
        return objects;
    }

    @Override
    public  Optional get(String id, Class configurable) {
        doLookup();
        Schema s = getSchema(configurable);
        Map schemas = schemaManager.getSchemas();
        BeanId beanId = BeanId.create(id, s.getName());
        Optional bean = beanManager.getEager(beanId);
        if (!bean.isPresent()) {
            initFile(configurable);
            Bean fileBean = FILE_CONFIG.get(beanId);
            if (fileBean != null) {
                bean = Optional.of(fileBean);
            } else {
                return Optional.absent();
            }
        }
        core.setSchema(bean.get(), schemas);
        setSingletonReferences(bean.get(), schemas);
        T object = conversion.convert(bean.get(), configurable);
        core.cache(bean.get());
        return Optional.of(object);
    }

    @Override
    public  ConfigQuery newQuery(Class configurable) {
        doLookup();
        Schema schema = getSchema(configurable);
        ConfigIndexedCollection collection = core.get(schema);
        if(collection == null) {
            throw Events.CFG101_SCHEMA_NOT_EXIST(configurable.getName());
        }
        if(!cacheManager.isPresent()) {
            throw new IllegalStateException("Queries are not possible without a cache manager.");
        }
        return new ConfigQuery(collection, cacheManager.get());
    }

    private BeanId getSingletonId(Schema s, Class configurable) {
        return BeanId.createSingleton(s.getName());
    }

    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()) {
                    initFile(null);
                    Bean fileBean = FILE_CONFIG.get(BeanId.createSingleton(ref.getSchemaName()));
                    if (fileBean != null) {
                        singleton = Optional.of(fileBean);
                    }
                }
                if (!singleton.isPresent()) {
                    singleton = Optional.of(Bean.create(BeanId.createSingleton(ref.getSchemaName())));
                }
                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 synchronized void initFile(Class configurable) {
        if (configurable == null) {
            return;
        }
        if (FILE_CONFIG == null) {
            FILE_CONFIG = new HashMap<>();
        }
        if (initalized.get(configurable) != null) {
            return;
        }
        Schema schema = getSchema(configurable);
        for (Bean bean : properties.list(schema)) {
            FILE_CONFIG.put(bean.getId(), bean);
        }
    }

    public void doLookup() {
        // core would already be injected in a cdi environment
        if (core == null) {
            core = new ConfigCore();
        }
        if (conversion == null) {
            conversion = Conversion.get();
            conversion.register(new ObjectToBeanConverter());
            conversion.register(new ClassToSchemaConverter());
            conversion.register(new FieldToSchemaPropertyConverter());
            conversion.register(new BeanToObjectConverter());
        }
        if (cacheManager == null) {
            cacheManager = core.lookupCacheManager();
        }
    }

    private Schema getSchema(Class clazz) {
        Schema schema = schemas.get(clazz);
        if(schema != null) {
            return schema;
        }
        ClassIntrospector introspector = new ClassIntrospector(clazz);
        Config config = introspector.getAnnotation(Config.class);
        if (config == null) {
            throw CFG102_NOT_CONFIGURABLE(clazz);
        }
        String schemaName = config.name();
        if (schemaName == null || "".equals(schemaName)) {
            schemaName = clazz.getName();
        }
        schema = conversion.convert(clazz, Schema.class);
        for (Class cls : schema.getReferenceSchemaTypes()) {
            if (schemas.get(clazz) != null) {
                getSchema(cls);
            }
        }
        properties.registerSchema(schema);
        schemas.put(schema.getName(), schema);
        schemaManager.registerSchema(schema);
        core.putIndex(schema);
        return schema;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy