Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit fa43cde8792573eb3e998b0f32a1bf5ffac6825e @joewilliams joewilliams committed Apr 6, 2012
BIN rebar
Binary file not shown.
8 src/childspec_validator.app.src
@@ -0,0 +1,8 @@
+{application, childspec_validator,
+ [
+ {description, ""},
+ {vsn, git},
+ {registered, []},
+ {applications, []},
+ {env, []}
+ ]}.
172 src/childspec_validator.erl
@@ -0,0 +1,172 @@
+-module(childspec_validator).
+
+-export([validate/1]).
+
+validate({Id, {M, F, A}, Restart, Shutdown, Type, Modules}) when is_atom(Id) ->
+ MFARes = validate_and_error(check_mfa(M, F, A),
+ "Childspec validation error [~p]:"
+ " MFA check failed, the arity or"
+ " function name is incorrect.~n",
+ [Id]),
+
+ RestartRes = validate_and_error(check_restart(Restart),
+ "Childspec validation error [~p]:"
+ " Restart is not permanent, temporary"
+ " or transient.~n",
+ [Id]),
+
+ ShutdownRes = validate_and_error(check_shutdown(Shutdown),
+ "Childspec validation error [~p]:"
+ " Shutdown is not brutal_kill,"
+ " infinity or an integer.~n",
+ [Id]),
+
+ TypeRes = validate_and_error(check_type(M, Type),
+ "Childspec validation error [~p]:"
+ " Module type mismatch, if module is"
+ " a supervisor it should be the atom"
+ " 'supervisor', if not it should be"
+ " the atom 'worker'.~n",
+ [Id]),
+
+ ModsRes = validate_and_error(check_modules(M, Modules),
+ "Childspec validation error [~p]:"
+ " Modules mismatch, if gen_event it"
+ " should be the atom 'dynamic', else"
+ " should be a list including the"
+ " callback module as its only"
+ " element.~n",
+ [Id]),
+
+ Results = [MFARes, RestartRes, ShutdownRes, TypeRes, ModsRes],
+
+ case lists:member(false, Results) of
+ true ->
+ false;
+ _ ->
+ true
+ end;
+validate(_) ->
+ error_logger:error_msg("Childspec validation error:"
+ " Childspec ID is not an atom.~n", []),
+ false.
+
+%%
+%% Internal functions
+%%
+
+%% Make sure the result of the check is good, if so return 'true'.
+%% If not error out with a message and return 'false'.
+
+validate_and_error(ok, _, _) ->
+ true;
+validate_and_error(error, Msg, Args) ->
+ error_logger:error_msg(Msg, Args),
+ false.
+
+%% Check to make sure the childspec's module has the function
+%% specified and the arity is right.
+
+check_mfa(M, F, A) ->
+ Exports = M:module_info(exports),
+ Arity = length(A),
+
+ case proplists:is_defined(F, Exports) of
+ true ->
+ case proplists:get_value(F, Exports) of
+ Arity ->
+ ok;
+ _ ->
+ error
+ end;
+ _ ->
+ error
+ end.
+
+%% Make sure the restart spec is a valid option.
+
+check_restart(permanent) ->
+ ok;
+check_restart(temporary) ->
+ ok;
+check_restart(transient) ->
+ ok;
+check_restart(_) ->
+ error.
+
+%% Make sure the shutdown spec is a valid option.
+
+check_shutdown(brutal_kill) ->
+ ok;
+check_shutdown(infinity) ->
+ ok;
+check_shutdown(Timeout) when is_integer(Timeout) ->
+ ok;
+check_shutdown(_) ->
+ error.
+
+%% If the module is a supervisor it should be specified as one in the
+%% childspec. If it is not a supervisor it should be classified as a
+%% worker in the childspec.
+
+check_type(M, Type) ->
+ case worker_or_supervisor(M) of
+ Type ->
+ ok;
+ _ ->
+ error
+ end.
+
+%% If the module is a gen_event then the modules spec should be
+%% 'dynamic', otherwise it should be a single element list where the
+%% element is an atom of the callback module name.
+
+check_modules(M, Modules) ->
+ case check_dynamic(is_gen_event(M), Modules) of
+ ok ->
+ ok;
+ _ ->
+ error
+ end.
+
+%% Check to see if a module should be defined as a worker or a
+%% supervisor in the childspec.
+
+worker_or_supervisor(M) ->
+ Attr = M:module_info(attributes),
+
+ case proplists:is_defined(behaviour, Attr) of
+ true ->
+ List = proplists:get_value(behaviour, Attr),
+ case lists:member(supervisor, List) of
+ true ->
+ supervisor;
+ _ ->
+ worker
+ end;
+ _ ->
+ worker
+ end.
+
+%% Is the module a gen_event?
+
+is_gen_event(M) ->
+ Attr = M:module_info(attributes),
+
+ case proplists:is_defined(behaviour, Attr) of
+ true ->
+ List = proplists:get_value(behaviour, Attr),
+ lists:member(gen_event, List);
+ _ ->
+ false
+ end.
+
+%% Check for the right combination of gen_event and dynamic or
+%% non-gen_event and a callback module list with single atom element.
+
+check_dynamic(true, dynamic) ->
+ ok;
+check_dynamic(false, [Element]) when is_atom(Element) ->
+ ok;
+check_dynamic(_, _) ->
+ error.
61 test/childspec_validator_tests.erl
@@ -0,0 +1,61 @@
+-module(childspec_validator_tests).
+
+-exports([run_test/0]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+run_test() ->
+ positive(),
+ negative().
+
+positive() ->
+ Folsom = {folsom,
+ {folsom_sup, start_link, []},
+ permanent,
+ 5000,
+ supervisor,
+ [folsom_sup]
+ },
+
+ true = childspec_validator:validate(Folsom),
+
+
+ Web =
+ {webmachine_mochiweb,
+ {webmachine_mochiweb, start, [[{dispatch,[]}]]},
+ permanent,
+ 5000,
+ worker,
+ [webmachine_mochiweb]
+ },
+
+ true = childspec_validator:validate(Web).
+
+
+negative() ->
+ ?debugFmt("errors are expected for these tests ...", []),
+
+ Folsom = {folsom,
+ {folsom_sup, start_link, [asdf]}, % arity is zero
+ permanet, % spelling
+ 5000,
+ worker, % should be a supervisor
+ [folsom_sup]
+ },
+
+ false = childspec_validator:validate(Folsom),
+
+ Web =
+ {webmachine_mochiweb,
+ {webmachine_mochiweb, burrito, [[{dispatch,[]}]]}, % burrito function doesnt exist
+ permanent,
+ a, % not an integer
+ worker,
+ dynamic % should not be dynamic
+ },
+
+ false = childspec_validator:validate(Web),
+
+ NotAtomID = {123, {m, f, []}, blah, werker, []},
+
+ false = childspec_validator:validate(NotAtomID).
113 test/folsom_sup.erl
@@ -0,0 +1,113 @@
+%%
+%%% Copyright 2011, Boundary
+%%%
+%%% 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.
+%%%
+
+
+%%%-------------------------------------------------------------------
+%%% File: folsom_sup.erl
+%%% @author joe williams <j@boundary.com>
+%%% @doc
+%%%
+%%% @end
+%%%-------------------------------------------------------------------
+
+-module(folsom_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+%-include("folsom.hrl").
+
+-define(SERVER, ?MODULE).
+
+%%%===================================================================
+%%% API functions
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the supervisor
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%%===================================================================
+%%% Supervisor callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Whenever a supervisor is started using supervisor:start_link/[2,3],
+%% this function is called by the new process to find out about
+%% restart strategy, maximum restart frequency and child
+%% specifications.
+%%
+%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([]) ->
+ %create_tables(),
+
+ RestartStrategy = one_for_one,
+ MaxRestarts = 1000,
+ MaxSecondsBetweenRestarts = 3600,
+
+ SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
+
+ Restart = permanent,
+ Shutdown = 2000,
+ Type = worker,
+
+ TimerServer = {folsom_meter_timer_server,
+ {folsom_meter_timer_server, start_link, []},
+ Restart, Shutdown, Type, [folsom_meter_timer_server]},
+
+ HistETSServer = {folsom_metrics_histogram_ets,
+ {folsom_metrics_histogram_ets, start_link, []},
+ Restart, Shutdown, Type, [folsom_metrics_histogram_ets]},
+
+ {ok, {SupFlags, [TimerServer, HistETSServer]}}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+%create_tables() ->
+% Tables = [
+% {?FOLSOM_TABLE, [set, named_table, public, {read_concurrency, true}]},
+% {?COUNTER_TABLE, [set, named_table, public, {write_concurrency, true}]},
+% {?GAUGE_TABLE, [set, named_table, public, {write_concurrency, true}]},
+% {?HISTOGRAM_TABLE, [set, named_table, public, {write_concurrency, true}]},
+% {?METER_TABLE, [set, named_table, public, {write_concurrency, true}]},
+% {?HISTORY_TABLE, [set, named_table, public, {write_concurrency, true}]}
+% ],
+% [maybe_create_table(ets:info(Name), Name, Opts) || {Name, Opts} <- Tables],
+% ok.
+
+%maybe_create_table(undefined, Name, Opts) ->
+% ets:new(Name, Opts);
+%maybe_create_table(_, _, _) ->
+% ok.
133 test/webmachine_mochiweb.erl
@@ -0,0 +1,133 @@
+%% @author Justin Sheehy <justin@basho.com>
+%% @author Andy Gross <andy@basho.com>
+%% @copyright 2007-2008 Basho Technologies
+%%
+%% 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.
+
+%% @doc Mochiweb interface for webmachine.
+-module(webmachine_mochiweb).
+-author('Justin Sheehy <justin@basho.com>').
+-author('Andy Gross <andy@basho.com>').
+-export([start/1, stop/0, loop/1]).
+
+start(Options) ->
+ {DispatchList, Options1} = get_option(dispatch, Options),
+ {ErrorHandler0, Options2} = get_option(error_handler, Options1),
+ {EnablePerfLog, Options3} = get_option(enable_perf_logger, Options2),
+ ErrorHandler =
+ case ErrorHandler0 of
+ undefined ->
+ webmachine_error_handler;
+ EH -> EH
+ end,
+ {LogDir, Options4} = get_option(log_dir, Options3),
+ case whereis(webmachine_logger) of
+ undefined ->
+ webmachine_sup:start_logger(LogDir);
+ _ ->
+ ignore
+ end,
+ case EnablePerfLog of
+ true ->
+ case whereis(webmachine_perf_logger) of
+ undefined ->
+ application_set_unless_env(webmachine, enable_perf_logger, true),
+ webmachine_sup:start_perf_logger(LogDir);
+ _ ->
+ ignore
+ end;
+ _ ->
+ ignore
+ end,
+ {PName, Options5} = case get_option(name, Options4) of
+ {undefined, _} -> {?MODULE, Options4};
+ {PN, O5} -> {PN, O5}
+ end,
+ application_set_unless_env(webmachine, dispatch_list, DispatchList),
+ application_set_unless_env(webmachine, error_handler, ErrorHandler),
+ mochiweb_http:start([{name, PName}, {loop, fun loop/1} | Options5]).
+
+stop() ->
+ {registered_name, PName} = process_info(self(), registered_name),
+ mochiweb_http:stop(PName).
+
+loop(MochiReq) ->
+ Req = webmachine:new_request(mochiweb, MochiReq),
+ {ok, DispatchList} = application:get_env(webmachine, dispatch_list),
+ Host = case host_headers(Req) of
+ [H|_] -> H;
+ [] -> []
+ end,
+ {Path, _} = Req:path(),
+ {RD, _} = Req:get_reqdata(),
+
+ %% Run the dispatch code, catch any errors...
+ try webmachine_dispatcher:dispatch(Host, Path, DispatchList, RD) of
+ {no_dispatch_match, _UnmatchedHost, _UnmatchedPathTokens} ->
+ handle_error(404, {none, none, []}, Req);
+ {Mod, ModOpts, HostTokens, Port, PathTokens, Bindings,
+ AppRoot, StringPath} ->
+ BootstrapResource = webmachine_resource:new(x,x,x,x),
+ {ok,RS1} = Req:load_dispatch_data(Bindings,HostTokens,Port,
+ PathTokens,AppRoot,StringPath),
+ XReq1 = {webmachine_request,RS1},
+ try
+ {ok, Resource} = BootstrapResource:wrap(Mod, ModOpts),
+ {ok,RS2} = XReq1:set_metadata('resource_module', Mod),
+ webmachine_decision_core:handle_request(Resource, RS2)
+ catch
+ error:Error ->
+ handle_error(500, {error, Error}, Req)
+ end
+ catch
+ Type : Error ->
+ handle_error(500, {Type, Error}, Req)
+ end.
+
+handle_error(Code, Error, Req) ->
+ {ok, ErrorHandler} = application:get_env(webmachine, error_handler),
+ {ErrorHTML,ReqState1} =
+ ErrorHandler:render_error(Code, Req, Error),
+ Req1 = {webmachine_request,ReqState1},
+ {ok,ReqState2} = Req1:append_to_response_body(ErrorHTML),
+ Req2 = {webmachine_request,ReqState2},
+ {ok,ReqState3} = Req2:send_response(Code),
+ Req3 = {webmachine_request,ReqState3},
+ {LogData,_ReqState4} = Req3:log_data(),
+ case application:get_env(webmachine,webmachine_logger_module) of
+ {ok, LogModule} ->
+ spawn(LogModule, log_access, [LogData]);
+ _ -> nop
+ end.
+
+
+
+get_option(Option, Options) ->
+ {proplists:get_value(Option, Options), proplists:delete(Option, Options)}.
+
+application_set_unless_env(App, Var, Value) ->
+ Current = application:get_all_env(App),
+ CurrentKeys = proplists:get_keys(Current),
+ case lists:member(Var, CurrentKeys) of
+ true ->
+ ok;
+ false ->
+ application:set_env(App, Var, Value)
+ end.
+
+host_headers(Req) ->
+ [ V || {V,_ReqState} <- [Req:get_header_value(H)
+ || H <- ["x-forwarded-host",
+ "x-forwarded-server",
+ "host"]],
+ V /= undefined].

0 comments on commit fa43cde

Please sign in to comment.