<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[DevRealm – Cloud Architecture, Optimization, CX and AI]]></title><description><![CDATA[Insights and best practices for enhancing customer experience through cloud, AI, and system integration.]]></description><link>https://devrealm.org</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 17:58:23 GMT</lastBuildDate><atom:link href="https://devrealm.org/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Infracost and Terraform: Giving Developers the Tools to Manage Cloud Costs]]></title><description><![CDATA[Managing the cost of your cloud infrastructure can be a complex and daunting task, especially as your organization grows and the number of resources increases. One way to handle this challenge is to use a tool like Infracost, which allows you to see ...]]></description><link>https://devrealm.org/infracost-and-terraform-giving-developers-the-tools-to-manage-cloud-costs</link><guid isPermaLink="true">https://devrealm.org/infracost-and-terraform-giving-developers-the-tools-to-manage-cloud-costs</guid><category><![CDATA[cloudcostmanagement]]></category><category><![CDATA[costvisibility]]></category><category><![CDATA[infracost]]></category><category><![CDATA[Terraform]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Thu, 12 Jan 2023 09:48:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ffd117cbb62c9fd2fb062207b662ac33.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Managing the cost of your cloud infrastructure can be a complex and daunting task, especially as your organization grows and the number of resources increases. One way to handle this challenge is to use a tool like <a target="_blank" href="https://www.infracost.io">Infracost</a><em>,</em> which allows you to see the cost of your resources in real-time and make more informed decisions about where to optimize.</p>
<p>In this post, we'll take a look at how to use Infracost with Terraform to gain greater visibility into your infrastructure costs and make cost control a shared responsibility across your organization.</p>
<p>First, let's talk about what Infracost is and how it works. Infracost is an open-source tool that generates cost estimates for your cloud resources by integrating with your infrastructure as code repository. It supports multiple cloud providers, including AWS, Azure, and GCP, and can be used with Terraform and soon with CloudFormation and Pulumi.</p>
<p>The most fascinating aspect here is that Infracost empowers developers to take the driver's seat in cloud cost control by providing them with real-time visibility into the costs of their resources and the ability to see the cost impact of changes before they are applied.<br />This gives developers the tools they need to identify high-cost resources and make adjustments to them, such as scaling down or deleting them, to reduce costs. Additionally, the ability to see cost savings opportunities and include cost estimates in their pull requests enables developers to make more informed decisions about which resources to create, modify or delete and share their cost-saving measures with other stakeholders.<br />With Infracost, developers can take ownership of their resources costs and take action to optimize them, and also, they can assist in the budgeting process and make sure that they are aligned with the organization's financial goals.<br />This way, Infracost can be a valuable tool that empowers developers to help with cost control, promoting a culture of cost awareness, and encouraging collaboration across the organization to optimize the cloud infrastructure costs.</p>
<h2 id="heading-a-word-about-cost-estimate-reports">A word about cost estimate reports</h2>
<p>It is important to note that Infracost cost estimates are based on the standard public pricing provided by cloud providers such as AWS, GCP, or Azure and do not take into account any discounts that your project or organization may have.</p>
<p>However, even with standard public prices, Infracost can still provide a good estimate of your project's costs.</p>
<p>By using Infracost Cloud, the SaaS product that builds on top of the Infracost open-source tool, you can create <a target="_blank" href="https://www.infracost.io/docs/infracost_cloud/custom_price_books/">custom price books</a> that reflect any discounts you may have, resulting in more accurate cost estimates that align with the invoices you receive at the end of each month.</p>
<h2 id="heading-how-to-use">How to use</h2>
<p>To use Infracost, you can easily install it by following the instructions provided on the <a target="_blank" href="https://www.infracost.io/docs/">Infracost website</a>. Once installed, it can be integrated into any Terraform project.</p>
<p>In this post, we will be using a simple Terraform project as an example. You can access this example project on GitHub at the following link: <a target="_blank" href="https://github.com/devrealm/terraform-infracost">https://github.com/devrealm/terraform-infracost</a></p>
<pre><code class="lang-json">provider <span class="hljs-string">"aws"</span> {
  region                      = <span class="hljs-attr">"us-east-1"</span>
  skip_credentials_validation = true
  skip_requesting_account_id  = true
  access_key                  = <span class="hljs-attr">"mock_access_key"</span>
  secret_key                  = <span class="hljs-attr">"mock_secret_key"</span>
}

resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"ec2_instance_example"</span> {
  ami           = <span class="hljs-attr">"ami-0abe92d15a280b758"</span>
  instance_type = <span class="hljs-attr">"t2.micro"</span>

  tags = {
    Name = <span class="hljs-attr">"example-instance"</span>
  }
}

resource <span class="hljs-string">"aws_s3_bucket"</span> <span class="hljs-string">"s3_example_bucket"</span> {
  bucket = <span class="hljs-attr">"example-bucket"</span>
}

resource <span class="hljs-string">"aws_db_instance"</span> <span class="hljs-string">"rds_example"</span> {
  engine                  = <span class="hljs-attr">"postgres"</span>
  instance_class          = <span class="hljs-attr">"db.t2.micro"</span>
  name                    = <span class="hljs-attr">"example-db"</span>
  allocated_storage       = 20
  storage_type            = <span class="hljs-attr">"gp2"</span>

  tags = {
    Name = <span class="hljs-attr">"example-rds-instance"</span>
  }
}
</code></pre>
<p>After installing Infracost, we can start getting cost estimates for our infrastructure:</p>
<pre><code class="lang-plaintext">$ cd terraform-infracost
$ infracost breakdown --path .

Evaluating Terraform directory at .
Project: devrealm/terraform-infracost

 Name                                                            Monthly Qty  Unit                    Monthly Cost

 aws_db_instance.rds_example
 ├─ Database instance (on-demand, Single-AZ, db.t2.micro)                730  hours                         $13.14
 └─ Storage (general purpose SSD, gp2)                                    20  GB                             $2.30

 aws_instance.ec2_instance_example
 ├─ Instance usage (Linux/UNIX, on-demand, t2.micro)                     730  hours                          $8.47
 └─ root_block_device
    └─ Storage (general purpose SSD, gp2)                                  8  GB                             $0.80

 aws_s3_bucket.s3_example_bucket
 └─ Standard
    ├─ Storage                                             Monthly cost depends on usage: $0.023 per GB
    ├─ PUT, COPY, POST, LIST requests                      Monthly cost depends on usage: $0.005 per 1k requests
    ├─ GET, SELECT, and all other requests                 Monthly cost depends on usage: $0.0004 per 1k requests
    ├─ Select data scanned                                 Monthly cost depends on usage: $0.002 per GB
    └─ Select data returned                                Monthly cost depends on usage: $0.0007 per GB

 OVERALL TOTAL                                                                                              $24.71
──────────────────────────────────
3 cloud resources were detected:
∙ 3 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
</code></pre>
<p>It's worth noting that for certain services that cost is based on usage, such as S3, Infracost may not be able to provide cost estimates by default. However, Infracost has a solution for this by allowing you to provide usage information.</p>
<p>In this example, you can create a file named <code>infracost-usage.yml</code> that contains the estimations of your S3 bucket usage. This file would look something like this:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># You can use this file to define resource usage estimates for Infracost to use when calculating</span>
<span class="hljs-comment"># the cost of usage-based resource, such as AWS Lambda.</span>
<span class="hljs-comment"># `infracost breakdown --usage-file infracost-usage.yml [other flags]`</span>
<span class="hljs-comment"># See https://infracost.io/usage-file/ for docs</span>
<span class="hljs-attr">version:</span> <span class="hljs-number">0.1</span>
<span class="hljs-attr">resource_usage:</span>
  <span class="hljs-attr">aws_s3_bucket.s3_example_bucket:</span>
    <span class="hljs-attr">standard:</span> <span class="hljs-comment"># Usages of S3 Standard:</span>
      <span class="hljs-attr">storage_gb:</span> <span class="hljs-number">10000</span> <span class="hljs-comment"># Total storage in GB.</span>
      <span class="hljs-attr">monthly_tier_1_requests:</span> <span class="hljs-number">1000000</span> <span class="hljs-comment"># Monthly PUT, COPY, POST, LIST requests (Tier 1).</span>
      <span class="hljs-attr">monthly_tier_2_requests:</span> <span class="hljs-number">100000</span> <span class="hljs-comment"># Monthly GET, SELECT, and all other requests (Tier 2).</span>
      <span class="hljs-attr">monthly_select_data_scanned_gb:</span> <span class="hljs-number">10000</span> <span class="hljs-comment"># Monthly data scanned by S3 Select in GB.</span>
      <span class="hljs-attr">monthly_select_data_returned_gb:</span> <span class="hljs-number">1000</span> <span class="hljs-comment"># Monthly data returned by S3 Select in GB.</span>
</code></pre>
<p>You can provide this usage file as an input to Infracost and it will use this information to generate cost estimates for your S3 bucket.</p>
<p>Now, with the usage information provided in the <code>infracost-usage.yml</code> file, Infracost will be able to calculate the cost for the S3 service and provide an estimate of, for example, $280.45.</p>
<pre><code class="lang-bash">$ infracost breakdown --path . --usage-file infracost-usage.yml
Project: devrealm/terraform-infracost

 Name                                                      Monthly Qty  Unit         Monthly Cost

 aws_db_instance.rds_example
 ├─ Database instance (on-demand, Single-AZ, db.t2.micro)          730  hours              <span class="hljs-variable">$13</span>.14
 └─ Storage (general purpose SSD, gp2)                              20  GB                  <span class="hljs-variable">$2</span>.30

 aws_instance.ec2_instance_example
 ├─ Instance usage (Linux/UNIX, on-demand, t2.micro)               730  hours               <span class="hljs-variable">$8</span>.47
 └─ root_block_device
    └─ Storage (general purpose SSD, gp2)                            8  GB                  <span class="hljs-variable">$0</span>.80

 aws_s3_bucket.s3_example_bucket
 └─ Standard
    ├─ Storage                                                  10,000  GB                <span class="hljs-variable">$230</span>.00
    ├─ PUT, COPY, POST, LIST requests                            1,000  1k requests         <span class="hljs-variable">$5</span>.00
    ├─ GET, SELECT, and all other requests                         100  1k requests         <span class="hljs-variable">$0</span>.04
    ├─ Select data scanned                                      10,000  GB                 <span class="hljs-variable">$20</span>.00
    └─ Select data returned                                      1,000  GB                  <span class="hljs-variable">$0</span>.70

 OVERALL TOTAL                                                                            <span class="hljs-variable">$280</span>.45
