Browse Source

Merge pull request #1755 from waiteb3/chicagoboss

Add Chicagoboss
Nate 9 years ago
parent
commit
931b44c5f5

+ 1 - 0
.travis.yml

@@ -45,6 +45,7 @@ env:
     - "TESTDIR=Dart/stream"
     - "TESTDIR=Elixir/phoenix"
     - "TESTDIR=Elixir/cowboy"
+    - "TESTDIR=Erlang/chicagoboss"
     - "TESTDIR=Erlang/cowboy"
     - "TESTDIR=Erlang/elli"
     - "TESTDIR=Go/beego"

+ 4 - 0
frameworks/Erlang/chicagoboss/.gitignore

@@ -0,0 +1,4 @@
+erl_crash.dump
+deps
+ebin
+.rebar

+ 23 - 0
frameworks/Erlang/chicagoboss/benchmark_config.json

@@ -0,0 +1,23 @@
+{
+  "framework": "chicagoboss",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "plaintext_url": "/plaintext",
+      "json_url": "/json",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "chicagoboss",
+      "language": "Erlang",
+      "orm": "raw",
+      "platform": "cowboy",
+      "webserver": "cowboy",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "ChicagoBoss",
+      "notes": "",
+      "versus": ""
+  }}]
+}

+ 320 - 0
frameworks/Erlang/chicagoboss/boss.config

