tag:blogger.com,1999:blog-16219895973213722682024-03-14T04:30:32.881+10:30Lakmali Erandi Baminiwatta’s blogLakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.comBlogger48125tag:blogger.com,1999:blog-1621989597321372268.post-64362517938462876202019-07-17T14:54:00.001+09:302019-07-17T14:54:37.359+09:30Boomi Mapping - Removing special chars from an input<div dir="ltr" style="text-align: left;" trbidi="on">
Dell Boomi mapping shape provides numerous ways to modify/enrich an input via functions. In this post I am going to show how I validated and removed special chars from an input using Scripting and do it along with another string function.<br />
<br />
The user defined functions available with mapping, allows us to apply sequence of functions to the input. In this example, I am going to use it.<br />
<br />
Use Case:<br />
<br />
I have two input strings coming from the source profile (first_name and last_name), which I want to first concatanate together and then remove non-alphanumeric characters if present.<br />
<br />
<br />
Solution<br />
<br />
<br />
<ol style="text-align: left;">
<li>In your map, add an User Defined function and add two inputs; first_name, last_name. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/-juw_UpWmP1w/XNoq0ZJNuCI/AAAAAAAAnBs/aI03hZfAUhkm_2Uv0FpVrLIrdJGTp3wrgCLcBGAs/s1600/add-function.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="839" data-original-width="1331" height="201" src="https://4.bp.blogspot.com/-juw_UpWmP1w/XNoq0ZJNuCI/AAAAAAAAnBs/aI03hZfAUhkm_2Uv0FpVrLIrdJGTp3wrgCLcBGAs/s320/add-function.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Add User Defined function into the map</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/-PEA1xJesFxY/XNoovqce5CI/AAAAAAAAnA0/FlmF8FPS0UU4QGhAqh7b6G8ILe8cEY9WQCLcBGAs/s1600/inputs.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="503" data-original-width="678" height="295" src="https://4.bp.blogspot.com/-PEA1xJesFxY/XNoovqce5CI/AAAAAAAAnA0/FlmF8FPS0UU4QGhAqh7b6G8ILe8cEY9WQCLcBGAs/s400/inputs.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Added inputs to the user defined function</td></tr>
</tbody></table>
</li>
<li>As the first step, add a function "String Concat" under the "String" category. <div class="separator" style="clear: both; text-align: center;">
</div>
</li>
<li>Specify first_name and last_name as the inputs. Also set a delimiter, if you need a one. In my case, I want to concatenate the values with '.'.<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://2.bp.blogspot.com/-FfO2QBX0pZc/XNoo1lBI9yI/AAAAAAAAnA4/2o-9bAdcQMM-Kv1lVgXD0NiA1AHLc4F9gCEwYBhgL/s1600/concat.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="456" data-original-width="493" height="295" src="https://2.bp.blogspot.com/-FfO2QBX0pZc/XNoo1lBI9yI/AAAAAAAAnA4/2o-9bAdcQMM-Kv1lVgXD0NiA1AHLc4F9gCEwYBhgL/s320/concat.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">String concat function</td></tr>
</tbody></table>
</li>
<li>Map first_name and last_name input variables to the added function. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/-VPN8JZ50KPU/XNopBQtGGnI/AAAAAAAAnA8/SgG6_Lgw2rQJ2dwntRaM-zzKs-ApTOAGgCLcBGAs/s1600/map-inputs.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="520" data-original-width="589" height="282" src="https://4.bp.blogspot.com/-VPN8JZ50KPU/XNopBQtGGnI/AAAAAAAAnA8/SgG6_Lgw2rQJ2dwntRaM-zzKs-ApTOAGgCLcBGAs/s320/map-inputs.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Map User Defined function input to the String concat </td></tr>
</tbody></table>
</li>
<li>As the second step add a "Scripting" function, under "Custom Scripting".</li>
<li>Select "Use Inline Script" as the source and "Javascript" as the language.</li>
<li>Define an input variable(name) and an output variable(name_modified). <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/--XZviefp6To/XNopfqL-VGI/AAAAAAAAnBI/UwcJF-dBqmwu5OjcCJIlX6NseLnW8uePQCLcBGAs/s1600/scripting.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="582" data-original-width="422" height="320" src="https://4.bp.blogspot.com/--XZviefp6To/XNopfqL-VGI/AAAAAAAAnBI/UwcJF-dBqmwu5OjcCJIlX6NseLnW8uePQCLcBGAs/s320/scripting.png" width="232" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Scripting function</td></tr>
</tbody></table>
</li>
<li>Use the below as the script to execute.</li>
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">name_modified <span style="color: #333333;">=</span> name.replace(<span style="background-color: #fff0ff; color: black;">/[^A-Za-z0-9.]/g</span>, <span style="background-color: #fff0f0;">""</span>);
</pre>
</div>
</div>
<li>After adding it, map the result of first function as the input of the second function. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://2.bp.blogspot.com/-axDwWDG91D8/XNop6tkovUI/AAAAAAAAnBY/vLw9jED6UEklADG7730wT5uKaLcqyh82QCLcBGAs/s1600/map.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="667" data-original-width="1083" height="197" src="https://2.bp.blogspot.com/-axDwWDG91D8/XNop6tkovUI/AAAAAAAAnBY/vLw9jED6UEklADG7730wT5uKaLcqyh82QCLcBGAs/s320/map.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Map string concat output to the scripting function input</td></tr>
</tbody></table>
</li>
<li>Add an output variable to the map function to store the final output of function sequence. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://3.bp.blogspot.com/-TnDgJz7jYfc/XNopprYYZdI/AAAAAAAAnBU/9NrHsBxfYg4jJG-wcpQhpI7k8qlE0JoAgCEwYBhgL/s1600/output.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="785" data-original-width="1495" height="168" src="https://3.bp.blogspot.com/-TnDgJz7jYfc/XNopprYYZdI/AAAAAAAAnBU/9NrHsBxfYg4jJG-wcpQhpI7k8qlE0JoAgCEwYBhgL/s320/output.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Add output to the user defined function</td></tr>
</tbody></table>
</li>
<li>Map the "name_modified" result of script function to the output variable added above. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/-xZNwK4gcnLU/XNop_Djv1JI/AAAAAAAAnBc/8VYWk0cE7iYpO0NxGl4KnOOZvjJF5_eQQCLcBGAs/s1600/final.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="781" data-original-width="1511" height="165" src="https://4.bp.blogspot.com/-xZNwK4gcnLU/XNop_Djv1JI/AAAAAAAAnBc/8VYWk0cE7iYpO0NxGl4KnOOZvjJF5_eQQCLcBGAs/s320/final.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Map scripting output to the user defined function output. </td></tr>
</tbody></table>
</li>
</ol>
That's it. Here we added a function which take two inputs and concat them, remove special chars and return the resulting string.<br />
<br />
Thank you!<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-55900388390261757582019-07-17T14:54:00.000+09:302019-07-17T14:54:26.785+09:30Boomi Mapping - User Defined function based on list of elements in a collection<div dir="ltr" style="text-align: left;" trbidi="on">
Recently I came across a requirement to validate all the elements in a collection and return an output based on that. Let me explain it with an example. I have a XML document containing information about users including a collection to indicate the roles of the person.<br />
<br />
<br />
<!-- HTML generated using hilite.me -->Source Document<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><users></span>
<span style="color: #007700;"><user></span>
<span style="color: #007700;"><first_name></first_name></span>
<span style="color: #007700;"><roles></span>
<span style="color: #007700;"><role></span>admin<span style="color: #007700;"></role></span>
<span style="color: #007700;"><role></span>subscriber<span style="color: #007700;"></role></span>
<span style="color: #007700;"><role></span>creator<span style="color: #007700;"></role></span>
<span style="color: #007700;"></roles></span>
<span style="color: #007700;"></user></span>
<span style="color: #007700;"></users></span>
</pre>
</div>
<br />
Destination Document<br />
<br />
I want to map this into a destination profile which has elements to indicate whther the user is an admin or a subsriber.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><users></span>
<span style="color: #007700;"><user></span>
<span style="color: #007700;"><isAdmin></span>true<span style="color: #007700;"></isAdmin></span>
<span style="color: #007700;"><isSubscriber></span>true<span style="color: #007700;"></isSubscriber></span>
<span style="color: #007700;"><user></span>
<span style="color: #007700;"><users></span>
<span style="color: #007700;"></users></span>
</pre>
</div>
<br />
<div style="text-align: justify;">
In order to achieve this I have to write a map funtion. But for a map funtion, we can't input a collection. If we map the "roles" collection into the map fuction, it creates multiple output documents, one per element in the collection. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So I came up with a solution with the help of dynamic document property. Here, all the elements in the collection are concatanated into a single string while using the dynamic document property as a </div>
<div style="text-align: justify;">
temporary variable. Then this dynamic document property is validated to derive relevant elements in the destination profile. </div>
<div style="text-align: justify;">
<br /></div>
<h4 style="text-align: justify;">
Function 1 - Accumulating all the values in the collection into a single property. </h4>
<div>
<ol style="text-align: left;">
<li>Write a User define funtion with "role" as the input (The individual element inside the collection).</li>
<li> Add a function step with a scripting function (Javascript). This should take 2 inputs. </li>
<ul>
<li>new_role - contains single role.</li>
<li>all_roles - contains comma separated roles. </li>
<li>The script should concatanate new_role into all_roles. Then return the result - all_roles_result. <div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-fuN7K2EGwnU/XS6rKPM0YhI/AAAAAAAApRA/Mz3efcnyC80P22Q9wcmg3kSmT1beOxTiQCLcBGAs/s1600/script1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="583" data-original-width="418" height="320" src="https://1.bp.blogspot.com/-fuN7K2EGwnU/XS6rKPM0YhI/AAAAAAAApRA/Mz3efcnyC80P22Q9wcmg3kSmT1beOxTiQCLcBGAs/s320/script1.png" width="229" /></a></div>
</li>
</ul>
<li>Add the second function step to set a dynamic document property (DDP_roles) to hold roles result. Map the output of above function step into this one. </li>
<li>Now add the third function step to get above document property(DDP_roles) and map that into "all_roles" input of scripting function step. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-gQ3Mknmlu7g/XS6re4eQamI/AAAAAAAApRI/nSgxoYFPwCwJ5rATN5-pFFgLvuEdKOe9wCLcBGAs/s1600/UDF1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="772" data-original-width="1600" height="192" src="https://1.bp.blogspot.com/-gQ3Mknmlu7g/XS6re4eQamI/AAAAAAAApRI/nSgxoYFPwCwJ5rATN5-pFFgLvuEdKOe9wCLcBGAs/s400/UDF1.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">User Defined Function 1</td></tr>
</tbody></table>
</li>
</ol>
</div>
<div>
What above will do is, accumulate all the values in the collection into a dynamic document property as a comma separated string. </div>
<div>
<br /></div>
<div>
<h4 style="text-align: left;">
Function 2 - Validate the property containing all the values</h4>
</div>
<div>
<ol style="text-align: left;">
<li>Write a user deine function with no input.</li>
<li>As the first step get the dynamic document proerty abdefined above "DDP_roles"</li>
<li> Add another step for Scripting with one input variable - roles_list. Map above property as the input into it. </li>
<li>Validate the roles_list using Javascript and return isAdmin and isSubscriber as output.<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-wYULQqR9axY/XS6sMbGdecI/AAAAAAAApRU/RLVSVvlzSGodjBvyTyUhNxDvvyJm9uN5QCEwYBhgL/s1600/script2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="589" data-original-width="416" height="320" src="https://1.bp.blogspot.com/-wYULQqR9axY/XS6sMbGdecI/AAAAAAAApRU/RLVSVvlzSGodjBvyTyUhNxDvvyJm9uN5QCEwYBhgL/s320/script2.png" width="226" /></a></div>
</li>
<li>Now above output variables can be mapped to the destination profile. <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-zXBr4yrbMIc/XS6sR_M_1FI/AAAAAAAApRY/UXWpVLkCyK0AgBchpXwD_zXU8byqLdXfwCLcBGAs/s1600/UDF2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="787" data-original-width="1597" height="157" src="https://1.bp.blogspot.com/-zXBr4yrbMIc/XS6sR_M_1FI/AAAAAAAApRY/UXWpVLkCyK0AgBchpXwD_zXU8byqLdXfwCLcBGAs/s320/UDF2.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">User Defined Function 2</td></tr>
</tbody></table>
</li>
</ol>
</div>
<h4 style="text-align: left;">
Enable map function ordering</h4>
<div>
<div>
Since Function 1 must run before the Function 2, we have to enable ordering of them. For that, click on "Order the function execution" option in the top right corner of the functions </div>
<div>
section in the mapcomponent. Then enable "Enable map function ordering?" option and make sure order is correctly listed. </div>
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-djyd8KRU7GQ/XS6s5vTqdkI/AAAAAAAApRo/n5aqFTzbdcopi0jd-YwrnKWOfRaTZ3lvgCLcBGAs/s1600/map.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="774" data-original-width="1600" height="154" src="https://1.bp.blogspot.com/-djyd8KRU7GQ/XS6s5vTqdkI/AAAAAAAApRo/n5aqFTzbdcopi0jd-YwrnKWOfRaTZ3lvgCLcBGAs/s320/map.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Map Component with 2 functions</td></tr>
</tbody></table>
<div>
<br /></div>
<h4 style="text-align: left;">
Split documents</h4>
<div>
<div>
If you have multiple records in the XML document (multiple <user> elements), it will accumulate the document property with values in all the user records. In order to stop that, you have to process send each user record separately into the Map. So we have to place "data-process" shape and split the document by users/user element before the map shape. </user></div>
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-NoDdToaeTh0/XS6s1AInm9I/AAAAAAAApRk/BHrDrH5gzooNvhCWebLP_6A4LzUd6SnEgCLcBGAs/s1600/split.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="820" data-original-width="756" height="320" src="https://1.bp.blogspot.com/-NoDdToaeTh0/XS6s1AInm9I/AAAAAAAApRk/BHrDrH5gzooNvhCWebLP_6A4LzUd6SnEgCLcBGAs/s320/split.png" width="295" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Split Document configuration</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-ZchFJBEq4Yg/XS6tHtYZAVI/AAAAAAAApRw/Gd1RQ9lfV40EDWN4kAeaWYKE5RDJktxWwCLcBGAs/s1600/process.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="331" data-original-width="964" height="109" src="https://1.bp.blogspot.com/-ZchFJBEq4Yg/XS6tHtYZAVI/AAAAAAAApRw/Gd1RQ9lfV40EDWN4kAeaWYKE5RDJktxWwCLcBGAs/s320/process.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Place Data Process shape before the Map</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
Thank you!</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-37474343476496015062019-02-13T10:41:00.002+10:302019-02-13T10:41:52.373+10:30Java Switch statements : Executing same code for two values without redundant code<div dir="ltr" style="text-align: left;" trbidi="on">
This is something I learnt recently. Assume that you want to execute the same code when the switch variable value is one of multiple values. This can be dine without repeating the same code in multiple case statements.<br />
<br />
For example consider below code. There two case statements that check value for 3 or 4, executes same code block. We can do this without duplicating the code.<br />
<br />
<br />
<!-- HTML generated using hilite.me -->
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">switch</span> <span style="color: #333333;">(</span>number<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 1"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 2"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">3</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 3 or 4"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 3 or 4"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is not 1, 2, 3 or 4"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
See below.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">switch</span> <span style="color: #333333;">(</span>number<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 1"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 2"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">3</span><span style="color: #333333;">):</span><span style="color: #008800; font-weight: bold;">case</span> <span style="color: #333333;">(</span><span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">):</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is 3 or 4"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Number is not 1, 2, 3 or 4"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-45335786662294216512019-02-12T11:16:00.003+10:302019-02-12T11:17:25.058+10:30Java: Difference between Conditional and Bitwise AND operator - & vs &&<div dir="ltr" style="text-align: left;" trbidi="on">
There two AND operators in Java that we can use.<br />
<br />
<b>& - Bitwise AND operator</b><br />
<b>&& - Conditional AND operator.</b><br />
<br />
In Java both above operators can be used in if conditions. However there is a difference how each works. Let's see with an example.<br />
<br />
<b>(x != 0) & (x > 1) </b> - With bitwise AND, it evaluates both (x !=0) and (x > 1) conditions. Then takes the AND of the two results.<br />
<br />
<b>(x != 0) && (x > 1)</b> - With conditional AND, it first valuates (x !=0) and only if it is true, (x > 1) condition will be evaluated. Then takes the AND of the two results. If (x!= 0) was false, it simply returns false.<br />
<br />
<h4 style="text-align: left;">
What is the problem with using & in a condition?</h4>
There are cases where we can only execute a condition only some other condition is true.<br />
See the example below.<br />
<br />
<b>(x != 0) & (3/x > 1) </b>- This will throw an exception if the x=0. So for such cases we can only use &&.<br />
<br />
So in summary, it is always advisable to use conditional AND (&&) in if conditions. & should be used for bitwise operations with numbers. </div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-59495940058056097892019-01-06T16:55:00.001+10:302019-01-06T16:57:33.795+10:30Understanding Java-8 method references with examples<div dir="ltr" style="text-align: left;" trbidi="on">
In my <a href="https://blog.lakmali.com/2019/01/understanding-java-lamda-expression.html">previous post</a>, I described about Lamda expression and its usages. Now I am going to write about method references in Java 8.<br />
<br />
<b>What is a method reference?</b><br />
<br />
As I described in my <a href="https://blog.lakmali.com/2019/01/understanding-java-lamda-expression.html">previous post</a>, a lamda expression is an anonymous function. However, sometimes lamda expression is only calling an existing method. On the other hand, if the function code in the lamda expression is too complicated or has many lines, it makes sense to include it in a separate method. This is when method references comes in handy. Instead of writing a lamda expression, we can refer to an existing method.<br />
<br />
Based on the method type, there are 4 types of method reference syntax.<br />
<br />
<table border="1" summary="Kinds of method references">
<tbody>
<tr>
<th>Type</th>
<th>Syntax</th>
</tr>
<tr>
<td>Reference to a static method</td>
<td><code>ContainingClass::staticMethodName</code></td>
</tr>
<tr>
<td>Reference to an instance method of a particular object</td>
<td><code>containingObject::instanceMethodName</code></td>
</tr>
<tr>
<td>Reference to an instance method of an arbitrary object of a particular type</td>
<td><code>ContainingType::methodName</code></td>
</tr>
<tr>
<td>Reference to a constructor</td>
<td><code>ClassName::new</code></td>
</tr>
</tbody></table>
<br />
<!-- HTML generated using hilite.me --><b>Example usages</b><br />
<br />
I am going to take the same example used in my <a href="https://blog.lakmali.com/2019/01/understanding-java-lamda-expression.html">previous post</a>. Here I have done a slight modification, where GreetProgram has an existing method which has the same function code of the lamda expression. It is the "<span style="background-color: white; color: #0066bb; font-size: 15px; font-weight: bold;">getMyGreet</span>" method.<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><pre style="color: #757575; font-size: 15px; line-height: 18.75px;"><pre style="color: #333333; line-height: 16.25px;"><span style="color: #008800; font-weight: bold;">interface</span> <span style="color: #bb0066; font-weight: bold;">MyInterface</span> {
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">sayWelcome</span>(String name);
}
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">GreetProgram</span> {
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">greet</span>(MyInterface myIn) {
System.<span style="color: #0000cc;">out</span>.<span style="color: #0000cc;">println</span>(myIn.<span style="color: #0000cc;">sayWelcome</span>(<span style="background-color: #fff0f0;">"Lakmali"</span>));
}
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">getMyGreet</span>(String name) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> + name;
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LamdaExpSample</span> {
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">main</span>(String args[]) {
GreetProgram greetProg = <span style="color: #008800; font-weight: bold;">new</span> GreetProgram ();
greetProg.<span style="color: #0000cc;">greet</span>((name) -> {
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> + name;
});
}
}</pre>
</pre>
</pre>
</div>
<br />
So instead of a lamda expression, it can use a method reference as below. Refer the MethodReferSample class code.<br />
<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><pre style="color: #757575; font-size: 15px; line-height: 18.75px;"><pre style="color: #333333; line-height: 16.25px;"><span style="color: #008800; font-weight: bold;">interface</span> <span style="color: #bb0066; font-weight: bold;">MyInterface</span> {
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">sayWelcome</span>(String name);
}
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">GreetProgram</span> {
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">greet</span>(MyInterface myIn) {
System.<span style="color: #0000cc;">out</span>.<span style="color: #0000cc;">println</span>(myIn.<span style="color: #0000cc;">sayWelcome</span>(<span style="background-color: #fff0f0;">"Lakmali"</span>));
}
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">getMyGreet</span>(String name) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> + name;
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MethodRefSample</span> {
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">main</span>(String args[]) {
GreetProgram greetProg = <span style="color: #008800; font-weight: bold;">new</span> GreetProgram ();
greetProg.<span style="color: #0000cc;">greet</span>(<span style="color: #997700; font-weight: bold;">greetProg:</span>:getMyGreet);
}
}</pre>
</pre>
</pre>
</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-44542058357137624402019-01-03T22:09:00.001+10:302019-01-04T22:26:31.542+10:30Understanding Java Lamda Expression with examples<div dir="ltr" style="text-align: left;" trbidi="on">
Lamda expression in Java was introduced in Java 8. This is one of my favorite, cool features of Java 8. This blog is intended to help understanding what is it, where and how can we use it.<br />
<br />
<b>What is lamda expression?</b><br />
<br />
In simple words, Lamda expression in java is an anonymous function. It is defined with the parameter list and the function body.<br />
<br />
Below is the syntax of lamda expression.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #333333;">{</span>parameter list<span style="color: #333333;">}</span> <span style="color: #333333;">-></span> <span style="color: #333333;">{</span>function body<span style="color: #333333;">}</span>
</pre>
</div>
<br />
<span style="background-color: orange; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
So what is actually meant by this definition? Although we define an anonymous function here, this is actually like an implementation to a method in an interface.<br />
<br />
Also, we can assign this lamda expression to a reference of the interface type.<br />
<br />
See example below.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">interface</span> <span style="color: #bb0066; font-weight: bold;">MyInterface</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">sayWelcome</span><span style="color: #333333;">(</span>String name<span style="color: #333333;">);</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LamdaExpSample</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">main</span><span style="color: #333333;">(</span>String args<span style="color: #333333;">[])</span> <span style="color: #333333;">{</span>
MyInterface myIn <span style="color: #333333;">=</span> <span style="color: #333333;">(</span>name<span style="color: #333333;">)</span> <span style="color: #333333;">-></span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> <span style="color: #333333;">+</span> name<span style="color: #333333;">;</span>
<span style="color: #333333;">};</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
As above, we have defined a Lamda expression to return a greet message. It has implemented the "sayWelcome" method and also assigns the expression to a reference called "myIn". This reference can be passed to anywhere MyInterface object is expected.<br />
<br />
The lamda expression can be defined with no parameters, one parameter or multiple parameters. Also the function body can be wrapped with curly braces when there are multiple lines.<br />
<br />
<i>Note</i><br />
<span style="background-color: #fce5cd;">One important thing to note here is that the interface should only have a single method. Because with lamda expression we don't specify the method name we implement. In Java 8 these interfaces are known as Functional interface. Those are normal java interfaces with a single method.</span><br />
<br />
Below section explains the usage with further examples.<br />
<b><br /></b>
<b>Where and how can we use Lamda expression? </b><br />
<br />
Prior to java 8, remember situations when we wanted to implement an interface and override a method? At such times, what we did was creating an anonymous inner class and overriding the method where we wanted to pass that interface object to. Now with Java 8, this is super easy. All we have to do is defining a Lamda expression there.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">interface</span> <span style="color: #bb0066; font-weight: bold;">MyInterface</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">sayWelcome</span><span style="color: #333333;">(</span>String name<span style="color: #333333;">);</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">GreetProgram</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">greet</span><span style="color: #333333;">(</span>MyInterface myIn<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
System<span style="color: #333333;">.</span><span style="color: #0000cc;">out</span><span style="color: #333333;">.</span><span style="color: #0000cc;">println</span><span style="color: #333333;">(</span>myIn<span style="color: #333333;">.</span><span style="color: #0000cc;">sayWelcome</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Lakmali"</span><span style="color: #333333;">));</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LamdaExpSample</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">main</span><span style="color: #333333;">(</span>String args<span style="color: #333333;">[])</span> <span style="color: #333333;">{</span>
GreetProgram greetProg <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> GreetProgram <span style="color: #333333;">();</span>
greetProg<span style="color: #333333;">.</span><span style="color: #0000cc;">greet</span><span style="color: #333333;">((</span>name<span style="color: #333333;">)</span> <span style="color: #333333;">-></span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> <span style="color: #333333;">+</span> name<span style="color: #333333;">;</span>
<span style="color: #333333;">});</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
As shown above, there is this GreetProgram class which has a method expecting an object from the MyInterface. So what we have done is defining an lamda expression as the interface object. Here I have done it inline. The same can be done by defining the lamda expression separately and passing the MyInterface reference to greet method as well.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">GreetProgram greetProg <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> GreetProgram <span style="color: #333333;">();</span>
MyInterface myIn <span style="color: #333333;">=</span> <span style="color: #333333;">(</span>name<span style="color: #333333;">)</span> <span style="color: #333333;">-></span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"Welcome "</span> <span style="color: #333333;">+</span> name<span style="color: #333333;">;</span>
<span style="color: #333333;">};</span>
greetProg<span style="color: #333333;">.</span><span style="color: #0000cc;">greet</span><span style="color: #333333;">(</span>myIn<span style="color: #333333;">);</span>
</pre>
</div>
<br />
So this is pretty much the basics about Lamda expression to get a good understanding. How this helps! Thank you.</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com1tag:blogger.com,1999:blog-1621989597321372268.post-40420132543445176872018-10-13T10:40:00.000+10:302019-01-18T10:40:46.941+10:30REST API Caching<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
REST APIs being exposed over HTTP mainly, there is a great advantage for APIs through HTTP Caching.<br />
<br />
<h3 style="text-align: left;">
Why caching is important for REST APIs? </h3>
<br />
<ul style="text-align: left;">
<li><b>Reduced server load,</b></li>
<li><b>Low response time</b></li>
<li><b>Save bandwidth</b></li>
</ul>
<br />
<span style="text-align: justify;">The biggest gain through caching for REST APIs is reduced server load, because the clients can store a cached response for sometime in their local store and access it without hitting the server. So it will result in a low response time to the client making things faster for them.</span><br />
<br />
<div style="text-align: justify;">
Further, using E-tags (Entity tags), clients have the ability to check with the server whether the response has updated or not. The response body is sent to the client only if the response has changed from what client has cached. Otherwise a 304 Not-Modified response is sent without a response body. </div>
<br />
We'll discuss about ETags more later in this post.<br />
<br />
<h3 style="text-align: left;">
What to cache? </h3>
<div>
In your REST API, there can be data that doesn't change more frequently and also data that changes frequently. We can define those data types as near static data and dynamic data. At a glance one might think, it is pointless to cache dynamic data. However, it isn't the case. Supporting HTTP caching on dynamic data would be beneficial specially for a system with high traffic. When the content are cached even for a short time, it reduces the server load significantly.<br />
<br />
On the other hand, static content can be cached for a long time period. Then a mechanism can be provided for client to check with the sever whether the response has been changed or not.<br />
<br />
<h3 style="text-align: left;">
How to support caching?</h3>
There are number of options in terms of setting HTTP Caching related headings to support caching. We have to select the suitable method based on the requirement.<br />
<br />
So let's see what are the options we have.<br />
<h4 style="text-align: left;">
Max-age</h4>
This is a directive supported in Cache-Control header. It says the maximum time duration which the data can be used from the cache. The API response should include this in the response header. So the client can use the cached response for that period of time and after that send a request to the server.<br />
Since dynamic data can be cached for a short time period, the best way is to use the <b>max-age.</b><br />
<b><br /></b>
<br />
<div style="text-align: center;">
<b><span style="font-family: "courier new" , "courier" , monospace;">Cache-Control: max-age=3600</span></b></div>
<h4 style="text-align: left;">
<b><span style="font-family: inherit;">Last-Modified and Modified-Since</span></b></h4>
<div>
The Last-Modified header says the date-time the response was last updated. The server can add this to the API response.<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;"><b>Last-Modified: Fri, 18 Jan 2019 10:19:00 GMT</b></span></div>
<div style="text-align: center;">
<br /></div>
Then the clients can store the response in the local cache and when they need the same data again, they have to send the API request by including "Modified-Since" with the date-time they received in the first response.<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;"><b>Modified-Since: Fri, 18 Jan 2019 10:19:00 GMT</b></span></div>
<div>
<br /></div>
Now the server should validate whether the particular data was modified since then and if not send a 304-Not Modified response with an empty body. So the client can use the cached response from their local store. If the data has been modified since, the server has to the send the response again.<br />
<br />
This method is suitable for caching both near static and dynamic data. However, it is required to know that since this approach is time centered, there is a chance that client and servers has a time difference more than the expected cache time of a particular data. In that case this is approach is not suitable.<br />
<br />
<b>Etag and If-None-Match</b><br />
<br />
<br />
This is very similar to the above flow of how caching works, except that this depends on the data itself, but not time. Etag is a unique value generated from the response data. The server adds that to the response, so that clients and store that response.<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;"><b>Etag: 7890854718304728402gd</b></span></div>
<br />
Whenever client wants the same data, it can do the API call by adding received Etag to the "If-None-Match" header.<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;"><b>If-None-Match: 7890854718304728402gd</b></span></div>
<br />
Now the server has to generate the Etag for the requested data and see whether what client has sent matches to that or not. If it doesn't match, that means the data has been changed and response should be sent again with the new Etag. If it does, server can just send a 304-Not Modified response.<br />
<br />
Etags is suitable when using a time related solution can not be used.<br />
<br />
So this is some basic information on how to support response caching in REST APIs over HTTP. Hope this helps. </div>
<div style="text-align: center;">
<b><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b></div>
</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-29359253609096586112018-09-15T22:41:00.000+09:302019-01-05T22:43:00.198+10:30What is HTTP/2? <div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: justify;">
Not so long ago, I happened to do a research about HTTP/2 and how it affects performance of web services for my Masters. In this blog post, I am describing the basic details of the HTTP/2 protocol. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
HTTP/2 the latest version of Hyper Text Transfer Protocol, is an optimized transport for HTTP semantics. Hence, it supports all the core features of HTTP/1.1 [1] . The aim of HTTP/2 is to be more efficient by addressing limitations of HTTP/1.1 [1] .</div>
<br />
There are 5 main features of HTTP/2.<br />
<br />
<br />
<ol style="text-align: left;">
<li>Multiplexing</li>
<li>Header Compression</li>
<li>Request prioritization</li>
<li>Server push</li>
<li>Binary message frames. </li>
</ol>
<h3 style="text-align: left;">
<b>Connection establishment in HTTP/2</b></h3>
<div style="text-align: justify;">
HTTP/2 also uses the same “http” and “https” URI schemas and same port numbers as HTTP/1.1. Therefore, implementations processing requests for target URIs with“http” and “https” should have a way to discover whether the next hop supports HTTP/2 or not. The determination procedure for HTTP/2 support is different for “http” and “https” URIs [1] .</div>
<br />
<div>
<br /></div>
<div>
<h4 style="text-align: left;">
Starting HTTP/2 for “http” URIs</h4>
<div style="text-align: justify;">
A client without prior knowledge about HTTP/2 support in next hop, uses an HTTP upgrade mechanism when sending a request for a “http” URI. The client first sends a HTTP/1.1 request which consists of the “h2c” token [1] .</div>
</div>
<div style="text-align: justify;">
<br /></div>
<div>
<div style="text-align: justify;">
A server which supports HTTP/2 sends a 101 response in return. This is the switching protocol response. The server can begin sending response to the request which initiated the upgrade by client, right after the empty line which terminates the 101 response. These are sent as HTTP /2 frames. The first HTTP/2 frame sent by the server must be a connection preface and after client receiving 101 response, it also should send a connection preface. This connection preface is the final confirmation</div>
<div style="text-align: justify;">
about the protocol being used and this needs to be sent by each endpoint in the connection. A server that doesn’t support HTTP/2 can respond to the upgrade request by ignoring the upgrade header [1] .</div>
</div>
<h4 style="text-align: justify;">
<br />Starting HTTP/2 for “https” URIs</h4>
<div>
A client which sends a request to an “https” URI, uses TLS 1.2 with the Application Layer Protocol Negotiation extension (TLS-ALPN). It uses “h2” as the protocol identifier when sending a HTTP/2 request over TLS. After completion of the TLS negotiation, both server and client must send a connection preface [1].</div>
<div>
<br /></div>
<h3 style="text-align: left;">
Frames</h3>
<div>
<div style="text-align: justify;">
All the data that are sent through HTTP/2 protocol are frames. Once HTTP/2 connection is established as above described, endpoints can start sending HTTP/2 frames. There are different frame types in HTTP/2 and each frame has a frame header, followed by some frame payload. The format of the frame payload depends on the frame type [1]. </div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Header Compression</h3>
</div>
<div>
<div style="text-align: justify;">
As mentioned in RFC7230, header fields are not compressed in HTTP/1.1 [2] . With the advancements in web pages, sometimes it requires sending hundreds of requests to load the page. Hence redundant headers sent in these requests consume bandwidth unnecessarily resulting in increased latency. HTTP/2 addresses this issue by using a new form of header compression known as HPACK. . All the headers sent via HTTP/2 (frames of type HEADRES, CONTNUATION and PUSH_PROMISE) are encoded using HPACK. In HPACK, a header will be encoded either of below</div>
<div style="text-align: justify;">
ways [1] .</div>
<div>
<ul style="text-align: left;">
<li>Encode commonly used headers as a reference to the header fields in header tables</li>
<li>Encode literals using a static Huffman code</li>
</ul>
</div>
<div style="text-align: justify;">
Hence, header fields of HTTP/2 can be references to one of the header tables and encoded literals. In HPACK, there are two types of header tables [2] . Those are the static table and the dynamic table. Both client and server maintain a copy of the dynamic header table. When a client sends a header to the server, the client can tell the server to store it in its dynamic table. If the client has to send the same header again, the index value in the dynamic table can be sent instead of the real header. The</div>
<div style="text-align: justify;">
same encoding happens in response path (Server to client) as well. By default, the size of the dynamic table is 4k and it can be changed using a SETTING frame [1] .</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
HPACK also has a static table which contains set of predefined commonly used static headers. In that case, HPACK enables header compression even before dynamic tables are populated [2] . </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
With this approach, it saves a significant amount of bandwidth, when many requests and responses need to be sent with same headers. After the first request, most headers can be represented as index values referencing dynamic or static table [2] . </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Apart from these, HPACK also allows compressing headers by encoding header names and values via a fixed Huffman encoding [2].</div>
</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Streams and Multiplexing</h3>
<div>
<div style="text-align: justify;">
In HTTP/2, a stream is an independent, bi-directional sequence of frames exchanged between the client and server [1] . In a single HTTP/2 connection, there can be multiple streams operating concurrently. The endpoint initializing the stream gives an identifier to the stream which is an integer number. Each frame sent will have a stream identifier in the header and it allows the endpoints to track the request to which a frame belongs to [1] .</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Having streams in HTTP/2 allows sending multiple requests between two endpoints using the same connection and the responses are interleaved whenever they are available. This is known as multiplexing [1] .</div>
</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Stream Priority</h3>
<div>
<div>
Streams can be assigned to a priority which can be used by client to suggest the server about resource allocation in handling concurrent streams [19] . Moreover, in the client end itself, if there is limited capacity to send frames, this priority can be used to decide which streams will be used to send frames. This priority information is included in the HEADER frame which is sent to open the stream [1] . In order to change the priority of an existing stream, PRIORITY frame shall be used [1] . </div>
<div>
<br /></div>
<div>
The priority of streams is defined by setting dependencies among streams. A stream that is dependent on another stream is a dependent stream. The stream on which a stream is dependent is a parent stream. Resources will be allocated for dependent streams upon the completion of the parent streams [1] .</div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
References</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
[1] M. Belshe, R. Peon, and M. Thomson, “Hypertext Transfer Protocol Version 2<br />
(HTTP/2),” Internet Eng. Task Force, no. RFC7540, 2015.<br />
<br />
[2] R. Peon and H. Ruellan, “RFC 7541 HPACK: Header Compression for<br />
HTTP/2,” Internet Eng. Task Force, vol. 1, 2015.</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-82309669376512937782017-06-29T20:00:00.000+09:302017-08-03T14:31:30.395+09:30WSO2 API Manager- Customizing Store User Sign-Up <div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 API Manager allows on boarding new users to the API store through a Sign-up page. The default sign-up page has set of mandatory and optional fields for user to provide details. However, there can be cases where one needs to customize the available fields by modifying available ones or/and adding new fields.<br />
<br />
This can be easily achieved in WSO2 API manager since the fields are loaded dynamically from the user claim attributes. So this post explains how we can customize the default Sign-up page.<br />
<br />
By default API Store Sign-up looks as below. Note that this blog posts shows how to do this in APIM 2.1.0.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-IoW9hU6YhaM/WVTGklqd9zI/AAAAAAAAP90/Q-Ozx_LtM0sJRLOXp0Dd0j486tsCbesXgCLcBGAs/s1600/default-signup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="913" data-original-width="932" height="313" src="https://1.bp.blogspot.com/-IoW9hU6YhaM/WVTGklqd9zI/AAAAAAAAP90/Q-Ozx_LtM0sJRLOXp0Dd0j486tsCbesXgCLcBGAs/s320/default-signup.png" width="320" /></a></div>
<br />
<br />
Let's say you want to add a new field called 'City' to Store Sign-up page. This post provides step by step instructions on how to achieve this.<br />
<br />
1. Start API Manager 2.1.0 and go to Management Console (https://localhost:9443/carbon/)<br />
<br />
2. Go to Claims -> Add -> Add Local Claim<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-lF9Y5PNtucc/WVTHGpyBbKI/AAAAAAAAP98/HdE0Er6tsbM874Uxkf7pbk67QNtbokLQgCLcBGAs/s1600/add-claim1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="318" data-original-width="1346" height="75" src="https://2.bp.blogspot.com/-lF9Y5PNtucc/WVTHGpyBbKI/AAAAAAAAP98/HdE0Er6tsbM874Uxkf7pbk67QNtbokLQgCLcBGAs/s320/add-claim1.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
3. Enter the below values for the new claim.<br />
<br />
<br />
Claim URI : <span style="background-color: white; color: #111111; font-family: "lucida grande" , "lucida sans" , "microsoft sans serif" , "lucida sans unicode" , "verdana" , sans-serif , "trebuchet ms"; font-size: 12px;"><b>http://wso2.org/claims/city</b></span><br />
Display Name : <b>City</b><br />
Description : <b>City</b><br />
Mapped Attribute : <b>city</b><br />
Supported by Default : select<br />
<br />
Note that claims which are 'Supported by Default' true, are only displayed in the Sign-up page. Therefore when you are adding new claims make sure to check 'Supported by Default' checkbox.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-sGkayPur0GQ/WVTKgxekoqI/AAAAAAAAP-I/sbg44XQD94YbxI5NvxXFsBiBKryrAbxNACLcBGAs/s1600/add-city-claim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="448" data-original-width="1346" height="106" src="https://1.bp.blogspot.com/-sGkayPur0GQ/WVTKgxekoqI/AAAAAAAAP-I/sbg44XQD94YbxI5NvxXFsBiBKryrAbxNACLcBGAs/s320/add-city-claim.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
If you need this claim to be a required field [Mandatory field in Sign-up], make sure to check 'Required' checkbox.<br />
<br />
After entering the values, click 'Add'.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
7. Now go to API Store Sign-up page and refresh. You should see the newly added field.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-F6fyyJRttHk/WVTObtm-ADI/AAAAAAAAP-Y/JzQ2PS25yPIddF0sl8ko15VIPByAECGkgCLcBGAs/s1600/city-dispaly.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="951" data-original-width="889" height="320" src="https://3.bp.blogspot.com/-F6fyyJRttHk/WVTObtm-ADI/AAAAAAAAP-Y/JzQ2PS25yPIddF0sl8ko15VIPByAECGkgCLcBGAs/s320/city-dispaly.png" width="299" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<div style="text-align: left;">
<b>Modifying Existing Claims</b></div>
<div style="text-align: left;">
<b><br /></b></div>
<div style="text-align: left;">
Let's say now you want to make the city field 'required'. Also you want to change the field display order. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
1. For that go to Claims -> List and click on <span style="color: #386698; font-family: "lucida grande" , "lucida sans" , "microsoft sans" serif , "lucida sans unicode" , "verdana" , sans-serif , "trebuchet ms";"><span style="background-color: white; font-size: 12px;"><b>http://wso2.org/claims</b></span></span>. In the displaying list of claims click Edit on "City" claim.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-9xOa_7edLws/WVTPUNSxznI/AAAAAAAAP-k/GopLxnYUZd0MCvo6u3F0EWvtCVI1prOvwCLcBGAs/s1600/claims-ui1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="1346" height="86" src="https://1.bp.blogspot.com/-9xOa_7edLws/WVTPUNSxznI/AAAAAAAAP-k/GopLxnYUZd0MCvo6u3F0EWvtCVI1prOvwCLcBGAs/s320/claims-ui1.png" width="320" /></a></div>
<br /></div>
<div style="text-align: left;">
<div style="text-align: center;">
<b><i>Listing Claims</i></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-wOB4P_9_YPA/WVTPdg3aQSI/AAAAAAAAP-o/gqJsDnMOadg0ihA-Ww63ObqMkNSgR1-9gCLcBGAs/s1600/edit-city-claim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="184" data-original-width="1346" height="43" src="https://2.bp.blogspot.com/-wOB4P_9_YPA/WVTPdg3aQSI/AAAAAAAAP-o/gqJsDnMOadg0ihA-Ww63ObqMkNSgR1-9gCLcBGAs/s320/edit-city-claim.png" width="320" /></a></div>
<div style="text-align: center;">
<b><i><br /></i></b></div>
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<i><b>Edit Claim</b></i></div>
<div class="separator" style="clear: both; text-align: center;">
<i><b><br /></b></i></div>
<div class="separator" style="clear: both; text-align: left;">
Now select <span style="background-color: white; color: #111111; font-family: "lucida grande" , "lucida sans" , "microsoft sans serif" , "lucida sans unicode" , "verdana" , sans-serif , "trebuchet ms"; font-size: 12px;">Required </span>checkbox. Also I have changed the display order of all the city claim to 4. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-tzlGLcBmKvw/WVTP7yC3bfI/AAAAAAAAP-s/lOG0Wqq38vI4peJhC-14tr15B3XHjebLwCLcBGAs/s1600/edit-city-claim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="496" data-original-width="1346" height="117" src="https://4.bp.blogspot.com/-tzlGLcBmKvw/WVTP7yC3bfI/AAAAAAAAP-s/lOG0Wqq38vI4peJhC-14tr15B3XHjebLwCLcBGAs/s320/edit-city-claim.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<i><b>Check Required and change display order</b></i></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
</div>
<br />
<br />
2. Now Access the API Store Sign-up page. You will see that the "City" field is re-ordered and marked as required.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-DBiDBs-4sak/WVTQcUXTtkI/AAAAAAAAP-w/GM8DuKpM9wQUYkID6-h-_ptKFGyMM4B6ACLcBGAs/s1600/ordered-city.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="932" data-original-width="919" height="320" src="https://2.bp.blogspot.com/-DBiDBs-4sak/WVTQcUXTtkI/AAAAAAAAP-w/GM8DuKpM9wQUYkID6-h-_ptKFGyMM4B6ACLcBGAs/s320/ordered-city.png" width="315" /></a></div>
<br />
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<br /></div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com4tag:blogger.com,1999:blog-1621989597321372268.post-57792920644162458162017-05-23T03:52:00.000+09:302018-04-29T20:18:06.577+09:30Customizing Lifecycle states in WSO2 API Manager <div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 API Manageris a 100% open source API Management solution inluding support for API publishing, lifecycle management, developer portal, access control and analytics. APIs have their own life cycle which can be managed through WSO2 API Publisher while enabling many essential features for API Management, such as,<br />
<br />
<ul style="text-align: left;">
<li>Create new APIs from existing versions</li>
<li>Deploy multiple versions in parallel</li>
<li>Deprecate versions to remove them from store</li>
<li>Retire them to un-deploy from gateway</li>
<li>Keeps audit of lifecycle changes</li>
<li>Supports customizing lifecycles </li>
</ul>
<div>
<br /></div>
<div>
The ability to customize API life cycle provides a greater flexibility to achieve various requirements. There are few extension points available for customizing the API Lifecycle. Find more details about those from the product <a href="https://docs.wso2.com/display/AM210/Extending+the+API+Life+Cycle">documentation</a> [1]. </div>
<div>
<ul style="text-align: left;">
<li>Adding new lifecycle state</li>
<li>Changing the state transition events</li>
<li>Changing the state transition execution (In each state transition, we can configure an execution logic to be run)</li>
</ul>
</div>
<br />
<div>
In this blog post, I will explain how we can add a custom life cycle state to APIM 2.1.0. </div>
<div>
<div>
<b><br /></b></div>
<div>
<b>Example scenario</b> : Assume that in your organization, you need an intermediate state in between <b>Created</b> and <b>Published</b>, because only the admin user is allowed to publish the API. The API developers/publishers should complete the API and mark it in an intermediate state such as "<b>Ready To Publish</b>". Then the admin users will come to the Publisher, review the APIs in "<b>Ready To Publish</b>" state and mark them as "<b>Published</b>".</div>
</div>
<div>
<br /></div>
<h3 style="text-align: left;">
Customizing the Lifecycle(LC) configuration.</h3>
<div>
<div>
You can find the default LC configuration in APIM as follows.</div>
<div>
<br /></div>
<div>
1. Login to the management console.</div>
<div>
2. Click on "Extensions" -> "Configure" -> "Lifecycles"</div>
<div>
3. Click "View/Edit" "APILifeCycle". It will show you the default LC configuration.</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-ch8RQVlYiQs/WSMlRYgadBI/AAAAAAAAPgA/xrYriqbBQRAryiqo-V94oCRZShrOFbP-gCEw/s1600/Lc-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="119" src="https://3.bp.blogspot.com/-ch8RQVlYiQs/WSMlRYgadBI/AAAAAAAAPgA/xrYriqbBQRAryiqo-V94oCRZShrOFbP-gCEw/s320/Lc-1.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Now we will be introducing a new LC state as "<b>ReadyToPublish</b>" which allows the transition to "<b>Published</b>" and "<b>Prototyped</b>" states by users with "admin" role. Note that, "<b>Prototyped</b>" is an API status which is used when early versions of APIs will be made available for the subscribers. Therefore, it is also considered as a similar state to "Published" state here.</div>
<div>
<br /></div>
<div>
Find the configuration part of the new state.</div>
<div>
<br /></div>
<pre class="brush: xml"><state id="ReadyToPublish">
<datamodel>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
</execution>
</data>
<data name="transitionPermission">
<permission forevent="Deploy as a Prototype" roles="admin">
<permission forevent="Publish" roles="admin">
</permission></permission></data>
</datamodel>
<transition event="Publish" target="Published">
<transition event="Deploy as a Prototype" target="Prototyped">
<transition event="Demote to Created" target="Created">
</transition></transition></transition></state>
</pre>
<div>
Then "<b>Created</b>" status is modified such that it allows transition to "<b>ReadyToPublish</b>" status without any role restriction. However, admin should be able to change the status to "Published" and "Prototyped" directly from "Created".<br />
<br />
The "<b>transitionPermission</b>" configuration sets the roles which are allowed to do the transitions. Here we have set it as admin.<br />
<br />
Note that here we do not have an "<b>transitionExecution</b>" config for "<b>Ready To Publish</b>" state since, we are not performing any execution here. If you need to perform any execution when changing status from "<b>Created</b>" to "<b>Ready To Publish</b>", you can write and plug-in a LC executor for this. Refer <a href="https://docs.wso2.com/display/AM200/Extending+the+API+Life+Cycle">here</a> [2].<br />
<br />
Find the "Created" state configuration with above mentioned modifications.<br />
<br />
<br /></div>
<pre class="brush: xml"><state id="Created">
<datamodel>
<data name="checkItems">
<item forevent="" name="Deprecate old versions after publish the API">
</item>
<item forevent="" name="Requires re-subscription when publish the API">
</item>
</data>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
</execution>
</data>
<data name="transitionPermission">
<permission forevent="Deploy as a Prototype" roles="admin">
<permission forevent="Publish" roles="admin">
</permission></permission></data>
</datamodel>
<transition event="Ready To Publish" target="ReadyToPublish">
<transition event="Publish" target="Published">
<transition event="Deploy as a Prototype" target="Prototyped">
</transition></transition></transition></state>
</pre>
<br />
Find the complete LC configuration with above mentioned changes.
<br />
<pre class="brush: xml"><!--
~ Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<aspect class="org.wso2.carbon.governance.registry.extensions.aspects.DefaultLifeCycle" name="APILifeCycle">
<configuration type="literal">
<lifecycle>
<scxml initialstate="Created" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<state id="Created">
<datamodel>
<data name="checkItems">
<item forevent="" name="Deprecate old versions after publish the API">
</item>
<item forevent="" name="Requires re-subscription when publish the API">
</item>
</data>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
</execution>
</data>
<data name="transitionPermission">
<permission forevent="Deploy as a Prototype" roles="admin">
<permission forevent="Publish" roles="admin">
</permission></permission></data>
</datamodel>
<transition event="Ready To Publish" target="ReadyToPublish">
<transition event="Publish" target="Published">
<transition event="Deploy as a Prototype" target="Prototyped">
</transition></transition></transition></state>
<state id="ReadyToPublish">
<datamodel>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
</execution>
</data>
<data name="transitionPermission">
<permission forevent="Deploy as a Prototype" roles="admin">
<permission forevent="Publish" roles="admin">
</permission></permission></data>
</datamodel>
<transition event="Publish" target="Published">
<transition event="Deploy as a Prototype" target="Prototyped">
<transition event="Demote to Created" target="Created">
</transition></transition></transition></state>
<state id="Prototyped">
<datamodel>
<data name="checkItems">
<item forevent="" name="Deprecate old versions after publish the API">
</item>
<item forevent="" name="Requires re-subscription when publish the API">
</item>
</data>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
</execution>
</data>
</datamodel>
<transition event="Publish" target="Published">
<transition event="Demote to Created" target="Created">
<transition event="Deploy as a Prototype" target="Prototyped">
</transition></transition></transition></state>
<state id="Published">
<datamodel>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Block">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deprecate">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
</execution>
</data>
</datamodel>
<transition event="Block" target="Blocked">
<transition event="Deploy as a Prototype" target="Prototyped">
<transition event="Demote to Created" target="Created">
<transition event="Deprecate" target="Deprecated">
<transition event="Publish" target="Published">
</transition></transition></transition></transition></transition></state>
<state id="Blocked">
<datamodel>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Re-Publish">
</execution>
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deprecate">
</execution>
</data>
</datamodel>
<transition event="Deprecate" target="Deprecated">
<transition event="Re-Publish" target="Published">
</transition></transition></state>
<state id="Deprecated">
<datamodel>
<data name="transitionExecution">
<execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Retire">
</execution>
</data>
</datamodel>
<transition event="Retire" target="Retired">
</transition></state>
<state id="Retired">
</state>
</scxml>
</lifecycle>
</configuration>
</aspect>
</pre>
<br />
<br />
Now add this configuration to the APIM's Lifecycle configuration through the management console and Save.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-8wjKJDFU3zw/WSMlV4HHmbI/AAAAAAAAPgI/_qO8QNtIA6gQ7L0B5RReOvaiTXtGLuEcACEw/s1600/Lc-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="82" src="https://1.bp.blogspot.com/-8wjKJDFU3zw/WSMlV4HHmbI/AAAAAAAAPgI/_qO8QNtIA6gQ7L0B5RReOvaiTXtGLuEcACEw/s320/Lc-2.png" width="320" /></a></div>
<br />
<h3 style="text-align: left;">
Configure the UI to show the new LC state with a preferred display name.</h3>
<div>
<div>
When you add the new LC state, it will be displayed in the Publisher UI as "ready to publish". You can change it as you prefer as below.</div>
<div>
<br /></div>
<div>
Go to <AM_HOME>/repository/deployment/server/jaggeryapps/publisher/site/conf/locales/jaggery/locale_default.json . Add "ready to publish": "Ready To Publish" to end of the file. Note that the key in the JSON pair should be lowercase.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-rrqYmbOWXws/WSMqCHboASI/AAAAAAAAPgQ/HNC_xnD0vtEuWSXMylRcequxqdStRvv9ACLcB/s1600/LC-publisher.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="173" src="https://3.bp.blogspot.com/-rrqYmbOWXws/WSMqCHboASI/AAAAAAAAPgQ/HNC_xnD0vtEuWSXMylRcequxqdStRvv9ACLcB/s320/LC-publisher.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Now the configuration required are completed. When a user with publish permission (no admin permissions) goes to the LC tab of an API in "Created" state, user can only change it to "Ready to Publish" state as above.</div>
<div>
<br /></div>
<div>
One the state is changed to "Ready to Publish", user can then demote it to Created again. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-Bn_L1O2Vmp8/WSMrQKyBgDI/AAAAAAAAPgc/-fToY5QQXBAh1LbJKdeZxs1WDtceae2GACLcB/s1600/LC-Publisher2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="162" src="https://2.bp.blogspot.com/-Bn_L1O2Vmp8/WSMrQKyBgDI/AAAAAAAAPgc/-fToY5QQXBAh1LbJKdeZxs1WDtceae2GACLcB/s320/LC-Publisher2.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Now if the admin logs in and checks this API, he will be getting options to "Publish" and "Deploy as Prototype" as well.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-kUA19LGAa-o/WSMrxBswdfI/AAAAAAAAPgk/AklLjp0dBZo47Z7XDR1XTEMQbnI5BpfvgCLcB/s1600/LC-admin1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://3.bp.blogspot.com/-kUA19LGAa-o/WSMrxBswdfI/AAAAAAAAPgk/AklLjp0dBZo47Z7XDR1XTEMQbnI5BpfvgCLcB/s320/LC-admin1.png" width="320" /></a></div>
<div>
<br /></div>
<div>
This way, we can control who can Publish the API by role. This is just an example scenario to explain the capabilities available in WSO2 API Manager to customize the Lifecycle states. So based on your requirements, these extension options can be used accordingly.</div>
<div>
<br /></div>
<div>
Thank You!</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com1tag:blogger.com,1999:blog-1621989597321372268.post-41298078799984164042017-01-24T12:57:00.000+10:302017-01-24T13:01:02.516+10:30Encrypting passwords in WSO2 APIM 2.0.0<div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 products support encrypting passwords which are in configuration files using secure vault.<br />
You can find the detailed documentation form <a href="https://docs.wso2.com/display/Carbon443/Encrypting+Passwords+with+Cipher+Tool">here</a> of how to apply secure vault to WSO2 products.<br />
<br />
This post will provide you the required instructions to apply secure vault to WSO2 APIM 2.0.0.<br />
<br />
<h3 style="text-align: left;">
1. Using the automatic approach to encrypt the passwords given in XML configuration files.</h3>
<br />
Most of the passwords in WSO2 APIM 2.0.0 are in XML configuration files. Therefore you can follow the instructions given in <a href="https://docs.wso2.com/display/Carbon443/Encrypting+Passwords+with+Cipher+Tool#EncryptingPasswordswithCipherTool-Encryptingpasswordsusingtheautomatedprocess">here</a> to encrypt them.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-QtnBIhhVxPU/WIYVUwOzggI/AAAAAAAAOB0/uxFXAE1UcMk8CI0WYwOsEN5v5XouWaRpACLcB/s1600/blog-pc-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://1.bp.blogspot.com/-QtnBIhhVxPU/WIYVUwOzggI/AAAAAAAAOB0/uxFXAE1UcMk8CI0WYwOsEN5v5XouWaRpACLcB/s320/blog-pc-1.png" width="320" /></a></div>
<br />
<br />
<h3 style="text-align: left;">
2. Encrypting passwords in jndi.properties file and log4j.properties files.</h3>
<br />
As did in above section, the passwords in XML configurations can be referred in cipher-tool.properties file via Xpaths. Therefore cipher-tool can automatically replace the plain text passwords in XML configuration files.<br />
<br />
However, passwords in files such as jndi.properties file and log4j.properties filee need to be manually encrypted.<br />
<h4>
</h4>
<ul style="text-align: left;">
<li><b><u>Encrypting passwords in jndi.properties file.</u></b></li>
</ul>
<div>
Since passwords in jndi.properties file are embedded into the connection URLs of connectionfactory.TopicConnectionFactory and connectionfactory.QueueConnectionFactory, we have to encrypt the complete connection URL. </div>
<div>
<br /></div>
<div>
Assume that I have my connection URLs as below.</div>
<div>
<br /></div>
<br />
<div>
<b><span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">connectionfactory.TopicConnectionFactory = amqp://admin:admin@clientid/carbon?brokerlist='tcp://localhost:5672'</span></b></div>
<div>
<div>
<b><span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></b></div>
<div>
<b><span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">connectionfactory.QueueConnectionFactory = amqp://admin:admin@clientID/test?brokerlist='tcp://localhost:5672'</span></b></div>
</div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b></div>
<div>
First I will be encrypting the connection URL of connectionfactory.TopicConnectionFactory.</div>
<div>
For that I am going to execute ciphertool which will prompt me to enter the plain text password.</div>
<div>
<br /></div>
<div>
So I gave <b><span style="color: blue; font-family: "courier new" , "courier" , monospace;">amqp://admin:admin@clientid/carbon?brokerlist='tcp://localhost:5672'</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b></div>
<div>
<span style="font-family: inherit;">It returned me the encrypted value as below.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-SU3CVes6kaQ/WIYYA0Nh1oI/AAAAAAAAOCE/_8f4uROCyMcQt1mgvkYh2pSFmRq-ZvSnwCLcB/s1600/blog-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="51" src="https://2.bp.blogspot.com/-SU3CVes6kaQ/WIYYA0Nh1oI/AAAAAAAAOCE/_8f4uROCyMcQt1mgvkYh2pSFmRq-ZvSnwCLcB/s320/blog-3.png" width="320" /></a></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Now I have to update the cipher-text.properties file with the encrypted string as below. As the alias I used </span>connectionfactory.TopicConnectionFactory</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">connectionfactory.TopicConnectionFactory=hY17z32eA/AWzsGuJPf+XNgd5YkhgYkAgxse/JoPIUmxDMl6XnDen+JN7319tRS8aYLN1LcKOgOpUpbm9DAKfm/zXXGdLPLb7QzCCabkAXEtiloH02jMyNYjvUd9cLFksNojaJyZT6c5j4Je4niRuRjr/scyhzBsQ6L3HHJ5hkQ=</span></div>
<div>
<br /></div>
<div>
Similarly I encrypted the connection URL of connectionfactory.QueueConnectionFactory and updated the cipher-text.properties file.</div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;">connectionfactory.QueueConnectionFactory=c3uectqczNf28SOTW3IFYcj4Sk6ZhdXaFd1ie44XCvA4q4McKFGn1FdicscVvXTD2pp8zVZkDoFE3PQ23J85+QoCOy7jICfLwagkbqi8fSlJcjorhMEOzMJ7xgzFrEJ/AnOHHJqw3vsh/NU13wG3dNy0QRkfYWzQWmfp+i9HeL0=</span></div>
<div>
<br /></div>
<div>
Then I have to modify the jndi.properties file with the alias values instead of the plain text URLs. For that update it as below.</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b><br /></b></span></div>
<div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>connectionfactory.TopicConnectionFactory = secretAlias:connectionfactory.TopicConnectionFactory</b></span></div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b><br /></b></span></div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>connectionfactory.QueueConnectionFactory = secretAlias:connectionfactory.QueueConnectionFactory</b></span></div>
</div>
<div>
<u><br /></u></div>
<ul style="text-align: left;">
<li><b><u>Encrypting passwords in log4j.properties file.</u></b></li>
</ul>
<div>
Similar to above we can encrypt the password of log4j.appender.LOGEVENT.password in log4j.properties file and add the encrypted string to cipher-text.properties and update the log4.properties file with the alias.</div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: blue; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>log4j.appender.LOGEVENT.password=secretAlias:log4j.appender.LOGEVENT.password</b></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b><br /></b></span></div>
<div>
<br class="Apple-interchange-newline" />
That's it. </div>
<div>
<br /></div>
<div>
Now when you start the server, provide the keystore password which will be used to decrypt the passwords in run time.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-BHSyq8oWDB0/WIYYAFsFyGI/AAAAAAAAOCA/pBfd7Q5dEAw0ME4uDE0OLxuJV28zREiTgCEw/s1600/blog-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="50" src="https://3.bp.blogspot.com/-BHSyq8oWDB0/WIYYAFsFyGI/AAAAAAAAOCA/pBfd7Q5dEAw0ME4uDE0OLxuJV28zREiTgCEw/s320/blog-2.png" width="320" /></a></div>
<div>
<br /></div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-45138689335757500662016-08-05T19:40:00.002+09:302017-08-03T15:43:57.377+09:30Dynamic Endpoints in WSO2 API Manager<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
From WSO2 APIM 1.10.0, we have introduced new feature to define dynamic endpoints through synapse default endpoints support. In this blog article, I am going to show how we can create an API with dynamic endpoints in APIM.<br />
<br />
Assume that you have a scenario where depending on the request payload, the backend URL of the API differs. For instance, if the value of "operation" element in the payload is "menu", you have to route the request to endpoint1 and else you need to route the request to endpoint2.<br />
<br />
<br /></div>
<pre class="brush: js">{
"srvNum": "XXXX",
"operation": "menu"
}
</pre>
In APIM, dynamic endpoints are achieved through mediation extension sequences. For more information about mediation extensions refer <a href="https://docs.wso2.com/display/AM200/Adding+Mediation+Extensions">this</a> documentation.<br />
<br />
For dynamic endpoints we have to set the "To" header with the endpoint address through a mediation In-flow sequence. So let's first create the sequence which sets the "To" header based on the payload. Create a file named dynamic_ep.xml with below content.<br />
<br /></div>
<pre class="brush: xml">
<sequence xmlns="http://ws.apache.org/ns/synapse" name="dynamic_ep">
<property expression="json-eval($.operation)" name="operation" />
<filter regex="menu" source="$ctx:operation">
<then>
<header name="To" value="https://localhost:9448/am/sample/pizzashack/v1/api/menu" />
</then>
<else>
<header name="To" value="https://localhost:9448/defaultep" />
</else>
</filter>
<property expression="get-property('To')" name="ENDPOINT_ADDRESS" />
</sequence>
</pre>
<br />
<b>Supporting Destination based usage tracing for dynamic endpoints.</b><br />
In here note that we have to set "ENDPOINT_ADDRESS" additional property with the "To" header value which is required for populating destination address for statistics (API Usage by Destination). So if you have statistics enabled in your APIM setup, you have to set this property as well with the endpoint value in order to see the destination address in the statistic views.<br />
<br />
Now let's assign this sequence to the API. For that go to the "Implement" tab of the API creation wizard.<br />
<br />
<ul style="text-align: left;">
<li>Select "Dynamic Endpoint" as the "Endpoint Type"</li>
<li>Upload dynamic_ep.xml to the "In Flow" under message mediation policies. </li>
<li>Save the API</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-TWXvsJPDBrU/V6RkLLjRABI/AAAAAAAAMFQ/omz2eTagq9AFsLxwxAwOWYUIEMgCkMZfQCLcB/s1600/dynamic_ep.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="215" src="https://2.bp.blogspot.com/-TWXvsJPDBrU/V6RkLLjRABI/AAAAAAAAMFQ/omz2eTagq9AFsLxwxAwOWYUIEMgCkMZfQCLcB/s320/dynamic_ep.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Now let's try out the API.</div>
<div>
<br /></div>
<div>
With Payload containing "menu"</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-MVeMeLCsXOw/V6Rk0rSA3PI/AAAAAAAAMFY/VoFq5hfx_6IONmrRWH6YfzLzFbjrwtwAACLcB/s1600/menu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://4.bp.blogspot.com/-MVeMeLCsXOw/V6Rk0rSA3PI/AAAAAAAAMFY/VoFq5hfx_6IONmrRWH6YfzLzFbjrwtwAACLcB/s320/menu.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Wire log showing request going to endpoint 1.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-8CO6-6ObBpA/V6RlugbnPtI/AAAAAAAAMFk/SNLHAODsvyECFyCRPYV11Jai_wsoW9z1gCLcB/s1600/menu2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="98" src="https://2.bp.blogspot.com/-8CO6-6ObBpA/V6RlugbnPtI/AAAAAAAAMFk/SNLHAODsvyECFyCRPYV11Jai_wsoW9z1gCLcB/s320/menu2.png" width="320" /></a></div>
<div>
<br /></div>
<div>
With Payload NOT containing "menu".</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-lJpJqRfIRpg/V6RlzNnzMZI/AAAAAAAAMFo/K85X3xbJGr8gkZvSqaSSIdsqW_ua6BLtQCLcB/s1600/oder.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://3.bp.blogspot.com/-lJpJqRfIRpg/V6RlzNnzMZI/AAAAAAAAMFo/K85X3xbJGr8gkZvSqaSSIdsqW_ua6BLtQCLcB/s320/oder.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Wire log showing request going to endpoint 2.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-XZcyIYSSahY/V6Rl354whtI/AAAAAAAAMFs/F49vQS6_1dsT1DjohCZKXzDYFrSmujT5gCLcB/s1600/order2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="96" src="https://3.bp.blogspot.com/-XZcyIYSSahY/V6Rl354whtI/AAAAAAAAMFs/F49vQS6_1dsT1DjohCZKXzDYFrSmujT5gCLcB/s320/order2.png" width="320" /></a></div>
<div>
<br /></div>
<div>
This way you can write your own logic using mediation extensions and dynamic endpoints in APIM to route your requests to dynamic destinations. </div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com6tag:blogger.com,1999:blog-1621989597321372268.post-82625104408672525762015-01-15T23:28:00.003+10:302018-04-29T20:20:27.664+09:30How to invoke APIs in SOAP style in Swagger <div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 API Manager has integrated Swagger to allow API consumers to explore APIs through a interactive console which is known as 'API Console'<br />
<br />
This swagger based API Console supports invoking APIs i REST style out of the box. So this post going to show how we can invoke APIs in SOAP style in API console of WSO2 API Manager 1.7.0. For that we need to do few extra configurations.<br />
<br />
1. Send SOAPAction and Content-Type header in the request<br />
2. Enable sending SOAPAction header in the CORS configuration<br />
<br />
<br />
<br />
First create an API for a SOAP Service. In this example I am using HelloService sample SOAP service of WSO2 Application Server. This HelloService has a operation named greet which accepts a payload as below.<br />
<br />
<pre class="brush: js"><soapenv:envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://www.wso2.org/types">
<soapenv:header>
<soapenv:body>
<typ:greet>
<!--Optional:-->
<name>lakmali</name>
</typ:greet>
</soapenv:body>
</soapenv:header></soapenv:envelope>
</pre>
<br />
<h3 style="text-align: left;">
1. Create API</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-4pzQ46UuSFU/VLer400efsI/AAAAAAAAFDo/NFZKoU1zEWQ/s1600/APICreate-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-4pzQ46UuSFU/VLer400efsI/AAAAAAAAFDo/NFZKoU1zEWQ/s1600/APICreate-1.png" height="221" width="400"></a></div>
<br />
<br />
<div style="text-align: center;">
<i>Figure-1 : Design API </i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-zShJ-mhLurg/VLesG-02mVI/AAAAAAAAFDw/MabhUdXfr2c/s1600/APICreate-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-zShJ-mhLurg/VLesG-02mVI/AAAAAAAAFDw/MabhUdXfr2c/s1600/APICreate-2.png" height="185" width="400"></a></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: center;">
<i>Figure-2 : Implement API by giving SOAP endpoint</i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-ybgFSgLGozo/VLesQtI_yCI/AAAAAAAAFD4/9CwHbPHCmCI/s1600/APICreate-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/-ybgFSgLGozo/VLesQtI_yCI/AAAAAAAAFD4/9CwHbPHCmCI/s1600/APICreate-3.png" height="201" width="400"></a></div>
<i><br /></i></div>
<div style="text-align: center;">
<i>Figure-3 :Save and Publish API</i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: left;">
<br />
<h3 style="text-align: left;">
2. Update Swagger API Definition</h3>
<br />
Now we have to edit the default Swagger content and add SOAPAction and Content-Type header. For that go to 'Docs' tab and click 'Edit Content' for API definition.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/--zqc1EgvziY/VLev2mfBdiI/AAAAAAAAFEE/-OcRGoJc9do/s1600/edit-content.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/--zqc1EgvziY/VLev2mfBdiI/AAAAAAAAFEE/-OcRGoJc9do/s1600/edit-content.png" height="115" width="400"></a></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: center;">
<i>Figure-4: Edit Swagger API definition</i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: left;">
Since we have to send a payload in the request, locate the POST http method in the content. Then add below content into the 'parameters' section of POST http method. </div>
<div style="text-align: left;">
<br /></div>
{<br />
"name": "SOAPAction",<br />
"description": "OAuth2 Authorization Header",<br />
"paramType": "header",<br />
"required": false,<br />
"allowMultiple": false,<br />
"dataType": "String"<br />
},<br />
{<br />
"name": "Content-Type",<br />
"description": "OAuth2 Authorization Header",<br />
"paramType": "header",<br />
"required": false,<br />
"allowMultiple": false,<br />
"dataType": "String"<br />
}<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: right;">
<i style="text-align: center;"><br /></i></div>
<div style="text-align: right;">
<i style="text-align: center;"><br /></i></div>
<div style="text-align: left;">
<span style="text-align: center;">Then the complete POST HTTP method definition would look like below.</span></div>
<div style="text-align: left;">
<i style="text-align: center;"><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-9teCbPYnPWc/VLex4sPiUyI/AAAAAAAAFEQ/2_MuhKDHbfc/s1600/HTTP-POST.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-9teCbPYnPWc/VLex4sPiUyI/AAAAAAAAFEQ/2_MuhKDHbfc/s1600/HTTP-POST.png" height="640" width="556"></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<i>Figure-5: Edited Swagger API definition</i></div>
<div style="text-align: left;">
<i style="text-align: center;"><br /></i></div>
<div style="text-align: left;">
<span style="text-align: center;">After doing the above changes Save & Close.</span></div>
<div style="text-align: left;">
<span style="text-align: center;"><br /></span></div>
<div style="text-align: left;">
<span style="text-align: center;">Now if you go to <b>API Store </b>and click on the created API, and the go to API Console, you should see the SOAPAction and Content-Type fields are added to the Swagger UI.</span></div>
<div style="text-align: left;">
<span style="text-align: center;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-cFuScAz6f_Q/VLezzqARURI/AAAAAAAAFEc/3pSniTqW_bI/s1600/Store-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-cFuScAz6f_Q/VLezzqARURI/AAAAAAAAFEc/3pSniTqW_bI/s1600/Store-1.png" height="261" width="400"></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<i>Figure-6: API Console with new header parameters</i></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<h3 style="clear: both; text-align: left;">
3. Add New Headers to CORS Configuration</h3>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
Although we have added required headers, those will be sent in the request oly if they are set as allowed headers in the CORS configuration.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
For that open APIM_HOME/repository/conf/api-manager.xml file and locate CORSConfiguration. Then add SOAPAction in to available list of Access-Control-Allow-Headers as below (Content-Type is added by default, So we have to only add SOAPAction). </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-6ffxkuYJqmE/VLe1BqBfAnI/AAAAAAAAFEo/5OX_OQnVw6Y/s1600/CORS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-6ffxkuYJqmE/VLe1BqBfAnI/AAAAAAAAFEo/5OX_OQnVw6Y/s1600/CORS.png" height="91" width="400"></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<i>Figure-7: API Console with new header parameters</i></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
After adding the headers, restart the api manager and invoke the API through API Console. </div>
<div class="separator" style="clear: both; text-align: left;">
When invoking the API, set the SOAPAction according to your SOAP service. Also set the COntent-Type header as 'text/xml'</div>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-PviC8VFqbQA/VLe4z2l5VZI/AAAAAAAAFE0/VcpAEq3oUh0/s1600/invoke.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-PviC8VFqbQA/VLe4z2l5VZI/AAAAAAAAFE0/VcpAEq3oUh0/s1600/invoke.png" height="302" width="400"></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<i>Figure-8: API Console Invoke API</i></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
If you face any issues with swagger invoke, please go through <a href="http://blog.lakmali.com/2014/11/troubleshooting-issues-with-swagger-in.html">this</a>.</div>
</div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com3tag:blogger.com,1999:blog-1621989597321372268.post-68746083170741181802014-11-19T03:51:00.000+10:302015-01-18T13:02:45.151+10:30Troubleshooting Swagger issues in WSO2 API Manager<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: justify;">
WSO2 API Manager provides this functionality through the integration of Swagger (<a class="external-link" href="https://developers.helloreverb.com/swagger" rel="nofollow" target="_blank">https://developers.helloreverb.com/swagger</a>). Swagger-based interactive documentation allows you to try out APIs from the documentation itself which is available as the "API Console" in API Store. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There are certain requirements that need to be satisfied in order to swagger Try-it functionality to work. First requirement is to enable CORS in API Mananger Store. <a href="https://docs.wso2.com/display/AM170/Adding+Documentation+Using+Swagger#AddingDocumentationUsingSwagger-Enablingcross-originresourcesharing">This documentation</a> describes how that should be done. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But most of them face many issues in getting the swagger Try-it into work. So this blog post describes common issues faced by users with Swagger and how to troubleshoot them. </div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
<b>Issue-1</b></h3>
<div style="text-align: justify;">
API Console keeps on loading the response for ever as below.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Yxjyx4VunYY/VKLJHOUmpJI/AAAAAAAAE9s/A_0Dhlgef18/s1600/loading-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-Yxjyx4VunYY/VKLJHOUmpJI/AAAAAAAAE9s/A_0Dhlgef18/s1600/loading-1.png" height="163" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: justify;">
<b>Cause -1</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
API resource not supporting OPTIONS HTTP verb. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Solution</b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
Add OPTIONS HTTP verb for API resources as below. Then Save the API and Try again. </div>
<div style="text-align: justify;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-poPO0umq4oU/VKLJ-q86qqI/AAAAAAAAE94/CAQIH9eK4tw/s1600/options.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-poPO0umq4oU/VKLJ-q86qqI/AAAAAAAAE94/CAQIH9eK4tw/s1600/options.png" height="125" width="400" /></a></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Cause -2 </b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Backend endpoint not supporting OPTIONS HTTP verb. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Note: You can verify this by directly invoking the backend for OPTIONS verb. If backend is not supporting OPTIONS verb, "403 HTTP method not allowed" will be returned. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-vrtrVe4NQZc/VKLR1EU2DJI/AAAAAAAAE-U/KzE-sMWQcOI/s1600/method_not_allowed.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-vrtrVe4NQZc/VKLR1EU2DJI/AAAAAAAAE-U/KzE-sMWQcOI/s1600/method_not_allowed.png" height="137" width="320" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Solution</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
If you have control over the Backend service/api, enable OPTIONS HTTP verb. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Note: You can verify this by directly invoking the backend for OPTIONS verb. If backend is supporting OPTIONS verb, 200/202/204 success response should be returned.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-8oNCTs0-mYA/VKLQiF1ymoI/AAAAAAAAE-I/2RDPL2F8BeY/s1600/options-supported.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-8oNCTs0-mYA/VKLQiF1ymoI/AAAAAAAAE-I/2RDPL2F8BeY/s1600/options-supported.png" height="125" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
If you can't enable OPTIONS HTTP verb in the backend, then what you can do is modify the API synapse sequence of the API, which returns back without sending the request to the backend if it is an OPTIONS request. </div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Issue-2</h3>
<div style="text-align: justify;">
API Console completes request execution, but no response is returned. </div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-xc8qVW58yCs/VKLSLlKOTsI/AAAAAAAAE-c/PFE8kT6iMIY/s1600/no-response.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-xc8qVW58yCs/VKLSLlKOTsI/AAAAAAAAE-c/PFE8kT6iMIY/s1600/no-response.png" height="231" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Cause-1</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Authentication Type enabled for OPTIONS HTTP verb is not 'None'. </div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-3b4Yhl7XlW8/VKLTDo7_SfI/AAAAAAAAE-o/I690RVkSU2s/s1600/not-none.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-3b4Yhl7XlW8/VKLTDo7_SfI/AAAAAAAAE-o/I690RVkSU2s/s1600/not-none.png" height="203" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
If this is the cause below error message will be shown in the wso2carbon.log.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException: Required OAuth credentials not provided</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.wso2.carbon.apimgt.gateway.handlers.security.oauth.OAuthAuthenticator.authenticate(OAuthAuthenticator.java:122)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler.handleRequest(APIAuthenticationHandler.java:92)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.rest.API.process(API.java:285)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:83)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:64)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:220)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.core.axis2.SynapseMessageReceiver.receive(SynapseMessageReceiver.java:83)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:344)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:168)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)</span></i></div>
<div style="text-align: justify;">
<i><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>at java.lang.Thread.run(Thread.java:662)</span></i></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
<b>Solution</b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
Make the Auth Type as none for OPTIONS HTTP verb as below. Then Save & Publish the API.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-a1dm5gcUags/VKLUR4MPhtI/AAAAAAAAE-0/1wPt9CI8YVU/s1600/none.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-a1dm5gcUags/VKLUR4MPhtI/AAAAAAAAE-0/1wPt9CI8YVU/s1600/none.png" height="208" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
<b>Note: If you are seeing the Issue -2 , even though Authentication type is shown as none for OPTIONS, then please re-select the authentication type as 'none' as above. </b><b>Then Save & Publish the API. There is an UI bug in API Manager 1.7.0, where although you have set some other authentication type other than 'None' for OPTIONS verb, UI shows it as none. </b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
<b>Cause-2</b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
API Store domain/port which you are currently trying swagger API Console, is not
included in the CORS Access-Control-Allow-Origin configuration. For example, in below CORS configuration, only localhost domain addresses are allowed for API Store. But API Console is accessed using IP address. </div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-r9NjvAYUJDs/VKLYLLfLdUI/AAAAAAAAE_A/_7RurNtuoZA/s1600/cors-config-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-r9NjvAYUJDs/VKLYLLfLdUI/AAAAAAAAE_A/_7RurNtuoZA/s1600/cors-config-1.png" height="86" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-sw2ZsUhDrSc/VKLYi-N_M9I/AAAAAAAAE_I/ft267vIAnX0/s1600/different-origin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-sw2ZsUhDrSc/VKLYi-N_M9I/AAAAAAAAE_I/ft267vIAnX0/s1600/different-origin.png" height="248" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Solution</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Include domain/port in the CORS Access-Control-Allow-Origin configuration. For above example, we have to include IP address as below. Then restart the server and try API Console again. </div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-vtvoTJWn7W8/VKLadoErrHI/AAAAAAAAE_U/8wDP3TY1kRk/s1600/cors-config-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-vtvoTJWn7W8/VKLadoErrHI/AAAAAAAAE_U/8wDP3TY1kRk/s1600/cors-config-2.png" height="55" width="320" /></a></div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Issue-3</h3>
<div>
<span style="text-align: justify;">API Console keeps on loading the response for ever as below when API Store is accessed as HTTPs, while HTTP is working properly. </span></div>
<div>
<span style="text-align: justify;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Yxjyx4VunYY/VKLJHOUmpJI/AAAAAAAAE9s/A_0Dhlgef18/s1600/loading-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" src="http://1.bp.blogspot.com/-Yxjyx4VunYY/VKLJHOUmpJI/AAAAAAAAE9s/A_0Dhlgef18/s1600/loading-1.png" height="163" width="400" /></a></div>
<div>
</div>
<div>
<b>Cause-1</b></div>
<div>
<b><br /></b></div>
<div>
Browser blocking the request due to accessing the API Gateway in HTTP from HTTPs. </div>
<div>
<br /></div>
<div>
<b>Solution</b></div>
<div>
<b><br /></b></div>
<div>
Go to API Publisher and edit "Swagger API Definition" of the API and change the <b>basePath</b> with https gateway address as below. The Save the "Swagger API Definition" and try again. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-_hJf0hP_Uys/VKLdwpCdLYI/AAAAAAAAE_g/Y8YhLcWZh8g/s1600/edit-doc-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-_hJf0hP_Uys/VKLdwpCdLYI/AAAAAAAAE_g/Y8YhLcWZh8g/s1600/edit-doc-1.png" height="91" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-CI8tOZHHQmI/VKLdw8QqQBI/AAAAAAAAE_k/inAkIo-LmX8/s1600/edit-doc-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-CI8tOZHHQmI/VKLdw8QqQBI/AAAAAAAAE_k/inAkIo-LmX8/s1600/edit-doc-2.png" height="292" width="400" /></a></div>
<div>
<b>Cause-2 </b></div>
<div>
<b><br /></b></div>
<div>
If you are still getting the issue, even after applying the above then, cause can be that the security certificate issued by the server is
not trusted by your browser.</div>
<div>
<br /></div>
<div>
<b>Solution</b></div>
<div>
<br /></div>
<div>
Access the HTTPS gateway endpoint directly from your browser and accept the security certificate. Then try again. </div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com4tag:blogger.com,1999:blog-1621989597321372268.post-38776648996807924292014-11-02T04:24:00.000+10:302018-04-29T20:25:30.086+09:30Customizing workflows in WSO2 API Manager<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: justify;">
In WSO2 API Manager,<strong> Workflow extensions</strong>
allow you to attach a custom workflow to various operations in the API
Manager for</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>User Signup</li>
<li>Application Creation</li>
<li>Application Registration</li>
<li>Subscription</li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
By default, the API Manager workflows have <strong>Simple Workflow Executor</strong> engaged in them. The Simple Workflow Executor carries out an operation without any intervention by a workflow admin. For example, when the user creates an application, the Simple Workflow Executor allows the application to be created without the need for an admin to approve the creation process.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
In order to enforce intervention by a workflow admin, you can engage the <strong>WS Workflow Executor</strong>.
It invokes an external Web service when executing a workflow and the
process completes based on the output of the Web service. For example, when
the user creates an application, the request goes into an intermediary
state where it remains until authorized by a workflow admin.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
You can try out the default workflow extensions provided by WSO2 API Manager to engage business processes with API management operations as described in <a href="https://docs.wso2.com/display/AM170/Adding+Workflow+Extensions">here</a>. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There are two extension points exposed with WSO2 API Manager to customize workflows.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Customizing the Workflow Executor</div>
<div style="text-align: justify;">
</div>
<ul>
<li>When you need to change the workflow logic</li>
<li>When you need to change the Data Formats</li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Customizing the Business Process</div>
<div style="text-align: justify;">
</div>
<ul>
<li>When you are happy with the Data Formats and need to change only the business flow</li>
</ul>
<div>
This blog post will provide a sample on how we can customize workflow executors and change the workflow logic.<br />
<br /></div>
<div>
First let's look at WorkflowExecutor class which each WS workflow executor is extended from.</div>
<div>
<br /></div>
<pre class="brush: js">/**
* This is the class that should be extended by each workflow executor implementation.
*/
public abstract class WorkflowExecutor {
/**
* The Application Registration Web Service Executor.
*/
public class ApplicationRegistrationWSWorkflowExecutor extends WorkflowExecutor{
//Logic to execute the workflow
public void execute(WorkflowDTO workflowDTO) { }
//Logic to complete the workflow
public void complete(WorkflowDTO workflowDTO) { }
//Returns the workflow type - ex: WF_TYPE_AM_USER_SIGNUP
public String getWorkflowType() { }
//Used to get workflow details
public List getWorkflowDetails(String workflowStatus) { }
}</pre>
<br /></div>
</div>
<br />
<div style="text-align: justify;">
As the example scenario, let's consider the Application registration workflow of WSO2 API manager.</div>
<div style="text-align: justify;">
After an application is created, you can subscribe to available APIs, but you get the consumer key/secret and access tokens only after registering the application. There are two types of registrations that can be done to an application: production and sandbox. You change the default application registration workflow in situations such as the following:</div>
<br />
<br />
<ul style="text-align: left;">
<li>To issue only sandbox keys when creating production keys is deferred until testing is complete.</li>
<li>To restrict untrusted applications from creating production keys. You allow only the creation of sandbox keys.</li>
<li>To make API subscribers go through an approval process before creating any type of access token.</li>
</ul>
<div>
Find step by step instructions on how we can configure Application Registration Workflow from <a href="https://docs.wso2.com/display/AM170/Adding+an+Application+Registration+Workflow">here</a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-0bTFEOzexhs/VKA5WUmBQnI/AAAAAAAAE9M/ZnwVJlg_ifc/s1600/blog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-0bTFEOzexhs/VKA5WUmBQnI/AAAAAAAAE9M/ZnwVJlg_ifc/s1600/blog.png" height="187" width="400"></a></div>
<br />
<br />
<h4 style="text-align: left;">
Sending an email to Administrator upon Application Registration</h4>
As the extension of this Application Registration workflow, we are going customize the workflow executor and send an email to Administrator once the workflow is triggered<br />
<br />
<div style="text-align: justify;">
1. First write a new executor extending ApplicationRegistrationWSWorkflowExecutor<br />
<br />
<pre class="brush: js">public class AppRegistrationEmailSender extends
ApplicationRegistrationWSWorkflowExecutor {
</pre>
<br />
2. Add private String attributes and public getters and setters for email properties (adminEmail, emailAddress, emailPassword)<br />
<br />
<pre class="brush: js">
private String adminEmail;
private String emailAddress;
private String emailPassword;
public String getAdminEmail() {
return adminEmail;
}
public void setAdminEmail(String adminEmail) {
this.adminEmail = adminEmail;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailPassword() {
return emailPassword;
}
public void setEmailPassword(String emailPassword) {
this.emailPassword = emailPassword;
}
</pre>
<br />
3. Override execute(WorkflowDTO workflowDTO) method and implement email sending logic. Finally invoke super.execute(workflowDTO).<br />
<br />
<pre class="brush: js"> @Override
public void execute(WorkflowDTO workflowDTO) throws WorkflowException {
ApplicationRegistrationWorkflowDTO appDTO = (ApplicationRegistrationWorkflowDTO) workflowDTO;
String emailSubject = appDTO.getKeyType() + "Application Registration";
String emailText = "Appplication " + appDTO.getApplication().getName() + " is registered for " +
appDTO.getKeyType() + " key by user " + appDTO.getUserName();
try {
EmailSender.sendEmail(emailAddress, emailPassword, adminEmail, emailSubject, emailText);
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//SEND EMAIL
super.execute(workflowDTO);
}
</pre>
<br />
<br /></div>
Find the complete source code of custom workflow executor.
<br />
<pre class="brush: js">
package org.wso2.sample.workflow;
import javax.mail.MessagingException;
import org.wso2.carbon.apimgt.impl.dto.ApplicationRegistrationWorkflowDTO;
import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO;
import org.wso2.carbon.apimgt.impl.workflow.ApplicationRegistrationWSWorkflowExecutor;
import org.wso2.carbon.apimgt.impl.workflow.WorkflowException;
public class AppRegistrationEmailSender extends ApplicationRegistrationWSWorkflowExecutor {
private String adminEmail;
private String emailAddress;
private String emailPassword;
@Override
public void execute(WorkflowDTO workflowDTO) throws WorkflowException {
ApplicationRegistrationWorkflowDTO appDTO = (ApplicationRegistrationWorkflowDTO) workflowDTO;
String emailSubject = appDTO.getKeyType() + "Application Registration";
String emailText = "Appplication " + appDTO.getApplication().getName() + " is registered for " +
appDTO.getKeyType() + " key by user " + appDTO.getUserName();
try {
EmailSender.sendEmail(emailAddress, emailPassword, adminEmail, emailSubject, emailText);
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//SEND EMAIL
super.execute(workflowDTO);
}
public String getAdminEmail() {
return adminEmail;
}
public void setAdminEmail(String adminEmail) {
this.adminEmail = adminEmail;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailPassword() {
return emailPassword;
}
public void setEmailPassword(String emailPassword) {
this.emailPassword = emailPassword;
}
}
</pre>
Now modify the existing ProductionApplicationRegistration as below.<br />
<pre class="brush: js">
<ProductionApplicationRegistration executor="org.wso2.sample.workflow.AppRegistrationEmailSender">
<Property name="adminEmail">admin@wso2.com</Property >
<Property name="emailAddress">admin@gmail.com</Property >
<Property name="emailPassword">admin123</Property >
<Property name="serviceEndpoint">http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/</Property >
<Property name="username">admin</Property >
<Property name="password">admin</Property >
<Property name="callbackURL">https://localhost:8248/services/WorkflowCallbackService</Property >
</ProductionApplicationRegistration>
</pre>
<br />
You can do the same modification to SandboxApplicationRegistration workflow as below.
<br />
<pre class="brush: js">
<SandboxApplicationRegistration executor="org.wso2.sample.workflow.AppRegistrationEmailSender">
<Property name="adminEmail">admin@wso2.com</Property >
<Property name="emailAddress">admin@gmail.com</Property >
<Property name="emailPassword">admin123</Property >
<Property name="serviceEndpoint">http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/</Property >
<Property name="username">admin</Property >
<Property name="password">admin</Property >
<Property name="callbackURL">https://localhost:8248/services/WorkflowCallbackService</Property >
</SandboxApplicationRegistration>
</pre>
<br />
With this change, Application Registration workflows will trigger the workflows through AppRegistrationEmailSender which will send an email to adminEmail email address. Then it will invoke the default ApplicationRegistrationWSWorkflowExecutor.
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com1tag:blogger.com,1999:blog-1621989597321372268.post-2612143505752225752013-12-29T01:20:00.000+10:302013-12-29T01:20:04.208+10:30Migrating WSO2 API Manager 1.5.0 to 1.6.0<div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 API Manager latest version 1.6.0 got released recently. This post provides instructions on how to migrate your data from API Manager 1.5.0 to 1.6.0. If you had already used API Manager 1.5.0 and need to migrate your data to the latest version you can follow this.<br />
<br />
You can download WSO2 API Manager 1.6.0 from <a href="http://wso2.com/products/api-manager/">here</a>.<br />
<br />
<br />
You can download the latest migration scripts from<br />
<br />
<a href="https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.5.0_to_1.6.0">https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.5.0_to_1.6.0</a><br />
<br />
<br />
Checkout the migration kit by executing below command.<br />
<br />
%> svn co https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.5.0_to_1.6.0<br />
<br />
<br />
<ol style="text-align: left;">
<li>Shutdown AM 1.5.0 if it is running. </li>
<li>Backup your API Manager Databases of your AM 1.5.0 instance.</li>
<li>Execute relevant sql script in migration-1.5.0_to_1.6.0 against your API Manager Database. (ex:If your database is mysql run mysql.sql against your APIM mysql database)</li>
<li>Now point same WSO2 Carbon Database(User Store and Registry) and API Manager Databases of your AM 1.5.0 instance to AM 1.6.0. (Configure AM_1.6.0/repository/datasource/master-datasources.xml to point same databases configured in AM 1.5.0)</li>
<li>Move all your synapse configurations to APIM_1.6.0. For that, copy and replace APIM_1.5.0/repository/deployment/server/synapse-config/default directory to APIM_1.6.0/repository/deployment/server/synapse-config/default. [If you had APIs created by tenants copy tenant configs as well which can be found in repository/tenants]</li>
<li>Start AM 1.6.0 and Login.</li>
<li> Change the registry extension file[.rxt file] with the new one[which can be found from /rxt/api.rxt]. For that go API Manager Management console. Navigate to path 'Home-> Extensions-> Configure-> Artifact Types' from management console and click the link 'View/Edit' and replace above mentioned new api.rxt and save.</li>
<li>Configure endpoint-migration/build.xml with the information for the below properties.</li>
</ol>
<ul style="text-align: left;"><ul>
<li><b>registry.home</b>= Path to AM pack location [In a distributed setup, give the Publisher node path]</li>
<li><b>username</b>= Username for the AM server</li>
<li><b>password</b>= Password for the AM server</li>
<li><b>host</b>= IP of running AM server [In a distributed setup, give the host of the Publisher node] </li>
<li><b>port</b>= Port of running AM server [In a distributed setup, give the port of the Publisher node] </li>
<li><b>version</b>= Version of AM server</li>
</ul>
</ul>
<ol style="text-align: left;">
<li>Go inside endpoint-migration/ and execute "ant run". You should get a "BUILD SUCCESSFUL" message if it ran correctly.</li>
</ol>
<br />
Hope this instructions help you to migrate your data from API Manager 1.5.0 to 1.6.0. Queries are welcome if you face any issues with the migration.<br />
<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-10094326360250017412013-11-07T19:27:00.001+10:302018-04-29T20:28:59.850+09:30Migrating WSO2 API Manager 1.4.0 to 1.5.0<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<b>Migrating WSO2 API Manager 1.4.0 to 1.5.0</b><br />
<br />
WSO2 API Manager latest version 1.5.0 got released recently. This post provides instructions on how to migrate your data from API Manager 1.4.0 to 1.5.0. If you had already used API Manager 1.4.0 and need to migrate your data to the latest version you can follow this.<br />
<br />
You can download WSO2 API Manager 1.5.0 from <a href="http://wso2.com/products/api-manager/">here</a>.<br />
<br />
You can download the latest migration scripts from <a href="https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.4.0_to_1.5.0/">https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.4.0_to_1.5.0/</a><br />
<br />
Checkout the migration kit by executing below command.<br />
<br />
%> svn co <a href="https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.4.0_to_1.5.0/">https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/apimgt/1.6.0/modules/distribution/resources/migration-1.4.0_to_1.5.0/</a><br />
<br />
<br />
<br />
1. Shutdown APIM 1.4.0 if it is running.<br />
<br />
2. Backup your WSO2 Carbon Database(User Store and Registry) and API Manager Databases of your APIM 1.4.0 instance.<br />
<br />
3. Execute relevant sql script in '<b>migration-1.4.0_to_1.5.0/userstore_db</b>' directory against your WSO2 Carbon Database. This will migrate tables and data in your jdbc user store.<br />
<br />
4. Execute relevant sql script in '<b>migration-1.4.0_to_1.5.0/apimgt_db</b>' directory against your API Manager Database.<br />
<br />
5. Now point same WSO2 Carbon Database(User Store and Registry) and API Manager Databases of your AM 1.4.0 instance to AM 1.5.0.<br />
(Configure AM_1.5.0/repository/datasource/master-datasources.xml to point same databases configured in AM 1.4.0)<br />
<br />
6. Open AM_1.5.0/repository/conf/user-mgt.xml and add the property to existing 'AuthorizationManager' configuration.<br />
<br />
<br />
<pre class="brush: js"><Property name="CaseSensitiveAuthorizationRules">true</Property>
</pre>
ex:
<br />
<pre class="brush: js"><AuthorizationManager class="org.wso2.carbon.user.core.authorization.JDBCAuthorizationManager">
<Property name="AdminRoleManagementPermissions">/permission</Property>
<Property name="AuthorizationCacheEnabled">true</Property>
<Property name="CaseSensitiveAuthorizationRules">true</Property>
</AuthorizationManager>
</pre>
<br />
7. Move all your synapse configurations to APIM_1.5.0. For that, copy and replace APIM_1.4.0/repository/deployment/server/synapse-config/default directory to APIM_1.5.0/repository/deployment/server/synapse-config/default<br />
<br />
8. Start APIM 1.5.0<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-3483394546425318542013-10-02T19:00:00.001+09:302018-04-29T20:30:37.888+09:30How to add additional headers to WSO2 API Manager Swagger Console<div dir="ltr" style="text-align: left;" trbidi="on">
WSO2 API Manager has integrated Swagger to allow API consumers to explore APIs through a interactive console.<br />
<br />
When integrating Swagger with WSO2 API Manager we had to support CORS between API Store and the API Gateway. So in order to send any headers from Swagger, we need to add those required headers to the response coming from the API Gateway as 'Access-Control-Allow-Headers' . By default below set of headers are allowed to be send from swagger.<br />
<br />
<b>authorization,Access-Control-Allow-Origin,Content-Type</b><br />
<br />
So if you need to add any additional headers to Swagger UI, then we should add that header to list of 'Access-Control-Allow-Headers'.<br />
<br />
There are 2 options to modify 'Access-Control-Allow-Headers'.<br />
<br />
<span style="color: #0b5394;">1. Modify the Synapse configuration of APIs and add modified set of headers to OutSequence.</span><br />
<br />
If you choose this method, you have to modify API configuration of each API and add the 'Access-Control-Allow-Headers'. For that go to Management Console of API Manager and then Go to Source View. Then modify the OutSequence with Access-Control-Allow-Headers property setting required headers as the value.<br />
<br />
For example let's say the additional header wee need to add is 'Action', then outSequence should be modified as below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-rlPh1vCt_rg/Ukvj8Il7icI/AAAAAAAACwI/lomJ7duhP-0/s1600/SourceView.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="141" src="https://2.bp.blogspot.com/-rlPh1vCt_rg/Ukvj8Il7icI/AAAAAAAACwI/lomJ7duhP-0/s400/SourceView.png" width="400"></a></div>
<br />
<br />
<br />
<span style="color: #0b5394;">2. Modify API templates.</span><br />
<br />
Inside API Manager distribution you can find templates for APIs from APIM_HOME/repository/resources/api_templates. By modifying outSequences of below template files in there, all the APIs created thereafter will get the modified outSequence.<br />
<br />
<i>api_templates_complex_<wbr></wbr>resource.xml</i><br />
<i>api_templates_complex_<wbr></wbr>resource_with_jwt.xml</i><br />
<i>api_templates_resource.xml</i><br />
<i>api_templates_resource_with_<wbr></wbr>jwt.xml</i><br />
<br />
<pre class="brush: js"><outSequence>
<property name="Access-Control-Allow-Headers" scope="transport" value="authorization,Access-Control-Allow-Origin,Content-Type,Action"></property>
<send></send>
</outSequence>
</pre>
<br />
<br />
<b><br /></b>
Once you have followed one of the above approaches, then you will be able to send those headers through swagger UI. So only thing left to do is adding the header parameter to API definition. For that go to API Publisher and select required API. Go to 'Docs' tab and click 'Edit Content' for API definition.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-vJXjskpz_5A/UkvmALgKc6I/AAAAAAAACwU/FzAi7RadefE/s1600/editAPIDefinition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="113" src="https://1.bp.blogspot.com/-vJXjskpz_5A/UkvmALgKc6I/AAAAAAAACwU/FzAi7RadefE/s400/editAPIDefinition.png" width="400"></a></div>
<br />
Then add required header parameter to available parameter list of the required operation/s.<br />
<br />
ex:<br />
<br />
<span style="color: #38761d;">{</span><br />
<span style="color: #38761d;"> "name": "Action",</span><br />
<span style="color: #38761d;"> "description": "SoapAction",</span><br />
<span style="color: #38761d;"> "paramType": "header",</span><br />
<span style="color: #38761d;"> "required": false,</span><br />
<span style="color: #38761d;"> "allowMultiple": false,</span><br />
<span style="color: #38761d;"> "dataType": "String"</span><br />
<span style="color: #38761d;"> }</span><br />
<br />
Once you saved this, you will be able to see the added header parameter in the Swagger UI.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-YrksJCjdsoM/UkvnAAjZljI/AAAAAAAACwg/VxPxYLipmgM/s1600/Header.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://2.bp.blogspot.com/-YrksJCjdsoM/UkvnAAjZljI/AAAAAAAACwg/VxPxYLipmgM/s320/Header.png" width="320"></a></div>
<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com1tag:blogger.com,1999:blog-1621989597321372268.post-24101944480230624172013-08-30T22:39:00.000+09:302018-04-29T20:07:15.703+09:30CSV to XML transformation with WSO2 ESB Smooks Mediator<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="text-align: justify;">This post provides a sample CSV to XML transformation with WSO2 ESB. </span><span style="text-align: justify;">WSO2 ESB supports executing Smooks features through 'Smooks Mediator'. </span><br />
<span style="text-align: justify;"><br /></span>
<span style="text-align: justify;">Latest ESB can be downloaded from <a href="http://wso2.com/products/enterprise-service-bus/">here</a>. </span><br />
<span style="text-align: justify;"><br /></span>
<br />
<div style="text-align: justify;">
We are going to transform the below CSV to an XML message.</div>
<div style="text-align: justify;">
<br /></div>
<pre class="brush: js">Lakmali,Erandi,Female,20,SriLanka
Lakmali,Baminiwatta,Female,20,SriLanka</pre>
<div style="text-align: justify;">
<br />
This is the format of the XML output message.<br />
here</div>
<pre class="brush: js"><people>
<person number="1">
<firstname>Lakmali</firstname>
<lastname>Erandi</lastname>
<gender>Female</gender>
<age>20</age>
<country>SriLanka</country>
</person>
<person number="2">
<firstname>Lakmali</firstname>
<lastname>Baminiwatta</lastname>
<gender>Female</gender>
<age>20</age>
<country>SriLanka</country>
</person>
</people>
</pre>
<div style="text-align: justify;">
First lets write the smooks configuration to transform above CSV to given XML message (smooks-csv.xml).<br />
<br />
<br />
<pre class="brush: js"><smooks-resource-list
xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
<resource-config selector="org.xml.sax.driver">
<resource>org.milyn.csv.CSVReader</resource>
<param name="fields">firstname,lastname,gender,age,country</param>
<param name="rootElementName">people
</param>
<param name="recordElementName">person
</param>
</resource-config>
</smooks-resource-list>
</pre>
Now let's write a simple proxy service to take the CSV file as the input message and process through the smooks mediator. For that first you need to <a href="http://docs.wso2.org/display/ESB460/VFS+Transport">enable VFS transport sender and reciever</a>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Below is the service synapse configuration. Make sure to change the following parameters according to your file system. You can find more information about the parameters from <a href="http://docs.wso2.org/display/ESB460/VFS+Transport">here</a>.</div>
<div style="text-align: justify;">
</div>
<br />
<ul>
<li> transport.vfs.FileURI</li>
<li> transport.vfs.MoveAfterProcess</li>
<li> transport.vfs.ActionAfterFailure</li>
</ul>
<div>
<br /></div>
<div>
<br /></div>
<br /></div>
<span style="background-color: #f6b26b;"><proxy xmlns="http://ws.apache.org/ns/synapse"</span><br />
<span style="background-color: #f6b26b;"> name="CSVSmooks"</span><br />
<span style="background-color: #f6b26b;"> transports="https,http,vfs"</span><br />
<span style="background-color: #f6b26b;"> statistics="disable"</span><br />
<span style="background-color: #f6b26b;"> trace="disable"</span><br />
<span style="background-color: #f6b26b;"> startOnLoad="true"></span><br />
<span style="background-color: #f6b26b;"> <target></span><br />
<span style="background-color: #f6b26b;"> <inSequence></span><br />
<span style="background-color: #f6b26b;"> <smooks config-key="smooks-csv"></span><br />
<span style="background-color: #f6b26b;"> <input type="text"/></span><br />
<span style="background-color: #f6b26b;"> <output type="xml"/></span><br />
<span style="background-color: #f6b26b;"> </smooks></span><br />
<span style="background-color: #f6b26b;"> <log level="full"/></span><br />
<span style="background-color: #f6b26b;"> </inSequence></span><br />
<span style="background-color: #f6b26b;"> </target></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.PollInterval">5</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.FileURI">file:///home/lakmali/dev/test/smooks/in</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.MoveAfterProcess">file:///home/lakmali/dev/test/smooks/original</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.MoveAfterFailure">file:///home/lakmali/dev/test/smooks/original</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.FileNamePattern">.*.csv</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.ContentType">text/plain</parameter></span><br />
<span style="background-color: #f6b26b;"> <parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter></span><br />
<span style="background-color: #f6b26b;"> <description/></span><br />
<span style="background-color: #f6b26b;"></proxy></span><br />
<span style="background-color: #f6b26b;"><br /></span></div>
</div>
You have to make a ESB local entry with the key 'smooks-csv' and give path to smooks-csv.xml which we crated above. So in the smooks mediator above, we are loading the smooks config through the local entry key name (smooks-csv).<br />
<br />
To perform the transformation what you need to do is drop the input message file to <b>transport.vfs.FileURI</b> location. In the log you can see the transformed message in XML!! Now you got the CSV message in XML in your synapse sequence. So you can perform any further mediation to this message such as send to some endpoint/database/file etc.<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com5tag:blogger.com,1999:blog-1621989597321372268.post-48753860717801752082013-03-25T20:39:00.003+10:302018-04-29T20:35:45.790+09:30Huge Message Processing with WSO2 ESB Smooks Mediator<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<div style="text-align: justify;">
Smooks is a powerful framework for processing, manipulating and transforming XML and non XML data. WSO2 ESB supports executing Smooks features through 'Smooks Mediator'. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
One of the main features introduced in Smooks v1.0 is the ability to process huge messages (Gbs in size) [1]. Now with the <a href="http://wso2.com/more-downloads/esb">WSO2 ESB 4.5.0</a> release (and later), Huge Message Processing feature is supported through Smooks Mediator!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Smooks supports three types of processing for huge messages which are,</div>
<div style="text-align: justify;">
1. one-to-one transformation</div>
<div style="text-align: justify;">
2. splitting and routing</div>
<div style="text-align: justify;">
3. persistence</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
This post shows how to process large input messages using Splitting and routing approach. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><i>Step 1: Create sample Huge Input file. </i></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
This post assumes the input message is in the following format.<br />
<br />
<pre class="brush: xml"><order id="332">
<header>
<customer number="123">Joe</customer>
</header>
<order -items="-items">
<order -item="-item" id="1">
<product quantity="4">Pen</product>
<price>8.80</price>
</order>
<order -item="-item" id="2">
<product quantity="1">Book</product>
<price>8.80</price>
</order>
<order -item="-item" id="3">
<product quantity="2">Bottle</product>
<price>8.80</price>
</order>
<order -item="-item" id="4">
<product quantity="8">Note Book</product>
<price>8.80</price>
</order>
</order>
</order>
</pre>
<br />
You can write a simple java program to generate a file with large number of entries. </div>
</div>
<div style="text-align: justify;">
<br />
<pre class="brush: js">FileWriter fw = new FileWriter("input-message.txt");
PrintWriter pw = new PrintWriter(fw);
/*XML */
pw.print("<order id="332">\n <header>\n <customer number="123">Joe</customer>\n </header>\n <order -items="-items">\n");
for(int i=0;i<=2000000;i++){
pw.print("\t<order -item="-item" id="&quot;+i+&quot;">\n\t\t<product quantity="4">Pen</product>\n\t\t<price>8.80</price>\n\t</order>\n");
}
pw.write(" </order>\n</order>");
</pre>
</div>
<div style="text-align: justify;">
<br />
<b><i>Step 2: Smooks Configuration </i></b><br />
<b><i><br /></i></b></div>
<div style="text-align: justify;">
Let's write the Smooks configuration to split and route the above message. <span style="text-align: left;">When we are processing huge messages with Smooks, we should make sure to use the </span><b style="text-align: left;">SAX filter</b><span style="text-align: left;">.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The basic steps of this Smooks process are, </div>
<div style="text-align: left;">
1. Java Binding - Bind the input message to java beans</div>
<div style="text-align: left;">
2. Templating - Apply a template which represents split message on input message elements</div>
<div style="text-align: left;">
3. Routing - Route each split message <br />
<br />
So for doing each of the above steps we need to use the relevant Smooks cartridges.<br />
<br />
<b>1. Java Binding</b><br />
<br />
The Smooks JavaBean Cartridge allows you to create and populate Java objects from your message data [2]. We can map input message elements to real java objects by writing bean classes or to virtual objects which are Maps and Lists. Here we will be binding to virtual objects. In that way we can build complete object model without writing our own business classes.<br />
<br />
Let's assume that we are going to split the input message such that one split message contains a single order item information (item-id, product, quantity, price) with the order information (order-id, customer-id, customer-name).<br />
<br />
So we can define two beans in our smooks configuration; order and orderItem.<br />
<br />
<pre class="brush: js"><smooks-resource-list xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd" xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<core:filtersettings type="SAX"></core:filtersettings>
<!-- Extract and decode data from the message. Later Used in the freemarker template.
Note that we could also use a NodeModel here... -->
<jb:bean beanid="order" class="java.util.Hashtable" createonelement="order">
<jb:value data="order/@id" decoder="Integer" property="orderId"></jb:value>
<jb:value data="header/customer/@number" decoder="Long" property="customerNumber"></jb:value>
<jb:value data="header/customer" property="customerName"></jb:value>
<jb:wiring beanidref="orderItem" property="orderItem"></jb:wiring>
</jb:bean>
<jb:bean beanid="orderItem" class="java.util.Hashtable" createonelement="order-item">
<jb:value data="order-item/@id" decoder="Integer" property="itemId"></jb:value>
<jb:value data="order-item/product" property="product"></jb:value>
<jb:value data="order-item/product/@quantity" decoder="Integer" property="quantity"></jb:value>
<jb:value data="order-item/price" decoder="Double" property="price"></jb:value>
</jb:bean>
</smooks-resource-list></pre>
</div>
</div>
<br />
<b>2. Templating</b><br />
<br />
Smooks Templating allows fragment-level templating using different templating solutions. Smooks supported templating technologies are FreeMarker and XSL templating. In here we are going to use FreeMarker templating solution.<br />
<br />
Configuring FreeMarker templates in Smooks is done through the <a class="external free" href="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd" rel="nofollow" title="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd</a> configuration namespace. We can refer the message content in template definition through the java beans which we have defined in the above step.<br />
<br />
There are two methods of FreeMarker template definitions. They are In line and External Template Reference. In this example let's use in-line templating.<br />
<br />
First we need to decide the format of a single split message. Since we are going to split the input message such that one split message contains a single order-item information (item-id, product, quantity, price) with the order information (order-id, customer-id, customer-name), it will look as follows.<br />
<br />
The java object model we had populated above is been used in template definition.<br />
<br />
<pre class="brush: js">
<orderitem id="${order.orderItem.itemId}" order="${order.orderId}">
<customer>
<name>${order.customerName}</name>
<number>${order.customerNumber?c}</number>
</customer>
<details open="">
<product>${order.orderItem.product}</product>
<quantity>${order.orderItem.quantity}</quantity>
<price>${order.orderItem.price}</price>
</details>
</orderitem>
</pre>
<br />
<br />
Let's add the templating configuration to our smooks configuration.<br />
<br />
<pre class="brush: js"><smooks-resource-list xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd" xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd" xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<core:filtersettings type="SAX"></core:filtersettings>
<!-- Extract and decode data from the message. Later Used in the freemarker template.
Note that we could also use a NodeModel here... -->
<jb:bean beanid="order" class="java.util.Hashtable" createonelement="order">
<jb:value data="order/@id" decoder="Integer" property="orderId"></jb:value>
<jb:value data="header/customer/@number" decoder="Long" property="customerNumber"></jb:value>
<jb:value data="header/customer" property="customerName"></jb:value>
<jb:wiring beanidref="orderItem" property="orderItem"></jb:wiring>
</jb:bean>
<jb:bean beanid="orderItem" class="java.util.Hashtable" createonelement="order-item">
<jb:value data="order-item/@id" decoder="Integer" property="itemId"></jb:value>
<jb:value data="order-item/product" property="product"></jb:value>
<jb:value data="order-item/product/@quantity" decoder="Integer" property="quantity"></jb:value>
<jb:value data="order-item/price" decoder="Double" property="price"></jb:value>
</jb:bean>
<ftl:freemarker applyonelement="order-item">
<ftl:template><!--<orderitem id="${order.orderItem.itemId}" order="${order.orderId}">
<customer>
<name>${order.customerName}</name>
<number>${order.customerNumber?c}</number>
</customer>
<details>
<product>${order.orderItem.product}</product>
<quantity>${order.orderItem.quantity}</quantity>
<price>${order.orderItem.price}</price>
</details>
</orderitem>-->
</ftl:template>
<ftl:use>
<!-- Output the templating result to the "orderItemSplitStream" file output stream... -->
<ftl:outputto outputstreamresource="orderItemSplitStream"></ftl:outputto>
</ftl:use>
</ftl:freemarker>
</smooks-resource-list>
</pre>
Please note that using <ftl:outputto>, you can direct Smooks to write the templating result directly to an OutputStreamResource.<br />
<br />
<b> 3. Routing</b><br />
<br />
So far we have defined the bean model of the message, then defined the template of a single split message. Now we have to continue smooks configuration to route each message fragment to an endpoint. These endpoints can be file, database or JMS endpoints.<br />
<br />
In this sample let's route the message fragments to file locations. As in the above step we defined the outputTo element to write to orderItemSplitStream resource, lets add outputStream named orderItemSplitStream to our smooks configuration.<br />
<br />
We need to define following attributes when defining the outputStream<br />
<br />
<b>fileNamePattern</b><br />
<br />
Can be composed by referring java object model we created. The composing name should be a unique name for each message fragment.<br />
<br />
<b>destinationDirectoryPattern</b><br />
<br />
Destination where files should be created.<br />
<br />
<b>highWaterMark</b><br />
<br />
Maximum number of files that can be created in the directory. This should be increased according to the input message size.<br />
<br />
<pre class="brush: js"><smooks-resource-list xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd" xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd" xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<core:filtersettings type="SAX"></core:filtersettings>
<!-- Extract and decode data from the message. Later Used in the freemarker template.
Note that we could also use a NodeModel here... -->
<jb:bean beanid="order" class="java.util.Hashtable" createonelement="order">
<jb:value data="order/@id" decoder="Integer" property="orderId"></jb:value>
<jb:value data="header/customer/@number" decoder="Long" property="customerNumber"></jb:value>
<jb:value data="header/customer" property="customerName"></jb:value>
<jb:wiring beanidref="orderItem" property="orderItem"></jb:wiring>
</jb:bean>
<jb:bean beanid="orderItem" class="java.util.Hashtable" createonelement="order-item">
<jb:value data="order-item/@id" decoder="Integer" property="itemId"></jb:value>
<jb:value data="order-item/product" property="product"></jb:value>
<jb:value data="order-item/product/@quantity" decoder="Integer" property="quantity"></jb:value>
<jb:value data="order-item/price" decoder="Double" property="price"></jb:value>
</jb:bean>
<ftl:freemarker applyonelement="order-item">
<ftl:template><!--<orderitem id="${order.orderItem.itemId}" order="${order.orderId}">
<customer>
<name>${order.customerName}</name>
<number>${order.customerNumber?c}</number>
</customer>
<details>
<product>${order.orderItem.product}</product>
<quantity>${order.orderItem.quantity}</quantity>
<price>${order.orderItem.price}</price>
</details>
</orderitem>-->
</ftl:template>
<ftl:use>
<!-- Output the templating result to the "orderItemSplitStream" file output stream... -->
<ftl:outputto outputstreamresource="orderItemSplitStream"></ftl:outputto>
</ftl:use>
</ftl:freemarker>
<!-- Create/open a file output stream. This is writen to by the freemarker template (above).. -->
<file:outputstream openonelement="order-item" resourcename="orderItemSplitStream">
<file:filenamepattern>order-${order.orderId}-${order.orderItem.itemId}.xml</file:filenamepattern>
<file:destinationdirectorypattern>
/home/lakmali/dev/test/smooks/orders
</file:destinationdirectorypattern>
<file:highwatermark mark="10000000"></file:highwatermark>
</file:outputstream>
</smooks-resource-list>
</pre>
<br />
<b style="text-align: justify;"><i>Step 3: Process with WSO2 ESB Smooks Mediator</i></b><br />
<b style="text-align: justify;"><i><br /></i></b>
Now we have finished writing the smooks configuration which will split and route an incoming message. So now we need to get this executed against our Huge Message. WSO2 ESB Smooks Mediator is a solution for this which integrates Smooks features with WSO2 ESB.<br />
<br />
So our next step is writing a synapse configuration to fetch the file containing the incoming message through VFS transport and mediate through the Smooks Mediator to get our task done.<br />
<br />
Here is the synpase Configuration<br />
<pre class="brush: js"><definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="SmooksSample" startonload="true" transports="vfs">
<target>
<insequence>
<smooks config-key="smooks-key">
<input type="xml" />
<output type="xml"/>
</smooks>
</insequence>
</target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.PollInterval">5</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file:///home/lakmali/dev/test/smooks/original</parameter>
<parameter name="transport.vfs.FileURI">file:///home/lakmali/dev/test/smooks/in</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file:///home/lakmali/dev/test/smooks/original</parameter>
<parameter name="transport.vfs.FileNamePattern">.*\.xml</parameter>
<parameter name="transport.vfs.ContentType">application/xml</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
</proxy>
<localentry key="smooks-key" src="file:repository/samples/resources/smooks/smooks-config-658.xml"></localentry>
<sequence name="fault">
<log level="full"/>
<property name="MESSAGE" value="Executing default fault sequence"/>
<property expression="get-property('ERROR_CODE')" name="ERROR_CODE"/>
<property expression="get-property('ERROR_MESSAGE')" name="ERROR_MESSAGE"/>
<drop/>
</sequence>
<sequence name="main">
<log/>
<drop/>
</sequence>
</definitions>
</pre>
Make sure to Change the VFS Transport Configuration Parameters.<br />
<br />
<br />
<b>transport.vfs.MoveAfterProcess</b> - Move the input file to this location after processing<br />
<b>transport.vfs.FileURI</b> - Input File location<br />
<b>transport.vfs.MoveAfterFailure</b> - Move the input file to this location after a failure<br />
<br />
Create a proxy service with the given synpase configuration. There is an available ESB sample with this configuration which you can run by executing the following command.<br />
<br />
Go to <b>ESB_HOME/bin</b><br />
And run<br />
<b>./wso2esb-samples.sh -sn 658</b><br />
<br />
Now drop the sample Huge Input file to <b>transport.vfs.FileURI</b> location.<br />
<br />
Now check the <b>destinationDirectoryPattern </b>location where you can find the split file results of the huge file.<br />
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , sans-serif; font-size: 13px;">MKKP78F3XW2U</span><br />
[1] <a href="http://www.smooks.org/mediawiki/index.php?title=V1.5:Smooks_v1.5_User_Guide#Processing_Huge_Messages_.28GBs.29">http://www.smooks.org/mediawiki/index.php?title=V1.5:Smooks_v1.5_User_Guide#Processing_Huge_Messages_.28GBs.29</a><br />
[2] <a href="http://www.smooks.org/mediawiki/index.php?title=V1.5:Smooks_v1.5_User_Guide#Java_Binding">http://www.smooks.org/mediawiki/index.php?title=V1.5:Smooks_v1.5_User_Guide#Java_Binding</a>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com5tag:blogger.com,1999:blog-1621989597321372268.post-41219125404945487922012-12-20T20:47:00.003+10:302012-12-20T20:49:38.898+10:30Google Analytics Tracking for WSO2 API Manager<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
WSO2 API Manager is a platform for creating, managing, consuming and monitoring
APIs. It employs proven SOA best practices to solve a wide range of API
management challenges such as API provisioning, API governance, API security
and API monitoring.<br />
<br />
<br />
You can download API Manager latest version from:<br />
<br />
<a href="http://wso2.com/products/api-manager">http://wso2.com/products/api-manager</a><br />
<br />
and find the online documentation from:<br />
<br />
<a href="http://docs.wso2.org/wiki/display/AM130/WSO2+API+Manager+Documentation">http://docs.wso2.org/wiki/display/AM130/WSO2+API+Manager+Documentation</a><br />
<br />
<br />
With WSO2 API Manager 1.3.0 release you can track your API invocations through Google Analytics! <br />
<br />
First let me explain you what is google analytics. Google analytics is a service offered by Google which tracks vists to a web site and generates detailed statistics based on those visits.<br />
Now WSO2 API Manager latest 1.3.0 release fascilitates you to integrate with Google Analytics to track run time statistics for API invocations.<br />
<br />
Here is the step by step guide to do this.<br />
<br />
<b>1. Setup a Google analytics account.</b><br />
<br />
If you already have a google account, Sign-In. Else Create a New Google Account and Sign-In.<br />
<br />
Then go to <a href="http://www.google.com/analytics/">http://www.google.com/analytics/</a> and Sign-In<br />
<br />
Click on the Admin Icon on top right<br />
<br />
Then Click Create New Account as highlighted in below image.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-hnM8lJAj8kw/UNLa4RG997I/AAAAAAAACoU/Ps1Prih5Bk0/s1600/newaccount.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="112" src="http://3.bp.blogspot.com/-hnM8lJAj8kw/UNLa4RG997I/AAAAAAAACoU/Ps1Prih5Bk0/s400/newaccount.png" width="400" /></a></div>
<br />
Now select 'Web Site' for what would you like to Track and give information about the account as follows. Please note that since we are actually not tracking a site, give any site URL for 'Web Site URL'.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-RKdYmpkTOX4/UNLcVKL9FTI/AAAAAAAACok/-vMZxxMAbU4/s1600/createaccount.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="http://1.bp.blogspot.com/-RKdYmpkTOX4/UNLcVKL9FTI/AAAAAAAACok/-vMZxxMAbU4/s400/createaccount.png" width="380" /></a></div>
<br />
Now Click Get '<b>Tracking ID</b>' bottom of the page.<br />
<br />
Accept the Google Analytics Terms of Service and you will directed to a page with Tracking information.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-XmoBUjf-lRE/UNLdzyL7JyI/AAAAAAAACo0/rjdVX44iHfg/s1600/save1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="265" src="http://3.bp.blogspot.com/-XmoBUjf-lRE/UNLdzyL7JyI/AAAAAAAACo0/rjdVX44iHfg/s400/save1.png" width="400" /></a></div>
<br />
<br />
Now you have sucessfully created your Tracking account and you will need the obtained Tracking-ID for further steps.<br />
<br />
<b>2. Enable Google Analytics Tracking in API Manager.</b><br />
<br />
Open <i>API_MANAGER_HOME/repository/conf/api-manager.xml</i>. Locate the <googleanalyticstracking> and set Enabled to true and enter the Tracking-ID obtained in <trackingid> as follows.</trackingid></googleanalyticstracking><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-66C_Vnha6DQ/UNLe7jWBMPI/AAAAAAAACpA/7zba62PGSVk/s1600/enabletrack.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="143" src="http://1.bp.blogspot.com/-66C_Vnha6DQ/UNLe7jWBMPI/AAAAAAAACpA/7zba62PGSVk/s400/enabletrack.png" width="400" /></a></div>
<br />
Save the changes to <i>API_MANAGER_HOME/repository/conf/api-manager.xml</i> and restart your API Manager running instance.<br />
<br />
Now we have successfully integrated WSO2 API Manager with Google Analytics. Now lets see how we can see the statistics.<br />
<br />
<b>3. View Google Analytics statistics.</b><br />
<br />
<b>Real Time Statistics</b><br />
<br />
First create and publish an API. Then through the API store subscribe to that API.<br />
<br />
Now go to Google Analytics [<a href="http://www.google.com/analytics/">http://www.google.com/analytics/</a>] and select the above created 'APISTORESTAT' account from the list of Accounts.<br />
<br />
On the appearing page go to 'Home' tab.<br />
<br />
Now you will see 'Real-Time' icon in left menu. Click on that and select 'Overview'.<br />
<br />
Then invoke/call the above created API through embedded RESTClient or Curl.<br />
<br />
Now you will be able to see a hit on 'PageViews' Per second graph and also 'Right Now' users as 1.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-e7mfD-iO_pA/UNLjN4H9LQI/AAAAAAAACpU/w6eHnZ1NX4g/s1600/realtime.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-e7mfD-iO_pA/UNLjN4H9LQI/AAAAAAAACpU/w6eHnZ1NX4g/s400/realtime.png" width="400" /></a></div>
<br />
<b>Reporting Statistics</b><br />
<br />
Google analytics reporting statistics population takes more than 24hours from the invocation. Therefore to view the statistics on the Dashboard you need to wait!<br />
<br />
Here is a sample Dashboard with populated statistics.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-T8Wrci0PtWQ/UNLk9YPUDNI/AAAAAAAACpk/QImxCIDCgjs/s1600/GoogleAnalyticsLatest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="217" src="http://1.bp.blogspot.com/-T8Wrci0PtWQ/UNLk9YPUDNI/AAAAAAAACpk/QImxCIDCgjs/s400/GoogleAnalyticsLatest.png" width="400" /></a></div>
<br />
Here as you can see there are Widgets with statistics related to Audience, Traffic, Page Content, Visit Duration etc. You can add any widgets for your preference through 'Add Widget'.<br />
<br />
<br />
<br />
<br />
<br /></div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com2tag:blogger.com,1999:blog-1621989597321372268.post-12822758399161964222012-05-17T14:11:00.003+09:302012-12-20T16:18:12.256+10:30How to enable remote access to mysql database server<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<span style="font-size: large;"><b>Enable remote access to mySQL database server</b></span><br />
<br />
1. Open the MySQL server configuration file my.cnf.<br />
<br />
<i>sudo gedit /etc/mysql/my.cnf</i><br />
<br />
2. Change the bind-address value to your MySQL server ip. If the MySQL server IP=10.100.2.200, change it as follows, save and close my.cnf file.<br />
<br />
<i>bind-address=10.100.2.200</i><br />
<br />
3. Now Grant access to remote IP.<br />
If the remote IP=10.100.2.180<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px; text-align: -webkit-auto;"> </span><br />
<br />
<u>Grant permission to a specific database (ex: testbd)</u><br />
<br />
<i>GRANT ALL ON testdb.* TO testuser@'10.100.2.180' IDENTIFIED BY 'test123';</i><br />
<br />
<u>Grant all permissions</u><br />
<br />
<i>GRANT ALL PRIVILEGES ON *.* TO testuser@'10.100.2.180' </i><i>IDENTIFIED BY 'test123'</i><i> WITH GRANT OPTION;</i><br />
<i><br /></i>
4. Open port 3306, if firewalls are enabled. Following is a sample iptables rule to open Linux iptables firewall.<br />
<br />
<br />
<pre><i>/sbin/iptables -A INPUT -i eth0 -p tcp --destination-port 3306 -j ACCEPT</i></pre>
<br />
<br />
5. logout of mysql.<br />
<br />
6. Connect from remote host<br />
<br />
<i>mysql -u root -h 10.100.2.200 -p</i><br />
<div>
<br /></div>
</div>
Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com1tag:blogger.com,1999:blog-1621989597321372268.post-27573853507934890302012-03-19T15:51:00.000+10:302018-04-29T20:39:02.191+09:30Smooks Entity Persistence Frameworks - Hibernate<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<div style="text-align: justify;">
With the new Smooks Persistence cartridge in Smooks 1.2, we can directly use several entity persistence frameworks from within Smooks (Hibernate, JPA etc). So in this blog post let's try out the Hibernate sample specified in <a href="http://www.smooks.org/mediawiki/index.php?title=V1.5:Smooks_v1.5_User_Guide#SQL_Support">here</a>.</div>
<div style="text-align: justify;">
Since smooks have given the basic configurations only, this blog post is going to assist the peolple who need full implementation. </div>
<br />
<div style="text-align: justify;">
What we are going to do is process the following XML message and store the product information to a bean and persist the order information.</div>
<br />
<br />
<br />
input.xml<br />
------------<br />
<br />
<pre class="brush: js"><order>
<ordernumber>1</ordernumber>
<customer>123456</customer>
<order-items>
<order-item>
<product>11</product>
<quantity>2</quantity>
</order-item>
<order-item>
<product>22</product>
<quantity>7</quantity>
</order-item>
</order-items>
</order>
</pre>
First we have to Specify our Entity classes (Order, OrderLine, Product)
<br />
<pre class="brush: js">//Order class
package example.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
@Entity
@Table(name="orders")
public class Order {
@Id
private Integer ordernumber;
@Basic
private String customerId;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<orderline> orderItems = new ArrayList<orderline>();
public void addOrderLine(OrderLine orderLine) {
orderItems.add(orderLine);
}
public Integer getOrdernumber() {
return ordernumber;
}
public void setOrdernumber(Integer ordernumber) {
this.ordernumber = ordernumber;
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public List getOrderItems() {
return orderItems;
}
public void setOrderItems(List orderItems) {
this.orderItems = orderItems;
}
}
</orderline></orderline></pre>
<pre class="brush: js">//OrderLine class
package example.entity;
import javax.persistence.*;
@Entity
@Table(name = "orderlines")
public class OrderLine {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne
@JoinColumn(name = "orderid")
private Order order;
@Basic
private Integer quantity;
@ManyToOne
@JoinColumn(name = "productid")
private Product product;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
</pre>
<pre class="brush: js">//Product Class
package example.entity;
import javax.persistence.*;
@Entity
@Table(name = "products")
public class Product {
@Id
private Integer id;
@Basic
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
</pre>
Here is the Smooks configuration to bind xml message to java beans and persist the order entity.
<br />
smooks-hbt-config.xml<br />
-----------------------------------<br />
<br />
<pre class="brush: js"><smooks-resource-list xmlns:dao="http://www.milyn.org/xsd/smooks/persistence-1.2.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd" xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<jb:bean beanid="order" class="example.entity.Order" createonelement="order">
<jb:value data="ordernumber" property="ordernumber"></jb:value>
<jb:value data="customer" property="customerId"></jb:value>
<jb:wiring beanidref="orderLine" settermethod="addOrderLine">
</jb:wiring></jb:bean>
<jb:bean beanid="orderLine" class="example.entity.OrderLine" createonelement="order-item">
<jb:value data="quantity" property="quantity"></jb:value>
<jb:wiring beanidref="order" property="order">
<jb:wiring beanidref="product" property="product">
</jb:wiring></jb:wiring></jb:bean>
<dao:locator beanid="product" lookuponelement="order-item" onnoresult="EXCEPTION" uniqueresult="true">
<dao:query>from Product p where p.id = :id</dao:query>
<dao:params>
<dao:value data="product" decoder="Integer" name="id"></dao:value>
</dao:params>
</dao:locator>
<dao:inserter beanid="order" insertonelement="order"></dao:inserter>
</smooks-resource-list>
</pre>
<div style="text-align: justify;">
So now you would wonder where we store the datasource configuration. If we just use Hibernate we can configure datasource information inside hibernate.cfg.xml
</div>
<pre class="brush: js"><hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/dbname</property>
<property name="connection.username">uname</property>
<property name="connection.password">pwd</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">false</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="connection.pool_size">1</property>
<property name="current_session_context_class">thread</property>
<mapping class="example.entity.Product"></mapping>
<mapping class="example.entity.Order"></mapping>
<mapping class="example.entity.OrderLine"></mapping>
</session-factory>
</hibernate-configuration> </pre>
The database represented in the connection must have 4 tables.<br />
<b><br /></b><br />
customers (id int(11), name varchar(30))<br />
products (id int(11), name varchar(30))<br />
orders (ordernumber int(11), customerId varchar(30))<br />
orderlines (id int(11), quantity int(11), orderid int(11), productid int(11))<br />
<br />
Insert the following sample data to customers and procucts tables.<br />
<br />
insert into customers (id, name) values (123456, 'Devin Snow');<br />
insert into customers (id, name) values (789101, 'Homer Simpson');<br />
insert into customers (id, name) values (999999, 'John Doe');<br />
<br />
insert into products (id, name) values (11, 'Cheese cake');<br />
insert into products (id, name) values (22, 'Chocolate 300gr');<br />
insert into products (id, name) values (33, 'Beer');<br />
insert into products (id, name) values (44, 'Smooks in Action');<br />
insert into products (id, name) values (55, 'Ultimate guide to Smooks');<br />
<br />
Let's execute Smooks now.
<br />
<br />
<pre class="brush: js">package example.main;
import java.io.File;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.milyn.Smooks;
import org.milyn.container.ExecutionContext;
import org.milyn.persistence.util.PersistenceUtil;
import org.milyn.scribe.adapter.hibernate.SessionRegister;
import org.milyn.scribe.register.DaoRegister;
import org.xml.sax.SAXException;
public class Main {
public static void main(String args[]) throws IOException, SAXException {
Smooks smooks = new Smooks("smooks-hbt-config.xml");
ExecutionContext executionContext = smooks.createExecutionContext();
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
DaoRegister register = new SessionRegister(session);
// This sets the DAO Register in the executionContext for Smooks //to access it.
PersistenceUtil.setDAORegister(executionContext,register);
Transaction transaction = session.beginTransaction();
Source source = new StreamSource(new File("input.xml"));
smooks.filterSource(executionContext, source);
transaction.commit();
}
</pre>
</div>Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com3tag:blogger.com,1999:blog-1621989597321372268.post-29140669037293838622012-02-22T20:23:00.000+10:302018-04-29T20:49:24.041+09:30A way to transform message content in between the client and the backend server - WSO2 Payload Factory Mediator<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
WSO2 ESB version - 4.0.3<br />
<br />
<div style="text-align: justify;">
WSO2 PayLoad Factory Mediator is for transforming or replacing message content in between the client and the backend server. Incomming message from client can be transformed by the Payload Factory mediator into the format expected by the service. Then the response message can be formatted into which is expected by the client.</div>
<br />
<div style="text-align: justify;">
Each argument in the mediator configuration could be a static value or an XPath expression. When an expression is used, argument value is fetched at runtime by evaluating the provided XPath expression against the existing SOAP message. Also the format of the request or response message can be configured which is mapped with the arguments provided in order.</div>
<br />
For instance in the following the values for format parameters Code & Price will be assigned with values evaluated from args given in the specified order.<br />
<br />
<pre class="brush: js"><payloadFactory>
<format>
<m:checkpriceresponse xmlns:m="http://services.samples/xsd">
<m:code>$1</m:code>
<m:price>$2</m:price>
</m:checkpriceresponse>
</format>
<args>
<arg expression="//m0:symbol" xmlns:m0="http://services.samples/xsd">
<arg expression="//m0:last" xmlns:m0="http://services.samples/xsd">
</arg></arg></args>
</payloadFactory></pre>
<br />
<div style="text-align: justify;">
A sample service of WSO2 Payload Factory Mediator can be found from <a href="http://wso2.org/project/esb/java/4.0.3/docs/samples/message_mediation_samples.html#Sample17">here</a>. The sample mediates the incomming message, send to the server and response is sent back to the client. Inside 'In' mediator, PayloadFactory mediator transforms the message. The response message is transformed inside 'Out' mediator.</div>
<br />
<div style="text-align: justify;">
We can use PayloadFactory mediator in WSO2 ESB proxy services as well. In the inSequence we can transform the request message, and in outSequence we can transform the response message. Here the publishWSDL must be specified with the WSDL which is visible to the user.</div>
<br />
<div style="text-align: justify;">
Imagine that there is a web service endpoint which has the getQuote operation with 'symbol' parameter. But client who invokes the service see that there is a getQuote operation with 'Code' parameter. So request message will be sent as,</div>
<div>
<br />
<pre class="brush: js"><p:getQuote xmlns:p="http://services.samples">
<p:request>
<p:code>IBM</p:code>
</p:request>
</p:getQuote>
</pre>
But server expects a message as,
<br />
<pre class="brush: js"><p:getQuote xmlns:p="http://services.samples">
<p:request>
<p:symbol>IBM</p:symbol>
</p:request>
</p:getQuote>
</pre>
The PayloadFactory mediator does this transformation as follows.
<br />
<pre class="brush: js"><proxy name="test" startonload="true" statistics="disable" trace="disable" transports="https,http" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<payloadFactory>
<format>
<m:getquote xmlns:m="http://services.samples">
<m:request>
<m:symbol>$1</m:symbol>
</m:request>
</m:getquote>
</format>
<args>
<arg expression="//m0:Code" xmlns:m0="http://services.samples"></arg>
</args>
</payloadFactory>
</inSequence>
<outSequence>
<payloadFactory>
<format>
<m:checkpriceresponse xmlns:m="http://services.samples/xsd">
<m:code>$1</m:code>
<m:price>$2</m:price>
</m:checkpriceresponse>
</format>
<args>
<arg expression="//m0:symbol" xmlns:m0="http://services.samples/xsd"></arg>
<arg expression="//m0:last" xmlns:m0="http://services.samples/xsd"></arg>
</args>
</payloadFactory>
<log level="full"></log>
<send></send>
</outSequence>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService">
</address>
</endpoint>
</target>
<publishwsdl uri="ClientVisibleWSDL.wsdl"></publishwsdl>
</proxy></pre>
Similarly the web service will send the response in the format of,
<br />
<pre class="brush: js"><m:checkpriceresponse xmlns:m="http://services.samples/xsd">
<m:symbol>IBM</m:symbol>
<m:last>84.76940826343248</m:last>
</m:checkpriceresponse>
</pre>
But the client expects the response message as,
<br />
<pre class="brush: js"><m:checkpriceresponse xmlns:m="http://services.samples/xsd">
<m:code>IBM</m:code>
<m:price>84.76940826343248</m:price>
</m:checkpriceresponse>
</pre>
So this response message transformation happend on the outSequennce.
</div>
</div>Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0tag:blogger.com,1999:blog-1621989597321372268.post-86201097949875834612011-12-05T16:01:00.001+10:302011-12-05T16:10:07.883+10:30Manually install a maven dependency<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
execute the following command from the command line with the correct values for options. -Dfile option locates the downloaded jar file. Therefore make sure to specify the correct location or reach the jar location from the command line and execute the command.<br />
<br />
<br /></div>
<pre class="brush: js">mvn install:install-file -DgroupId=ojdbc -DartifactId=ojdbc6 \
-Dversion=10.2.0.3.0 -Dpackaging=jar -Dfile=ojdbc6.jar -DgeneratePom=true
</pre>
</div>Lakmalihttp://www.blogger.com/profile/06183648962849727542noreply@blogger.com0