──────────────────────────────────
3 cloud resources were detected:
∙ 3 were estimated, all of <span class="hljs-built_in">which</span> include usage-based costs, see https://infracost.io/usage-file
</code></pre>
<p>It's important to note that the usage file can be tailored to the specific resources in your project, and Infracost also provides a r<a target="_blank" href="https://github.com/infracost/infracost/blob/master/infracost-usage-example.yml">eference usage file</a> that can serve as a guide for providing usage information for different supported resources.</p>
<h3 id="heading-show-cost-estimate-diff">Show cost estimate diff</h3>
<p>Infracost also allows you to see the impact of changes to your resources on your cost estimates.</p>
<p>For instance, you can modify the EC2 and RDS instance types and see how it would affect the overall cost.</p>
<p>First, let's start by getting a baseline cost estimate by running the infracost breakdown command and save the output to a file.</p>
<pre><code class="lang-bash">infracost breakdown --path . --format json --out-file infracost-base.json --usage-file infracost-usage.ym
</code></pre>
<p><mark>It's important to remember that when creating the baseline you need to include the usage file by passing the flag </mark> <code>--usage-file infracost-usage.yml</code> <mark>in the infracost breakdown command.</mark></p>
<p>After that, we can make changes in the Terraform project by updating the EC2 and RDS instance types to "m5.4xlarge" and "m5.8xlarge" respectively. You can find the updated Terraform project in a new <a target="_blank" href="https://github.com/devrealm/terraform-infracost/tree/upgrade_instance_types">branch</a> in the project's repository.</p>
<p>To see the impact of these changes on the cost estimate, we can then run the Infracost diff command to generate a new cost estimate report.</p>
<pre><code class="lang-bash">$ infracost diff --path . --compare-to infracost-base.json --usage-file infracost-usage.yml

Project: devrealm/terraform-infracost

~ aws_db_instance.rds_example
  +<span class="hljs-variable">$2</span>,066 (<span class="hljs-variable">$15</span>.44 → <span class="hljs-variable">$2</span>,081)

    ~ Database instance (on-demand, Single-AZ, db.t2.micro → db.m5.8xlarge)
      +<span class="hljs-variable">$2</span>,066 (<span class="hljs-variable">$13</span>.14 → <span class="hljs-variable">$2</span>,079)

~ aws_instance.ec2_instance_example
  +<span class="hljs-variable">$552</span> (<span class="hljs-variable">$9</span>.27 → <span class="hljs-variable">$561</span>)

    ~ Instance usage (Linux/UNIX, on-demand, t2.micro → m5.4xlarge)
      +<span class="hljs-variable">$552</span> (<span class="hljs-variable">$8</span>.47 → <span class="hljs-variable">$561</span>)

Monthly cost change <span class="hljs-keyword">for</span> devrealm/terraform-infracost
Amount:  +<span class="hljs-variable">$2</span>,618 (<span class="hljs-variable">$280</span> → <span class="hljs-variable">$2</span>,899)
Percent: +934%

──────────────────────────────────
Key: ~ changed, + added, - removed