@@ -0,0 +1,320 @@
+%% vim: ts=4 sw=4 et ft=erlang
+%%%
+%%% CHICAGO BOSS PROJECT SKELETON
+%%%
+%%% This file can be modified by you to avoid you needing to reenter
+%%% defaults when creating new projects.  For full configuration
+%%% details, please visit
+%%% https://github.com/ChicagoBoss/ChicagoBoss/wiki/Configuration
+
+%%% When running tests, you may want to create a separate configuration file
+%%% "boss.test.config" which, if present, will be read instead of boss.config.
+
+[{boss, [
+    {path, "./deps/boss"},
+    {applications, [chicagoboss]},
+    {assume_locale, "en"},
+
+%%%%%%%%%%%%
+%% System %%
+%%%%%%%%%%%%
+
+%% vm_cookie - Erlang cookie, must be the same for all nodes in the
+%%   cluster.
+
+%% vm_name - Node name to use in production. Must be unique for all
+%%   nodes in the cluster. Defaults to <application_name>@<host_name>.
+%% vm_sname - Node name to use if you wish to use a "short name" instead of a
+%%   full name.
+%% vm_max_processes - The limit of processes that the VM is allowed to
+%%   spawn. Defaults to 32768 (the usual system default).
+
+%    {vm_cookie, "secret"},
+%    {vm_name, "leader@localhost"}
+%    {vm_sname, "shortname"},
+%    {vm_max_processes, 32768},
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%
+%% Controller Filters %%
+%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% controller_filter_config - Specify defaults for controller filters
+%%   Sub-key 'lang' can be set to the atom 'auto' to autodetermine language
+%%     universally, or can be set to a specific language by setting a string (e.g.
+%%     "en" or "de")
+
+%    {controller_filter_config, [
+%        {lang, auto}
+%    ]},
+
+%%%%%%%%%%%%%%
+%% Compiler %%
+%%%%%%%%%%%%%%
+
+%% See compile(3) for a full list of options
+
+%    {compiler_options, [return_errors]},
+
+%%%%%%%%%%%
+%% Cache %%
+%%%%%%%%%%%
+
+%% cache_adapter - Which cache adapter to use. Currently the only
+%%   valid value is memcached_bin.
+%% cache_enable - Whether to enable the cache. Defaults to false.
+%% cache_servers - A list of cache servers ({Host, Port,
+%%   PoolSize}). Defaults to [{"localhost", 11211, 1}].
+%% cache_exp_time- The maximum time to keep a cache entry, in
+%%   seconds. Defaults to 60.
+
+%    {cache_adapter, memcached_bin},
+%    {cache_enable, false},
+%    {cache_servers, [{"localhost", 11211, 1}]},
+%    {cache_exp_time, 60}, 
+
+%%%%%%%%%%%%%%
+%% Database %%
+%%%%%%%%%%%%%%
+
+%% db_host - The hostname of the database. Defaults to "localhost".
+%% db_port - The port of the database. Defaults to 1978.
+%% db_adapter - The database adapter to use. Valid values are: 
+%%     mock - In-memory (non-persistent) database, useful for testing
+%%     mnesia - Mnesia
+%%     mongodb- MongoDB
+%%     mysql - MySQL
+%%     pgsql - PostgreSQL
+%%     riak - Riak
+%%     tyrant - Tokyo Tyrant
+%% db_username - The username used for connecting to the database (if
+%%   needed).
+%% db_password - The password used for connecting to the database (if
+%%   needed).
+%% db_database - The name of the database to connect to (if needed).
+%% db_cache_enable - Whether to enable the cache in boss_db. Defaults 
+%%   to false. Requires cache_enable to be set to true.
+
+    {db_host, "localhost"},
+    {db_port, 1978},
+    {db_adapter, mock},
+%    {db_username, "boss"},
+%    {db_password, "boss"},
+%    {db_database, "boss"},
+
+%%  MongoDB only
+%%
+%% Read https://github.com/TonyGen/mongodb-erlang#readme for details
+%% db_write_mode - defaults to safe
+%% db_read_mode - defaults to master
+%    {db_write_mode, safe},
+%    {db_read_mode, master},
+
+%% Database sharding
+%% A list of proplists with per-shard database configuration. 
+%% The proplists override the above options, and should contain two
+%% additional options: 
+%%  {db_shards, [ 
+%%      [ 
+%%          {db_host, "localhost"}, 
+%%          {db_adapter, mysql}, 
+%%          {db_port, 3306}, 
+%%          {db_username, "dbuser"}, 
+%%          {db_password, "dbpass"}, 
+%%          {db_database, "database"},
+%%          {db_shard_id, shard_id_atom}, 
+%%          {db_shard_models, [model_atom_1, model_atom_2,
+%%                             model_atom_3, etc]}  
+%%      ] 
+%%  ]},
+
+%%%%%%%%%%
+%% Mail %%
+%%%%%%%%%%
+
+%% mail_driver - The email delivery driver to use. Valid values are:
+%%   boss_mail_driver_smtp - SMTP delivery. If mail_relay is present, 
+%%     it is used as a relay, otherwise direct delivery is attempted.
+%%   boss_mail_driver_mock - A black hole, useful for testing.
+%% mail_relay_host - The relay server for SMTP mail deliveries.
+%% mail_relay_username -The username used for connecting to the SMTP
+%%   relay (if needed).
+%% mail_relay_password -The password used for connecting to the SMTP
+%%   relay (if needed).
+
+%    {mail_driver, boss_mail_driver_mock},
+%    {mail_relay_host, "smtp.example.com"},
+%    {mail_relay_username, "[email protected]"},
+%    {mail_relay_password, "mailpassword"},
+
+
+%%%%%%%%%%%%%%%%%%
+%% Master Node  %%
+%%%%%%%%%%%%%%%%%%
+
+
+%% master_node - 
+%%   For distributed configurations, the name of the master node. 
+%%   The master node runs global services (incoming mail, message
+%%   queue, events, sessions).
+%%   Should be an atom, e.g. somenode@somehost. 
+%%   The node name is specified in the -sname or -name argument in the
+%%   startup script.
+
+%    {master_node, '[email protected]'},
+
+%%%%%%%%%%%%%%%
+%% Webserver %%
+%%%%%%%%%%%%%%%
+
+%% port - The port to run the server on. Defaults to 8001.
+%% server - The HTTP server to use. Valid values are: 
+%%   mochiweb - The Mochiweb Web Server
+%%   cowboy - The Cowboy Web Server (Comet, WebSockets, highly scalable, ...)
+    {port, 8080},
+    {server, cowboy},
+
+%%%%%%%%%%%%%%
+%% Websocket %%
+%%%%%%%%%%%%%%
+    %% you can specify a global timeout for your websocket connection
+    %% when a websocket is idle more than the timeout, it is closed by the webserver
+    %% and you receive in your handle_close function  {normal, timeout} as the
+    %% reason.
+
+    %{websocket_timeout, 5000},
+
+%%%%%%%%%%%%%%
+%% Sessions %%
+%%%%%%%%%%%%%%
+
+%% session_adapter - Selects the session driver to use. Valid values:
+%%   cache - Store sessions in the configured cache
+%%     servers. Requires cache_enable to be set to true.
+%%   ets (default)
+%%   mnesia
+
+%% session_enable - Whether to enable sessions. Defaults to true.
+%% session_key - Cookie key for sessions. Defaults to "_boss_session".
+%% session_exp_time - Expiration time in seconds for the session
+%%   cookie. Defaults to 525600, i.e. 6 days, 2 hours.
+%% session_mnesia_nodes, for {session_adapter, mnesia} only - List of
+%%   Mnesia nodes, defaults to node(). 
+%% session_domain - (optional, sets the Domain=x cookie option), 
+%%   this can be used by ex: to enable subdomain apps 
+%%     (*.domain.com) with the param ".domain.com" => {session_domain,
+%%     ".domain.com"}
+
+    {session_adapter, mock},
+    {session_key, "_boss_session"},
+    {session_exp_time, 525600},
+    {session_cookie_http_only, false},
+    {session_cookie_secure, false},
+%    {session_enable, true},
+%    {session_mnesia_nodes, [node()]}, % <- replace "node()" with a node name
+%    {session_domain, ".domain.com"},
+
+%%%%%%%%%%%%%%%
+%% Templates %%
+%%%%%%%%%%%%%%%
+
+%% template_tag_modules - List of external modules to search for
+%%   custom ErlyDTL tags.
+%% template_filter_modules - List of external modules to search for
+%%   custom ErlyDTL filters.
+%% template_auto_escape - Controls automatic HTML escaping of template
+%%   values. Enabled by default.
+    {template_tag_modules, []},
+    {template_filter_modules, []},
+    {template_auto_escape, true},
+
+%%%%%%%%%%%%%%%%%%%%%
+%% Incoming Emails %%
+%%%%%%%%%%%%%%%%%%%%%
+
+%% smtp_server_enable - Enable the SMTP server for incoming mail
+%% smtp_server_address - The address that the SMTP server should bind
+%%   to. Defaults to {0, 0, 0, 0} (all interfaces).
+%% smtp_server_domain - The host name of the SMTP server
+%% smtp_server_port - The port that the SMTP server should listen
+%%   on. Defaults to 25.
+
+%    {smtp_server_enable, false},
+%    {smtp_server_address, {0, 0, 0, 0}},
+%    {smtp_server_domain, "smtp.example.com"},
+%    {smtp_server_port, 25},
+
+%% smtp_server_protocol - The protocol that the SMTP server should
+%%   use. Valid values are:
+%%     tcp (default)
+%%     ssl
+%    {smtp_server_protocol, tcp},
+
+%%%%%%%%%
+%% SSL %%
+%%%%%%%%%
+
+%% ssl_enable - Enable HTTP over SSL
+%% ssl_options - SSL options; see ssl(3erl)
+
+%    {ssl_enable, true},
+%    {ssl_options, []},
+
+%%%%%%%%%%%%%%%%%%%%
+%% LOG FORMATTING %%
+%%%%%%%%%%%%%%%%%%%%
+
+%% Set log_stack_multiline to true to make stack traces more readable at the
+%% cost of spanning multiple lines
+
+%    {log_stack_multiline, true},
+
+     {dummy, true} % a final dummy option so we don't have to keep track of commas
+]},
+
+%% MESSAGE QUEUE
+
+{ tinymq, [
+%% max_age- Maximum age of messages in the [message queue], in
+%%   seconds. Defaults to 60.
+    % {max_age, 60}
+]},
+
+%%%%%%%%%%%%%
+%% Logging %%
+%%%%%%%%%%%%%
+
+%% Lager default config. 
+%% More info: https://github.com/basho/lager 
+
+{lager, [
+    {handlers, [
+      {lager_console_backend, info},
+      {lager_file_backend, [
+        {"log/error.log", error, 10485760, "$D0", 5},
+        {"log/console.log", info, 10485760, "$D0", 5}
+      ]}
+    ]},
+
+    %% Colored output, if you want to modify the colors, see
+    %% https://github.com/basho/lager/blob/master/src/lager.app.src
+    % {colored, true},
+
+    {dummy, true}
+  ]},
+
+%% APPLICATION CONFIGURATIONS
+
+%% domains - A list of domains to serve the application on
+%% static_prefix - The URL prefix of static assets
+%% doc_prefix - The URL prefix for developer documentation
+{ chicagoboss, [
+    {path, "../chicagoboss"},
+    {base_url, "/"},
+%    {domains, all},
+%    {static_prefix, "/static"},
+%    {doc_prefix, "/doc"},
+
+    {dummy, true}
+]}
+].

