<!-- Module User's Guide -->

<chapter>
	<title>&adminguide;</title>

	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para> This module introduces a new type of variable that provides both
	serialization and de-serialization from JSON format.
	</para>
	<para>
	The variable provides ways to access objects and arrays to add,replace
	or delete values from the script.
	</para>

	<para>
	The correct approach is to consider a json object as a hashtable
	( you can put (key;value) pairs, and you can delete and get
	 values by key) and a json array as an array ( you can append,
	 delete and replace values).
	</para>

	<para>
	Since the JSON format can have objects inside other objects
	you can have multiple nested hashtables or arrays and you can
	access these using paths.
	</para>

	
	</section>

	<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<section>
		<title>&osips; Modules</title>
		<para>
		This module does not depend on other modules.
		</para>
	</section>

	<section>
		<title>External Libraries or Applications</title>
		<itemizedlist>
			<listitem>
			<para>
				<emphasis>libjson</emphasis>
				The libjson C library can be downloaded from:
				http://oss.metaparadigm.com/json-c/
			</para>
			</listitem>
		</itemizedlist>

		</section>
	</section>
	
	<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>
	
	<section id="param_enable_long_quoting" xreflabel="enable_long_quoting">
		<title><varname>enable_long_quoting</varname> (boolean)</title>
		<para>
		Enable this parameter if your input JSONs contain signed integers which
		do not fit into 4 bytes (e.g. larger than 2147483647, etc.).  If the
		parameter is enabled, 4-byte integers will continue to be returned as
		integers, while larger values will be returned as strings, in order to
		avoid the integer overflow.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis>false</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>enable_long_quoting</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("json", "enable_long_quoting", true)
...
# normalize the "gateway_id" int/string value to be always a string
$var(gateway_id) = "" + $json(body/gateway_id);
...
</programlisting>
		</example>
	</section>
	
	</section>


	<section id="exported_pseudo_variables" xreflabel="Exported Pseudo-Variables">
	<title>Exported Pseudo-Variables</title>

	<section id="pv_json" xreflabel="$json">
		<title><varname>$json(id)</varname></title>
		<para>
			The <varname>json</varname> variable provides
			methods to access fields in json objects and
			indexes in json arrays.
		</para>

		<section>
		<title>Variable lifetime </title>

		<para>
			The json variables will be available to the
			process that created them from the moment they were
			initialized. They will not reset per message or per
			transaction. If you want to use the on a per message
			basis you should initialize them each time.
		</para>


		</section>

		<section>
		<title>Accessing the $json(id) variable </title>

		<para>
			The grammar that describes the id is:
		</para>

		<para>
			id = name(identifier)*
		</para>
		<para>
			identifier = key | index
		</para>
		<para>
			key = /string | /$var
		</para>
		<para>
			index = [integer] | [$var] | []
		</para>

		<para>
			The "[]" index represents appending to the array.
			It should only be used when trying to set a value and
			not when trying to get one.
		</para>

		<para>
			Negative indexes can be used to access an array starting
			from the end. So "[-1]" signifies the last element.
		</para>

		<para>
			IMPORTANT: The id strictly complies to this grammar.
			You should be careful when using spaces because they will
			NOT be ignored. This was done to allow keys that contain
			spaces.
		</para>

		<para>
			Variables can be used as indexes or keys. Variables
			that will be used as indexes must contain integer values.
			Variables that will be used as keys should contain
			string values.


		</para>


		<para>
			Trying to get a value from a non-existing path
			(key or value) will return the NULL value and notice
			messages will be placed in the log describing the value
			of the json and the path used.
		</para>

		<para>
			Trying to replace or insert a value in a
			non-existing path will cause an error in setting the value
			and notice messages will be printed in the log
			describing the value of the json and the path used
		</para>


		<example>
		<title>Accessing the $json variable </title>
		<programlisting format="linespecific">
...
$json(obj1/key) = "value"; #replace or insert the (key,value)
			   #pair into the json object;
			   
$json(matrix1[1][2]) = 1;  #replace the element at index 2 in the element
			   #at index 1 in an array

