Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit

  • Loading branch information...
commit fa43cde8792573eb3e998b0f32a1bf5ffac6825e 0 parents
Joe Williams joewilliams authored
BIN  rebar
Binary file not shown
8 src/childspec_validator.app.src
... ... @@ -0,0 +1,8 @@
  1 +{application, childspec_validator,
  2 + [
  3 + {description, ""},
  4 + {vsn, git},
  5 + {registered, []},
  6 + {applications, []},
  7 + {env, []}
  8 + ]}.
172 src/childspec_validator.erl
... ... @@ -0,0 +1,172 @@
  1 +-module(childspec_validator).
  2 +
  3 +-export([validate/1]).
  4 +
  5 +validate({Id, {M, F, A}, Restart, Shutdown, Type, Modules}) when is_atom(Id) ->
  6 + MFARes = validate_and_error(check_mfa(M, F, A),
  7 + "Childspec validation error [~p]:"
  8 + " MFA check failed, the arity or"
  9 + " function name is incorrect.~n",
  10 + [Id]),
  11 +
  12 + RestartRes = validate_and_error(check_restart(Restart),
  13 + "Childspec validation error [~p]:"
  14 + " Restart is not permanent, temporary"
  15 + " or transient.~n",
  16 + [Id]),
  17 +
  18 + ShutdownRes = validate_and_error(check_shutdown(Shutdown),
  19 + "Childspec validation error [~p]:"
  20 + " Shutdown is not brutal_kill,"
  21 + " infinity or an integer.~n",
  22 + [Id]),
  23 +
  24 + TypeRes = validate_and_error(check_type(M, Type),
  25 + "Childspec validation error [~p]:"
  26 + " Module type mismatch, if module is"
  27 + " a supervisor it should be the atom"
  28 + " 'supervisor', if not it should be"
  29 + " the atom 'worker'.~n",
  30 + [Id]),
  31 +
  32 + ModsRes = validate_and_error(check_modules(M, Modules),
  33 + "Childspec validation error [~p]:"
  34 + " Modules mismatch, if gen_event it"
  35 + " should be the atom 'dynamic', else"
  36 + " should be a list including the"
  37 + " callback module as its only"
  38 + " element.~n",
  39 + [Id]),
  40 +
  41 + Results = [MFARes, RestartRes, ShutdownRes, TypeRes, ModsRes],
  42 +
  43 + case lists:member(false, Results) of
  44 + true ->
  45 + false;
  46 + _ ->
  47 + true
  48 + end;
  49 +validate(_) ->
  50 + error_logger:error_msg("Childspec validation error:"
  51 + " Childspec ID is not an atom.~n", []),
  52 + false.
  53 +
  54 +%%
  55 +%% Internal functions
  56 +%%
  57 +
  58 +%% Make sure the result of the check is good, if so return 'true'.
  59 +%% If not error out with a message and return 'false'.
  60 +
  61 +validate_and_error(ok, _, _) ->
  62 + true;
  63 +validate_and_error(error, Msg, Args) ->
  64 + error_logger:error_msg(Msg, Args),
  65 + false.
  66 +
  67 +%% Check to make sure the childspec's module has the function
  68 +%% specified and the arity is right.
  69 +
  70 +check_mfa(M, F, A) ->
  71 + Exports = M:module_info(exports),
  72 + Arity = length(A),
  73 +
  74 + case proplists:is_defined(F, Exports) of
  75 + true ->
  76 + case proplists:get_value(F, Exports) of
  77 + Arity ->
  78 + ok;
  79 + _ ->
  80 + error
  81 + end;
  82 + _ ->
  83 + error
  84 + end.
  85 +
  86 +%% Make sure the restart spec is a valid option.
  87 +
  88 +check_restart(permanent) ->
  89 + ok;
  90 +check_restart(temporary) ->
  91 + ok;
  92 +check_restart(transient) ->
  93 + ok;
  94 +check_restart(_) ->
  95 + error.
  96 +
  97 +%% Make sure the shutdown spec is a valid option.
  98 +
  99 +check_shutdown(brutal_kill) ->
  100 + ok;
  101 +check_shutdown(infinity) ->
  102 + ok;
  103 +check_shutdown(Timeout) when is_integer(Timeout) ->
  104 + ok;
  105 +check_shutdown(_) ->
  106 + error.
  107 +
  108 +%% If the module is a supervisor it should be specified as one in the
  109 +%% childspec. If it is not a supervisor it should be classified as a
  110 +%% worker in the childspec.
  111 +
  112 +check_type(M, Type) ->
  113 + case worker_or_supervisor(M) of
  114 + Type ->
  115 + ok;
  116 + _ ->
  117 + error
  118 + end.
  119 +
  120 +%% If the module is a gen_event then the modules spec should be
  121 +%% 'dynamic', otherwise it should be a single element list where the
  122 +%% element is an atom of the callback module name.
  123 +
  124 +check_modules(M, Modules) ->
  125 + case check_dynamic(is_gen_event(M), Modules) of
  126 + ok ->
  127 + ok;
  128 + _ ->
  129 + error
  130 + end.
  131 +
  132 +%% Check to see if a module should be defined as a worker or a
  133 +%% supervisor in the childspec.
  134 +
  135 +worker_or_supervisor(M) ->
  136 + Attr = M:module_info(attributes),
  137 +
  138 + case proplists:is_defined(behaviour, Attr) of
  139 + true ->
  140 + List = proplists:get_value(behaviour, Attr),
  141 + case lists:member(supervisor, List) of
  142 + true ->
  143 + supervisor;
  144 + _ ->
  145 + worker
  146 + end;
  147 + _ ->
  148 + worker
  149 + end.
  150 +
  151 +%% Is the module a gen_event?
  152 +
  153 +is_gen_event(M) ->
  154 + Attr = M:module_info(attributes),
  155 +
  156 + case proplists:is_defined(behaviour, Attr) of
  157 + true ->
  158 + List = proplists:get_value(behaviour, Attr),
  159 + lists:member(gen_event, List);
  160 + _ ->
  161 + false
  162 + end.
  163 +
  164 +%% Check for the right combination of gen_event and dynamic or
  165 +%% non-gen_event and a callback module list with single atom element.
  166 +
  167 +check_dynamic(true, dynamic) ->
  168 + ok;
  169 +check_dynamic(false, [Element]) when is_atom(Element) ->
  170 + ok;
  171 +check_dynamic(_, _) ->
  172 + error.