3 cloud resources were detected:
∙ 3 were estimated, all of <span class="hljs-built_in">which</span> include usage-based costs, see https://infracost.io/usage-file
</code></pre>
<p>As you can see, the cost for RDS service has increased dramatically from $13.14 to $2,079 and the cost for EC2 service has increased from $280 to $2,899.</p>
<p>With Infracost, you can also see the cost estimate difference as a comment on a pull request or a commit, which can be useful in a CI/CD pipeline. You can learn more about this feature by reading the <a target="_blank" href="https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests">Infracost documentation</a>.</p>
<h2 id="heading-infracost-cloud">Infracost Cloud</h2>
<p>Infracost Cloud is a SaaS product that builds on top of the Infracost open-source tool, providing an easy-to-use dashboard and detailed reports for controlling costs in one central location.</p>
<p>To set up Infracost Cloud, you can follow the <a target="_blank" href="https://www.infracost.io/docs/infracost_cloud/get_started/">instructions provided</a> and link your Terraform project repository. Once setup is completed, you will have access to your repositories and their associated cost estimate reports.  </p>
<p>For example, in the screenshot below, you can see the main screen of the <code>devrealm/terraform-infracost</code> repository, which shows a pull request to upgrade the EC2 and RDS instance types, and the resulting increase in costs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673473664201/d537c6e0-3536-42e9-8b60-db353b8f2576.png" alt class="image--center mx-auto" /></p>
<p>By navigating to the "All estimates" tab, you can see the cost estimate report for the initial commit in the main branch.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673473719983/fe895563-857b-4c70-bea8-23641847b8b9.png" alt class="image--center mx-auto" /></p>
<p>Finally, by checking the "Pull requests" tab, you can view the cost estimate report for the PR and see the details of the difference compared to the main branch or the total cost in a tabular format.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673473784363/f9d129dd-d4ff-43d0-98a4-67f7a7aef474.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673473803231/3974d0d9-af61-4536-ac43-0b1cafff9e33.png" alt class="image--center mx-auto" /></p>
<p>In conclusion, Infracost is a powerful tool that allows developers to take a proactive approach to manage cloud infrastructure costs.<br />By providing real-time cost estimates and alerts, developers can identify and address cost issues before they become significant problems. This not only helps to keep costs under control but also promotes a culture of cost awareness and responsibility within development teams. By integrating Infracost into your development workflow, you can gain greater visibility and control over your cloud infrastructure costs, enabling you to make more informed decisions and optimize your resources.</p>
<p>To start using Infracost, you can visit their website at <a target="_blank" href="https://www.infracost.io">https://www.infracost.io</a> and check their documentation.</p>
<h2 id="heading-get-in-touch">Get in touch</h2>
<p>Your feedback is appreciated, please leave a comment on the post to let me know what you think.</p>
<p>If you're ready to take the next step in cost-effective cloud management with Infracost and Terraform, reach out at <a target="_blank" href="mailto:george@devrealm.org">george@devrealm.org</a> or connect on LinkedIn at <a target="_blank" href="https://www.linkedin.com/in/georgevagenas/">https://www.linkedin.com/in/georgevagenas/</a> to see how I can help.</p>
]]></content:encoded></item><item><title><![CDATA[Testing proprietary systems]]></title><description><![CDATA[There are times when you have to integrate into a proprietary or legacy system, most of the time, using an API to implement the integration.
Testing such integration with a proprietary or legacy system can be complex, if possible at all, since most o...]]></description><link>https://devrealm.org/testing-proprietary-systems</link><guid isPermaLink="true">https://devrealm.org/testing-proprietary-systems</guid><category><![CDATA[jtapi]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Automated Testing]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Mon, 30 Mar 2020 17:56:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/36103c41b1b5c5c6546217567ed7108c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are times when you have to integrate into a proprietary or legacy system, most of the time, using an API to implement the integration.</p>
<p>Testing such integration with a proprietary or legacy system can be complex, if possible at all, since most of the time, the proprietary system is not based on an open-source protocol and mocking the internals of the system is not an option.</p>
<p>Examples of such proprietary or legacy systems are banking software and telephony systems.</p>
<p>To test such projects, you are only left with live tests, which means using the live system, sometimes the system in the production environment, to simulate use cases and check that your application behaves as expected.</p>
<p>But live testing shouldn't be an option at all. Here are some of the downsides of live testing</p>
<ul>
<li><p>they are not automated</p>
</li>
<li><p>they cannot be run as part of a CI/CD pipeline</p>
</li>
<li><p>they are error-prone</p>
</li>
<li><p>they are time-consuming</p>
</li>
</ul>
<h2 id="heading-pcap-replay">PCAP Replay</h2>
<p>Looking for any tools that can help here, I came across the excellent project Wiresham (<a target="_blank" href="https://github.com/abstracta/wiresham/">https://github.com/abstracta/wiresham/</a>) a simple TCP service mocking tool for replaying <a target="_blank" href="http://www.tcpdump.org/">tcpdump</a> or <a target="_blank" href="https://www.wireshark.org/">Wireshark</a> captured service traffic.</p>
<p>You can check <a target="_blank" href="https://github.com/abstracta/wiresham/blob/master/README.md">project details</a> on how to set up Wiresham on your application.</p>
<p>The required tools are:</p>
<ul>
<li><p><a target="_blank" href="http://www.tcpdump.org/">tcpdump</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/abstracta/wiresham">wiresham</a></p>
</li>
</ul>
<p>Following are the steps needed to capture live traffic, prepare dump flows and set up replays in your test case.</p>
<h2 id="heading-capture-live-traffic-with-tcpdump">Capture live traffic with tcpdump</h2>
<p>To capture live traffic we need the external proprietary system and our application.</p>
<p>Some of the important things to consider on capturing live traffic:</p>
<ol>
<li><p>Check which ports are involved. For some applications, ports might include signaling and media</p>
</li>
<li><p>Start <strong>tcpdump</strong> for each of the discovered ports. <strong>Make sure you define the proper network interface</strong>, for example, if traffic goes through VPN, start tcpdump on the VPN interface.</p>
</li>
</ol>
<p>For example:<br /><code>sudo tcpdump port 450 -i ppp0 -w jtapi_450.pcap</code></p>
<h2 id="heading-dump-flow-files-with-wiresham">Dump flow files with wiresham</h2>
<p>Use standalone <a target="_blank" href="https://github.com/abstracta/wiresham">wiresham</a> to dump data from pcap to a simple flow file that later will be used in the integration test.</p>
<p><strong>It is important to specify the ip address of the service that we want to mock using the "-a" option, this way wiresham can properly prepare the dump flow.<br />Using the "-a" option allows Wiresham to identify which tcp packets are coming from the mocked service, and prepare the flow accordingly - remember we need to mock the external service and have our application receive any request/response from the mocked service.</strong></p>
<p>If for example the ip address of the server we need to mock is 10.100.26.31 we need to run the command:</p>
<p><code>java -jar ./wiresham-0.4.3-standalone.jar -d dump-450.yml -a 10.100.26.31 jtapi_450.pcap</code></p>
<p><code>-a (--server-address) ip address : When using a Wireshark generated JSON dump or PCAP file, this parameter specifies the IP address which identifies the service to be virtualized</code><br /><code>...</code><br /><code>-d (--dump-file) .yml file : File path to dump loaded flow config. The virtual service will not be started when this option is specified. This option makes sense when a Wireshark JSON file is used for config to dump a simplified and smaller file and then manually tune it if needed</code></p>
<p>The result of the operation will be yaml files that will be used in the test.</p>
<h2 id="heading-integration-test">Integration test</h2>
<p>To properly set up an integration test we need wiresham dependency to use the tools such as <strong>VirtualTcpService</strong>.</p>
<p>The test will have to instantiate as many <strong>VirtualTcpService</strong> tools as the number of flow files prepared earlier.</p>
<p>The <strong>VirtualTcpService tools need</strong> to be set with the proper port, flow file and started.</p>
<p>In the test, reference the mocked remote service using the localhost ip address and the service port.</p>
<h2 id="heading-avaya-application-enablement-services-example">Avaya Application Enablement Services Example</h2>
<p><a target="_blank" href="https://www.devconnectprogram.com/site/global/products_resources/avaya_aura_application_enablement_services/overview/index.gsp">Avaya AES</a> is one of the proprietary systems that are very complicated to mock and prepare tests for an application that uses JTAPI library to integrate with the service.</p>
<p>Using the tcpdump and wiresham project, we can capture live traffic and then prepare flows to be used in integration test cases for applications using JTAPI.</p>
<p>Following, you will see the steps needed  how to capture JTAPI traffic and replay it in a test case.</p>
<h3 id="heading-capture-with-tcpdump">Capture with tcpdump</h3>
<p>AES traffic uses the following two ports</p>
<ul>
<li><p>TCP/450</p>
</li>
<li><p>TCP/1050</p>
</li>
</ul>
<p>To prepare the test we first need to start tcpdump capture and second start the JTAPI application and connect to AES server.</p>
<p>Use two different tcpdump process to capture AES real traffic</p>
<ul>
<li><p>sudo tcpdump port 450 -i ppp0 -w jtapi_450.pcap</p>
</li>
<li><p>sudo tcpdump port 1050 -i ppp0 -w jtapi_1050.pcap</p>
</li>
</ul>
<p>Depending on your needs, you can capture just the AES connection, register a station for events and capture events.</p>
<h3 id="heading-dump-flow-files">Dump flow files</h3>
<p>Use standalone wiresham to dump data from pcap to simple flow file.</p>
<p>Make sure to specify the ip address of the Avaya AES server using the "-a" option, which in the example is 10.100.26.31.</p>
<ul>
<li><p>java -jar ./wiresham-0.4.3-standalone.jar -d dump-450.yml -a 10.100.26.31 jtapi_450.pcap</p>
</li>
<li><p>java -jar ./wiresham-0.4.3-standalone.jar -d dump-1050.yml -a 10.100.26.31 jtapi_1050.pcap</p>
</li>
</ul>
<p>The result of the operation will be two files:</p>
<ul>
<li><p>dump-450.yml</p>
</li>
<li><p>dump-1050.yml</p>
</li>
</ul>
<h3 id="heading-prepare-the-test">Prepare the test</h3>
<p>We need to prepare the test with two instances of <strong>VirtualTcpService</strong>, set their port to <strong>450</strong> and <strong>1050</strong> and set the flow to the relevant files.</p>
<p><code>private VirtualTcpService service450 = new VirtualTcpService();</code><br /><code>private VirtualTcpService service1050 = new VirtualTcpService();</code></p>
<p><code>@BeforeEach</code><br /><code>public void setUp() throws Exception {</code><br /><code>service450.setPort(450);</code><br /><code>service450.setFlow(loadFlow("/dump-450.yml"));</code><br /><code>service450.start();</code></p>
<p><code>service1050.setPort(1050);</code><br /><code>service1050.setFlow(loadFlow("/dump-1050.yml"));</code><br /><code>service1050.start();</code><br /><code>}</code></p>
<p>The above setup is everything we need to have the test to mock the JTAPI link to Avaya AES.</p>
<p>Leave your comments and suggestions below</p>
]]></content:encoded></item><item><title><![CDATA[Use H2 Database to connect to any database]]></title><description><![CDATA[H2 database is a powerful Java SQL database that is very fast, implements JDBC API, provides an html console, and has a very small footprint, around 2MB.
Because of its size and the SQL compatibility that the H2 database provides, it can be used as a...]]></description><link>https://devrealm.org/use-h2-database-to-connect-to-any-database</link><guid isPermaLink="true">https://devrealm.org/use-h2-database-to-connect-to-any-database</guid><category><![CDATA[h2]]></category><category><![CDATA[JDBC]]></category><category><![CDATA[SQL]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[MSSQL]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Mon, 24 Jun 2019 18:34:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/dcea9bdbd30ceaf346ced82f78a76a95.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>H2 database is a powerful Java SQL database that is very fast, implements JDBC API, provides an html console, and has a very small footprint, around 2MB.</p>
<p>Because of its size and the SQL compatibility that the H2 database provides, it can be used as an embedded database instead of HSQLDB or other, and of course in the test suite of an application instead of using the DB used in production (for example MySQL, Postgres etc)</p>
<p>The H2 database can connect to any remote or local DB that supports JDBC for checking DB connection, checking or modify data etc. The html console is a very handy tool for all those cases.</p>
<h2 id="heading-setup-jdbc-connection">Setup JDBC connection</h2>
<p>We start by downloading the h2 standalone archive from <a target="_blank" href="https://h2database.com/html/main.html">https://h2database.com/html/main.html</a></p>
<p>Next we need to provide the JDBC driver for the DB server we want to connect.</p>
<p>For example, for MS SQL DB server, proceed to <a target="_blank" href="https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server?view=sql-server-2017">https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server?view=sql-server-2017</a> and download the version of JDBC driver you need for the SQL Server.</p>
<p>Create a folder <strong><em>drivers</em></strong> inside <strong><em>/h2</em></strong> and place the download JDBC jar file there.</p>
<p>Now we need to tell H2 to load this JDBC jar in the classpath and make it available so we need to define the <strong><em>H2DRIVERS</em></strong> system variable.</p>
<p><code>export H2DRIVERS=/home/user/h2/drivers/mssql-jdbc-6.1.0.jre8.jar</code></p>
<p>You might want to have more JDBC jars in the classpath, for MySQL for example, in that case the <strong><em>H2DRIVERS</em></strong> will have to include all of them like this</p>
<p><code>export H2DRIVERS=/home/user/h2/drivers/mssql-jdbc-6.1.0.jre8.jar:/home/user/h2/drivers/mysql-connector-java-8.0.16.jar</code></p>
<p>Make sure you change the folder location from <strong><em>/home/user/h2</em></strong> to the actual location in your machine.</p>
<p>The <strong><em>h2</em></strong> folder will look like this</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258106521/jezhgjsGB.png" alt /></p>
<p>Next we can start <strong><em>h2</em></strong>. Head to <strong><em>bin</em></strong> folder and use the startup script for your OS (Windows → /bat or for Linux/Mac → .sh)</p>
<p>When the <strong><em>h2</em></strong> start, the console will start at the console and now we can setup the connection details.</p>
<p>First thing is to pick the proper DB server from the dropdown menu, for MS SQL DB you need to pick <strong><em>Generic MS SQL Server 2005</em></strong>. By setting the server, the <strong><em>Driver</em></strong> <strong><em>class</em></strong> will be set for you automatically.</p>
<p>The only thing left for you to provide are:</p>
<ul>
<li><p>JDBC URL, for example <strong><em>jdbc:sqlserver:/SQLSERVER.company.com\INSTANCEID;databaseName=MyDB</em></strong></p>
</li>
<li><p>Username</p>
</li>
<li><p>Password</p>
</li>
</ul>
<p>The Login screen will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258108953/7yQ6fb12b.png" alt /></p>
<p>Now press <strong><em>Connect</em></strong> and you are in!!!</p>
<h2 id="heading-bonus-allow-web-connections-from-remote-hosts">Bonus, allow web connections from remote hosts</h2>
<p>By default H2 database does not allow connections from other machines when starting the H2 Console. So if you deploy and start H2 on a remote server, lets say in a dev environment, you won't be able to reach the H2 Console unless you instruct H2 to allow connections from remote hosts.</p>
<p>Remote access can be enabled using the command line options <strong><em>-webAllowOthers</em></strong></p>
<p>To use this option run H2 like this</p>
<p><code>./h2.sh -webAllowOthers</code></p>
<p>This will allow web connection to H2 Console from remote hosts.</p>
<p>You can check more details about remote access here <a target="_blank" href="https://h2database.com/html/advanced.html?highlight=webAllowOthers&amp;search=webAllowOth#remote_access">https://h2database.com/html/advanced.html?highlight=webAllowOthers&amp;search=webAllowOth#remote_access</a></p>
]]></content:encoded></item><item><title><![CDATA[Locating SIP Servers - Comments on the RFC3263 for SIPS URIs]]></title><description><![CDATA[RFC3263 describes the DNS procedure and guidelines to be followed in order to locate SIP Servers.
From the abstract of RFC3263:

The Session Initiation Protocol (SIP) uses DNS procedures to allow a client to resolve a SIP Uniform
Resource Identifier ...]]></description><link>https://devrealm.org/locating-sip-servers-comments-on-the-rfc3263-for-sips-uris</link><guid isPermaLink="true">https://devrealm.org/locating-sip-servers-comments-on-the-rfc3263-for-sips-uris</guid><category><![CDATA[SIP]]></category><category><![CDATA[voip]]></category><category><![CDATA[dns]]></category><category><![CDATA[rfc]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Wed, 26 Sep 2018 10:18:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/11f50f5d72ae17305cd35bb0c117a105.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>RFC3263 describes the DNS procedure and guidelines to be followed in order to locate SIP Servers.</p>
<p>From the abstract of RFC3263:</p>
<ul>
<li>The Session Initiation Protocol (SIP) uses DNS procedures to allow a client to resolve a SIP Uniform</li>
<li>Resource Identifier (URI) into the IP address, port, and transport protocol of the next hop to contact.</li>
<li>It also uses DNS to allow a server to send a response to a backup client if the primary client has failed.</li>
</ul>
<p>The document here describes those DNS procedures in detail.</p>
<p>When it comes to implement the proposed guidelines from RFC3263 in order to locate SIP server, the specification doesn’t seem to cover enough all the possible situations, specially for SIPS URI, and that is why we should consider to change some points there.</p>
<p>The purpose of this post is, first to indicate which points of the proposed RFC3263 mechanisms could create problems when it comes to resolve the transport for SIPS URIs and how these points should be changed by applying some rules on the results of the DNS query. Second this post provides what is the minimum DNS configuration for SIP, that is the minimum required NAPTR, SRV and A records according to the RFC3263. </p>
<h2 id="heading-1-rfc3263-misconceptions-when-it-comes-to-transport-resolution">1. RFC3263 misconceptions when it comes to transport resolution</h2>
<p>The proposed mechanism from the specification for the transport resolution, suggest to have NAPTR query first and if this doesn’t return any results to issue a SRV query. At this point the the specification fails to provide clear directions on how to choose the transport when the URI under question is a SIPS URI.</p>
<p>We should consider to change the way the transport resolution mechanism have to be done keeping in mind the RFC5630 “The Use of the SIPS URI Scheme in the Session Initiation Protocol (SIP)” guidelines.</p>
<p>So as said before RFC3263 states that if the NATPR query returns no records, an SRV query should be performed and if that query returns any results that contains transports that the client can support, then the client can choose any of the results:  </p>
<ul>
<li>A particular transport is supported if the query is successful. The client MAY use any transport protocol it desires which is supported by the server.</li>
</ul>
<p>The “..use any transport protocol it desires which is supported by the server.”  creates a confusion and problems when it comes to SIPS URIs. The SRV query results should be examined and some rules should be applied before we choose the transport.</p>
<p>Another point of conflict coming from RFC3263 for the transport resolution, is in the case where port is available in the URI. The specification states :</p>
<ul>
<li>if no transport protocol is specified, and the TARGET is not numeric, but an explicit port is provided, the client SHOULD use UDP for a SIP URI, and TCP for a SIPS URI.</li>
</ul>
<p>This should be “TLS for a SIPS URI” </p>
<h2 id="heading-2-sips-uri-clarifications-from-the-rfc5630-the-use-of-the-sips-uri-scheme-in-the-session-initiation-protocol-sip">2. SIPS URI clarifications from the RFC5630 “The Use of the SIPS URI Scheme in the Session Initiation Protocol (SIP)”</h2>
<p>RFC5630 purpose is to clarify the use of SIPS URI.</p>
<ul>
<li>The meaning and usage of the SIPS URI scheme and of Transport Layer Security (TLS) RFC5246 are underspecified in SIP RFC3261 and have been a source of confusion for implementers. This document provides clarifications and guidelines concerning the use of the SIPS URI scheme in the Session Initiation Protocol(SIP). It also makes normative changes to SIP (including both RFC3261 and RFC3608).</li>
</ul>
<p>RFC5630 [3.1.3 – Using TLS with SIP Instead of SIPS]  defines two uses of TLS, one with SIPS URI, and one with SIP URI. As it states SIPS URI should be treated as “TLS-only” requests, while using TLS with SIP URI should be treated as “best-effort TLS”.Taken from there, we should further enhance RFC3263 guidelines by taking into account RFC5630.SRV records of a DNS server should be clear of what they want to provide.</p>
<p>So if one would like to use the “best-effort TLS” approach this DNS SRV record should be included:</p>
<ul>
<li>_sip._tls.example.com.  43200 IN SRV 0 0 5060  <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
</ul>
<p>And if the client supports TLS, then TLS should be the chosen transport.</p>
<p>If the SIP server should follow the “TLS only” approach, then one of the following SRV records should be included (or both to support all possible queries) :</p>
<ul>
<li>_sips._tcp.example.com.  43200 IN SRV 0 0 5060 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
</ul>
<p><strong>OR</strong></p>
<ul>
<li>_sips._tls.example.com.  43200 IN SRV 0 0 5060 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
</ul>
<p>And the client will have to go with the TLS transport.</p>
<p>Of course, a server could provide both and so to give the ability to the client even if using SIP URI to go with a TLS transport if available.</p>
<h2 id="heading-3-how-the-dns-naptr-results-should-be-treated">3. How the DNS NAPTR results should be treated</h2>
<p>When it comes to the NAPTR lookup, RFC3263 proposed mechanism to resolve transport is sufficient and the guidelines for SIP and SIPS URIs are clear enough:</p>
<ul>
<li>If a SIPS URI is given, discard any service that do not contain “SIPS” as the protocol in the service field. That conforms with the RFC5630 that SIPS URI should be treated as “TLS only”</li>
<li>If a SIP URI is given, the client should retain records with “SIPS” as the protocol, if the client supports TLS. Again this conforms to the RFC5630 for “best-effort TLS” - Results should be processed according to the order of each record and the first one should be picked up to set the transport - If the result contain “SIPS” as a service protocol, the transport should be set to TLS</li>
<li>If the result contain “D2T” as a service protocol, the transport should be set to TCP</li>
<li>If the result contain “D2U” as a service protocol, the transport should be set UDP</li>
<li>The “SIPS” service should be the preferred if the client can support it.</li>
</ul>
<h2 id="heading-4-how-the-dns-srv-results-should-be-treated">4. How the DNS SRV results should be treated</h2>
<p>If the NAPTR lookup returns no results, a DNS SRV query should be done.</p>
<p>Here we need to clarify and change how the DNS results should be treated for a given request when transport is to be discovered, given the fact that the client supports TCP, UDP and TLS.</p>
<p>The statement from RFC5623 that the client should “use any transport protocol it desires which is supported by the server” is not enough to make a clear decision for the transport and further process of the result should be done using some rules.</p>
<p>For example, a SIP Registrar may provide the following SRV record for SIPS URI:</p>
<ul>
<li>_sips._tcp.example.com.  86400 IN SRV 0 0 5061 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
</ul>
<p>If the client is to pick the TCP transport as is, then this will fail because the TCP connector wont be able to establish a connection with the TLS connector on the other side. In this example, the client should treat _sips._tcp result as “TLS only” and choose TLS as transport.</p>
<p>Since the DNS SRV records defined for a SIP server may vary from one application to the other, the client should collect all the results of a DNS SRV lookup, and then apply the following rules:</p>
<ul>
<li>Lookup for a SIP URI- SRV Record Results: [ _sip._tls, _sip._tcp, _sip._udp]    =&gt; The _sip._tls should interpreted as “best-effort TLS” and the client should choose TLS as transport if available, otherwise ANY available transport</li>
<li>SRV Record Results: [_sip._tcp, _sip._udp] =&gt; Client should choose ANY of the two results as long as they are available</li>
<li>SRV Record Results: [_sip._tcp] =&gt; Client should choose TCP as transport</li>
<li>SRV Record Results: [_sip._udp] =&gt; Client should choose UDP as transport</li>
<li>Lookup for a SIPS URI- SRV Record Results: [_sips._tcp, any others] =&gt; Should be treated as “TLS only” approach and the client should set TLS as transport</li>
<li>SRV Record Results: [_sips._tls, any others]  =&gt; Should be treated as _sips._tcp, that is “TLS only” and the client should set TLS as transport</li>
</ul>
<p>Of course if an SRV lookup doesn’t returns any result, the regular approach should be followed, that is to pick the default transport for the given URI.</p>
<ul>
<li>TLS for SIPS URI</li>
<li>UDP for SIP URI OR</li>
<li>TCP for SIP URI if UDP is not available</li>
</ul>
<p>Should there be a preference between TCP and UDP?</p>
<h2 id="heading-5-dns-naptr-required-records">5. DNS NAPTR required records</h2>
<p>According to RFC3263 4.1, the minimum required NAPTR records a SIP proxy, redirect server, or registrar should have, if it comes to be resolved through a DNS lookup, are the following: </p>
<ul>
<li>example.com. IN NAPTR 50 50 “s” “SIPS+D2T” “” _sips._tcp.example.com.</li>
<li>example.com. IN NAPTR 90 50 “s” “SIP+D2T” “” _sip._tcp.example.com</li>
<li>example.com. IN NAPTR 100 50 “s” “SIP+D2U” “” sip._udp.example.com.</li>
</ul>
<p>From RFC3263:</p>
<ul>
<li>If a SIP proxy, redirect server, or registrar is to be contacted through the lookup of NAPTR records, there MUST be at least three records – one with a “SIP+D2T” service field, one with a “SIP+D2U” service field, and one with a “SIPS+D2T” service field. The records with SIPS as the protocol in the service field SHOULD be preferred (i.e., have a lower value of the order field) above records with SIP as the protocol in the service field. A record with a “SIPS+D2U” service field SHOULD NOT be placed into the DNS, since it is not possible to use TLS over UDP.</li>
</ul>
<p>Of course Domain, TTL, Priority, Preference, Port and FQDN of the the record should be set according to the application/needs. </p>
<h2 id="heading-6-dns-srv-required-records">6. DNS SRV required records</h2>
<p>Accordingly, the minimum DNS SRV records that should be defined are:</p>
<ul>
<li>_sip._udp.example.com.   86400 IN SRV 0 0 5060 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
<li>_sip._tcp.example.com.   86400 IN SRV 0 0 5060 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
<li>_sips._tcp.example.com.  86400 IN SRV 0 0 5061 <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.</li>
</ul>
<p>So in the above example for SIP URIs and UDP or TCP transport, the request will be routed using port 5060 to the <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>. For secure SIPS URIs, the 5061 port should be used and the same server.</p>
<p>Of course Domain, TTL, Priority, Weight, Port and FQDN of the the record should be set according to the application/needs.</p>
<h2 id="heading-7-dns-a-records">7. DNS A Records</h2>
<p>Finally the DNS zone configuration should contain an A record for the domain:</p>
<ul>
<li><a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a>.  86400 IN A       10.0.0.21</li>
</ul>
<p>That will be used to resolve the FQDN of servers to an IP Address.</p>
<h2 id="heading-8-a-complete-dns-zone-configuration-file">8. A complete DNS Zone configuration file</h2>
<p>Here is an example of a complete DNS Zone configuration for the <a target="_blank" href="http://example.com">example.com</a> domain.</p>
<blockquote>
<p>$TTL 1800</p>
<p>@       IN     SOA    ns1.example.com. root.example.com. (</p>
<pre><code>                   <span class="hljs-number">2012030101</span> ; serial#

                   <span class="hljs-number">1800</span>            ; refresh, seconds

                   <span class="hljs-number">1800</span>            ; retry, seconds

                   <span class="hljs-number">1800</span>            ; expire, seconds

                   <span class="hljs-number">1800</span> )          ; minimum TTL, seconds