xlog("$json(name/key1[0][-1]/key2)"); # a more complex example

...
		</programlisting>
		</example>
		
		<example>
		<title>Iterating through an array using variables </title>
		<programlisting format="linespecific">
...

$json(ar1) := "[1,2,3,4]";

$var(i) = 0;

while( $json(ar1[$var(i)]) )
{

	#print each value
	xlog("Found:[$json(ar1[$var(i)])]\n");

	#increment each value
	$json(ar1[$var(i)])  = $json(ar1[$var(i)]) + 1 ;

	$var(i) = $var(i) + 1;

}


...
		</programlisting>
		</example>

		</section>

		<section>
		<title>Traversal</title>
		<para>
			Dynamic traversal of a JSON object or array is possible by using a
			for each statement, similarly to the indexed pseudo variables iteration.
			However, note that indexing the $json variable is not supported in
			any other statements (this refers to indexing the entire variable
			and not to the indexes accepted in the grammar of the <emphasis>id</emphasis>).
		</para>
		<para>
			In order to explicitly iterate over a JSON object keys or values, you can use the
			<emphasis>.keys</emphasis> or <emphasis>.values</emphasis> suffix for the path
			specified in the <emphasis>id</emphasis>.
		</para>

		<example>
		<title>iteration over $json object keys</title>
		<programlisting format="linespecific">
...
$json(foo) := "{\"a\": 1, \"b\": 2, \"c\": 3}";
for ($var(k) in $(json(foo.keys)[*]))
    xlog("$var(k) ");
...
		</programlisting>
		</example>

		<example>
		<title>iteration over $json object values</title>
		<programlisting format="linespecific">
...
$json(foo) := "{\"a\": 1, \"b\": 2, \"c\": 3}";
for ($var(v) in $(json(foo.values)[*]))
    xlog("$var(v) ");

# equivalent to:

$json(foo) := "{\"a\": 1, \"b\": 2, \"c\": 3}";
for ($var(v) in $(json(foo)[*]))
    xlog("$var(v) ");
...
		</programlisting>
		</example>

		<example>
		<title>iteration over $json array values</title>
		<programlisting format="linespecific">
...
$json(foo) := "[1, 2, 3]";
for ($var(v) in $(json(foo)[*]))
    xlog("$var(v) ");
...
		</programlisting>
		</example>
		</section>

		<section>
		<title> Returned values from $json(id) </title>

		<para>
			If the value specified by the id is an integer
			it will be returned as an integer value.
		</para>

		<para>
			If the value specified by the id is a string it will
			be returned as a string.
		</para>

		<para>
			If the value specified by the id is any other
			type of json ( null, boolean, object, array )
			the serialized version of the object will be returned
			as a string value. Using this and the ":="
			operator you can duplicate json objects and put them
			in other json objects ( for string or integer you may
			use the "=" operator).
		</para>
		
	

		<para>
			If the id does not exist a NULL value will be returned.
			
		</para>

		</section>

		<section>
		<title> Operators for the $json(id) variable </title>

		<para>
			There are 2 operators available for this variable.
		</para>

			<section>
			<title> The "=" operator </title>
			<para>
				This will cause the value to be taken
				as is and be added to the json object
				( e.g. string value or integer	value ).
			</para>

			<para>
				Setting a value to NULL will cause it to be
				deleted.
			</para>

			<example>
			<title>Appending integers to arrays</title>
			<programlisting format="linespecific">
...
$json(array1[]) = 1;
...
			</programlisting>
			</example>

			<example>
			<title>Deleting the last element in an array</title>
			<programlisting format="linespecific">
...
$json(array1[-1]) = NULL;
...
			</programlisting>
			</example>


			<example>
			<title>Adding a string value to a json object</title>
			<programlisting format="linespecific">
...
$json(object1/some_key) = "some_value";
...
			</programlisting>
			</example>

			</section>

			<section>
			<title> The ":=" operator </title>
			<para>
				This will cause the value to be taken
				and interpreted as a json object
				( e.g. this operator should be used to parse
				 json inputs ).
			</para>

			<example>
			<title>Initializing an array</title>
			<programlisting format="linespecific">
