package org.deephacks.confit.internal.core.property; import com.google.common.base.Optional; import com.google.common.base.Strings; import org.deephacks.confit.internal.core.property.typesafe.Config; import org.deephacks.confit.internal.core.property.typesafe.ConfigException; import org.deephacks.confit.internal.core.property.typesafe.ConfigFactory; import org.deephacks.confit.model.Bean; import org.deephacks.confit.model.BeanId; import org.deephacks.confit.model.Events; import org.deephacks.confit.model.Schema; import org.deephacks.confit.spi.PropertyManager; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import static org.deephacks.confit.model.Events.CFG301_MISSING_RUNTIME_REF; /** * DefaultPropertyManager provides a way for reading simple properties. * * Properties will be read from multiple sources using a fall-back mechanism. The first * source to return a valid value will be returned. * * Properties are read in the following order: * * 1) System.getProperty * 2) User home level file * 3) System level file * 4) Class path file * */ public class DefaultPropertyManager extends PropertyManager { public static final String PROPERTY_FILE_PROPERTY = "application.conf"; private final Config config; public DefaultPropertyManager() { String value = System.getProperty(PROPERTY_FILE_PROPERTY); final Config config; if (!Strings.isNullOrEmpty(value) && new File(value).exists()) { config = ConfigFactory.parseFile(new File(value)); } else { config = ConfigFactory.load(); } this.config = config; } public DefaultPropertyManager(File file) { if(!file.exists()) { throw new IllegalArgumentException("File does not exist [" + file.getAbsolutePath() + "]"); } this.config = ConfigFactory.parseFile(file); } public Optional<String> get(String name) { try { Object object = config.getAnyRef(name).toString(); if (object == null) { return Optional.absent(); } else { return Optional.of(object.toString()); } } catch (Exception e) { return Optional.absent(); } } public List<Bean> list(Schema schema, Map<String, Schema> schemas) { List<Bean> beans = new ArrayList<>(); Config schemaConfig; try { String schemaName = schema.getName().replaceAll("\\$", "\\."); schemaConfig = config.getConfig(schemaName); if (schemaConfig == null) { return beans; } } catch (Exception e) { return beans; } if (schema.getId().isSingleton()) { final Bean bean = Bean.create(BeanId.createSingleton(schema.getName())); beans.add(bean); constructBean(schemaConfig, schema, bean, schemas); } else { for (Object instanceId : schemaConfig.root().keySet()) { Config instance = schemaConfig.getConfig(instanceId.toString()); final Bean bean = Bean.create(BeanId.create(instanceId.toString(), schema.getName())); beans.add(bean); constructBean(instance, schema, bean, schemas); } } return beans; } private void constructBean(Config properties, Schema schema, Bean bean, Map<String, Schema> schemas) { bean.set(schemas.get(bean.getId().getSchemaName())); for (String propertyName : schema.getPropertyNames()) { Object value; try { value = properties.getAnyRef(propertyName); } catch (Exception e) { continue; } if (value == null) { continue; } if (value instanceof Collection) { bean.addProperty(propertyName, toStrings((Collection) value)); } else { bean.addProperty(propertyName, value.toString()); } } for (String propertyName : schema.getReferenceNames()) { Object value; try { value = properties.getAnyRef(propertyName); } catch (Exception e) { value = null; } String schemaName = schema.getReferenceSchemaName(propertyName); if (schemaName == null) { throw new IllegalArgumentException("Schema [" + schema.getName() + "] does not have reference typed property [" + propertyName + "]."); } Schema refSchema = schemas.get(schemaName); if (refSchema == null) { throw Events.CFG101_SCHEMA_NOT_EXIST(schemaName); } if (refSchema.getId().isSingleton()) { BeanId id = BeanId.createSingleton(refSchema.getName()); Optional<Bean> optional = get(id, schemas); if (!optional.isPresent()) { throw CFG301_MISSING_RUNTIME_REF(id); } Bean b = optional.get(); b.set(schemas.get(b.getId().getSchemaName())); id.setBean(b); bean.addReference(propertyName, id); } if (value == null) { continue; } if (value instanceof Collection) { Collection<String> stringValues = toStrings((Collection) value); List<BeanId> beanIds = new ArrayList<>(); for (String id : stringValues) { BeanId beanId = BeanId.create(id, refSchema.getName()); Optional<Bean> ref = get(beanId, schemas); if (!ref.isPresent()) { throw CFG301_MISSING_RUNTIME_REF(beanId); } Bean b = ref.get(); b.set(schemas.get(b.getId().getSchemaName())); beanId.setBean(b); beanIds.add(beanId); } bean.addReference(propertyName, beanIds); } else { BeanId id = BeanId.create(value.toString(), refSchema.getName()); Optional<Bean> idBean = get(id, schemas); if (!idBean.isPresent()) { throw Events.CFG301_MISSING_RUNTIME_REF(id); } Bean b = idBean.get(); b.set(schemas.get(b.getId().getSchemaName())); id.setBean(b); bean.addReference(propertyName, id); } } } Optional<Bean> get(BeanId beanId, Map<String, Schema> schemas) { Schema schema = schemas.get(beanId.getSchemaName()); if (schema == null) { throw Events.CFG101_SCHEMA_NOT_EXIST(beanId.getSchemaName()); } try { String schemaName = schema.getName().replaceAll("\\$", "\\."); Config schemaConfig = config.getConfig(schemaName); Bean bean; if (schema.getId().isSingleton()) { bean = Bean.create(BeanId.createSingleton(schema.getName())); constructBean(schemaConfig, schema, bean, schemas); return Optional.of(bean); } else { if (schemaConfig == null) { return Optional.absent(); } bean = Bean.create(beanId); try { for (Object instanceId : schemaConfig.root().keySet()) { if (instanceId.equals(beanId.getInstanceId())) { Config instance = schemaConfig.getConfig(instanceId.toString()); bean = Bean.create(BeanId.create(instanceId.toString(), schema.getName())); constructBean(instance, schema, bean, schemas); return Optional.of(bean); } } } catch (Exception e) { return Optional.absent(); } } return Optional.absent(); } catch (ConfigException e) { return Optional.absent(); } } private Collection<String> toStrings(Collection<Object> values) { ArrayList<String> stringValues = new ArrayList<>(); for (Object value : values) { if (value != null) { stringValues.add(value.toString()); } } return stringValues; } }