+ 28 - 0
frameworks/Erlang/chicagoboss/priv/chicagoboss.routes

@@ -0,0 +1,28 @@
+% Routes file.
+
+% Formats: 
+%   {"/some/route", [{controller, "Controller"}, {action, "Action"}]}.
+%   {"/some/route", [{controller, "Controller"}, {action, "Action"}, {id, "42"}]}.
+%   {"/(some|any)/route/(\\d+)", [{controller, '$1'}, {action, "Action"}, {id, '$2'}]}.
+%   {"/some/route/(?<route_id>\\d+)", [{controller, "Controller"}, {action, "Action"}, {id, '$route_id'}]}.
+%   {"/some/route", [{application, some_app}, {controller, "Controller"}, {action, "Action"}, {id, "42"}]}.
+%
+%   {404, [{controller, "Controller"}, {action, "Action"}]}.
+%   {404, [{controller, "Controller"}, {action, "Action"}, {id, "42"}]}.
+%   {404, [{application, some_app}, {controller, "Controller"}, {action, "Action"}, {id, "42"}]}.
+%
+% Note that routing across applications results in a 302 redirect.
+
+% Front page
+%{"/", [{controller, "plaintext"}, {action, "index"}]}.
+
+% 404 File Not Found handler
+% {404, [{controller, "world"}, {action, "lost"}]}.
+
+% 500 Internal Error handler (only invoked in production)
+% {500, [{controller, "world"}, {action, "calamity"}]}.
+
+{"/plaintext", [{controller, "world"}, {action, "plaintext"}]}.
+{"/json", [{controller, "world"}, {action, "json"}]}.
+{"/", [{controller, "world"}, {action, "plaintext"}]}.
+

