%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you 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(thrift_transport_state_test). -behaviour(gen_server). -behaviour(thrift_transport). %% API -export([new/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% thrift_transport callbacks -export([write/2, read/2, flush/1, close/1]). -record(trans, {wrapped, % #thrift_transport{} version :: integer(), counter :: pid() }). -type state() :: #trans{}. -include("thrift_transport_behaviour.hrl"). -record(state, {cversion :: integer()}). new(WrappedTransport) -> case gen_server:start_link(?MODULE, [], []) of {ok, Pid} -> Trans = #trans{wrapped = WrappedTransport, version = 0, counter = Pid}, thrift_transport:new(?MODULE, Trans); Else -> Else end. %%==================================================================== %% thrift_transport callbacks %%==================================================================== write(Transport0 = #trans{wrapped = Wrapped0}, Data) -> Transport1 = check_version(Transport0), {Wrapped1, Result} = thrift_transport:write(Wrapped0, Data), Transport2 = Transport1#trans{wrapped = Wrapped1}, {Transport2, Result}. flush(Transport0 = #trans{wrapped = Wrapped0}) -> Transport1 = check_version(Transport0), {Wrapped1, Result} = thrift_transport:flush(Wrapped0), Transport2 = Transport1#trans{wrapped = Wrapped1}, {Transport2, Result}. close(Transport0 = #trans{wrapped = Wrapped0}) -> Transport1 = check_version(Transport0), shutdown_counter(Transport1), {Wrapped1, Result} = thrift_transport:close(Wrapped0), Transport2 = Transport1#trans{wrapped = Wrapped1}, {Transport2, Result}. read(Transport0 = #trans{wrapped = Wrapped0}, Len) -> Transport1 = check_version(Transport0), {Wrapped1, Result} = thrift_transport:read(Wrapped0, Len), Transport2 = Transport1#trans{wrapped = Wrapped1}, {Transport2, Result}. %%==================================================================== %% gen_server callbacks %%==================================================================== init([]) -> {ok, #state{cversion = 0}}. handle_call(check_version, _From, State = #state{cversion = Version}) -> {reply, Version, State#state{cversion = Version+1}}. handle_cast(shutdown, State) -> {stop, normal, State}. handle_info(_Info, State) -> {noreply, State}. code_change(_OldVsn, State, _Extra) -> {ok, State}. terminate(_Reason, _State) -> ok. %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- check_version(Transport = #trans{version = Version, counter = Counter}) -> case gen_server:call(Counter, check_version) of Version -> Transport#trans{version = Version+1}; _Else -> % State wasn't propagated properly. Die. erlang:error(state_not_propagated) end. shutdown_counter(#trans{counter = Counter}) -> gen_server:cast(Counter, shutdown).