diff options
Diffstat (limited to 'src/couch_epi/src/couch_epi_plugin.erl')
-rw-r--r-- | src/couch_epi/src/couch_epi_plugin.erl | 395 |
1 files changed, 0 insertions, 395 deletions
diff --git a/src/couch_epi/src/couch_epi_plugin.erl b/src/couch_epi/src/couch_epi_plugin.erl deleted file mode 100644 index 1ec09d8dc..000000000 --- a/src/couch_epi/src/couch_epi_plugin.erl +++ /dev/null @@ -1,395 +0,0 @@ -% 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. - --module(couch_epi_plugin). - --include("couch_epi.hrl"). - --export([ - definitions/1, - definitions/2, - grouped_definitions/1, - plugin_processes/2, - codegen/1 -]). - --export([notify/4]). - -%% ------------------------------------------------------------------ -%% Types Definitions -%% ------------------------------------------------------------------ - --type kind() :: - providers - | data_providers - | services - | data_subscriptions. - --type key() :: - {ServiceId :: couch_epi:service_id(), Key :: couch_epi:key()} - | couch_epi:service_id(). - --callback app() -> couch_epi:app(). --callback providers() -> [{couch_epi:service_id(), module()}]. --callback services() -> [{couch_epi:service_id(), module()}]. --callback data_subscriptions() -> [{couch_epi:service_id(), couch_epi:key()}]. --callback data_providers() -> - [ - {couch_epi:key(), couch_epi:data_spec()} - | {couch_epi:key(), couch_epi:data_spec(), [couch_epi:data_spec_opt()]} - ]. --callback processes() -> [{couch_epi:plugin_id(), [supervisor:child_spec()]}]. --callback notify(Key :: term(), Old :: term(), New :: term()) -> ok. - -%% ------------------------------------------------------------------ -%% API Function Definitions -%% ------------------------------------------------------------------ - -definitions(Plugins) -> - lists:append([extract_definitions(Plugin) || Plugin <- Plugins]). - -plugin_processes(Plugin, Plugins) -> - lists:append([Specs || P0 <- Plugins, {P1, Specs} <- P0:processes(), P1 =:= Plugin]). - -grouped_definitions(Plugins) -> - Defs = lists:append([extract_definitions(Plugin) || Plugin <- Plugins]), - group_specs(Defs). - -definitions(Kind, Key) -> - Plugins = application:get_env(couch_epi, plugins, []), - Definitions = definitions(Plugins), - Filtered = filter_by_key(Definitions, Kind, Key), - case group_specs(Filtered) of - [] -> []; - [{_, Defs}] -> Defs - end. - -notify(Key, OldData, NewData, Specs) -> - Plugins = lists:usort([Plugin || #couch_epi_spec{behaviour = Plugin} <- Specs]), - [notify_plugin(Plugin, Key, OldData, NewData) || Plugin <- Plugins], - ok. - -%% ------------------------------------------------------------------ -%% Internal Function Definitions -%% ------------------------------------------------------------------ - -notify_plugin(Plugin, Key, OldData, NewData) -> - App = Plugin:app(), - Plugin:notify(Key, app_data(App, OldData), app_data(App, NewData)). - -app_data(App, Data) -> - case lists:keyfind(App, 1, Data) of - {App, AppData} -> AppData; - false -> [] - end. - -filter_by_key(Definitions, Kind, Key) -> - lists:filter(fun(Spec) -> by_key(Spec, Kind, Key) end, Definitions). - -by_key(#couch_epi_spec{kind = Kind, key = Key}, Kind, Key) -> true; -by_key(_, _, _) -> false. - -extract_definitions(Plugin) -> - specs(Plugin, providers) ++ - specs(Plugin, data_providers) ++ - specs(Plugin, services) ++ - specs(Plugin, data_subscriptions). - --spec group_specs(Specs :: [#couch_epi_spec{}]) -> GroupedSpecs when - GroupedSpecs :: - [{{kind(), key()}, [{couch_epi:app(), #couch_epi_spec{}}]}]. - -group_specs(Specs) -> - Grouped = group( - [ - {{Kind, Key}, group([{App, Spec}])} - || #couch_epi_spec{kind = Kind, key = Key, app = App} = Spec <- Specs - ] - ), - [{K, lists:reverse(V)} || {K, V} <- Grouped]. - -group(KV) -> - dict:to_list( - lists:foldr( - fun({K, V}, D) -> - dict:append_list(K, V, D) - end, - dict:new(), - KV - ) - ). - -specs(Plugin, Kind) -> - [spec(parse(Spec, Kind), Plugin, Kind) || Spec <- Plugin:Kind()]. - -spec({Key, Value, Options}, Plugin, Kind) -> - App = Plugin:app(), - #couch_epi_spec{ - app = App, - behaviour = Plugin, - kind = Kind, - options = Options, - key = Key, - value = Value, - codegen = codegen(Kind), - type = type(Kind, Value) - }. - -parse({Key, Value}, Kind) -> - parse({Key, Value, []}, Kind); -parse({Key, Value, Options}, data_subscriptions) -> - {{Key, Value}, undefined, Options}; -parse({_, _, _} = Tuple, _Kind) -> - Tuple. - -codegen(providers) -> couch_epi_functions_gen; -codegen(services) -> couch_epi_functions_gen; -codegen(data_providers) -> couch_epi_data_gen; -codegen(data_subscriptions) -> couch_epi_data_gen. - -type(providers, _) -> couch_epi_functions; -type(services, _) -> couch_epi_functions; -type(data_providers, _) -> couch_epi_data; -type(data_subscriptions, _) -> undefined. - -%% ------------------------------------------------------------------ -%% Tests -%% ------------------------------------------------------------------ - --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - -plugin_module(foo_epi) -> - "\n" - " -compile([export_all]).\n" - "\n" - " app() -> foo.\n" - " providers() ->\n" - " [\n" - " {chttpd_handlers, foo_provider},\n" - " {bar_handlers, bar_provider1},\n" - " {bar_handlers, bar_provider2}\n" - " ].\n" - "\n" - " services() ->\n" - " [\n" - " {foo_handlers, foo_service}\n" - " ].\n" - "\n" - " data_providers() ->\n" - " [\n" - " {{foo_service, data1}, {file, \"abs_file\"}, [{interval, 5000}]},\n" - " {{foo_service, data2}, {priv_file, \"priv_file\"}},\n" - " {{foo_service, data3}, {module, foo_data}}\n" - " ].\n" - "\n" - " data_subscriptions() ->\n" - " [\n" - " {stats, foo_definitions}\n" - " ].\n" - "\n" - " processes() -> [].\n" - "\n" - " notify(_, _, _) -> ok.\n" - " "; -plugin_module(bar_epi) -> - "\n" - " -compile([export_all]).\n" - "\n" - " app() -> bar.\n" - " providers() ->\n" - " [\n" - " {chttpd_handlers, bar_provider},\n" - " {bar_handlers, bar_provider}\n" - " ].\n" - "\n" - " services() ->\n" - " [\n" - " {bar_handlers, bar_service}\n" - " ].\n" - "\n" - " data_providers() ->\n" - " [].\n" - "\n" - " data_subscriptions() ->\n" - " [\n" - " {foo_service, data1}\n" - " ].\n" - "\n" - " processes() -> [].\n" - "\n" - " notify(_, _, _) -> ok.\n" - " ". - -generate_module(Name, Body) -> - Tokens = couch_epi_codegen:scan(Body), - couch_epi_codegen:generate(Name, Tokens). - -generate_modules(Kind, Providers) -> - [generate_module(P, Kind(P)) || P <- Providers]. - -provider_modules_order_test() -> - [ok, ok] = generate_modules(fun plugin_module/1, [foo_epi, bar_epi]), - ok = application:set_env(couch_epi, plugins, [foo_epi, bar_epi]), - Expected = [ - {foo, bar_provider1}, - {foo, bar_provider2}, - {bar, bar_provider} - ], - - Defs = definitions(providers, bar_handlers), - Results = [{App, V} || {App, #couch_epi_spec{value = V}} <- Defs], - Tests = lists:zip(Expected, Results), - [?assertEqual(Expect, Result) || {Expect, Result} <- Tests], - ok. - -providers_order_test() -> - [ok, ok] = generate_modules(fun plugin_module/1, [foo_epi, bar_epi]), - Expected = [ - {foo, bar_provider1}, - {foo, bar_provider2}, - {bar, bar_provider} - ], - AllDefs = grouped_definitions([foo_epi, bar_epi]), - {_, Defs} = lists:keyfind({providers, bar_handlers}, 1, AllDefs), - Results = [{App, V} || {App, #couch_epi_spec{value = V}} <- Defs], - Tests = lists:zip(Expected, Results), - [?assertEqual(Expect, Result) || {Expect, Result} <- Tests], - ok. - -definitions_test() -> - Expected = lists:sort([ - #couch_epi_spec{ - behaviour = bar_epi, - app = bar, - kind = providers, - options = [], - key = bar_handlers, - value = bar_provider, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = bar_epi, - app = bar, - kind = services, - options = [], - key = bar_handlers, - value = bar_service, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = bar_epi, - app = bar, - kind = providers, - options = [], - key = chttpd_handlers, - value = bar_provider, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = bar_epi, - app = bar, - kind = data_subscriptions, - options = [], - key = {foo_service, data1}, - value = undefined, - codegen = couch_epi_data_gen - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = providers, - options = [], - key = bar_handlers, - value = bar_provider1, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = providers, - options = [], - key = bar_handlers, - value = bar_provider2, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = providers, - options = [], - key = chttpd_handlers, - value = foo_provider, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = services, - options = [], - key = foo_handlers, - value = foo_service, - codegen = couch_epi_functions_gen, - type = couch_epi_functions - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = data_providers, - options = [{interval, 5000}], - key = {foo_service, data1}, - value = {file, "abs_file"}, - codegen = couch_epi_data_gen, - type = couch_epi_data - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = data_providers, - options = [], - key = {foo_service, data2}, - value = {priv_file, "priv_file"}, - codegen = couch_epi_data_gen, - type = couch_epi_data - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = data_providers, - options = [], - key = {foo_service, data3}, - value = {module, foo_data}, - codegen = couch_epi_data_gen, - type = couch_epi_data - }, - #couch_epi_spec{ - behaviour = foo_epi, - app = foo, - kind = data_subscriptions, - options = [], - key = {stats, foo_definitions}, - value = undefined, - codegen = couch_epi_data_gen - } - ]), - - [ok, ok] = generate_modules(fun plugin_module/1, [foo_epi, bar_epi]), - Tests = lists:zip(Expected, lists:sort(definitions([foo_epi, bar_epi]))), - [?assertEqual(Expect, Result) || {Expect, Result} <- Tests], - ok. --endif. |