%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(ic_attribute_java).
-include("icforms.hrl").
-include("ic.hrl").
%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([emit_attribute_prototype/4,
emit_attribute_stub_code/4,
emit_atrribute_on_dictionary/5,
emit_attribute_switch_case/5]).
%%%-----------------------------------------------------
%%%
%%% Generates operation in interface
%%%
%%%-----------------------------------------------------
emit_attribute_prototype(G, N, X, Fd) ->
emit_attribute_prototype(G, N, X, Fd, ic_forms:get_idlist(X)).
emit_attribute_prototype(_G, _N, _X, _Fd, []) ->
ok;
emit_attribute_prototype(G, N, X, Fd, [V|Vs]) ->
WireAttrName = ic_forms:get_id(V),
AttrName = ic_forms:get_java_id(WireAttrName),
emit_attr_prototype(G, N, X, Fd, AttrName,WireAttrName),
emit_attribute_prototype(G, N, X, Fd, Vs).
emit_attr_prototype(G, N, X, Fd, OpName, WireOpName) ->
ic_codegen:emit(Fd, "/****\n"),
ic_codegen:emit(Fd, " * Attribute ~p interface functions \n", [ic_util:to_colon([WireOpName|N])]),
ic_codegen:emit(Fd, " *\n"),
ic_codegen:emit(Fd, " */\n\n"),
AT = ic_forms:get_type(X),
Type = ic_java_type:getType(G, N, AT),
% HolderType = ic_java_type:getHolderType(G, N, AT),
ic_codegen:emit(Fd, " ~s ~s() throws java.lang.Exception;\n\n",[Type, OpName]),
case X#attr.readonly of
{readonly, _} ->
ok;
_ ->
ic_codegen:emit(Fd, " void ~s(~s _value) throws java.lang.Exception;\n\n",[OpName, Type])
end.
%%%-----------------------------------------------------
%%%
%%% Generates attribute insertion in dictionary
%%%
%%%-----------------------------------------------------
emit_atrribute_on_dictionary(G, N, X, Fd, C) ->
emit_atrribute_on_dictionary(G, N, X, Fd, C, ic_forms:get_idlist(X)).
emit_atrribute_on_dictionary(_G, _N, _X, _Fd, C, []) ->
C;
emit_atrribute_on_dictionary(G, N, X, Fd, C, [V|Vs]) ->
WireAttrName = ic_forms:get_id(V),
ic_codegen:emit(Fd, " _operations.put(\"_get_~s\", new java.lang.Integer(~p));\n",
[WireAttrName,C]),
case X#attr.readonly of
{readonly, _} ->
emit_atrribute_on_dictionary(G, N, X, Fd, C+1, Vs);
_ ->
ic_codegen:emit(Fd, " _operations.put(\"_set_~s\", new java.lang.Integer(~p));\n",
[WireAttrName,C+1]),
emit_atrribute_on_dictionary(G, N, X, Fd, C+2, Vs)
end.
%%%-----------------------------------------------------
%%%
%%% Generates attribute case in server switch
%%%
%%%-----------------------------------------------------
emit_attribute_switch_case(G, N, X, Fd, C) ->
Tk = ic_forms:get_tk(X),
emit_attribute_switch_case(G, N, X, Fd, Tk, C, ic_forms:get_idlist(X)).
emit_attribute_switch_case(_G, _N, _X, _Fd, _Tk, C, []) ->
C;
emit_attribute_switch_case(G, N, X, Fd, Tk, C, [V|Vs]) ->
AttrName = ic_forms:get_java_id(V),
emit_attribute_switch_case1(G,N,X,Fd,"_get_",AttrName,Tk,C),
case X#attr.readonly of
{readonly, _} ->
emit_attribute_switch_case(G, N, X, Fd, Tk, C+1, Vs);
_ ->
emit_attribute_switch_case1(G,N,X,Fd,"_set_",AttrName,Tk,C+1),
emit_attribute_switch_case(G, N, X, Fd, Tk, C+2, Vs)
end.
emit_attribute_switch_case1(G, N, X, Fd, "_get_", Name, _Tk, C) ->
R = ic_forms:get_type(X),
RT = ic_java_type:getParamType(G,N,R,ret),
ic_codegen:emit(Fd, " case ~p: { // Get operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]),
ic_codegen:emit(Fd, " // Calling implementation function\n"),
ic_codegen:emit(Fd, " ~s _result = this.~s();\n\n", [RT, Name]),
ic_codegen:emit(Fd, " // Marshalling output\n"),
ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]),
ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"),
case ic_java_type:isBasicType(G,N,R) of
true ->
ic_codegen:emit(Fd, " __os~s(_result); // Return value\n\n",
[ic_java_type:marshalFun(G,N,X,R)]);
false ->
ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n\n",
[ic_java_type:marshalFun(G,N,X,R)])
end,
ic_codegen:emit(Fd, " } break;\n\n");
emit_attribute_switch_case1(G, N, X, Fd, "_set_", Name, _Tk, C) ->
ic_codegen:emit(Fd, " case ~p: { // Set operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]),
Type = ic_forms:get_type(X),
ic_codegen:emit(Fd, " // Preparing input\n"),
ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n",[?ERLANGPACKAGE]),
case ic_java_type:isBasicType(G,N,Type) of
true ->
ic_codegen:emit(Fd, " ~s _value = __is~s; // In value\n\n",
[ic_java_type:getParamType(G,N,Type,in),
ic_java_type:unMarshalFun(G,N,X,Type)]);
false ->
ic_codegen:emit(Fd, " ~s _value = ~s.unmarshal(__is); // In value\n\n",
[ic_java_type:getParamType(G,N,Type,in),
ic_java_type:getUnmarshalType(G,N,X,Type)])
end,
ic_codegen:emit(Fd, " // Calling implementation function\n"),
ic_codegen:emit(Fd, " this.~s(_value);\n\n", [Name]),
ic_codegen:emit(Fd, " // Marshalling output\n"),
ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]),
ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"),
ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n\n"),
ic_codegen:emit(Fd, " } break;\n\n").
%%%-----------------------------------------------------
%%%
%%% Generates attribute function in stub
%%%
%%%-----------------------------------------------------
emit_attribute_stub_code(G, N, X, Fd) ->
emit_attribute_stub_code(G, N, X, Fd, ic_forms:get_idlist(X)).
emit_attribute_stub_code(_G, _N, _X, _Fd, []) ->
ok;
emit_attribute_stub_code(G, N, X, Fd, [V|Vs]) ->
WireAttrName = ic_forms:get_id(V),
AttrName = ic_forms:get_java_id(WireAttrName),
emit_attribute_stub_code1(G,N,X,Fd,"_get_",AttrName,WireAttrName),
case X#attr.readonly of
{readonly, _} ->
emit_attribute_stub_code(G, N, X, Fd, Vs);
_ ->
emit_attribute_stub_code1(G,N,X,Fd,"_set_",AttrName,WireAttrName),
emit_attribute_stub_code(G, N, X, Fd, Vs)
end.
emit_attribute_stub_code1(G,N,X,Fd,"_get_",Name,WireName) ->
Type = ic_forms:get_type(X),
RT = ic_java_type:getType(G,N,Type),
%%
%% Main get operation
%%
ic_codegen:emit(Fd, " // Attribute ~p get operation implementation\n", [ic_util:to_colon([WireName|N])]),
ic_codegen:emit(Fd, " public ~s ~s() throws java.lang.Exception {\n\n", [RT, Name]),
%% Function marshal call
ic_codegen:emit(Fd, " // Calling the marshal function\n"),
ic_codegen:emit(Fd, " _~s_marshal(_env);\n\n", [Name]),
%% Sending call
ic_codegen:emit(Fd, " // Message send\n"),
ic_codegen:emit(Fd, " _env.send();\n\n"),
%% Receiving return value
ic_codegen:emit(Fd, " // Message receive\n"),
ic_codegen:emit(Fd, " _env.receive();\n\n"),
ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
ic_codegen:emit(Fd, " return _~s_get_unmarshal(_env);\n", [Name]),
ic_codegen:emit(Fd, " }\n\n"),
%%
%% Marshal get operation
%%
ic_codegen:emit(Fd, " // Marshal operation for get attribute ~p\n", [Name]),
ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env)\n",
[Name, ?ICPACKAGE]),
ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
ic_codegen:emit(Fd, " // Get output stream\n"),
ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]),
%% Initiating Message header
ic_codegen:emit(Fd, " // Message header assembly\n"),
ic_codegen:emit(Fd, " __os.reset();\n"),
ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"),
ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"),
%% Creating call identity tuple
ic_codegen:emit(Fd, " // Message identity part creation\n"),
ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
ic_codegen:emit(Fd, " __env.write_client_pid();\n"),
ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"),
OpCallName = case ic_options:get_opt(G, scoped_op_calls) of
true ->
ic_util:to_undersc(["_get_"++WireName|N]);
false ->
"_get_"++WireName
end,
%% Creating operation identity
ic_codegen:emit(Fd, " // Message operation part creation\n"),
ic_codegen:emit(Fd, " __os.write_atom(~p);\n\n",[OpCallName]),
ic_codegen:emit(Fd, " }\n\n"),
%%
%% Unmarshal get operation
%%
MRT = ic_java_type:getParamType(G,N,Type,ret),
ic_codegen:emit(Fd, " // Unmarshal operation for get attribute ~p\n", [Name]),
ic_codegen:emit(Fd, " public static ~s _~s_get_unmarshal(~sEnvironment __env)\n",
[MRT, Name, ?ICPACKAGE]),
ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
ic_codegen:emit(Fd, " // Get input stream\n"),
ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]),
ic_codegen:emit(Fd, " // Extracting return value\n"),
case ic_java_type:isBasicType(G, N, Type) of
true ->
ic_codegen:emit(Fd, " return __is~s;\n",
[ic_java_type:unMarshalFun(G, N, X, Type)]);
false ->
ic_codegen:emit(Fd, " return ~s.unmarshal(__is);\n",
[ic_java_type:getUnmarshalType(G, N, X, Type)])
end,
ic_codegen:emit(Fd, " }\n\n");
emit_attribute_stub_code1(G,N,X,Fd,"_set_",Name,WireName) ->
Type = ic_forms:get_type(X),
%%
%% Main set operation
%%
IT = ic_java_type:getType(G,N,Type),
ic_codegen:emit(Fd, " // Attribute ~p set operation implementation\n", [ic_util:to_colon([WireName|N])]),
ic_codegen:emit(Fd, " public void ~s(~s _value) throws java.lang.Exception {\n\n", [Name,IT]),
%% Function marshal call
ic_codegen:emit(Fd, " // Calling the marshal function\n"),
ic_codegen:emit(Fd, " _~s_marshal(_env, _value);\n\n", [Name]),
%% Sending call
ic_codegen:emit(Fd, " // Message send\n"),
ic_codegen:emit(Fd, " _env.send();\n\n"),
%% Receiving return value
ic_codegen:emit(Fd, " // Message receive\n"),
ic_codegen:emit(Fd, " _env.receive();\n\n"),
ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
ic_codegen:emit(Fd, " _~s_set_unmarshal(_env);\n", [Name]),
ic_codegen:emit(Fd, " }\n\n"),
%%
%% Marshal set operation
%%
IP = ic_java_type:getParamType(G, N, Type, in),
OpCallName = case ic_options:get_opt(G, scoped_op_calls) of
true ->
ic_util:to_undersc(["_set_"++WireName|N]);
false ->
"_set_"++WireName
end,
ic_codegen:emit(Fd, " // Marshal operation for set attribute ~p\n", [Name]),
ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env, ~s _value)\n",
[Name, ?ICPACKAGE, IP]),
ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
ic_codegen:emit(Fd, " // Get output stream\n"),
ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]),
%% Initiating Message header
ic_codegen:emit(Fd, " // Message header assembly\n"),
ic_codegen:emit(Fd, " __os.reset();\n"),
ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"),
ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"),
%% Creating call identity tuple
ic_codegen:emit(Fd, " // Message identity part creation\n"),
ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
ic_codegen:emit(Fd, " __env.write_client_pid();\n"),
ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"),
%% Creating operation identity
ic_codegen:emit(Fd, " // Message operation part creation\n"),
ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
ic_codegen:emit(Fd, " __os.write_atom(~p);\n",[OpCallName]),
case ic_java_type:isBasicType(G, N, Type) of
true ->
ic_codegen:emit(Fd, " __os~s(_value);\n\n",
[ic_java_type:marshalFun(G, N, X, Type)]);
false ->
ic_codegen:emit(Fd, " ~s(__os, _value);\n\n",
[ic_java_type:marshalFun(G, N, X, Type)])
end,
ic_codegen:emit(Fd, " }\n\n"),
ic_codegen:emit(Fd, " // Unmarshal operation for set attribute ~p\n", [Name]),
ic_codegen:emit(Fd, " public static void _~s_set_unmarshal(~sEnvironment __env)\n",
[Name, ?ICPACKAGE]),
ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
ic_codegen:emit(Fd, " // Get input stream\n"),
ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]),
ic_codegen:emit(Fd, " __is.read_atom();\n"),
ic_codegen:emit(Fd, " }\n\n").