Skip to content
Browse files

created helper to generate record_utils dynamically for records

  • Loading branch information...
1 parent 180bb0d commit 0b13b0c4248d26c2d4f7c35474aef481055c2dd3 @trung committed Oct 6, 2009
Showing with 450 additions and 181 deletions.
  1. +10 −1 Makefile
  2. +2 −2 include/types.hrl
  3. +2 −0 src/Makefile
  4. +87 −49 src/amf0.erl
  5. +2 −2 src/amf3.erl
  6. +113 −0 src/record_helper.erl
  7. +172 −90 src/record_utils.erl
  8. +13 −0 src/registry.erl
  9. +6 −0 src/utils.erl
  10. +2 −0 support/include.mk
  11. +26 −35 test/amf0_test.erl
  12. +15 −2 test/record_utils_test.erl
View
11 Makefile
@@ -1,9 +1,18 @@
all:
+ (cd src;$(MAKE) generate)
(cd src;$(MAKE))
(cd test;$(MAKE))
+tests: all
+ @for f in $(patsubst ebin/%.beam,%,$(wildcard ebin/*_test.beam)) ; do echo "++++++ Running $$f ++++++" ; erl -noshell -pa ebin -s $$f test -s init stop ; done
+
test: all
- for f in $(patsubst ebin/%.beam,%,$(wildcard ebin/*_test.beam)) ; do echo "Running $$f" ; erl -noshell -pa ebin -s $$f test -s init stop ; done
+ ifdef m
+ @echo "++++++ Running $(m)_test ++++++"
+ @erl -noshell -pa ebin -s $(m)_test test -s init stop
+ else
+ @echo "Please specify module for test (m=xxx)"
+ endif
docs:
erl -pa `pwd`/ebin \
View
4 include/types.hrl
@@ -6,9 +6,9 @@
-record(ecma_array, {data = []}).
--record(asobject, {data = []}).
+-record(asobject, {array = []}).
-record(xml, {data = []}).
%% AMF3 custom types
--record(string_3, {data = ""}).
+-record(string_3, {data = ""}).
View
2 src/Makefile
@@ -2,6 +2,8 @@ include ../support/include.mk
all: $(EBIN_FILES_NO_DOCS)
+generate: $(EBIN_GENERATE)
+ erl -noshell -pa ../ebin -s record_helper make ../include/messages.hrl ../include/types.hrl -s init stop
debug:
$(MAKE) DEBUG=-DDEBUG
View
136 src/amf0.erl
@@ -95,7 +95,6 @@ read_date(Bin) ->
%% Just read, not use
{ok, _, BinAfterTimeZone} = read_u16(Bin),
{ok, TimeInMilli, NextBin} = read_number(BinAfterTimeZone),
- io:fwrite("~p~n", [TimeInMilli]),
%% convert to erlang date
Date = utils:milliseconds_to_date(TimeInMilli),
{ok, Date, NextBin}.
@@ -111,9 +110,25 @@ read_xml(Bin) ->
{ok, LongString, NextBin} = read_long_string(Bin),
{ok, #xml{data = LongString#long_string.data}, NextBin}.
+read_typed_object_property(Bin, Obj) ->
+ {ok, PropertyName, BinAfterName} = read_string(Bin),
+ case read_object(BinAfterName) of
+ {object_end_marker, NextBin, _} ->
+ {ok, Obj, NextBin};
+ {ok, ObjValue, NextBin} ->
+ {ok, NewObj, _} = record_utils:set(Obj, PropertyName, ObjValue),
+ read_typed_object_property(NextBin, NewObj)
+ end.
+
read_typed_object(Bin) ->
- {ok, _ClassName, _BinAfterClassName} = read_string(Bin),
- {bad, {"Not yet implemented", ?MODULE, ?LINE, Bin}}.
+ {ok, ClassName, BinAfterClassName} = read_string(Bin),
+ case registry:fc_to_record(ClassName#string.data) of
+ {ok, undefined} ->
+ % create asobject
+ read_typed_object_property(BinAfterClassName, #asobject{});
+ {ok, NewObject} ->
+ read_typed_object_property(BinAfterClassName, NewObject)
+ end.
read_null(Bin) ->
{ok, null, Bin}.
@@ -127,7 +142,7 @@ read_objects_until_end(Bin, Acc) ->
%% Always read value but be careful to ignore erroneous 'length' prop
%% that is sometimes sent by the player. (via BlazeDS)
if
- Name == "length" ->
+ Name#string.data == "length" ->
read_objects_until_end(NextBin, Acc);
true ->
read_objects_until_end(NextBin, Acc ++ [{Name, Obj}])
@@ -173,23 +188,41 @@ read_object(<<?avm_plus_object_marker:8, Rest/binary>>) -> amf3:read_object(Rest
%% Use xxx(marker, Value) to build binary with marker
%% ===========================================================
-write_object(marker, Value) ->
- {ok, Bin} = write_object(Value),
- write_object_now(?object_marker, Bin).
-
write_object(null) -> write_null();
write_object(true) -> write_boolean(true);
write_object(false) -> write_boolean(false);
write_object(Number) when is_number(Number) -> write_number(Number);
write_object(String) when is_record(String, string) -> write_string(String);
write_object(LongString) when is_record(LongString, long_string) -> write_long_string(LongString);
write_object(EcmaArray) when is_record(EcmaArray, ecma_array) -> write_ecma_array(EcmaArray);
-write_object({{Y, M, D}, {H, M, S}}) -> write_date({{Y, M, D}, {H, M, S}});
+write_object({{Ye, Mo, Da}, {Ho, Mi, Se}}) -> write_date({{Ye, Mo, Da}, {Ho, Mi, Se}});
write_object(Xml) when is_record(Xml, xml) -> write_xml(Xml);
-write_object(Obj) -> {bad, {"Unknown object", Obj}}.
-
+write_object(Array) when is_list(Array) -> write_strict_array(Array);
+write_object(Obj) ->
+ case registry:record_to_fc(Obj) of
+ {ok, undefined} ->
+ {bad, {"Unknown object", ?MODULE, ?LINE}};
+ {ok, ClassName} ->
+ {ok, ClassNameBin} = write_string(#string{data = ClassName}),
+ case record_utils:type(Obj) of
+ Type ->
+ Fields = record_utils:fields_atom(Type),
+ ObjBin = list_to_binary([write_object_info(Obj, X) || X <- Fields ]),
+ ObjEnd = write_object_end(),
+ write_object_now(?typed_object_marker, [ClassNameBin, ObjBin, ObjEnd]);
+ _ ->
+ {bad, {"Object type not found even it was registered", ClassName, Obj}}
+ end
+ end.
+write_object(ref, Ref) -> write_reference(Ref);
+write_object(amf3, Obj) -> amf3:write_object(Obj).
+write_object_info(Obj, Field) ->
+ {ok, FieldBin} = write_string(#string{data = atom_to_list(Field)}),
+ {ok, Value} = record_utils:get(Obj, Field),
+ {ok, ValueBin} = write_object(Value),
+ [FieldBin, ValueBin].
%% return {ok, ReturnBin} or {bad, Reason}
write_u8(Value) -> {ok, <<Value:8>>}.
@@ -201,93 +234,98 @@ write_u32(Value) -> {ok, <<Value:32>>}.
write_object_now(Marker, Bin) ->
{ok, list_to_binary([<<Marker:8>>, Bin])}.
-write_number(marker, Value) ->
- {ok, Bin} = write_number(Value),
+write_number(Value) ->
+ {ok, Bin} = number_to_binary(Value),
write_object_now(?number_marker, Bin).
-write_number(Value) ->
+number_to_binary(Value) ->
{ok, <<Value/float>>}.
-write_string(marker, Value) ->
- {ok, Bin} = write_string(Value),
+write_string(Value) ->
+ {ok, Bin} = string_to_binary(Value),
write_object_now(?string_marker, Bin).
%% write UTF-8-empty
-write_string(#string{data = Value}) when length(Value) == 0 ->
+string_to_binary(#string{data = Value}) when length(Value) == 0 ->
write_u16(0);
%% write utf8 string to binary
-write_string(#string{data = Value}) ->
+string_to_binary(#string{data = Value}) ->
Len = length(Value),
{ok, LenBin} = write_u16(Len),
{ok, StringBin} = utf8:to_binary(Value),
{ok, list_to_binary([LenBin, StringBin])}.
-write_long_string(marker, Value) ->
- {ok, Bin} = write_long_string(Value),
+write_long_string(Value) ->
+ {ok, Bin} = long_string_to_binary(Value),
write_object_now(?long_string_marker, Bin).
%% write utf8 long string to binary
-write_long_string(#long_string{data = Value}) ->
+long_string_to_binary(#long_string{data = Value}) ->
Len = length(Value),
{ok, LenBin} = write_u32(Len),
{ok, StringBin} = utf8:to_binary(Value),
{ok, list_to_binary([LenBin, StringBin])}.
-write_xml(marker, Value) ->
- {ok, Bin} = write_xml(Value),
+write_xml(Value) ->
+ {ok, Bin} = xml_to_binary(Value),
write_object_now(?xml_document_marker, Bin).
-write_xml(#xml{data = Value}) ->
- write_long_string(#long_string{data = Value}).
+xml_to_binary(#xml{data = Value}) ->
+ long_string_to_binary(#long_string{data = Value}).
-write_date(marker, Value) ->
- {ok, Bin} = write_date(Value),
+write_date(Value) ->
+ {ok, Bin} = date_to_binary(Value),
write_object_now(?date_marker, Bin).
-write_date({Date, Time}) -> write_date(utils:date_to_milliseconds({Date, Time}));
-write_date(Milliseconds) when is_number(Milliseconds) ->
+date_to_binary({Date, Time}) -> date_to_binary(utils:date_to_milliseconds({Date, Time}));
+date_to_binary(Milliseconds) when is_number(Milliseconds) ->
{ok, TimezoneBin} = write_u16(0), %% just for reserved, not used
- {ok, DateBin} = write_number(Milliseconds),
+ {ok, DateBin} = number_to_binary(Milliseconds),
{ok, list_to_binary([TimezoneBin, DateBin])}.
-write_boolean(marker, Value) ->
- {ok, Bin} = write_boolean(Value),
+write_boolean(Value) ->
+ {ok, Bin} = boolean_to_binary(Value),
write_object_now(?boolean_marker, Bin).
-write_boolean(true) -> write_u8(1);
-write_boolean(false) -> write_u8(0).
-
-write_strict_array(marker, Value) ->
- {bad, {"Not yet implemented", ?MODULE, ?LINE}}.
+boolean_to_binary(true) -> write_u8(1);
+boolean_to_binary(false) -> write_u8(0).
+%% input Value is the list of objects
write_strict_array(Value) ->
- {bad, {"Not yet implemented", ?MODULE, ?LINE}}.
+ {ok, Bin} = strict_array_to_binary(Value),
+ write_object_now(?strict_array_marker, Bin).
+
+item_to_binary(Obj) ->
+ {ok, Bin} = write_object(Obj),
+ Bin.
-write_typed_object(marker, Value) ->
- {ok, Bin} = write_typed_object(Value),
- write_object_now(?typed_object_marker, Bin).
+strict_array_to_binary(Value) ->
+ Len = length(Value),
+ {ok, LenBin} = write_u32(Len),
+ ObjBinArray = [ item_to_binary(X) || X <- Value ],
+ {ok, list_to_binary([LenBin, ObjBinArray])}.
write_typed_object(Value) ->
{bad, {"Not yet implemented", ?MODULE, ?LINE}}.
-write_reference(marker, Value) ->
- {ok, Bin} = write_reference(Value),
+write_reference(Value) ->
+ {ok, Bin} = reference_to_binary(Value),
write_object_now(?reference_marker, Bin).
-write_reference(Value) ->
+reference_to_binary(Value) ->
write_u16(Value).
-write_ecma_array(marker, Value) ->
- {ok, Bin} = write_ecma_array(Value),
+write_ecma_array(Value) ->
+ {ok, Bin} = ecma_array_to_binary(Value),
write_object_now(?ecma_array_marker, Bin).
write_ecma_array_item({Name, Value}) ->
- {ok, NameBin} = write_string(Name),
- {ok, ValueBin} = write_object(marker, Value),
+ {ok, NameBin} = string_to_binary(Name),
+ {ok, ValueBin} = write_object(Value),
[NameBin, ValueBin].
-write_ecma_array(#ecma_array{data = Value}) ->
+ecma_array_to_binary(#ecma_array{data = Value}) ->
{ok, LenBin} = write_u32(0),
ArrayBin = [write_ecma_array_item(X) || X <- Value],
{ok, ObjectEndBin} = write_object_end(),
View
4 src/amf3.erl
@@ -229,12 +229,12 @@ read_object_property(Bin, [PropertyStr|Tail], PropertyMap) when is_list(Property
read_object_property(NextBin, Tail, PropertyMap ++ [{PropertyStr, Value}]);
read_object_property(Bin, [PropertyStr|Tail], Object) ->
{ok, Value, NextBin} = read_object(Bin),
- PropertyName = record_utils:to_term(PropertyStr),
+ PropertyName = utils:to_term(PropertyStr#string_3.data),
{ok, NewObject, _} = record_utils:set(Object, PropertyName, Value),
read_object_property(NextBin, Tail, NewObject).
read_object_with_trait(Bin, TraitObj) when is_record(TraitObj, trait) ->
- case record_utils:fc_to_record(TraitObj#trait.className) of
+ case registry:fc_to_record((TraitObj#trait.className)#string_3.data) of
{ok, undefined} ->
{ok, PropertyMap, BinAfterProperty} = read_object_property(Bin, TraitObj#trait.properties, []),
{ok, PropertyMapAll, NextBin} = read_object_property(BinAfterProperty, {dynamic, TraitObj#trait.dynamic}, PropertyMap),
View
113 src/record_helper.erl
@@ -0,0 +1,113 @@
+%% For each header file, it scans thru all records and create helper functions
+-module(record_helper).
+-author("trung@mdkt.org").
+
+-export([make/1, make/2]).
+
+make(HeaderFiles) ->
+ make([ atom_to_list(X) || X <- HeaderFiles ], ".").
+
+%% .hrl file, relative to current dir
+make(HeaderFiles, OutDir) ->
+ ModuleName = "record_utils",
+ HeaderComment = "%% This is auto generated file. Please don't edit it\n\n",
+ ModuleDeclaration = "-module(" ++ ModuleName ++ ").\n"
+ ++ "-author(\"trung@mdkt.org\").\n"
+ ++ "-compile(export_all).\n"
+ ++ [ "-include(\"" ++ X ++ "\").\n" || X <- HeaderFiles ]
+ ++ "\n",
+ Src = format_src(lists:sort(lists:flatten([read(X) || X <- HeaderFiles]))),
+ file:write_file(OutDir++"/" ++ ModuleName ++ ".erl", list_to_binary([HeaderComment, ModuleDeclaration, Src])).
+
+read(HeaderFile) ->
+ try epp:parse_file(HeaderFile,[],[]) of
+ {ok, Tree} ->
+ parse(Tree)
+ catch
+ _:Error ->
+ {error, Error}
+ end.
+
+format_src([{_, _, _, Src}|T]) when length(T) == 0 ->
+ Src ++ ".\n\n";
+format_src([{Type, _, _, Src}|[{Type, A, B, NSrc}|T]]) ->
+ Src ++ ";\n\n" ++ format_src([{Type, A, B, NSrc}|T]);
+format_src([{_Type, _, _, Src}|[{Type1, A, B, NSrc}|T]]) ->
+ Src ++ ".\n\n" ++ format_src([{Type1, A, B, NSrc}|T]);
+format_src([{_, _, _, Src}|T]) when length(T) > 0 ->
+ Src ++ ";\n\n" ++ format_src(T).
+
+parse(Tree) ->
+ [ parse_record(X) || X <- Tree ].
+
+parse_record({attribute, _, record, RecordInfo}) ->
+ {RecordName, RecordFields} = RecordInfo,
+ if
+ length(RecordFields) == 1 ->
+ lists:flatten([ generate_setter_function(RecordName, X) || X <- RecordFields ]
+ ++ [generate_type_function(RecordName)]);
+ true ->
+ lists:flatten([generate_fields_function(RecordName, RecordFields)]
+ ++ [generate_fields_atom_function(RecordName, RecordFields)]
+ ++ [ generate_setter_function(RecordName, X) || X <- RecordFields ]
+ ++ [generate_type_function(RecordName)])
+ end;
+parse_record(_) -> [].
+
+parse_field_name({record_field, _, {atom, _, FieldName}}) ->
+ "\"" ++ atom_to_list(FieldName) ++ "\"";
+parse_field_name({record_field, _, {atom, _, FieldName}, _}) ->
+ "\"" ++ atom_to_list(FieldName) ++ "\"".
+
+parse_field_name_atom({record_field, _, {atom, _, FieldName}}) ->
+ atom_to_list(FieldName);
+parse_field_name_atom({record_field, _, {atom, _, FieldName}, _}) ->
+ atom_to_list(FieldName).
+
+parse_field([F|T]) when length(T) == 0 -> parse_field_name(F);
+parse_field([F|T]) ->
+ parse_field_name(F) ++ ", " ++ parse_field(T).
+
+parse_field_atom([F|T]) when length(T) == 0 -> parse_field_name_atom(F);
+parse_field_atom([F|T]) ->
+ parse_field_name_atom(F) ++ ", " ++ parse_field_atom(T).
+
+generate_type_function(RecordName) ->
+ {type, RecordName, 0, "type(Obj) when is_record(Obj, " ++ atom_to_list(RecordName) ++ ") -> " ++ atom_to_list(RecordName)}.
+
+generate_fields_function(RecordName, RecordFields) ->
+ Fields = parse_field(RecordFields),
+ {field, RecordName, 1, "fields(" ++ atom_to_list(RecordName) ++ ") -> \n\t[" ++ Fields ++ "]"}.
+
+generate_fields_atom_function(RecordName, RecordFields) ->
+ Fields = parse_field_atom(RecordFields),
+ {field_atom, RecordName, 1, "fields_atom(" ++ atom_to_list(RecordName) ++ ") -> \n\t[" ++ Fields ++ "]"}.
+
+generate_setter_function(RecordName, {record_field, _, {atom, _, FieldName}, {record, _, ParentRecordName, _}}) ->
+ to_setter_function(atom_to_list(RecordName), atom_to_list(FieldName), atom_to_list(ParentRecordName));
+generate_setter_function(RecordName, {record_field, _, {atom, _, array}, _}) ->
+ to_setter_function(atom_to_list(RecordName));
+generate_setter_function(RecordName, {record_field, _, {atom, _, FieldName}, _}) ->
+ to_setter_function(atom_to_list(RecordName), atom_to_list(FieldName));
+generate_setter_function(RecordName, {record_field, _, {atom, _, FieldName}}) ->
+ to_setter_function(atom_to_list(RecordName), atom_to_list(FieldName)).
+
+%% when field name is array of object
+to_setter_function(RecordName) ->
+ {setter, RecordName, 1, "set(Obj, PropertyName, Value) when is_record(Obj, " ++ RecordName ++ ") -> \n"
+ ++ "\tNewObj = #" ++ RecordName ++ "{array = Obj#" ++ RecordName ++ ".array ++ [{PropertyName, Value}]},\n"
+ ++ "\t{ok, NewObj, {array, Value}}"}.
+
+to_setter_function(RecordName, FieldName) ->
+ %% setters
+ {setter, RecordName, 1, "set(Obj, " ++ FieldName ++ ", Value) when is_record(Obj, " ++ RecordName ++ ") -> \n"
+ ++ "\tNewObj = Obj#" ++ RecordName ++ "{" ++ FieldName ++ " = Value},\n"
+ ++ "\t{ok, NewObj, {" ++ FieldName ++ ", Value}}"}.
+
+to_setter_function(RecordName, FieldName, ParentRecordName) ->
+ {setter, RecordName, 2, "set(Obj, " ++ FieldName ++ ", Value) when is_record(Obj, " ++ RecordName ++ ") and is_record(Value, " ++ ParentRecordName ++ ") -> \n"
+ ++ "\tNewObj = Obj#" ++ RecordName ++ "{" ++ FieldName ++ " = Value},\n"
+ ++ "\t{ok, NewObj, {" ++ FieldName ++ ", Value}};\n\n"
+ ++ "set(Obj, ParentProperty, Value) when is_record(Obj, " ++ RecordName ++ ") and is_atom(ParentProperty) -> \n"
+ ++ "\t{ok, NewParentObject, _} = set(Obj#" ++ RecordName ++ ".parent, ParentProperty, Value),\n"
+ ++ "\tset(Obj, parent, NewParentObject)"}.
View
262 src/record_utils.erl
@@ -1,94 +1,176 @@
+%% This is auto generated file. Please don't edit it
+
-module(record_utils).
-author("trung@mdkt.org").
-compile(export_all).
-
-include("../include/messages.hrl").
--include("../include/flex_classes.hrl").
--include ("../include/types.hrl").
-
-%% Setters for records defined in messages.hrl file
-%% return {ok, NewObject, {propertyName, NewValue}}
-set(Obj, clientId, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{clientId = Value},
- {ok, NewObj, {clientId, Value}};
-set(Obj, destination, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{destination = Value},
- {ok, NewObj, {destination, Value}};
-set(Obj, messageId, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{messageId = Value},
- {ok, NewObj, {messageId, Value}};
-set(Obj, timestamp, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{timestamp = Value},
- {ok, NewObj, {timestamp, Value}};
-set(Obj, timeToLive, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{timeToLive = Value},
- {ok, NewObj, {timeToLive, Value}};
-set(Obj, headers, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{headers = Value},
- {ok, NewObj, {headers, Value}};
-set(Obj, body, Value) when is_record(Obj, abstract_message) ->
- NewObj = Obj#abstract_message{body = Value},
- {ok, NewObj, {body, Value}};
-
-set(Obj, remoteUsername, Value) when is_record(Obj, rpc_message) ->
- NewObj = Obj#rpc_message{remoteUsername = Value},
- {ok, NewObj, {remoteUsername, Value}};
-set(Obj, remotePassword, Value) when is_record(Obj, rpc_message) ->
- NewObj = Obj#rpc_message{remotePassword = Value},
- {ok, NewObj, {remotePassword, Value}};
-set(Obj, parent, Value) when is_record(Obj, rpc_message) and is_record(Value, abstract_message) ->
- NewObj = Obj#rpc_message{parent = Value},
- {ok, NewObj, {parent, Value}};
-set(Obj, AbstractMessageProperty, Value) when is_record(Obj, rpc_message) and is_atom(AbstractMessageProperty) ->
- {ok, NewAbstractMessage, _} = set(Obj#rpc_message.parent, AbstractMessageProperty, Value),
- set(Obj, parent, NewAbstractMessage);
-
-set(Obj, parent, Value) when is_record(Obj, remoting_message) and is_record(Value, rpc_message) ->
- NewObj = Obj#remoting_message{parent = Value},
- {ok, NewObj, {parent, Value}};
-set(Obj, source, Value) when is_record(Obj, remoting_message) ->
- NewObj = Obj#remoting_message{source = Value},
- {ok, NewObj, {source, Value}};
-set(Obj, operation, Value) when is_record(Obj, remoting_message) ->
- NewObj = Obj#remoting_message{operation = Value},
- {ok, NewObj, {operation, Value}};
-set(Obj, parameters, Value) when is_record(Obj, remoting_message) ->
- NewObj = Obj#remoting_message{parameters = Value},
- {ok, NewObj, {parameters, Value}};
-set(Obj, RpcMessageProperty, Value) when is_record(Obj, remoting_message) and is_atom(RpcMessageProperty) ->
- {ok, NewRpcMessage, _} = set(Obj#remoting_message.parent, RpcMessageProperty, Value),
- set(Obj, parent, NewRpcMessage);
-
-set(Obj, parent, Value) when is_record(Obj, async_message) and is_record(Value, abstract_message) ->
- NewObj = Obj#async_message{parent = Value},
- {ok, NewObj, {parent, Value}};
-set(Obj, correlationId, Value) when is_record(Obj, async_message) ->
- NewObj = Obj#async_message{correlationId = Value},
- {ok, NewObj, {correlationId, Value}};
-set(Obj, correlationIdBytes, Value) when is_record(Obj, async_message) ->
- NewObj = Obj#async_message{correlationIdBytes = Value},
- {ok, NewObj, {correlationIdBytes, Value}};
-set(Obj, AbstractMessageProperty, Value) when is_record(Obj, async_message) and is_atom(AbstractMessageProperty) ->
- {ok, NewAbstractMessage, _} = set(Obj#async_message.parent, AbstractMessageProperty, Value),
- set(Obj, parent, NewAbstractMessage);
-
-set(Obj, parent, Value) when is_record(Obj, command_message) and is_record(Value, async_message) ->
- NewObj = Obj#command_message{parent = Value},
- {ok, NewObj, {parent, Value}};
-set(Obj, operation, Value) when is_record(Obj, command_message) ->
- NewObj = Obj#command_message{operation = Value},
- {ok, NewObj, {operation, Value}};
-set(Obj, AsyncMessageProperty, Value) when is_record(Obj, command_message) and is_atom(AsyncMessageProperty) ->
- {ok, NewAsyncMessage, _} = set(Obj#command_message.parent, AsyncMessageProperty, Value),
- set(Obj, parent, NewAsyncMessage).
-
-
-fc_to_record(#string_3{data = ?FC_REMOTINGMESSAGE}) -> {ok, #remoting_message{}};
-fc_to_record(#string_3{data = ?FC_COMMANDMESSAGE}) -> {ok, #command_message{}};
-fc_to_record(_) -> {ok, undefined}.
-
-%% Convert String to term, Str must be term-like string
-to_term(#string_3{data = Str}) ->
- {ok, Tokens, _} = erl_scan:string(Str),
- {ok, Term} = erl_parse:parse_term(Tokens ++ [{dot,1}]),
- Term.
+-include("../include/types.hrl").
+
+fields(abstract_message) ->
+ ["clientId", "destination", "messageId", "timestamp", "timeToLive", "headers", "body"];
+
+fields(async_message) ->
+ ["parent", "correlationId", "correlationIdBytes"];
+
+fields(command_message) ->
+ ["parent", "operation"];
+
+fields(remoting_message) ->
+ ["parent", "source", "operation", "parameters"];
+
+fields(rpc_message) ->
+ ["parent", "remoteUsername", "remotePassword"].
+
+fields_atom(abstract_message) ->
+ [clientId, destination, messageId, timestamp, timeToLive, headers, body];
+
+fields_atom(async_message) ->
+ [parent, correlationId, correlationIdBytes];
+
+fields_atom(command_message) ->
+ [parent, operation];
+
+fields_atom(remoting_message) ->
+ [parent, source, operation, parameters];
+
+fields_atom(rpc_message) ->
+ [parent, remoteUsername, remotePassword].
+
+set(Obj, body, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{body = Value},
+ {ok, NewObj, {body, Value}};
+
+set(Obj, clientId, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{clientId = Value},
+ {ok, NewObj, {clientId, Value}};
+
+set(Obj, destination, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{destination = Value},
+ {ok, NewObj, {destination, Value}};
+
+set(Obj, headers, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{headers = Value},
+ {ok, NewObj, {headers, Value}};
+
+set(Obj, messageId, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{messageId = Value},
+ {ok, NewObj, {messageId, Value}};
+
+set(Obj, timeToLive, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{timeToLive = Value},
+ {ok, NewObj, {timeToLive, Value}};
+
+set(Obj, timestamp, Value) when is_record(Obj, abstract_message) ->
+ NewObj = Obj#abstract_message{timestamp = Value},
+ {ok, NewObj, {timestamp, Value}};
+
+set(Obj, PropertyName, Value) when is_record(Obj, asobject) ->
+ NewObj = #asobject{array = Obj#asobject.array ++ [{PropertyName, Value}]},
+ {ok, NewObj, {array, Value}};
+
+set(Obj, correlationId, Value) when is_record(Obj, async_message) ->
+ NewObj = Obj#async_message{correlationId = Value},
+ {ok, NewObj, {correlationId, Value}};
+
+set(Obj, correlationIdBytes, Value) when is_record(Obj, async_message) ->
+ NewObj = Obj#async_message{correlationIdBytes = Value},
+ {ok, NewObj, {correlationIdBytes, Value}};
+
+set(Obj, parent, Value) when is_record(Obj, async_message) and is_record(Value, abstract_message) ->
+ NewObj = Obj#async_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+
+set(Obj, ParentProperty, Value) when is_record(Obj, async_message) and is_atom(ParentProperty) ->
+ {ok, NewParentObject, _} = set(Obj#async_message.parent, ParentProperty, Value),
+ set(Obj, parent, NewParentObject);
+
+set(Obj, operation, Value) when is_record(Obj, command_message) ->
+ NewObj = Obj#command_message{operation = Value},
+ {ok, NewObj, {operation, Value}};
+
+set(Obj, parent, Value) when is_record(Obj, command_message) and is_record(Value, async_message) ->
+ NewObj = Obj#command_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+
+set(Obj, ParentProperty, Value) when is_record(Obj, command_message) and is_atom(ParentProperty) ->
+ {ok, NewParentObject, _} = set(Obj#command_message.parent, ParentProperty, Value),
+ set(Obj, parent, NewParentObject);
+
+set(Obj, data, Value) when is_record(Obj, ecma_array) ->
+ NewObj = Obj#ecma_array{data = Value},
+ {ok, NewObj, {data, Value}};
+
+set(Obj, data, Value) when is_record(Obj, long_string) ->
+ NewObj = Obj#long_string{data = Value},
+ {ok, NewObj, {data, Value}};
+
+set(Obj, operation, Value) when is_record(Obj, remoting_message) ->
+ NewObj = Obj#remoting_message{operation = Value},
+ {ok, NewObj, {operation, Value}};
+
+set(Obj, parameters, Value) when is_record(Obj, remoting_message) ->
+ NewObj = Obj#remoting_message{parameters = Value},
+ {ok, NewObj, {parameters, Value}};
+
+set(Obj, source, Value) when is_record(Obj, remoting_message) ->
+ NewObj = Obj#remoting_message{source = Value},
+ {ok, NewObj, {source, Value}};
+
+set(Obj, parent, Value) when is_record(Obj, remoting_message) and is_record(Value, rpc_message) ->
+ NewObj = Obj#remoting_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+
+set(Obj, ParentProperty, Value) when is_record(Obj, remoting_message) and is_atom(ParentProperty) ->
+ {ok, NewParentObject, _} = set(Obj#remoting_message.parent, ParentProperty, Value),
+ set(Obj, parent, NewParentObject);
+
+set(Obj, remotePassword, Value) when is_record(Obj, rpc_message) ->
+ NewObj = Obj#rpc_message{remotePassword = Value},
+ {ok, NewObj, {remotePassword, Value}};
+
+set(Obj, remoteUsername, Value) when is_record(Obj, rpc_message) ->
+ NewObj = Obj#rpc_message{remoteUsername = Value},
+ {ok, NewObj, {remoteUsername, Value}};
+
+set(Obj, parent, Value) when is_record(Obj, rpc_message) and is_record(Value, abstract_message) ->
+ NewObj = Obj#rpc_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+
+set(Obj, ParentProperty, Value) when is_record(Obj, rpc_message) and is_atom(ParentProperty) ->
+ {ok, NewParentObject, _} = set(Obj#rpc_message.parent, ParentProperty, Value),
+ set(Obj, parent, NewParentObject);
+
+set(Obj, data, Value) when is_record(Obj, string) ->
+ NewObj = Obj#string{data = Value},
+ {ok, NewObj, {data, Value}};
+
+set(Obj, data, Value) when is_record(Obj, string_3) ->
+ NewObj = Obj#string_3{data = Value},
+ {ok, NewObj, {data, Value}};
+
+set(Obj, data, Value) when is_record(Obj, xml) ->
+ NewObj = Obj#xml{data = Value},
+ {ok, NewObj, {data, Value}}.
+
+type(Obj) when is_record(Obj, abstract_message) -> abstract_message;
+
+type(Obj) when is_record(Obj, asobject) -> asobject;
+
+type(Obj) when is_record(Obj, async_message) -> async_message;
+
+type(Obj) when is_record(Obj, command_message) -> command_message;
+
+type(Obj) when is_record(Obj, ecma_array) -> ecma_array;
+
+type(Obj) when is_record(Obj, long_string) -> long_string;
+
+type(Obj) when is_record(Obj, remoting_message) -> remoting_message;
+
+type(Obj) when is_record(Obj, rpc_message) -> rpc_message;
+
+type(Obj) when is_record(Obj, string) -> string;
+
+type(Obj) when is_record(Obj, string_3) -> string_3;
+
+type(Obj) when is_record(Obj, xml) -> xml.
+
View
13 src/registry.erl
@@ -0,0 +1,13 @@
+-module(registry).
+-author("trung@mdkt.org").
+-include("../include/messages.hrl").
+-include("../include/flex_classes.hrl").
+-compile(export_all).
+
+fc_to_record(?FC_REMOTINGMESSAGE) -> {ok, #remoting_message{}};
+fc_to_record(?FC_COMMANDMESSAGE) -> {ok, #command_message{}};
+fc_to_record(_) -> {ok, undefined}.
+
+record_to_fc(remoting_message) -> {ok, ?FC_REMOTINGMESSAGE};
+record_to_fc(command_message) -> {ok, ?FC_COMMANDMESSAGE};
+record_to_fc(_) -> {ok, undefined}.
View
6 src/utils.erl
@@ -14,3 +14,9 @@ date_to_milliseconds(Date) ->
Seconds = calendar:datetime_to_gregorian_seconds(Date),
DiffSeconds = Seconds - BaseDate,
DiffSeconds * 1000.
+
+%% Convert String to term, Str must be term-like string
+to_term(Str) ->
+ {ok, Tokens, _} = erl_scan:string(Str),
+ {ok, Term} = erl_parse:parse_term(Tokens ++ [{dot,1}]),
+ Term.
View
2 support/include.mk
@@ -22,6 +22,7 @@ EBIN_DIR := ../ebin
DOC_DIR := ../doc
EMULATOR := beam
+ERL_HELPERS := $(wildcard *_helper.erl)
ERL_SOURCES := $(wildcard *.erl)
ERL_HEADERS := $(wildcard *.hrl) $(wildcard ../include/*.hrl)
ERL_OBJECTS := $(ERL_SOURCES:%.erl=$(EBIN_DIR)/%.$(EMULATOR))
@@ -30,6 +31,7 @@ ERL_OBJECTS_LOCAL := $(ERL_SOURCES:%.erl=./%.$(EMULATOR))
APP_FILES := $(wildcard *.app)
EBIN_FILES = $(ERL_OBJECTS) $(ERL_DOCUMENTS) $(APP_FILES:%.app=../ebin/%.app)
EBIN_FILES_NO_DOCS = $(ERL_OBJECTS) $(APP_FILES:%.app=../ebin/%.app)
+EBIN_GENERATE = $(ERL_HELPERS:%.erl=$(EBIN_DIR)/%.$(EMULATOR))
MODULES = $(ERL_SOURCES:%.erl=%)
../ebin/%.app: %.app
View
61 test/amf0_test.erl
@@ -5,9 +5,17 @@
-author("trung@mdkt.org").
-include_lib("eunit/include/eunit.hrl").
--include ("../include/types.hrl").
+-include("../include/types.hrl").
+-include("../include/messages.hrl").
-compile(export_all).
+%% Generic method to test write_object/read_object
+verify(ExpectedValue) ->
+ {ok, Bin} = amf0:write_object(ExpectedValue),
+ ?assert(Bin /= <<>>),
+ {ok, ActualValue, _Rest} = amf0:read_object(Bin),
+ ?assertEqual(ExpectedValue, ActualValue).
+
%%
%% Read/write an unsigned byte, 8-bit of data, an octet
%%
@@ -40,67 +48,50 @@ u32_test() ->
number_test() ->
ExpectedValue = 12.3,
- {ok, Bin} = amf0:write_number(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue, ActualValue).
+ verify(ExpectedValue).
string_test() ->
ExpectedValue = #string{data = "nguyen Kien trung"},
- {ok, Bin} = amf0:write_string(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assert(is_record(ActualValue, string)),
- ?assertEqual(ExpectedValue#string.data, ActualValue#string.data).
+ verify(ExpectedValue).
long_string_test() ->
ExpectedValue = #long_string{data = "nguyen Kien trung"},
- {ok, Bin} = amf0:write_long_string(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue#long_string.data, ActualValue#long_string.data).
+ verify(ExpectedValue).
xml_test() ->
ExpectedValue = #xml{data = "<xml><a></a></xml>"},
- {ok, Bin} = amf0:write_xml(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue#xml.data, ActualValue#xml.data).
+ verify(ExpectedValue).
date_test() ->
ExpectedValue = {{2009, 12, 12}, {12, 30, 40}},
- {ok, Bin} = amf0:write_date(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue, ActualValue).
+ verify(ExpectedValue).
boolean_true_test() ->
ExpectedValue = true,
- {ok, Bin} = amf0:write_boolean(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue, ActualValue).
+ verify(ExpectedValue).
boolean_false_test() ->
ExpectedValue = false,
- {ok, Bin} = amf0:write_boolean(marker, ExpectedValue),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue, ActualValue).
+ verify(ExpectedValue).
null_test() ->
ExpectedValue = null,
- {ok, Bin} = amf0:write_null(),
- ?assert(Bin /= <<>>),
- {ok, ActualValue, _Rest} = amf0:read_object(Bin),
- ?assertEqual(ExpectedValue, ActualValue).
+ verify(ExpectedValue).
reference_test() ->
ExpectedValue = "something",
%% First, store an object in to object reference table
amf0:reset(),
amf0:write_object_reference(ExpectedValue),
- {ok, Bin} = amf0:write_reference(marker, 0),
+ {ok, Bin} = amf0:write_object(ref, 0),
?assert(Bin /= <<>>),
{ok, ActualValue, _Rest} = amf0:read_object(Bin),
?assertEqual(ExpectedValue, ActualValue).
+
+strict_array_test() ->
+ ExpectedValue = [#string{data = "SomeString"}, #xml{data = "<b></b>"}, true, 13.4],
+ verify(ExpectedValue).
+
+registered_typed_object_test() ->
+ ExpectedValue = #remoting_message{source = #string{data = "somesource"}},
+ verify(ExpectedValue).
View
17 test/record_utils_test.erl
@@ -2,6 +2,7 @@
-author("trung@mdkt.org").
-include_lib("eunit/include/eunit.hrl").
+-include("../include/types.hrl").
-include("../include/messages.hrl").
new_record(abstract_message) ->
@@ -37,7 +38,12 @@ new_record(command_message) ->
#command_message{
parent = new_record(async_message),
operation = ?UNKNOWN_OPERATION
- }.
+ };
+
+new_record(asobject) ->
+ #asobject{
+ data = []
+ }.
abstract_message_set_clientId_test() ->
NewValue = 2,
@@ -151,4 +157,11 @@ command_message_set_operation_test() ->
NewValue = ?CLIENT_PING_OPERATION,
{ok, NewR, _} = record_utils:set(new_record(command_message), operation, NewValue),
?assert(is_record(NewR, command_message)),
- ?assertEqual(NewR#command_message.operation, NewValue).
+ ?assertEqual(NewR#command_message.operation, NewValue).
+
+asobject_set_test() ->
+ PropertyName = "some property",
+ PropertyValue = "some value",
+ {ok, NewR, _} = record_utils:set(new_record(asobject), PropertyName, PropertyValue),
+ ?assert(is_record(NewR, asobject)),
+ ?assertEqual(1, length(NewR#asobject.data)).

0 comments on commit 0b13b0c

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