...
$json(array1) := "[]";
...
			</programlisting>
			</example>

			<example>
			<title>Setting a boolean or null value </title>
			<programlisting format="linespecific">
...
$json(array1[]) := "null";
$json(array1[]) := "true";
$json(array1[]) := "false";
...
			</programlisting>
			</example>

			<example>
			<title>Adding a json to another json </title>
			<programlisting format="linespecific">
...

$json(array) := "[1,2,3]";
$json(object) := "{}";
$json(object/array) := $json(array) ;
...
			</programlisting>
			</example>

			</section>

		</section>
	</section>
	<section id="pv_json_pretty" xreflabel="$json_pretty">
		<title><varname>$json_pretty(id)</varname></title>
		<para>
			The <varname>json_pretty</varname> variable has the
			same purpose as the <varname>json</varname> variable,
			but prints the JSON object in a pretty format, adding
			spaces and tabs to make the output more readable.
		</para>
	</section>
	<section id="pv_json_compact" xreflabel="$json_compact">
		<title><varname>$json_compact(id)</varname></title>
		<para>
			The <varname>json_compact</varname> variable has the
			same purpose as the <varname>json</varname> variable,
			but prints the JSON object in a more compact form,
			without formatting spaces.
		</para>
	</section>
	</section>

	<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>

		<section id="func_json_link" xreflabel="json_link()">
			<title>
			<function moreinfo="none">
				json_link($json(dest_id), $json(source_id))
				</function>
			</title>
			<para>
			This function can be used to link json objects together.
			This will work simillar to setting a value to an object,
			the only difference is that the second object is not
			copied, only a reference is created.
			</para>

			<para>
			Changes to any of the objects will be visible in both of
			them.
			</para>

			<para>
			You can use this method either to create references
			so each time you access the field you don't
			have to go through the full path
			(for speed efficiency and shorter code), or
			if you have an object that must be added to many
			other objects and you don't want to copy it each
			time (space and speed efficiency).

			</para>

			<para>
			You can think of this object exactly as a reference
			in an object-oriented language. Modifying fields
			referenced by the variable will cause modifications
			in all the objects, BUT modifying the variable itsef
			will not cause any changes to other objects.
			</para>

			<para>
			WARNING: You should be careful when using references.
			If you accidentally create a circular reference and try
			to get the value from the object you will crash OPENSIPS.
			</para>

			<example>
			<title>Creating a reference </title>
			<programlisting format="linespecific">
...

$json(b) := "[{},{},{}]";

json_link($json(stub), $json(b[0]));

$json(stub/ana) = "are"; #add to the stub
$json(stub/ar) := "[]";
$json(stub/ar[]) = 1;
$json(stub/ar[]) = 2;
$json(stub/ar[]) = 3;

$json(b[0]/ar[0]) = NULL; # delete from the original object

xlog("\nTest link :\n$json(stub)\n$json(b)\n\n");

/*Output:

Test link :
{ "ana": "are", "ar": [ 2, 3 ] }
[ { "ana": "are", "ar": [ 2, 3 ] }, { }, { } ]

*/

$json(stub) = NULL; #delete the stub, no change will happen to the source


xlog("\nTest link :\n$json(stub)\n$json(b)\n\n");

/* Output:

Test link :
&lt;null&gt;
[ { "ana": "are", "ar": [ 2, 3 ] }, { }, { } ]

*/





...
			</programlisting>
			</example>


			<example>
			<title>[LOGICAL ERROR] Creating a  circular reference  </title>
			<programlisting format="linespecific">
...

$json(b) := "[1]";

/* NEVER do this, it is meant only to show where problems might occur  */
json_link($json(b[0]), $json(b)); # replace 1 with a reference to b

xlog("\nTest link :\n$json(stub)\n$json(b)\n\n");

/* this will cause OPENSIPS to crash because it will continuously try
 to get b, then b[0], then b ... */


...
			</programlisting>
			</example>


		</section>

		
	</section>

	



</chapter>