</code></pre><p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; DNS Servers for ‘example.com’</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; NS record for example.com</p>
<p>;    server: sipserver1.example.com</p>
<p>;</p>
<p>example.com.            IN     NS     sipserver1.example.com.</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; Call Routing for SIP domain ‘example.com’</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; NAPTR record for SIPS TCP example.com</p>
<p>;     priority: 2  weight: 0</p>
<p>;     protocol: “SIPS+D2T”  regex: “”  uri: _sips._tcp.example.com</p>
<p>;</p>
<p>example.com.           IN      NAPTR   2 0 “s” “SIPS+D2T” “” _sips._tcp.example.com.</p>
<p>; NAPTR record for SIP TCP example.com</p>
<p>;     priority: 2  weight: 0</p>
<p>;     protocol: “SIP+D2T”  regex: “”  uri: _sip._tcp.example.com</p>
<p>;</p>
<p>example.com.           IN      NAPTR   2 0 “s” “SIP+D2T” “” _sip._tcp.example.com.</p>
<p>; NAPTR record for SIP UDP example.com</p>
<p>;     priority: 2  weight: 0</p>
<p>;     protocol: “SIP+D2U”  regex: “”  uri: _sip._udp.example.com</p>
<p>;</p>
<p>example.com.           IN      NAPTR   2 0 “s” “SIP+D2U” “” _sip._udp.example.com.</p>
<p>; SRV record for domain SIP TCP example.com</p>
<p>;     priority: 1  weight: 0  port: 5060  server: sipserver1.example.com</p>
<p>;</p>
<p>_sip._tcp.example.com. IN      SRV     1 0 5060 sipserver1.example.com.</p>
<p>; SRV record for domain SIP UDP example.com</p>
<p>;     priority: 1  weight: 0  port: 5060  server: sipserver1.example.com</p>
<p>;</p>
<p>_sip._udp.example.com. IN      SRV     1 0 5060 sipserver1.example.com.</p>
<p>; SRV record for domain SIP TLS example.com</p>
<p>;     priority: 1  weight: 0  port: 5061  server: sipserver1.example.com</p>
<p>;</p>
<p>_sip._tls.example.com. IN      SRV     1 0 5061 sipserver1.example.com.</p>
<p>; SRV record for domain SIPS TCP example.com</p>
<p>;     priority: 1  weight: 0  port: 5061  server: sipserver1.example.com</p>
<p>;</p>
<p>_sips._tcp.example.com. IN      SRV     1 0 5061 sipserver1.example.com.</p>
<p>; SRV record for domain SIPS TLS example.com</p>
<p>;     priority: 1  weight: 0  port: 5061  server: sipserver1.example.com</p>
<p>;</p>
<p>_sips._tls.example.com. IN      SRV     1 0 5061 sipserver1.example.com.</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; IP Addresses</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>; A record for sipserver1.example.com</p>
<p>;</p>
<p>sipserver1.example.com.       IN      A       192.168.1.207</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
</blockquote>
<h2 id="heading-9-how-to-test-dns-configurations">9. How to test DNS configurations</h2>
<p>In order to test A records, a simple <strong>ping</strong> would be enough. If the command <strong>ping <a target="_blank" href="http://sipserver1.example.com">sipserver1.example.com</a></strong> would result some replies, then A record configuration is okTo test SRV records, for Linux use <strong>dig</strong> command and for Windows use <strong>nslookup</strong>.</p>
<ul>
<li>Linux example: <strong>dig _sips._tcp.example.com SRV</strong> should result the IP Address and port of the server for SIPS TLS</li>
<li>Windows example: use <strong>nslookup</strong>, then <strong>set querytype=SRV</strong> and then type the SRV record you wish, for example <strong>_sips._tcp.example.com</strong>. Should result the IP Address and port for SIPS TLS</li>
</ul>
<p>Also, in order to check NAPTR records again use Linux <strong>dig</strong>.</p>
<p>For Windows i am not aware of a program that could be used to check NAPTR records, as nslookup doesn’t support this type of records (tested on Windows XP and Windows 7)</p>
<p>Linux example: <code>dig example.com NAPTR</code> will result with the available NAPTR records on the DNS server</p>
<h2 id="heading-10-links-resources">10. Links / Resources</h2>
<ul>
<li>RFC3263 <a target="_blank" href="http://www.ietf.org/rfc/rfc3263.txt">http://www.ietf.org/rfc/rfc3263.txt</a></li>
<li>RFC5630 <a target="_blank" href="http://tools.ietf.org/html/rfc5630">http://tools.ietf.org/html/rfc5630</a></li>
<li>SIP.EDU – DNS Configuration <a target="_blank" href="http://mit.edu/sip/sip.edu/dns.shtml">http://mit.edu/sip/sip.edu/dns.shtml</a></li>
<li>Locating SIP Servers Blog by Binod – <a target="_blank" href="http://weblogs.java.net/blog/binod/archive/2008/02/using_dns_serve.html#comment-822520">http://weblogs.java.net/blog/binod/archive/2008/02/using_dns_serve.html#comment-822520</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[JTapi hands-on, part II]]></title><description><![CDATA[This is the next article in the JTapi hands-on series that will present the Call and Connection interfaces from the Jtapi API. Using the Call and Connection interface, this article shows how to create and disconnect calls, and also inspect Connection...]]></description><link>https://devrealm.org/jtapi-hands-on-part-ii</link><guid isPermaLink="true">https://devrealm.org/jtapi-hands-on-part-ii</guid><category><![CDATA[Java]]></category><category><![CDATA[jtapi]]></category><category><![CDATA[CTI ]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Fri, 22 May 2009 09:56:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1850a36962fbabe4b2ef2f216f380fda.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is the next article in the JTapi hands-on series that will present the Call and Connection interfaces from the Jtapi API. Using the Call and Connection interface, this article shows how to create and disconnect calls, and also inspect Connections of a call. This tutorial could be the base for a dialler application or a connector for a PBX with a CRM application.</p>
<p>Also please note that this article builds upon the previous articles <a target="_blank" href="https://blog.devrealm.org/2009/03/26/jtapi-overview/">JTapi Overview</a> and <a target="_blank" href="https://blog.devrealm.org/2009/04/05/jtapi-hands-on-part-i/">JTapi hands-on, part I</a>.</p>
<h2 id="heading-prerequisites-for-the-source-code">Prerequisites for the source code</h2>
<p>In the <a target="_blank" href="https://devrealm.org/jtapi-hands-on-part-ii/#Resources">Resources</a> section of this articles you can find the source code for the examples. In order to compile and run the source code you need the JTapi library in your classpath and of course a PBX equipped with the appropriate JTAPI software services. For any help please leave a comment.</p>
<h2 id="heading-use-case">Use case</h2>
<p>For the concepts and theories to be more easy to grasp, I will start by providing a specific use case to work with.</p>
<ul>
<li>Given that we have a PBX with JTapi services in place, we need to develop an application that will provide users with a list of telephone numbers to dial automatically using their PC; that is no manual dialling using their telephone set.</li>
</ul>
<p>For this we need to develop a library which will be the connector between the application and the JTapi enabled PBX. The purpose of this library will be to create calls on behalf of the users and deliver the calls to their telephone set. So for the rest of the article I will provide the necessary theory and examples with source code to develop such a library.</p>
<p>First will have some theory in order to get the basics of Call and Connection interface, since these two interfaces are the fundamentals in the application we want to develop.</p>
<h2 id="heading-the-call-interface">The Call interface</h2>
<p>The Call object represents a telephone call, the information flowing between the service provider and the call participants. A telephone call comprises a Call object and zero or more connections. In a two-party call scenario, a telephone call has one Call object and two connections. A conference call is three or more connections associated with one Call object.</p>
<p>In order to create a Call, an idle call object is instantiated using <em>Provider.createCall()</em>. Having the idle call object in place, the application must specify the originating Terminal (physical endpoint) and the originating Address (logical endpoint) of that Terminal (in the case that a Terminal has multiple telephone numbers on it). Next the application should provide the destination telephone number as a string. Two Connection objects are returned from the <em>Call.connect()</em> method, representing the originating and destination ends of the telephone call.</p>
<h3 id="heading-call-states">Call States</h3>
<p>A Call, like other Jtapi objects, has a state which is obtained via the <em>Call.getState()</em> method. This state describes the current progress of a telephone call, where is it in its life cycle, and how many Connections exist on the Call. The Call state may be one of three values: <strong>Call.IDLE</strong>, <strong>Call.ACTIVE</strong>, or <strong>Call.INVALID</strong>. Here is a description of each state:</p>
<ul>
<li><strong>Call.IDLE</strong>: This is the initial state for all Calls. In this state, the Call has zero Connections, that is <em>Call.getConnections()</em> must return null.</li>
<li><strong>Call.ACTIVE</strong>: A Call with some current ongoing activity is in this state. Calls with one or more associated Connections must be in this state. If a Call is in this state, the <em>Call.getConnections()</em> method must return an array of size at least one.</li>
<li><strong>Call.INVALID</strong>: This is the final state for all Calls. Call objects which lose all of their Connections objects (via a transition of the Connection object into the Connection.DISCONNECTED state) moves into this state. Calls in this state have zero Connections and these Call objects may not be used for any future action. In this state, the <em>Call.getConnections()</em> must return null.</li>
</ul>
<p><strong>Note</strong>: The Connection states mentioned above will be discussed <a target="_blank" href="https://devrealm.org/jtapi-hands-on-part-ii/#ConnectionStates">later</a> in this article.</p>
<h3 id="heading-call-state-transitions">Call State Transitions</h3>
<p>The possible Call state transitions are given in the diagram below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258128666/fB8IpFfwM.jpeg" alt="Call state transitions" /></p>
<h3 id="heading-calls-and-connections">Calls and Connections</h3>
<p>A Call object maintain a list of the Connections on that Call. Applications obtain an array of Connections associated with the Call via the <code>_Call.getConnections()_</code> method. A Call object retains a reference to a Connection only if it is not in the Connection.DISCONNECTED state. Therefore, if a Call object has a reference to a Connection, then that Connection must not be in the Connection.DISCONNECTED state. When a Connection moves into the Connection.DISCONNECTED state (e.g. when a party hangs up), the Call loses its reference to that Connection which is no longer reported via the <code>_Call.getConnections()_</code> method.</p>
<h2 id="heading-connection-interface">Connection interface</h2>
<p>A Connection represents a link (i.e. an association) between a Call object and an Address object.</p>
<p>The purpose of a Connection object is to describe the relationship between a Call object and an Address object. A Connection object exists if the Address is a part of the telephone call. Applications use the <code>_Connection.getCall()_</code> and <code>_Connection.getAddress()_</code> methods to obtain the Call and Address associated with this Connection, respectively.</p>
<h3 id="heading-connection-states">Connection States</h3>
<p>A connection can be in one of the states mentioned below and here is a description of each Connection state in real-world terms. These real-world descriptions have no bearing on the specifications of methods, they only serve to provide a more intuitive understanding of what is going on. Several methods in this specification state pre-conditions based upon the state of the Connection (for example see Connection.disconnect() method below)</p>
<ul>
<li><strong>Connection.IDLE</strong>: This state is the initial state for all new Connections. Connections which are in the Connection.IDLE state are not actively part of a telephone call, yet their references to the Call and Address objects are valid. Connections typically do not stay in the Connection.IDLE state for long, quickly transitioning to other states.</li>
<li><strong>Connection.DISCONNECTED</strong>: This state implies it is no longer part of the telephone call, although its references to Call and Address still remain valid. A Connection in this state is interpreted as once previously belonging to this telephone call.</li>
<li><strong>Connection.INPROGRESS</strong>: This state implies that the Connection, which represents the destination end of a telephone call, is in the process of contacting the destination side. Under certain circumstances, the Connection may not progress beyond this state.</li>
<li><strong>Connection.ALERTING</strong>: This state implies that the Address is being notified of an incoming call.</li>
<li><strong>Connection.CONNECTED</strong>: This state implies that a Connection and its Address is actively part of a telephone call. In common terms, two people talking to one another this call is represented by two Connections in the Connection.CONNECTED state.</li>
<li><strong>Connection.UNKNOWN</strong>: This state implies that the implementation is unable to determine the current state of the Connection. Typically, methods are invalid on Connections which are in this state. Connections may move in and out of the Connection.UNKNOWN state at any time.</li>
<li><strong>Connection.FAILED</strong>: This state indicates that a Connection to that end of the call has failed for some reason. One reason why a Connection would be in the Connection.FAILED state is because the party was busy.</li>
</ul>
<h3 id="heading-connection-state-transition">Connection State Transition</h3>
<p>With these loose, real-world meanings in the back of one’s mind, the Connection class defines a finite-state diagram which describes the allowable Connection state transitions. This finite-state diagram must be guaranteed by the implementation. Each method which causes a change in a Connection state must be consistent with this state diagram. This finite state diagram is below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258130008/iwsDosZiR.jpeg" alt="Connection State Transition" /></p>
<p>Note there is a general left-to-right progression of the state transitions. A Connection object may transition into and out of the Connection.UNKNOWN state at any time (hence, the asterisk qualifier next to its bidirectional transition arrow).</p>
<h3 id="heading-connectiondisconnect-method">Connection.disconnect() method</h3>
<p>In terms of controlling a call, an important method of the Connection interface is the <strong>Connection.disconnect()</strong> method. This method drops an entire Connection from a telephone call. The result of this method is to move the Connection object into the Connection.DISCONNECTED state.<br />This method drops a Connection from an active telephone call and the Connection’s Address is no longer associated with the telephone call. Important to notice is that this method does not necessarily drop the entire telephone call, only the particular Connection on the telephone call. The method provides the ability to disconnect a specific party from a telephone call, which is especially useful in telephone calls consisting of three or more parties. For example on a three party conference call, if one of the parties invoke the <code>_Connection.disconnect()_</code> method, then this party leaves the conference call, but the two parties left continue the call. Invoking this method may result in the entire telephone call being dropped though, which is a permitted outcome for this method. In that case, the appropriate events are delivered to the application, indicating that more than just a single Connection has been dropped from the telephone call.</p>
<p>This method returns successfully only after the Connection has been disconnected from the telephone call and has transitioned into the Connection.DISCONNECTED. Note that this method waits (i.e. the invocating thread blocks) until either the Connection is actually disconnected from the telephone call or an error is detected and an exception thrown.</p>
<p>Additional Connections may be dropped indirectly as a result of this method. For example, dropping the destination Connection of a two-party Call may result in the entire telephone call being dropped. It is up to the implementation to determine which Connections are dropped as a result of this method. Implementations should not, however, drop additional Connections if it does not reflect the natural response of the underlying telephone hardware.</p>
<p>Dropping additional Connections implies that their TerminalConnections are dropped as well. Also, if all of the Connections on a telephone call are dropped as a result of this method, the Call will move into the Call.INVALID state.</p>
<p>Be aware that the Connection object must be in one of several states in order for this method to be successfully invoked. These allowable states are: Connection.CONNECTED, Connection.ALERTING, Connection.INPROGRESS, or Connection.FAILED. If the Connection is not in one of these allowable states when this method is invoked, this method throws InvalidStateException. Having the Connection in one of the allowable states does not guarantee a successful invocation of this method.</p>
<p>Next will be discussed the structure of the project will be used for the library we need to implement the application in question.</p>
<h2 id="heading-project-structure">Project Structure</h2>
<p>The project has a bootstrap class, the ProviderService class, that provides the Jtapi Provider for the rest of the classes to use. This is convenient to have since several other classes can access the Provider (to retrieve resources, create calls etc.) without the need for each class to instantiate its own Provider object.<br />Next is the JTapiMakeCall class that is responsible to create and handle calls and side by side the CallTools class that provides useful information on the console about the progress of a call.</p>
<p>Even though this is a simple application, later can be used as a tool to create calls.</p>
<h2 id="heading-bootstrap">Bootstrap</h2>
<p>As usual, the kick off of any JTapi project is the instantiation of JtapiPeer and Provider, and here is exactly that. So below is the <strong>ProviderService</strong> class that will make available the Provider to the rest of the project.</p>
<p>import javax.telephony.JtapiPeer;<br />import javax.telephony.JtapiPeerFactory;<br />import javax.telephony.JtapiPeerUnavailableException;<br />import javax.telephony.Provider;  </p>
<p>public class ProviderService {<br />    private static ProviderService instance;<br />    private static Provider provider;  </p>
<pre><code>private ProviderService () {  
    bootStrap();  
}  

public <span class="hljs-keyword">static</span> Provider getProvider () {  
    <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">null</span>) {  
        instance = <span class="hljs-keyword">new</span> ProviderService();  
    }  
    <span class="hljs-keyword">return</span> provider;  
}  