+ 97 - 0
frameworks/Erlang/chicagoboss/priv/init/chicagoboss_01_news.erl

@@ -0,0 +1,97 @@
+-module(chicagoboss_01_news).
+
+-export([init/0, stop/1]).
+
+% This script is first executed at server startup and should
+% return a list of WatchIDs that should be cancelled in the stop
+% function below (stop is executed if the script is ever reloaded).
+init() ->
+    {ok, []}.
+
+stop(ListOfWatchIDs) ->
+    lists:map(fun boss_news:cancel_watch/1, ListOfWatchIDs).
+
+%%%%%%%%%%% Ideas
+%    boss_news:watch("user-42.*",
+%        fun
+%            (updated, {Donald, 'location', OldLocation, NewLocation}) ->
+%                ;
+%            (updated, {Donald, 'email_address', OldEmail, NewEmail})
+%        end),
+%
+%    boss_news:watch("user-*.status",
+%        fun(updated, {User, 'status', OldStatus, NewStatus}) ->
+%                Followers = User:followers(),
+%                lists:map(fun(Follower) ->
+%                            Follower:notify_status_update(User, NewStatus)
+%                    end, Followers)
+%        end),
+%
+%    boss_news:watch("users",
+%        fun
+%            (created, NewUser) ->
+%                boss_mail:send(?WEBSITE_EMAIL_ADDRESS,
+%                    ?ADMINISTRATOR_EMAIL_ADDRESS,
+%                    "New account!",
+%                    "~p just created an account!~n",
+%                    [NewUser:name()]);
+%            (deleted, OldUser) ->
+%                ok
+%        end),
+%    
+%    boss_news:watch("forum_replies",
+%        fun
+%            (created, Reply) ->
+%                OrignalPost = Reply:original_post(),
+%                OriginalAuthor = OriginalPost:author(),
+%                case OriginalAuthor:is_online() of
+%                    true ->
+%                        boss_mq:push(OriginalAuthor:comet_channel(), <<"Someone replied!">>);
+%                    false ->
+%                        case OriginalAuthor:likes_email() of
+%                            true ->
+%                                boss_mail:send("website@blahblahblah",
+%                                    OriginalAuthor:email_address(),
+%                                    "Someone replied!"
+%                                    "~p has replied to your post on ~p~n",
+%                                    [(Reply:author()):name(), OriginalPost:title()]);
+%                            false ->
+%                                ok
+%                        end
+%                end;
+%            (_, _) -> ok
+%        end),
+%    
+%    boss_news:watch("forum_categories",
+%        fun
+%            (created, NewCategory) ->
+%                boss_mail:send(?WEBSITE_EMAIL_ADDRESS,
+%                    ?ADMINISTRATOR_EMAIL_ADDRESS,
+%                    "New category: "++NewCategory:name(),
+%                    "~p has created a new forum category called \"~p\"~n",
+%                    [(NewCategory:created_by()):name(), NewCategory:name()]);
+%            (_, _) -> ok
+%        end),
+%
+%    boss_news:watch("forum_category-*.is_deleted",
+%        fun 
+%            (updated, {ForumCategory, 'is_deleted', false, true}) ->
+%                ;
+%            (updated, {ForumCategory, 'is_deleted', true, false}) ->
+%        end).
+
+% Invoking the API directly:
+%boss_news:deleted("person-42", OldAttrs),
+%boss_news:updated("person-42", OldAttrs, NewAttrs),
+%boss_news:created("person-42", NewAttrs)
+
+% Invoking the API via HTTP (with the admin application installed):
+% POST /admin/news_api/deleted/person-42
+% old[status] = something
+
+% POST /admin/news_api/updated/person-42
+% old[status] = blah
+% new[status] = barf
+
+% POST /admin/news_api/created/person-42
+% new[status] = something

