1 /** 2 * Модуль содержит методы для работы со совйствами приложения 3 * 4 * Copyright: (c) 2015-2017, Milofon Project. 5 * License: Subject to the terms of the BSD license, as written in the included LICENSE.txt file. 6 * Authors: Maksim Galanin 7 */ 8 module dango.system.properties; 9 10 public 11 { 12 import poodinis : Registration; 13 } 14 15 private 16 { 17 import poodinis; 18 import proped; 19 20 import dango.system.container : registerByName; 21 import dango.system.exception : configEnforce; 22 } 23 24 25 /** 26 * Получение настроек или генерация исключения 27 * Params: 28 * config = Объект содержащий необходимы ключ конфигурации 29 * key = Ключ конфигруации 30 * msg = Сообщение об ошибке 31 */ 32 T getOrEnforce(T)(Properties config, string key, lazy string msg) 33 { 34 static if (is(T == Properties)) 35 auto ret = config.sub(key); 36 else 37 auto ret = config.get!T(key); 38 39 configEnforce(!ret.isNull, msg); 40 return ret.get; 41 } 42 43 44 /** 45 * Извление имени из объекта конфигурации 46 * Params: 47 * config = Объект содержащий необходимы ключ конфигурации 48 * msg = Сообщение об ошибке 49 */ 50 string getNameOrEnforce(Properties config, string msg) 51 { 52 if (config.isObject) 53 return config.getOrEnforce!string("name", msg); 54 else 55 { 56 auto val = config.get!string; 57 configEnforce(!val.isNull, msg); 58 return val.get; 59 } 60 } 61 62 /** 63 * Контекст для регистрации системных компоненетов 64 */ 65 class PropertiesContext : ApplicationContext 66 { 67 public override void registerDependencies(shared(DependencyContainer) container) 68 { 69 container.registerByName!(PropertiesLoader, SDLPropertiesLoader)("SDL"); 70 container.registerByName!(PropertiesLoader, YAMLPropertiesLoader)("YAML"); 71 container.registerByName!(PropertiesLoader, JSONPropertiesLoader)("JSON"); 72 } 73 } 74 75 76 /** 77 * Класс обертка на объектом настроек для распространения в DI контейнере 78 */ 79 class PropertiesProxy 80 { 81 Properties _properties; 82 alias _properties this; 83 84 this(Properties properties) 85 { 86 _properties = properties; 87 } 88 } 89 90 91 /** 92 * Создает функцию загрузчик 93 * Params: 94 * 95 * container = Контейнер зависимостей 96 */ 97 Loader createLoaderFromContainer(shared(DependencyContainer) container) 98 { 99 PropertiesLoader[] loaders = container.resolveAll!PropertiesLoader; 100 101 return (string fileName) 102 { 103 return loaders.loadProperties(fileName); 104 }; 105 } 106 107 108 /** 109 * Функция позволяет назначить фабрику передающую параметры в конструктор 110 * для зарегистрированной в контейнере класса 111 * Params: 112 * 113 * registration = Объект регистрации в контейнере 114 * config = Конфигурация 115 */ 116 Registration propertiesInstance(T)(Registration registration, Properties config) { 117 118 Object propertiesInstanceMethod() 119 { 120 return new T(config); 121 } 122 123 registration.instanceFactory = new InstanceFactory(registration.instanceType, 124 CreatesSingleton.yes, null, &propertiesInstanceMethod); 125 return registration; 126 } 127 128 129 /** 130 * Шаблон для регистрации зависимостей массово 131 * Используется для более простой регистрации зависимостей в контейнер DI 132 * 133 * Params: 134 * 135 * pairs = Массив из пар (наименование, класс) 136 * 137 * Example: 138 * -------------------- 139 * auto callback = (Registration reg, string name, Properties cfg) {}; 140 * registerControllerDependencies!("api", ControllerApi)(container, config, callback); 141 * -------------------- 142 */ 143 mixin template registerPropertiesDependencies(C, pairs...) 144 { 145 template GenerateSwitch() 146 { 147 template GenerateSwitchBody(tpairs...) 148 { 149 static if (tpairs.length > 0) 150 { 151 enum GenerateSwitchBody = ` 152 case ("` ~ tpairs[0] ~ `"): 153 auto reg = container.register!(C, ` ~ tpairs[1].stringof ~ `) 154 .propertiesInstance!(` ~ tpairs[1].stringof ~ `)(cfg); 155 if (callback !is null) 156 callback(reg, name, cfg); 157 break;` ~ GenerateSwitchBody!(tpairs[2..$]); 158 } 159 else 160 enum GenerateSwitchBody = ""; 161 } 162 enum GenerateSwitch = "switch(name)\n{" ~ GenerateSwitchBody!(pairs) ~ "\ndefault: break;\n}"; 163 } 164 165 void registerPropertiesDependencies(shared(DependencyContainer) container, Properties config, 166 void function(Registration, string, Properties) callback = null) 167 { 168 pragma(msg, __MODULE__); 169 // pragma(msg, GenerateSwitch!()); 170 foreach (Properties cfg; config.getArray()) 171 { 172 auto pName = cfg.get!string("name"); 173 if (pName.isNull) 174 continue; 175 string name = pName.get; 176 mixin(GenerateSwitch!()); 177 } 178 } 179 } 180 181 182 /** 183 * Функция для регистрации существующего контекста 184 * Params: 185 * 186 * container = Контейнер зависимостей 187 * ctx = Объект контекста 188 */ 189 void registerExistsContext(Context : ApplicationContext)(shared(DependencyContainer) container, Context ctx) 190 { 191 ctx.registerDependencies(container); 192 ctx.registerContextComponents(container); 193 container.register!(ApplicationContext, Context)().existingInstance(ctx); 194 autowire(container, ctx); 195 } 196 197 198 void registerExtContext(Context : ApplicationContext)(shared(DependencyContainer) container, Properties config) 199 { 200 auto context = new Context(); 201 context.registerDependencies(container, config); 202 context.registerContextComponents(container); 203 container.register!(ApplicationContext, Context)().existingInstance(context); 204 autowire(container, context); 205 } 206