summaryrefslogtreecommitdiff
path: root/src/couch_epi/src/couch_epi_plugin.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch_epi/src/couch_epi_plugin.erl')
-rw-r--r--src/couch_epi/src/couch_epi_plugin.erl395
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.