+ 191 - 0
frameworks/Erlang/chicagoboss/priv/rebar/boss_plugin.erl

@@ -0,0 +1,191 @@
+%%%-------------------------------------------------------------------
+%%% @author Jose Luis Gordo Romero <[email protected]>
+%%% @doc Chicago Boss rebar plugin
+%%%  Manage compilation/configuration/scripts stuff the rebar way
+%%% @end
+%%%-------------------------------------------------------------------
+-module(boss_plugin).
+
+-export([boss/2,
+     pre_compile/2,
+     pre_eunit/2]).
+
+-define(BOSS_PLUGIN_CLIENT_VERSION, 1).
+-define(BOSS_CONFIG_FILE, "boss.config").
+-define(BOSS_TEST_CONFIG_FILE, "boss.test.config").
+
+%% ====================================================================
+%% Public API
+%% ====================================================================
+
+%%--------------------------------------------------------------------
+%% @doc boss command
+%% @spec boss(_Config, _AppFile) -> ok | {error, Reason}
+%%       Boss enabled rebar commands, usage:
+%%       ./rebar boss c=command
+%% @end
+%%--------------------------------------------------------------------
+boss(RebarConf, AppFile) ->
+  case is_base_dir(RebarConf) of
+    true -> 
+      Command = rebar_config:get_global(RebarConf, c, "help"),
+      {ok, BossConf} = init(RebarConf, AppFile, Command),
+      case boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, Command, RebarConf, BossConf, AppFile) of
+        {error, command_not_found} ->
+          io:format("ERROR: boss command not found.~n"), 
+          boss_rebar:help(),
+          halt(1);
+        {error, Reason} -> 
+          io:format("ERROR: executing ~s task: ~s~n", [Command, Reason]), 
+          halt(1);
+        ok -> ok
+      end;
+    false -> ok
+  end.
+
+%%--------------------------------------------------------------------
+%% @doc initializes the rebar boss connector plugin
+%% @spec init(Config, AppFile) -> {ok, BossConf} | {error, Reason}
+%%       Set's the ebin cb_apps and loads the connector 
+%% @end
+%%--------------------------------------------------------------------
+init(RebarConf, AppFile, Command) ->
+    %% Compile and load the boss_rebar code, this can't be compiled
+  %% as a normal boss lib without the rebar source dep
+  %% The load of ./rebar boss:
+  %% - Rebar itself searchs in rebar.config for {plugin_dir, ["priv/rebar"]}.
+  %% - Rebar itself compile this plugin and adds it to the execution chain
+  %% - This plugin compiles and loads the boss_rebar code in ["cb/priv/rebar"],
+  %%   so we can extend/bugfix/tweak the framework without the need of manually
+  %%   recopy code to user apps
+    {BossConf, BossConfFile} = boss_config(Command),
+  BossPath = case boss_config_value(boss, path, BossConf) of
+           {error, _} ->
+             filename:join([rebar_config:get_xconf(RebarConf, base_dir, undefined), "deps", "boss"]);
+           Val -> Val
+         end,
+  RebarErls = rebar_utils:find_files(filename:join([BossPath, "priv", "rebar"]), ".*\\.erl\$"),
+  
+  rebar_log:log(debug, "Auto-loading boss rebar modules ~p~n", [RebarErls]),
+  
+  lists:map(fun(F) ->
+            case compile:file(F, [binary]) of
+              error ->
+                io:format("FATAL: Failed compilation of ~s module~n", [F]),
+                halt(1);
+              {ok, M, Bin} ->
+                {module, _} = code:load_binary(M, F, Bin),
+                rebar_log:log(debug, "Loaded ~s~n", [M])
+            end
+        end, RebarErls),
+
+  %% add all cb_apps defined in config file to code path
+  %% including the deps ebin dirs
+  
+  case is_base_dir(RebarConf) of
+  true ->
+    code:add_paths(["ebin" | filelib:wildcard(rebar_config:get_xconf(RebarConf, base_dir, undefined) ++ "/deps/*/ebin")]);
+  false ->
+    code:add_paths(filelib:wildcard(rebar_utils:get_cwd() ++ "/../*/ebin"))
+  end,
+  %% Load the config in the environment
+  boss_rebar:init_conf(BossConf),
+  
+  {ok, BossConf}.
+  
+%%--------------------------------------------------------------------
+%% @doc pre_compile hook
+%% @spec pre_compile(_Config, AppFile) -> ok | {error, Reason}
+%%       Pre compile hook, compile the boss way
+%%       Compatibility hook, the normal ./rebar compile command works,
+%%         but only calls the ./rebar boss c=compile and halts (default
+%%         rebar task never hits)
+%% @end
+%%--------------------------------------------------------------------
+pre_compile(RebarConf, AppFile) ->
+  case is_boss_app(AppFile)  orelse is_base_dir(RebarConf) of
+    true -> 
+      {ok, BossConf} = init(RebarConf, AppFile, "compile"),
+      boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, compile, RebarConf, BossConf, AppFile),
+      halt(0);
+    false -> ok
+  end.
+
+%%--------------------------------------------------------------------
+%% @doc pre_eunit hook
+%% @spec pre_eunit(RebarConf, AppFile) -> ok | {error, Reason}
+%%       Pre eunit hook, .eunit compilation the boss way
+%%       Compatibility hook, the normal ./rebar eunit command works,
+%%         but only calls the ./rebar boss c=test_eunit and halts
+%%         (default rebar task never hits)
+%% @end
+%%--------------------------------------------------------------------
+pre_eunit(RebarConf, AppFile) ->
+  case is_boss_app(AppFile) orelse is_base_dir(RebarConf) of
+    true -> 
+      {ok, BossConf} = init(RebarConf, AppFile, "test_eunit"),
+      boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, test_eunit, RebarConf, BossConf, AppFile),
+      halt(0);
+    false -> ok
+  end.
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+is_boss_app(Filename)->
+  BossFileForApp = filename:join([filename:dirname(Filename), "..", "boss.config"]),
+  filelib:is_file(BossFileForApp).
+
+%% Checks if the current dir (rebar execution) is the base_dir
+%% Used to prevent run boss tasks in deps directory
+is_base_dir(RebarConf) ->
+    filename:absname(rebar_utils:get_cwd()) =:= rebar_config:get_xconf(RebarConf, base_dir, undefined).
+
+%% Gets the boss.config central configuration file
+boss_config(Command) ->
+    IsTest		= lists:prefix("test_", Command),
+    BossConfFile	= get_config_file(IsTest),
+    ConfigData		= file:consult(BossConfFile),
+    validate_config_data(BossConfFile, ConfigData).
+
+get_config_file(false) ->
+	    ?BOSS_CONFIG_FILE;
+get_config_file(true) ->
+    case file:read_file_info(?BOSS_TEST_CONFIG_FILE) of
+	{ok, _} -> ?BOSS_TEST_CONFIG_FILE;
+	_ -> ?BOSS_CONFIG_FILE
+    end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+validate_config_data(BossConfFile, {error, {Line, _Mod, [Term|_]}}) ->
+    io:format("FATAL: Config file ~p has a syntax error on line ~p, ~n ~p ~n~n", 
+	      [BossConfFile, Line,  Term]),
+    halt(1);
+validate_config_data(BossConfFile, {error, enoent}) ->
+    io:format("FATAL: Config file ~p not found.~n", [BossConfFile]),
+    halt(1);
+validate_config_data(BossConfFile, {ok, [BossConfig]}) ->
+    {BossConfig, BossConfFile}.
+    
+
+
+%%--------------------------------------------------------------------
+%% @doc Get Boss config value app, key
+%% @spec boss_config_value(App, Key) -> Value | {error, Reason}
+%%       Searchs in boss config for a given App and Key
+%% @end
+%%--------------------------------------------------------------------
+boss_config_value(App, Key, BossConfig) ->
+  case lists:keyfind(App, 1, BossConfig) of
+    false -> 
+      {error, boss_config_app_not_found};
+    {App, AppConfig} -> 
+      case lists:keyfind(Key, 1, AppConfig) of
+        false -> 
+          {error, boss_config_app_setting_not_found};
+        {Key, KeyConfig} ->
+          KeyConfig
+      end
+  end.