private <span class="hljs-keyword">void</span> bootStrap () {  
    <span class="hljs-keyword">try</span> {  
        JtapiPeer peer = JtapiPeerFactory.getJtapiPeer(<span class="hljs-string">""</span>);  
        <span class="hljs-built_in">String</span>\[\] myServices = peer.getServices();  
        <span class="hljs-built_in">String</span> providerString = myServices\[<span class="hljs-number">0</span>\] + <span class="hljs-string">";login=user;passwd=passwd"</span>;  
        provider = peer.getProvider(providerString);  
    } <span class="hljs-keyword">catch</span> (JtapiPeerUnavailableException e) {  
        e.printStackTrace();  
    }  
}  
</code></pre><p>}</p>
<p>Having the Provider available for the rest of the project, we are ready to move on the rest of the classes.</p>
<h2 id="heading-jtapimakecall-class">JTapiMakeCall Class</h2>
<p>The <strong>JTapiMakeCall</strong> class consists of 4 methods.</p>
<ul>
<li><strong>Call dial(String origAddrStr, String dialoutNumber)</strong>: Accepts two strings, the original address and the dialout number to be called. The method will create the call object and will connect the original address with the number requested. <strong>Note</strong>: Be aware that the original address must be in the Provider’s domain but the same is not true for the dialout number. That is, the original address must be an extension of the PBX that is handled by the Provider while the dialout number could be any external number or an extension of the PBX also.</li>
<li><strong>void disconnect(Call call)</strong>: If you noticed before, the <strong>dial</strong> method returns a Call object so any other method can work on this object. So the <strong>disconnect</strong> method accepts a Call object and terminates all the connections of call, if they are eligible for disconnect. As said earlier, a connection should be in one of the allowed states in order to be disconnected.</li>
<li><strong>Provider getProvider()</strong>: Will retrieve the Provider from the ProviderService class and make it available to the rest of the class.</li>
<li><strong>void shutdownProvider()</strong>: Will shut down the Provider when needed</li>
</ul>
<p>Following is the source code of the JTapiMakeCall class:</p>
<p>package org.devrealm.jtapitutorial2.jtapimakecall;  </p>
<p>import javax.telephony.Address;<br />import javax.telephony.Call;<br />import javax.telephony.Connection;<br />import javax.telephony.InvalidArgumentException;<br />import javax.telephony.InvalidPartyException;<br />import javax.telephony.InvalidStateException;<br />import javax.telephony.MethodNotSupportedException;<br />import javax.telephony.PrivilegeViolationException;<br />import javax.telephony.Provider;<br />import javax.telephony.ResourceUnavailableException;<br />import javax.telephony.Terminal;  </p>
<p>import org.devrealm.jtapitutorial2.bootstrap.ProviderService;  </p>
<p>public class JTapiMakeCall {<br />    private static Provider provider;  </p>
<pre><code>public <span class="hljs-keyword">static</span> Call dial (<span class="hljs-built_in">String</span> origAddrStr, <span class="hljs-built_in">String</span> dialoutNumber) {  
    Provider provider = JTapiMakeCall.getProvider();  
    Call call = <span class="hljs-literal">null</span>;  
    <span class="hljs-keyword">try</span> {  
        Address myAddr = provider.getAddress(origAddrStr);  
        Terminal myTerm = myAddr.getTerminals()\[<span class="hljs-number">0</span>\];  
        System.out.println(<span class="hljs-string">"Calling from: "</span> + origAddrStr + <span class="hljs-string">" to: "</span> + dialoutNumber);  
        call = provider.createCall();  
        call.connect(myTerm, myAddr, dialoutNumber);  
    } <span class="hljs-keyword">catch</span> (InvalidArgumentException e) {  
        e.printStackTrace();  
    } <span class="hljs-keyword">catch</span> (ResourceUnavailableException e) {  
        e.printStackTrace();  
    } <span class="hljs-keyword">catch</span> (InvalidStateException e) {  
        e.printStackTrace();  
    } <span class="hljs-keyword">catch</span> (PrivilegeViolationException e) {  
        e.printStackTrace();  
    } <span class="hljs-keyword">catch</span> (MethodNotSupportedException e) {  
        e.printStackTrace();  
    } <span class="hljs-keyword">catch</span> (InvalidPartyException e) {  
        e.printStackTrace();  
    }  
    <span class="hljs-keyword">return</span> call;  
}  

public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> disconnect (Call call) {  
    Connection\[\] connections = call.getConnections();  
    <span class="hljs-keyword">for</span> (Connection connection : connections) {  
        <span class="hljs-comment">//disconnect here  </span>
    }  
}  
</code></pre><p>}</p>
<h2 id="heading-calltools-class">CallTools class</h2>
<p>This class provides some methods to get useful information about a call.</p>
<p>The methods it provides are the following:</p>
<ul>
<li><strong>void inspect(Call call)</strong>: Using this method we can retrieve information about the connectios, addresses, call state etc. of a call object</li>
<li><strong>String connStateToString(int code)</strong>: This method converts the integer code of a connection state to a string</li>
</ul>
<p>Following is the source code of the CallTools class:</p>
<p>package org.devrealm.jtapitutorial2.dialout;  </p>
<p>import javax.telephony.Call;  </p>
<p>import org.devrealm.jtapitutorial2.jtapicalltools.CallTools;<br />import org.devrealm.jtapitutorial2.jtapimakecall.JTapiMakeCall;  </p>
<p>public class Dialout {<br />    public static void main (String[] args) {<br />        String origAddrStr = "1234";<br />        String dialoutNumber = "00123456789";<br />        // Optionally you can accept the original address and dialout number from the command prompt<br />        // String origAddrStr = args[0];<br />        //  String dialoutNumber = args[1];<br />        Call call = JTapiMakeCall.dial(origAddrStr, dialoutNumber);<br />        CallTools.inspect(call);<br />        try {<br />            Thread.sleep(10000);<br />        } catch (InterruptedException e) {<br />            e.printStackTrace();<br />        }<br />        System.out.println("Disconnect Call");<br />        JTapiMakeCall.disconnect(call);<br />        System.out.println("...............");<br />        CallTools.inspect(call);<br />        JTapiMakeCall.shutdownProvider();<br />    }<br />}</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Call and Connection interface are straight forward and easy to work with and the documentation provided is well written. Using these two interfaces we can easily integrate an application with a PBX and give a production boost to a call centre. Going back to the use case defined at the begining of the article, the connector for the auto-dial functionality and integration with the PBX is ready to use. Of course that kind of application needs a lot more to be complete but this library is one of the most, if not the most, important part of the application. What is left to see is how we can answer, transfer, conference and observe calls so we can give a call centre with full set of automatic tools to handle both incoming and outgoing calls. Specially the observers that the JTapi API provides are useful to implement applications that observe addresses, terminals or calls for incoming traffic and captures details of the caller that can be used to popup the agent's desktop with the caller details. Finally please share any comment or idea derived from this article since that's the driving power of thought and any effort made here.</p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li>JTapi Overview(<a target="_blank" href="https://blog.devrealm.org/2009/03/26/jtapi-overview/">https://blog.devrealm.org/2009/03/26/jtapi-overview/</a>)</li>
<li>JTapi hands-on, part I(https://blog.devrealm.org/2009/04/05/jtapi-hands-on-part-i/)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[JTapi hands-on, part I]]></title><description><![CDATA[The story so far
In the first article there was an introduction to the basic interfaces of JTAPI, that is JtapiPeer, Provider, Address, Terminal, Call and Connection. These are the basis on which we will built upon and continue in this article.
Start...]]></description><link>https://devrealm.org/jtapi-hands-on-part-i</link><guid isPermaLink="true">https://devrealm.org/jtapi-hands-on-part-i</guid><category><![CDATA[Java]]></category><category><![CDATA[jtapi]]></category><category><![CDATA[CTI ]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Sun, 05 Apr 2009 09:05:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1850a36962fbabe4b2ef2f216f380fda.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-the-story-so-far">The story so far</h3>
<p>In the first article there was an introduction to the basic interfaces of JTAPI, that is JtapiPeer, Provider, Address, Terminal, Call and Connection. These are the basis on which we will built upon and continue in this article.</p>
<p>Starting from this article, I will leave the plain theory behind, and I will delve into the Jtapi objects using code examples. Off course, each code snippet, will be supported by the appropriate theory in order to elaborate and deeply analyze each object.</p>
<p>This iteration will concentrate on the JTapiPeer and Provider interfaces, and will present the way can be used to further inside an application using two example classes. The first one <em>ProviderService</em> mainly shows how to use JtapiPeer in order to instantiate and supply the Provider object for the second class <em>JTapiDiscovery</em> which purpose is just to discover the Addresses and Terminals from the Provider’s domain.</p>
<h3 id="heading-prerequisites-for-the-source-code">Prerequisites for the source code</h3>
<p>In the <a target="_blank" href="https://devrealm.org/jtapi-hands-on-part-i/#Resources">Resources</a> section of this articles you can find the source code from the examples. In order to compile and run the source code you need the JTapi library in your classpath and of course a PBX equipped with the appropriate JTAPI software services. Most of the PBX vendors provides for free the JTapi library implementation for their platform. For any help please leave a comment.</p>
<h3 id="heading-providerservice-a-useful-helper-class-for-the-rest-of-the-tutorials">ProviderService: A useful helper class for the rest of the tutorial(s)</h3>
<p>Given that the instantiation of a Provider, is the first step for any application, i decided to create a helper class <em>ProviderService</em> that will be used for the rest of the tutorial in order to retrieve the Provider from the JTapiPeer.</p>
<p>The <em>ProviderService</em> class follows:</p>
<p>package org.devrealm.jtapitutorial.bootstrap;</p>
<p>import javax.telephony.JtapiPeer;<br />import javax.telephony.JtapiPeerFactory;<br />import javax.telephony.JtapiPeerUnavailableException;<br />import javax.telephony.Provider;</p>
<p>public class ProviderService {<br />private static ProviderService instance;<br />private static Provider provider;</p>
<p>private ProviderService () {<br />bootStrap();<br />}</p>
<p>public static Provider getProvider () {<br />if (instance == null) {<br />instance = new ProviderService();<br />}<br />return provider;<br />}</p>
<p>private void bootStrap () {<br />try {<br />JtapiPeer peer = JtapiPeerFactory.getJtapiPeer("");<br />String[] myServices = peer.getServices();<br />String providerString = myServices[0] + ";login=user;passwd=passwd";<br />provider = peer.getProvider(providerString);<br />} catch (JtapiPeerUnavailableException e) {<br />e.printStackTrace();<br />}<br />}<br />}</p>
<p>The <em>ProviderService</em> is a helper class that implements the Singleton pattern(see <a target="_blank" href="https://devrealm.org/jtapi-hands-on-part-i/#Resources">Resources</a> for more). The class supply a public static method getProvider that returns a Provider object to any other class request it.</p>
<p>Besides the usual singleton stuff, this class presents the method <code>_bootStrap()_</code>. Using this method, the class creates the Provider object and make it available.</p>
<p>Recall from the previous article, the JTapiPeer interface represents a vendor’s particular implementation of the Java Telephony API. So the first thing this class is doing is to retrieve an instance of the the JTapiPeer using the static method of the JtapiPeerFactory, <code>JtapiPeerFactory.getJtapiPeer("")</code> as you can see at line 19. Having a JTapiPeer instance in place, the bootStrap method, fetches all the available services this peer can provide.</p>
<ul>
<li><em>Depending on the vendor’s implementation of this interface, more than one service can be obtained if for example the telephony software-entity is connected to more than one telephony subsystems (e.g. a JTapi service/server connected to two PBX will result in two services).</em></li>
</ul>
<p>The next step is to create the providerString, which will include the service in question, the username and password for the JTapi service user. Having the providerString in hand, we go on and request the Provider from the JTapiPeer with the method <code>peer.getProvider(provideString)</code>.</p>
<p>Important things to remember from this class:</p>
<ul>
<li><p>Using the <code>_JtapiPeerFactory.getJtapiPeer("");_</code> we retrieve the vendor’s implementation of the Java Telephony API.</p>
</li>
<li><p>Having in hand the JtapiPeer, we construct the <em>providerString</em> which consists of the Jtapi service (most of the times will be only one), the user name and password for this service.</p>
</li>
<li><p>From the JtapiPeer object we retrieve the Provider object using <code>_Provider provider = peer.getProvider(providerString);_</code></p>
</li>
</ul>
<p>Bare in mind that the above three simple steps are the foundation in order to initialize all the Java Telephony applications.</p>
<p>Next we move on the JTapiDiscovery class where the Provider is getting into action.</p>
<h3 id="heading-jtapidiscovery-provider-in-action">JTapiDiscovery: Provider in action</h3>
<p>One of the things any JTapi application is supposed to do is first retrieve all available addresses and terminals (or otherwise all the requested addresses and terminals) and maybe place them in a storage area in order to be used later from the rest of the application’s logic. This is exactly what the next class, <em>JTapiDiscovery</em> is doing.</p>
<p>The <em>JTapiDiscovery</em> class follows:</p>
<p>package org.devrealm.jtapitutorial.discovery;</p>
<p>import javax.telephony.Address;<br />import javax.telephony.Provider;<br />import javax.telephony.ResourceUnavailableException;<br />import javax.telephony.Terminal;</p>
<p>import org.devrealm.jtapitutorial.bootstrap.ProviderService;</p>
<p>public class JTapiDiscovery {<br />public static void main (String[] args) {<br />Provider provider = ProviderService.getProvider();<br />//Print all the available addresses of the system.<br />try {<br />Address[] addresses = provider.getAddresses();<br />System.out.println("Avaialable Addresses : ");<br />for (int i = 0; i &lt; addresses.length; i++) {<br />System.out.println("Address : " + addresses[i].getName());<br />}<br />} catch (ResourceUnavailableException e) {<br />e.printStackTrace();<br />}<br />//Print all the available terminals of the system.<br />try {<br />Terminal[] terminals = provider.getTerminals();<br />System.out.println("Avaialable Terminals : ");<br />for (int i = 0; i &lt; terminals.length; i++) {<br />System.out.println("Terminal : " + terminals[i].getName());<br />}<br />} catch (ResourceUnavailableException e) {<br />e.printStackTrace();<br />}<br />//Always remember to shutdown the provider,<br />//otherwise the application won't return.<br />provider.shutdown();<br />}<br />}</p>
<p>So the <em>JTapiDiscovery</em> class, utilizing the previous <em>ProviderService</em> class, first retrieves the Provider object and start working with this.</p>
<p>If you take a look at the Javadoc of the Jtapi, the Provider interface supply a bunch of useful methods to retrieve the Addresses, Terminals, Capabilities etc, from the Provider’s domain. Thus, an array of Addresses is being retrieved and printed out. Similarly, an array of Terminals is being retrieved and printed out.</p>
<p>Notice, that its not the actual object that is printed out, but the name of the Address or the Terminal in question each time. As we will see in a future articles, an Address or Terminal interface among other methods, provides a getName() method in order to retrieve the unique name of the object. The getName() method is the main way to interact with the end users, since an Address object is known to the user only by its name, for example the extension number of his telephone set.</p>
<p>Also notice that the Provider’s methods <code>_provider.getAddresses()_</code> and <code>_provider.getTerminals()_</code> throw an exception of type <strong><em>ResourceUnavailableException</em></strong> that must handled when for example someone request an Address or Terminal that doesn’t exist or is not provided by this Jtapi service.</p>
<p>Finally, there is a call to the Provider’s method <code>_provider.shutdown()_</code>. This method, request the Provider to move the the state <em>Provider.SHUTDOWN</em> and the application to return. Provider’s states and state-transitions is the next issue to discuss.</p>
<h3 id="heading-provider-states">Provider states</h3>
<p>The Provider object can be in any of the following three states:</p>
<ul>
<li><p>Provider.IN_SERVICE: This state indicates that the Provider is currently alive and available for use.</p>
</li>
<li><p>Provider.OUT_OF_SERVICE: This state indicates that a Provider is temporarily not available for use. Many methods in the Java Telephony API are invalid when the Provider is in this state. Providers may come back in service at any time, however, <strong>the application can take no direct action to cause this change</strong>.</p>
</li>
<li><p>Provider.SHUTDOWN: This state indicates that a Provider is permanently no longer available for use. Most methods in the Java Telephony API are invalid when the Provider is in this state. Applications may use the Provider.shutdown() method on this interface to cause a Provider to move into the Provider.SHUTDOWN state.</p>
</li>
</ul>
<p>When first the Provider is instantiated using the <code>_JtapiPeer.getProvider(providerString)_</code> method, the Provider object returned is in the state IN_SERVICE and can be used straight away.</p>
<p>When an application calls <code>_provider.shutdown()_</code>, Provider is moving to the SHUTDOWN state, JTAPI loses communications permanently with the telephony subsystem and the application can assume that the Provider will not come up again, so the application must handle a complete shutdown. Applications invoke the <code>Provider.shutdown()</code> method when they no longer intend to use the Provider, usually, right before they exit. This method is intended to allow the Provider to perform any necessary cleanup that would not be handled when the Java objects are garbage collected. The<br /><code>Provider.shutdown()</code> method causes the Provider to move into the Provider.SHUTDOWN state where it will stay indefinitely. If the Provider is already in the Provider.SHUTDOWN state, this method does nothing.</p>
<p>Useful also for a developer, might be the Provider’s method, <code>_provider.getState()_</code>. This method will return a constant integer value that denotes the state of the provider as follows:</p>
<ul>
<li><p>Provider.IN_SERVICE: <strong>Constant Value 16</strong></p>
</li>
<li><p>Provider.OUT_OF_SERVICE: <strong>Constant Value 17</strong></p>
</li>
<li><p>Provider.SHUTDOWN: <strong>Constant Value 18</strong></p>
</li>
</ul>
<p>The figure below shows the allowable state transitions for the Provider object.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258135398/670W_nwWK.jpeg" alt="Provider states transition" /></p>
<p>Provider states transition</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Any kind of Java Telephony application you plan to implement will use the Provider object as the initial object to start interacting with the telephony subsystem. The Provider interface supplies additional methods that haven’t discussed over here but future articles that will describe the rest of the futures of JTapi, will present the full potential of Provider interface.</p>
]]></content:encoded></item><item><title><![CDATA[JTapi Overview]]></title><description><![CDATA[The Java Telephony API (JTAPI) is a portable, object-oriented application programming interface for Java-based computer-telephony applications.
This article is an introduction to the Java Telephony API, presenting the most important elements of this ...]]></description><link>https://devrealm.org/jtapi-overview</link><guid isPermaLink="true">https://devrealm.org/jtapi-overview</guid><category><![CDATA[jtapi]]></category><category><![CDATA[Java]]></category><category><![CDATA[CTI ]]></category><dc:creator><![CDATA[George]]></dc:creator><pubDate>Thu, 26 Mar 2009 09:48:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1850a36962fbabe4b2ef2f216f380fda.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Java Telephony API (<strong>JTAPI</strong>) is a portable, object-oriented application programming interface for Java-based computer-telephony applications.</p>
<p>This article is an introduction to the Java Telephony API, presenting the most important elements of this and attempts to clarify some basic issues that will be the base for the following articles.</p>
<p>JTapi can be used to integrate CRM or other applications with a telephone system, create applications that handle incoming calls, create application that place outgoing call on behalf of a user, or in general provide an automated way for a user to handle his telephone set.</p>
<p>The purpose of JTAPI is to serve as an interface between a Java application and a telephone system. The point where this interface is located determines the degree of control an application has. In a first-party call control scenario the interface is located at a terminal. The application has the same degree of control a normal telephone user has. In a third-party call control scenario the interface is located inside the telephone system. Depending on the telephone system this internal access provides the application usually with more control capabilities than a first-party call control scenario.</p>
<p><a target="_blank" href="https://devrealm.org/media/posts/2/gallery/gvag_first_party_call_control.jpg"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258141425/fN79Bc9jU.jpeg" alt /></a></p>
<p>First-party call control</p>
<p><a target="_blank" href="https://devrealm.org/media/posts/2/gallery/gvag_third_party_control_bu9uhv.jpg"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672258142698/lrhOSkZTW.jpeg" alt /></a></p>
<p>Third-party call control</p>
<p><strong>Figure 1: First-party and third-party call control in a Private Telephone Network with a PBX</strong></p>
<p>A design goal of JTAPI has been to cover both scenarios. As a consequence JTAPI provides a model of the telephone system and of telephone calls that corresponds to the more general third-party view, even when JTAPI is used for first-party call control. A third-party view of a call does not distinguish between the local end and the remote end of a call. Instead, the two ends are symmetrical.</p>
<p>In this article, the discussion is about the third-party call capabilities of the JTAPI and more important how to control or monitor the elements that the JTAPI offers. Next is an introduction of what are the basic JTAPI elements.</p>
<h3 id="heading-basic-jtapi-elements"><strong>Basic JTapi elements</strong></h3>
<p>Telephony applications, involve in the control or monitor of objects a telephone system exposes. Such objects could be logical objects, for example an Address, a Call, a Connection etc, or physical objects as a Terminal. Following is a list with the most important JTAPI objects that will be covered throughout this article series. This is an attempt to give an introduction so for everyone to be on the same page.</p>
<h4 id="heading-jtapipeer">JTapiPeer</h4>
<p>The <strong>JtapiPeer</strong> interface represents a vendor’s particular implementation of the Java Telephony API.</p>
<p>JtapiPeer is the first object an application must instantiate. Depending on the vendor’s implementation of this interface, one or more different services can be obtained by the JtapiPeer object.</p>
<h4 id="heading-provider">Provider</h4>
<p>A <strong>Provider</strong> represents the telephony software-entity that interfaces with a telephony subsystem.</p>
<p>A Provider is created and returned by the <code>JtapiPeer.getProvider()</code> method which is given a string to describe the desired Provider. This method sets up any needed communication paths between the application and the Provider. The string given is one of the services listed in the <code>JtapiPeer.getServices()</code>.</p>
<p>The rest of the JTAPI objects are derived from the provider and also the provider is responsible for the various actions the application is designed to make with the JTapi. For example, provider is will deliver Address events in case we monitor an Address or create a call between a local Address and a remote Address (example of an outgoing call).</p>
<p>Important to notice is the term <strong>Provider’s domain</strong> which refers to the collection of Address and Terminal objects which are local to the Provider, and typically, can be controlled by the Provider. For example,the domain of a Provider for a PBX may be the Addresses and Terminals in that PBX. The Provider implementation controls access to Addresses and Terminals by limiting the domain it presents to the application.</p>
<h4 id="heading-address">Address</h4>
<p>An <strong>Address</strong> object represents what we commonly think of as a “telephone number”.</p>
<p>The purpose of the address could be something different than a telephone number if the underlying network is not a telephone network. As an example if the underlying network is an IP network; then the address might represent an IP address (e.g. 192.168.0.100).</p>
<p>When the Address object is created, a unique string name is assigned to it (e.g. 15121) and does not change throughout the lifetime of the object. The method <code>Address.getName()</code> returns the name of the Address object.</p>
<p>Address objects may be classified into two categories: local and remote. Local Address objects are those addresses which are part of the local telephone system domain, for example the extension numbers of a PBX. These Address objects are created by the implementation of the Provider object when it is first instantiated. All of the Provider’s local addresses are reported via the <code>Provider.getAddresses()</code> method. Remote Address objects are those outside of the Provider’s domain which the Provider learns about during its lifetime through various happenings (e.g. an incoming call from a currently unknown address). Remote Addresses are not reported via the <code>Provider.getAddresses()</code> method.</p>
<p>Note that applications never explicitly create new Address objects.</p>
<h4 id="heading-terminal">Terminal</h4>
<p>A <strong>Terminal</strong> represents a physical hardware endpoint connected to the telephony domain. In other words, a Terminal is the telephone set of a PBX.</p>
<p>When the Terminal object is created, a unique string name is assigned to it and does not change throughout the lifetime of the object. The method <code>Terminal.getName()</code> returns the name of the Terminal. Important to notice here is that in contrary with the Address name, the name of the Terminal may not have any real-world interpretation since in order to interact with a Terminal (e.g. call a Terminal) we use the Address assigned to this Terminal.</p>
<p>Terminal objects may be classified into two categories: local and remote. Local Terminal objects are those terminals which are part of the local telephone system domain, for example the telephone sets of a PBX. These Terminal objects are created by the implementation of the Provider object when it is first instantiated. All of the Provider’s local terminals are reported via the <code>Provider.getTerminals()</code> method. Remote Terminal objects are those outside of the Provider’s domain which the Provider learns about during its lifetime through various happenings (e.g. an incoming call from a currently unknown address). Remote Terminal objects are not reported via the <code>Provider.getTerminals()</code> method.</p>
<p>Note that applications never explicitly create new Terminal objects.</p>
<h4 id="heading-address-and-terminal-objects">Address and Terminal objects</h4>
<p>Address and Terminal objects exist in a many-to-many relationship. An Address object may have zero or more Terminals associated with it. For each Terminal associated with an Address, that Terminal must also reflect its association with the Address. Since the implementation creates Address (and Terminal) objects, it is responsible for insuring the correctness of these relationships. The Terminals associated with an Address is given by the <code>Address.getTerminals()</code> method and the Addresses associated with a Terminal is given by the <code>Terminal.getAddresses()</code>.</p>
<p>An association between an Address and Terminal object indicates that the Terminal contains the Address object as one of its telephone number addresses. In many instances, a telephone set (represented by a Terminal object) has only one telephone number (represented by an Address object) associated with it. In more complex configurations, telephone sets may have several telephone numbers associated with them. Likewise, a telephone number may appear on more than one telephone set.</p>
<h4 id="heading-call">Call</h4>
<p>A <strong>Call</strong> object models a telephone call.</p>
<p>A Call can have zero or more Connections. A two-party call has two Connections, and a conference call has three or more Connections. Each Connection models the relationship between a Call and an Address, where an Address identifies a particular party or set of parties on a Call.</p>
<p>A Call maintain a list of the Connections on that Call. Applications obtain an array of Connections associated with the Call via the <code>Call.getConnections()</code> method. A Call retains a reference to a Connection only if it is not in the Connection.DISCONNECTED state. Therefore, if a Call has a reference to a Connection, then that Connection must not be in the Connection.DISCONNECTED state. When a Connection moves into the Connection.DISCONNECTED state (e.g. when a party hangs up), the Call loses its reference to that Connection which is no longer reported via the <code>Call.getConnections()</code> method.</p>
<p>The Provider maintains knowledge of the calls currently associated with it. Applications may obtain an array of these Calls via the <code>Provider.getCalls()</code> method. A Provider may have Calls associated with it which were created before it came into existence. It is the responsibility of the implementation of the Provider to model and report all existing telephone calls which were created prior to the Provider’s lifetime. The Provider maintains references to all calls until they move into the Call.INVALID state.</p>
<p>Applications may create new Calls using the <code>Provider.createCall()</code> method. A new Call is returned in the Call.IDLE state. Applications may then use this idle Call to place new telephone calls. Once created, this new Call object is returned via the <code>Provider.getCalls()</code> method.</p>
<h4 id="heading-address-and-call-objects">Address and Call objects</h4>
<p>Address objects represent the logical endpoints of a telephone call. A logical view of a telephone call views the call as originating from one Address endpoint and terminates at another Address endpoint.</p>
<p>Address objects are related to Call objects via the Connection object. The Connection object has a state which describes the current relationship between the Call and the Address. Each Address object may be part of more than one telephone call, and in each case, is represented by a separate Connection object. The <code>Address.getConnections()</code> method returns all Connection objects currently associated with the Call.</p>
<p>An Address is associated with a Call until the Connection moves into the Connection.DISCONNECTED state. At that time, the Connection is no longer reported via the <code>Address.getConnections()</code> method. Therefore, the <code>Address.getConnections()</code> method will never report a Connection in the Connection.DISCONNECTED state.</p>
<p><em>The Java Telephony API specification states that the implementation is responsible for reporting all existing telephone calls when a Provider is first created. This implies that an Address object must report information regarding existing telephone calls to that Address. In other words, Address objects must reports all Connection objects which represent existing telephone calls.</em></p>
<h4 id="heading-terminal-and-call-objects">Terminal and Call objects</h4>
<p>Terminal objects represent the physical endpoints of a telephone call. With respect to a single Address endpoint on a Call, multiple physical Terminal endpoints may exist. Terminal objects are related to Call objects via the TerminalConnection object. TerminalConnection objects are associated with Call indirectly via Connections. A Terminal may be associated with a Call only if one of its Addresses is associated with the Call. The TerminalConnection object has a state which describes the current relationship between the Connection and the Terminal. Each Terminal object may be part of more than one telephone call, and in each case, is represented by a separate TerminalConnection objet. The <code>Terminal.getTerminalConnections()</code> method returns all TerminalConnection object currently associated with the Terminal.</p>
<p>A Terminal object is associated with a Connection until the TerminalConnection moves into the TerminalConnection.DROPPED state. At that time, the TerminalConnection is no longer reported via the <code>Terminal.getTerminalConnections()</code> method. Therefore, the <code>Terminal.getTerminalConnections()</code> method never reports a TerminalConnection in the TerminalConnection.DROPPED state.</p>
<p><em>The Java Telephony API specification states that the implementation is responsible for reporting all existing telephone calls when a Provider is first created. This implies that an Terminal object must report information regarding existing telephone calls to that Terminal. In other words, Terminal objects must report all TerminalConnection objects which represent existing telephone calls.</em></p>
<h4 id="heading-connection">Connection</h4>
<p>A <strong>Connection</strong> represents a link (i.e. an association) between a Call object and an Address object.</p>
<p>The purpose of a Connection object is to describe the relationship between a Call object and an Address object. A Connection object exists if the Address is a part of the telephone call. Applications use the <code>Connection.getCall()</code> and <code>Connection.getAddress()</code> methods to obtain the Call and Address associated with this Connection, respectively.</p>
<p>From one perspective, an application may view a Call only in terms of the Address/Connection objects which are part of the Call. This is termed a <strong>logical view of the Call</strong> because it ignores the details provided by the Terminal and TerminalConnection objects which are also associated with a Call. In many instances, simple applications (such as an outcall program) may only need to concern itself with the logical view. In this logical view, a telephone call is views as two or more endpoint addresses in communication. The Connection object describes the state of each of these endpoint addresses with respect to the Call.</p>
<p>Connection objects are immutable in terms of their Call and Address references. In other words, the Call and Address object references do not change throughout the lifetime of the Connection object instance. The same Connection object may not be used in another telephone call. The existence of a Connection implies that its Address is associated with its Call in the manner described by the Connection’s state.</p>
<p>Although a Connection’s Address and Call references remain valid throughout the lifetime of the Connection object, the same is not true for the Call and Address object’s references to this Connection. Particularly, when a Connection moves into the Connection.DISCONNECTED state, it is no longer listed by the <code>Call.getConnections()</code> and <code>Address.getConnections()</code> methods. Typically, when a Connection moves into the Connection.DISCONNECTED state, the application loses its references to it to facilitate its garbage collection.</p>
<p>Connections objects are containers for zero or more <strong><em>TerminalConnection objects</em></strong>. Connection objects represent the relationship between the Call and the Address, whereas TerminalConnection objects represent the relationship between the Connection and the Terminal. The relationship between the Call and the Address may be viewed as a logical view of the Call.</p>
<p>The relationship between a Connection and a Terminal represents the <strong>physical view of the Call</strong>, i.e. at which Terminal the telephone calls terminates.</p>
<hr />
<h3 id="heading-resourceshttpsdevrealmorgjtapi-overviewith"><a target="_blank" href="https://devrealm.org/jtapi-overview/">Resources:</a></h3>
<ul>
<li><p><a target="_blank" href="http://java.sun.com/products/jtapi/">Sun Java Telephony API (JTAPI)</a></p>
</li>
<li><p><a target="_blank" href="http://www.zurich.ibm.com/csc/distribsys/j323/jtapi-tutorial.pdf">JTapi Tutorial by Marcel Graf/Zurich/IBM@IBMCH</a></p>
</li>
</ul>
<hr />
]]></content:encoded></item></channel></rss>