61 test/childspec_validator_tests.erl
... ... @@ -0,0 +1,61 @@
  1 +-module(childspec_validator_tests).
  2 +
  3 +-exports([run_test/0]).
  4 +
  5 +-include_lib("eunit/include/eunit.hrl").
  6 +
  7 +run_test() ->
  8 + positive(),
  9 + negative().
  10 +
  11 +positive() ->
  12 + Folsom = {folsom,
  13 + {folsom_sup, start_link, []},
  14 + permanent,
  15 + 5000,
  16 + supervisor,
  17 + [folsom_sup]
  18 + },
  19 +
  20 + true = childspec_validator:validate(Folsom),
  21 +
  22 +
  23 + Web =
  24 + {webmachine_mochiweb,
  25 + {webmachine_mochiweb, start, [[{dispatch,[]}]]},
  26 + permanent,
  27 + 5000,
  28 + worker,
  29 + [webmachine_mochiweb]
  30 + },
  31 +
  32 + true = childspec_validator:validate(Web).
  33 +
  34 +
  35 +negative() ->
  36 + ?debugFmt("errors are expected for these tests ...", []),
  37 +
  38 + Folsom = {folsom,
  39 + {folsom_sup, start_link, [asdf]}, % arity is zero
  40 + permanet, % spelling
  41 + 5000,
  42 + worker, % should be a supervisor
  43 + [folsom_sup]
  44 + },
  45 +
  46 + false = childspec_validator:validate(Folsom),
  47 +
  48 + Web =
  49 + {webmachine_mochiweb,
  50 + {webmachine_mochiweb, burrito, [[{dispatch,[]}]]}, % burrito function doesnt exist
  51 + permanent,
  52 + a, % not an integer
  53 + worker,
  54 + dynamic % should not be dynamic
  55 + },
  56 +
  57 + false = childspec_validator:validate(Web),
  58 +
  59 + NotAtomID = {123, {m, f, []}, blah, werker, []},
  60 +
  61 + false = childspec_validator:validate(NotAtomID).