+ 7 - 0
frameworks/Erlang/chicagoboss/rebar.config

@@ -0,0 +1,7 @@
+{deps, [
+  {boss, ".*", {git, "git://github.com/ChicagoBoss/ChicagoBoss.git", {tag, "v0.8.19"}}}
+]}.
+{plugin_dir, ["priv/rebar"]}.
+{plugins, [boss_plugin]}.
+{eunit_compile_opts, [{src_dirs, ["src/test"]}]}.
+{lib_dirs, ["../ChicagoBoss/deps/elixir/lib"]}.

+ 11 - 0
frameworks/Erlang/chicagoboss/setup.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+
+sed -i 's|"benchmarkdbpass", ".*", 3306|"benchmarkdbpass", "'"${DBHOST}"'", 3306|g' boss.config
+
+fw_depends erlang
+
+rm -rf deps/* ebin/*
+rebar get-deps
+rebar compile
+
+erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -config boss -s boss -sname chicagoboss -noshell -detached

+ 8 - 0
frameworks/Erlang/chicagoboss/src/chicagoboss.app.src

@@ -0,0 +1,8 @@
+{application, chicagoboss, [
+        {description, "My Awesome Web Framework"},
+        {vsn, "0.0.1"},
+        {modules, []},
+        {registered, []},
+        {applications, [kernel, stdlib, crypto]},
+        {env, []}
+    ]}.

+ 8 - 0
frameworks/Erlang/chicagoboss/src/controller/chicagoboss_world_controller.erl

@@ -0,0 +1,8 @@
+-module(chicagoboss_world_controller, [Req]).
+-compile(export_all).
+
+plaintext('GET', []) ->
+	{output, "Hello, world!", [{"Content-Type", "text/plain"}]}.
+
+json('GET', []) ->
+	{json, [{message, "Hello, world!"}]}.

+ 8 - 0
frameworks/Erlang/chicagoboss/src/mail/chicagoboss_incoming_mail_controller.erl

@@ -0,0 +1,8 @@
+-module(chicagoboss_incoming_mail_controller).
+-compile(export_all).
+
+authorize_(User, DomainName, IPAddress) ->
+    true.
+
+% post(FromAddress, Message) ->
+%    ok.

+ 12 - 0
frameworks/Erlang/chicagoboss/src/mail/chicagoboss_outgoing_mail_controller.erl

@@ -0,0 +1,12 @@
+-module(chicagoboss_outgoing_mail_controller).
+-compile(export_all).
+
+%% See http://www.chicagoboss.org/api-mail-controller.html for what should go in here
+
+test_message(FromAddress, ToAddress, Subject) ->
+    Headers = [
+        {"Subject", Subject},
+        {"To", ToAddress},
+        {"From", FromAddress}
+    ],
+    {ok, FromAddress, ToAddress, Headers, [{address, ToAddress}]}.