% ========================================================================================================== % MISULTIN - Example: Running Misultin from a gen_server. % % >-|-|-(°> % % Copyright (C) 2009, Roberto Ostinelli % All rights reserved. % % BSD License % % Redistribution and use in source and binary forms, with or without modification, are permitted provided % that the following conditions are met: % % * Redistributions of source code must retain the above copyright notice, this list of conditions and the % following disclaimer. % * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and % the following disclaimer in the documentation and/or other materials provided with the distribution. % * Neither the name of the authors nor the names of its contributors may be used to endorse or promote % products derived from this software without specific prior written permission. % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A % PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR % ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED % TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING % NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % ========================================================================================================== -module(misultin_gen_server). -behaviour(gen_server). % gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). % API -export([start_link/1, stop/0]). % records -record(state, { port }). % macros -define(SERVER, ?MODULE). % ============================ \/ API ====================================================================== % Function: {ok,Pid} | ignore | {error, Error} % Description: Starts the server. start_link(Port) -> gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []). % Function: -> ok % Description: Manually stops the server. stop() -> gen_server:cast(?SERVER, stop). % ============================ /\ API ====================================================================== % ============================ \/ GEN_SERVER CALLBACKS ===================================================== % ---------------------------------------------------------------------------------------------------------- % Function: -> {ok, State} | {ok, State, Timeout} | ignore | {stop, Reason} % Description: Initiates the server. % ---------------------------------------------------------------------------------------------------------- init([Port]) -> % trap_exit -> this gen_server needs to be supervised process_flag(trap_exit, true), % start misultin & set monitor misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req) end}]), erlang:monitor(process, misultin), {ok, #state{port = Port}}. % ---------------------------------------------------------------------------------------------------------- % Function: handle_call(Request, From, State) -> {reply, Reply, State} | {reply, Reply, State, Timeout} | % {noreply, State} | {noreply, State, Timeout} | % {stop, Reason, Reply, State} | {stop, Reason, State} % Description: Handling call messages. % ---------------------------------------------------------------------------------------------------------- % handle_call generic fallback handle_call(_Request, _From, State) -> {reply, undefined, State}. % ---------------------------------------------------------------------------------------------------------- % Function: handle_cast(Msg, State) -> {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State} % Description: Handling cast messages. % ---------------------------------------------------------------------------------------------------------- % manual shutdown handle_cast(stop, State) -> {stop, normal, State}; % handle_cast generic fallback (ignore) handle_cast(_Msg, State) -> {noreply, State}. % ---------------------------------------------------------------------------------------------------------- % Function: handle_info(Info, State) -> {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State} % Description: Handling all non call/cast messages. % ---------------------------------------------------------------------------------------------------------- % handle info when misultin server goes down -> take down misultin_gen_server too [the supervisor will take everything up again] handle_info({'DOWN', _, _, {misultin, _}, _}, State) -> {stop, normal, State}; % handle_info generic fallback (ignore) handle_info(_Info, State) -> {noreply, State}. % ---------------------------------------------------------------------------------------------------------- % Function: terminate(Reason, State) -> void() % Description: This function is called by a gen_server when it is about to terminate. When it returns, % the gen_server terminates with Reason. The return value is ignored. % ---------------------------------------------------------------------------------------------------------- terminate(_Reason, _State) -> % stop misultin misultin:stop(), terminated. % ---------------------------------------------------------------------------------------------------------- % Func: code_change(OldVsn, State, Extra) -> {ok, NewState} % Description: Convert process state when code is changed. % ---------------------------------------------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. % ============================ /\ GEN_SERVER CALLBACKS ===================================================== % ============================ \/ INTERNAL FUNCTIONS ======================================================= % ---------------------------- \/ misultin requests -------------------------------------------------------- handle_http(Req) -> % get params depending on method Method = Req:get(method), case Method of 'GET' -> Args = Req:parse_qs(); 'POST' -> Args = Req:parse_post() end, % build an XML with all parameters and values BuildXml = fun({Param, Value}, Acc) -> [lists:flatten(io_lib:format("~s~s", [Param, Value]))|Acc] end, Xml = lists:flatten(lists:reverse(lists:foldl(BuildXml, [], Args))), % output Req:ok([{"Content-Type", "text/xml"}], "~s~s", [Method, Xml]). % ---------------------------- /\ misultin requests -------------------------------------------------------- % ============================ /\ INTERNAL FUNCTIONS =======================================================