113 test/folsom_sup.erl
... ... @@ -0,0 +1,113 @@
  1 +%%
  2 +%%% Copyright 2011, Boundary
  3 +%%%
  4 +%%% Licensed under the Apache License, Version 2.0 (the "License");
  5 +%%% you may not use this file except in compliance with the License.
  6 +%%% You may obtain a copy of the License at
  7 +%%%
  8 +%%% http://www.apache.org/licenses/LICENSE-2.0
  9 +%%%
  10 +%%% Unless required by applicable law or agreed to in writing, software
  11 +%%% distributed under the License is distributed on an "AS IS" BASIS,
  12 +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +%%% See the License for the specific language governing permissions and
  14 +%%% limitations under the License.
  15 +%%%
  16 +
  17 +
  18 +%%%-------------------------------------------------------------------
  19 +%%% File: folsom_sup.erl
  20 +%%% @author joe williams <j@boundary.com>
  21 +%%% @doc
  22 +%%%
  23 +%%% @end
  24 +%%%-------------------------------------------------------------------
  25 +
  26 +-module(folsom_sup).
  27 +
  28 +-behaviour(supervisor).
  29 +
  30 +%% API
  31 +-export([start_link/0]).
  32 +
  33 +%% Supervisor callbacks
  34 +-export([init/1]).
  35 +
  36 +%-include("folsom.hrl").
  37 +
  38 +-define(SERVER, ?MODULE).
  39 +
  40 +%%%===================================================================
  41 +%%% API functions
  42 +%%%===================================================================
  43 +
  44 +%%--------------------------------------------------------------------
  45 +%% @doc
  46 +%% Starts the supervisor
  47 +%%
  48 +%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
  49 +%% @end
  50 +%%--------------------------------------------------------------------
  51 +start_link() ->
  52 + supervisor:start_link({local, ?SERVER}, ?MODULE, []).
  53 +
  54 +%%%===================================================================
  55 +%%% Supervisor callbacks
  56 +%%%===================================================================
  57 +
  58 +%%--------------------------------------------------------------------
  59 +%% @private
  60 +%% @doc
  61 +%% Whenever a supervisor is started using supervisor:start_link/[2,3],
  62 +%% this function is called by the new process to find out about
  63 +%% restart strategy, maximum restart frequency and child
  64 +%% specifications.
  65 +%%
  66 +%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
  67 +%% ignore |
  68 +%% {error, Reason}
  69 +%% @end
  70 +%%--------------------------------------------------------------------
  71 +init([]) ->
  72 + %create_tables(),
  73 +
  74 + RestartStrategy = one_for_one,
  75 + MaxRestarts = 1000,
  76 + MaxSecondsBetweenRestarts = 3600,
  77 +
  78 + SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
  79 +
  80 + Restart = permanent,
  81 + Shutdown = 2000,
  82 + Type = worker,
  83 +
  84 + TimerServer = {folsom_meter_timer_server,
  85 + {folsom_meter_timer_server, start_link, []},
  86 + Restart, Shutdown, Type, [folsom_meter_timer_server]},
  87 +
  88 + HistETSServer = {folsom_metrics_histogram_ets,
  89 + {folsom_metrics_histogram_ets, start_link, []},
  90 + Restart, Shutdown, Type, [folsom_metrics_histogram_ets]},
  91 +
  92 + {ok, {SupFlags, [TimerServer, HistETSServer]}}.
  93 +
  94 +%%%===================================================================
  95 +%%% Internal functions
  96 +%%%===================================================================
  97 +
  98 +%create_tables() ->
  99 +% Tables = [
  100 +% {?FOLSOM_TABLE, [set, named_table, public, {read_concurrency, true}]},
  101 +% {?COUNTER_TABLE, [set, named_table, public, {write_concurrency, true}]},
  102 +% {?GAUGE_TABLE, [set, named_table, public, {write_concurrency, true}]},
  103 +% {?HISTOGRAM_TABLE, [set, named_table, public, {write_concurrency, true}]},
  104 +% {?METER_TABLE, [set, named_table, public, {write_concurrency, true}]},
  105 +% {?HISTORY_TABLE, [set, named_table, public, {write_concurrency, true}]}
  106 +% ],
  107 +% [maybe_create_table(ets:info(Name), Name, Opts) || {Name, Opts} <- Tables],
  108 +% ok.
  109 +
  110 +%maybe_create_table(undefined, Name, Opts) ->
  111 +% ets:new(Name, Opts);
  112 +%maybe_create_table(_, _, _) ->
  113 +% ok.
133 test/webmachine_mochiweb.erl
... ... @@ -0,0 +1,133 @@
  1 +%% @author Justin Sheehy <justin@basho.com>
  2 +%% @author Andy Gross <andy@basho.com>
  3 +%% @copyright 2007-2008 Basho Technologies
  4 +%%
  5 +%% Licensed under the Apache License, Version 2.0 (the "License");
  6 +%% you may not use this file except in compliance with the License.
  7 +%% You may obtain a copy of the License at
  8 +%%
  9 +%% http://www.apache.org/licenses/LICENSE-2.0
  10 +%%
  11 +%% Unless required by applicable law or agreed to in writing, software
  12 +%% distributed under the License is distributed on an "AS IS" BASIS,
  13 +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 +%% See the License for the specific language governing permissions and
  15 +%% limitations under the License.
  16 +
  17 +%% @doc Mochiweb interface for webmachine.
  18 +-module(webmachine_mochiweb).
  19 +-author('Justin Sheehy <justin@basho.com>').
  20 +-author('Andy Gross <andy@basho.com>').
  21 +-export([start/1, stop/0, loop/1]).
  22 +
  23 +start(Options) ->
  24 + {DispatchList, Options1} = get_option(dispatch, Options),
  25 + {ErrorHandler0, Options2} = get_option(error_handler, Options1),
  26 + {EnablePerfLog, Options3} = get_option(enable_perf_logger, Options2),
  27 + ErrorHandler =
  28 + case ErrorHandler0 of
  29 + undefined ->
  30 + webmachine_error_handler;
  31 + EH -> EH
  32 + end,
  33 + {LogDir, Options4} = get_option(log_dir, Options3),
  34 + case whereis(webmachine_logger) of
  35 + undefined ->
  36 + webmachine_sup:start_logger(LogDir);
  37 + _ ->
  38 + ignore
  39 + end,
  40 + case EnablePerfLog of
  41 + true ->
  42 + case whereis(webmachine_perf_logger) of
  43 + undefined ->
  44 + application_set_unless_env(webmachine, enable_perf_logger, true),
  45 + webmachine_sup:start_perf_logger(LogDir);
  46 + _ ->
  47 + ignore
  48 + end;
  49 + _ ->
  50 + ignore
  51 + end,
  52 + {PName, Options5} = case get_option(name, Options4) of
  53 + {undefined, _} -> {?MODULE, Options4};
  54 + {PN, O5} -> {PN, O5}
  55 + end,
  56 + application_set_unless_env(webmachine, dispatch_list, DispatchList),
  57 + application_set_unless_env(webmachine, error_handler, ErrorHandler),
  58 + mochiweb_http:start([{name, PName}, {loop, fun loop/1} | Options5]).
  59 +
  60 +stop() ->
  61 + {registered_name, PName} = process_info(self(), registered_name),
  62 + mochiweb_http:stop(PName).
  63 +
  64 +loop(MochiReq) ->
  65 + Req = webmachine:new_request(mochiweb, MochiReq),
  66 + {ok, DispatchList} = application:get_env(webmachine, dispatch_list),
  67 + Host = case host_headers(Req) of
  68 + [H|_] -> H;
  69 + [] -> []
  70 + end,
  71 + {Path, _} = Req:path(),
  72 + {RD, _} = Req:get_reqdata(),
  73 +
  74 + %% Run the dispatch code, catch any errors...
  75 + try webmachine_dispatcher:dispatch(Host, Path, DispatchList, RD) of
  76 + {no_dispatch_match, _UnmatchedHost, _UnmatchedPathTokens} ->
  77 + handle_error(404, {none, none, []}, Req);
  78 + {Mod, ModOpts, HostTokens, Port, PathTokens, Bindings,
  79 + AppRoot, StringPath} ->
  80 + BootstrapResource = webmachine_resource:new(x,x,x,x),
  81 + {ok,RS1} = Req:load_dispatch_data(Bindings,HostTokens,Port,
  82 + PathTokens,AppRoot,StringPath),
  83 + XReq1 = {webmachine_request,RS1},
  84 + try
  85 + {ok, Resource} = BootstrapResource:wrap(Mod, ModOpts),
  86 + {ok,RS2} = XReq1:set_metadata('resource_module', Mod),
  87 + webmachine_decision_core:handle_request(Resource, RS2)
  88 + catch
  89 + error:Error ->
  90 + handle_error(500, {error, Error}, Req)
  91 + end
  92 + catch
  93 + Type : Error ->
  94 + handle_error(500, {Type, Error}, Req)
  95 + end.
  96 +
  97 +handle_error(Code, Error, Req) ->
  98 + {ok, ErrorHandler} = application:get_env(webmachine, error_handler),
  99 + {ErrorHTML,ReqState1} =
  100 + ErrorHandler:render_error(Code, Req, Error),
  101 + Req1 = {webmachine_request,ReqState1},
  102 + {ok,ReqState2} = Req1:append_to_response_body(ErrorHTML),
  103 + Req2 = {webmachine_request,ReqState2},
  104 + {ok,ReqState3} = Req2:send_response(Code),
  105 + Req3 = {webmachine_request,ReqState3},
  106 + {LogData,_ReqState4} = Req3:log_data(),
  107 + case application:get_env(webmachine,webmachine_logger_module) of
  108 + {ok, LogModule} ->
  109 + spawn(LogModule, log_access, [LogData]);
  110 + _ -> nop
  111 + end.
  112 +
  113 +
  114 +
  115 +get_option(Option, Options) ->
  116 + {proplists:get_value(Option, Options), proplists:delete(Option, Options)}.
  117 +
  118 +application_set_unless_env(App, Var, Value) ->
  119 + Current = application:get_all_env(App),
  120 + CurrentKeys = proplists:get_keys(Current),
  121 + case lists:member(Var, CurrentKeys) of
  122 + true ->
  123 + ok;
  124 + false ->
  125 + application:set_env(App, Var, Value)
  126 + end.
  127 +
  128 +host_headers(Req) ->
  129 + [ V || {V,_ReqState} <- [Req:get_header_value(H)
  130 + || H <- ["x-forwarded-host",
  131 + "x-forwarded-server",
  132 + "host"]],
  133 + V /= undefined].

0 comments on commit fa43cde

Please sign in to comment.
Something went wrong with that request. Please try again.