{"id":85497,"date":"2019-01-03T13:00:36","date_gmt":"2019-01-03T11:00:36","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=85497"},"modified":"2019-01-02T13:17:34","modified_gmt":"2019-01-02T11:17:34","slug":"validating-external-data-oracle","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html","title":{"rendered":"Validating external data with an Oracle"},"content":{"rendered":"<p>I hang out in the Corda Slack channel quite a lot and try to answer questions when I can. A reasonable number of questions I have attempted to answer are related to Oracles. More specifically, when to use one. I feel like I can answer that, \u201cUse an Oracle when you need to validate external data that can change frequently\u201d. I probably wrote an answer similar to that at some point. What I could not do though\u2026 Was tell someone how to implement one. Therefore, to correct that. I have written this post to learn how to implement one myself and share that knowledge with you and my future self.<\/p>\n<h3 class=\"wp-block-heading\">When to use an Oracle<\/h3>\n<p>Let\u2019s start with expanding on when to use an Oracle. As I touched on a minute ago, you should use an Oracle when you need to validate external data that can change frequently. This could be data such as exchange rates, stock prices or even whether my blog is currently up or down (although I haven\u2019t seen it be down yet!). I think the frequently part is important here. If data seldomly changes, it might be feasible to validate some data against an attachment containing the same sort of values the Oracle would be retrieving themselves. That is why validating data such as exchange rates, in my opinion, should only be done by an Oracle. All that being said, it really comes down to your particular use-case.<\/p>\n<h3 class=\"wp-block-heading\">How to use an Oracle<\/h3>\n<p>How does the Oracle do this validation? Well, that is up to you. But, it will likely follow these steps:<\/p>\n<ul class=\"wp-block-list\">\n<li>Receive data from a node<\/li>\n<li>Retrieve external data<\/li>\n<li>Validate the received data against the external data<\/li>\n<li>Provide a signature for the transaction<\/li>\n<\/ul>\n<p>These are the steps that I think most Oracle implementations will comprise of. More steps could be added in and the validation that is done could be as complex or simple as the use-case demands. Although more steps could be added, I really doubt that there would be much use out of an Oracle that excluded any of the steps shown above.<\/p>\n<p>All the steps shown above only show the process from the side of the Oracle. There is a bit more going on so I think a good diagram will help us out here. It will also go on to present the example that I will use for this post.<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"702\" height=\"1023\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/01\/oracle-flow-chart.png\" alt=\"\" class=\"wp-image-85499\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/01\/oracle-flow-chart.png 702w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/01\/oracle-flow-chart-206x300.png 206w\" sizes=\"(max-width: 702px) 100vw, 702px\" \/><figcaption>Sequence diagram showing the process of interacting with an Oracle <\/figcaption><\/figure>\n<p>Quite a few of these steps are generic ones that are going to be made in whatever Flow you put together. In this section, I will expand and show the code involved to implement the Flow shown in the diagram. Therefore it is worth having a reasonable look at it\u2026 I also spent a lot of time making that look nice, so please look at it!!<\/p>\n<p>Oh, another point before I continue. I want to highlight how helpful putting together sequence diagrams to model Corda Flows is. It really highlights who is involved, how many network hops need to be made and how much work each participant does. Furthermore, they go a good way of explaining what is going on to people who are only interested in the higher level processes that you are architecting and\/or implementing.<\/p>\n<h2 class=\"wp-block-heading\">Client \/ Not the Oracle side<\/h2>\n<p>As I mentioned before, some of the code here is generic code that you are likely to put into any Flow that you write. I have shown it all so there is no ambiguity around what is happening, but I will only expand on points that need to be highlighted as they contain code specific to interacting with an Oracle.<\/p>\n<p><pre class=\"brush:js\">@InitiatingFlow\n@StartableByRPC\nclass GiveAwayStockFlow(\n  private val symbol: String,\n  private val amount: Long,\n  private val recipient: String\n) :\n  FlowLogic&lt;SignedTransaction&gt;() {\n\n  @Suspendable\n  override fun call(): SignedTransaction {\n    val recipientParty = party()\n    val oracle = oracle()\n    val transaction =\n      collectRecipientSignature(\n        verifyAndSign(transaction(recipientParty, oracle)),\n        recipientParty\n      )\n    val allSignedTransaction = collectOracleSignature(transaction, oracle)\n    return subFlow(FinalityFlow(allSignedTransaction))\n  }\n\n  private fun party(): Party =\n    serviceHub.networkMapCache.getPeerByLegalName(CordaX500Name.parse(recipient))\n      ?: throw IllegalArgumentException(\"Party does not exist\")\n\n  private fun oracle(): Party = serviceHub.networkMapCache.getPeerByLegalName(\n    CordaX500Name(\n      \"Oracle\",\n      \"London\",\n      \"GB\"\n    )\n  )\n    ?: throw IllegalArgumentException(\"Oracle does not exist\")\n\n  @Suspendable\n  private fun collectRecipientSignature(\n    transaction: SignedTransaction,\n    party: Party\n  ): SignedTransaction {\n    val signature = subFlow(\n      CollectSignatureFlow(\n        transaction,\n        initiateFlow(party),\n        party.owningKey\n      )\n    ).single()\n    return transaction.withAdditionalSignature(signature)\n  }\n\n  private fun verifyAndSign(transaction: TransactionBuilder): SignedTransaction {\n    transaction.verify(serviceHub)\n    return serviceHub.signInitialTransaction(transaction)\n  }\n\n  private fun transaction(recipientParty: Party, oracle: Party): TransactionBuilder =\n    TransactionBuilder(notary()).apply {\n      val priceOfStock = priceOfStock()\n      addOutputState(state(recipientParty, priceOfStock), StockContract.CONTRACT_ID)\n      addCommand(\n        GiveAway(symbol, priceOfStock),\n        listOf(recipientParty, oracle).map(Party::owningKey)\n      )\n    }\n\n  private fun priceOfStock(): Double =\n    serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).price\n\n  private fun state(party: Party, priceOfStock: Double): StockGiftState =\n    StockGiftState(\n      symbol = symbol,\n      amount = amount,\n      price = priceOfStock * amount,\n      recipient = party\n    )\n\n  private fun notary(): Party = serviceHub.networkMapCache.notaryIdentities.first()\n\n  @Suspendable\n  private fun collectOracleSignature(\n    transaction: SignedTransaction,\n    oracle: Party\n  ): SignedTransaction {\n    val filtered = filteredTransaction(transaction, oracle)\n    val signature = subFlow(CollectOracleStockPriceSignatureFlow(oracle, filtered))\n    return transaction.withAdditionalSignature(signature)\n  }\n  \n  private fun filteredTransaction(\n    transaction: SignedTransaction,\n    oracle: Party\n  ): FilteredTransaction =\n    transaction.buildFilteredTransaction(Predicate {\n      when (it) {\n        is Command&lt;*&gt; -&gt; oracle.owningKey in it.signers &amp;&amp; it.value is GiveAway\n        else -&gt; false\n      }\n    })\n}\n\n@InitiatedBy(GiveAwayStockFlow::class)\nclass SendMessageResponder(val session: FlowSession) : FlowLogic&lt;Unit&gt;() {\n  @Suspendable\n  override fun call() {\n    subFlow(object : SignTransactionFlow(session) {\n      override fun checkTransaction(stx: SignedTransaction) {}\n    })\n  }\n}<\/pre>\n<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p><p>First, let\u2019s have a look at how the transaction is built:<\/p>\n<pre class=\"brush:java\">private fun transaction(recipientParty: Party, oracle: Party): TransactionBuilder =\n  TransactionBuilder(notary()).apply {\n    val priceOfStock = priceOfStock()\n    addOutputState(state(recipientParty, priceOfStock), StockContract.CONTRACT_ID)\n    addCommand(\n      GiveAway(symbol, priceOfStock),\n      listOf(recipientParty, oracle).map(Party::owningKey)\n    )\n  }\n\nprivate fun priceOfStock(): Double =\n  serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).price<\/pre>\n<\/p>\n<p>There is not too much different here from how I would create a transaction that does not involve an Oracle. The only two differences are, retrieving the stock price from an external source (hidden inside the <code>StockRetriever<\/code> service) and including the signature of the Oracle in the Command. These code additions line up with the reasons for using an Oracle. External data is included in the transaction and the Oracle needs to verify it is correct. To prove that the Oracle has deemed a transaction valid, we need its signature.<\/p>\n<p>We will look closer at retrieving the external data separately.<\/p>\n<p><p>Next up is collecting the recipients signature:<\/p>\n<pre class=\"brush:java\">@Suspendable\nprivate fun collectRecipientSignature(\n  transaction: SignedTransaction,\n  party: Party\n): SignedTransaction {\n  val signature = subFlow(\n    CollectSignatureFlow(\n      transaction,\n      initiateFlow(party),\n      party.owningKey\n    )\n  ).single()\n  return transaction.withAdditionalSignature(signature)\n}<\/pre>\n<\/p>\n<p>Collecting the counterparty\u2019s signature is not really an uncommon step of a Flow but what is done differently here is the use of <code>CollectSignatureFlow<\/code> rather than the <code>CollectSignaturesFlow<\/code> which is normally used (noticed the \u201cs\u201d missing in the middle). That is due to requiring the Oracle\u2019s signature in the transaction. Calling the <code>CollectSignaturesFlow<\/code> will go off to retrieve signatures from all required signers, including the Oracle. This treats the Oracle like a \u201cnormal\u201d participant. This is not what we want. Instead, we need to get the signature of the recipient and the Oracle individually and somewhat manually. The manual part is the use of <code>transaction.withAdditionalSignature<\/code>.<\/p>\n<p><p>Now that the recipient has signed the transaction, the Oracle needs to sign it:<\/p>\n<pre class=\"brush:java\">@Suspendable\nprivate fun collectOracleSignature(\n  transaction: SignedTransaction,\n  oracle: Party\n): SignedTransaction {\n  val filtered = filteredTransaction(transaction, oracle)\n  val signature = subFlow(CollectOracleStockPriceSignatureFlow(oracle, filtered))\n  return transaction.withAdditionalSignature(signature)\n}\n\nprivate fun filteredTransaction(\n  transaction: SignedTransaction,\n  oracle: Party\n): FilteredTransaction =\n  transaction.buildFilteredTransaction(Predicate {\n    when (it) {\n      is Command&lt;*&gt; -&gt; oracle.owningKey in it.signers &amp;&amp; it.value is GiveAway\n      else -&gt; false\n    }\n  })<\/pre>\n<\/p>\n<p>Before sending the transaction to the Oracle, it is recommended to filter it to remove any information that is not needed by the Oracle. This prevents information that shouldn\u2019t be shared from being seen by the Oracle. Remember the Oracle is likely to be a node controlled by another organisation and is not a participant that you are attempting to share states and transactions with.<\/p>\n<p><code>SignedTransaction<\/code> provides the <code>buildFilteredTransaction<\/code> function that only includes objects that match the predicate passed in. In the example above it filters out everything but the <code>GiveAway<\/code> (command I created) command which must also have the Oracle as a signer.<\/p>\n<p><p>This outputs a <code>FilteredTransaction<\/code> which is passed to <code>CollectOracleStockPriceSignatureFlow<\/code>:<\/p>\n<pre class=\"brush:java\">@InitiatingFlow\nclass CollectOracleStockPriceSignatureFlow(\n  private val oracle: Party,\n  private val filtered: FilteredTransaction\n) : FlowLogic&lt;TransactionSignature&gt;() {\n\n  @Suspendable\n  override fun call(): TransactionSignature {\n    val session = initiateFlow(oracle)\n    return session.sendAndReceive&lt;TransactionSignature&gt;(filtered).unwrap { it }\n  }\n}<\/pre>\n<\/p>\n<p>All this code does is send the <code>FilteredTransaction<\/code> to the Oracle and awaits its signature. The code here could be put into the main Flow but it is quite nice to split code out when we can.<\/p>\n<p>Finally, the <code>TransactionSignature<\/code> returned from the Oracle is added to the transaction in the same way the recipient\u2019s signature was added earlier. At this point, the transaction is ready to be committed as all the required signers have done their part.<\/p>\n<h2 class=\"wp-block-heading\">Oracle side<\/h2>\n<p><p>Now that we have covered the client side of the code, we need to have a look into how the Oracle validates the transaction. Below is the contents of the Oracle code:<\/p>\n<pre class=\"brush:java\">@InitiatedBy(CollectOracleStockPriceSignatureFlow::class)\nclass OracleStockPriceSignatureResponder(private val session: FlowSession) : FlowLogic&lt;Unit&gt;() {\n\n  @Suspendable\n  override fun call() {\n    val transaction = session.receive&lt;FilteredTransaction&gt;().unwrap { it }\n\n    val key = key()\n\n    val isValid = transaction.checkWithFun { element: Any -&gt;\n      when {\n        element is Command&lt;*&gt; &amp;&amp; element.value is GiveAway -&gt; {\n          val command = element.value as GiveAway\n          (key in element.signers).also {\n            validateStockPrice(\n              command.symbol,\n              command.price\n            )\n          }\n        }\n        else -&gt; false\n      }\n    }\n\n    if (isValid) {\n      session.send(serviceHub.createSignature(transaction, key))\n    } else {\n      throw InvalidStockPriceFlowException(\"Transaction: ${transaction.id} is invalid\")\n    }\n  }\n\n  private fun key(): PublicKey = serviceHub.myInfo.legalIdentities.first().owningKey\n\n  private fun validateStockPrice(symbol: String, price: Double) = try {\n    serviceHub.cordaService(StockPriceValidator::class.java).validate(symbol, price)\n  } catch (e: IllegalArgumentException) {\n    throw InvalidStockPriceFlowException(e.message)\n  }\n}<\/pre>\n<\/p>\n<p><p>Some of the code that should be here is hidden in the <code>StockPriceValidator<\/code> which retrieves the external stock price and compares it to the one passed to the Oracle. It doesn\u2019t have much code and its validation is basic so I won\u2019t elaborate on it. As it is short, I might as well show it now:<\/p>\n<pre class=\"brush:java\">@CordaService\nclass StockPriceValidator(private val serviceHub: AppServiceHub) :\n  SingletonSerializeAsToken() {\n\n  fun validate(symbol: String, price: Double) =\n    serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).let {\n      require(price == it.price) { \"The price of $symbol is ${it.price}, not $price\" }\n    }\n}<\/pre>\n<\/p>\n<p>Back to the <code>OracleStockPriceSignatureResponder<\/code>. Firstly, <code>receive<\/code> is called to get the <code>FilteredTransaction<\/code> that the client sent. It is then checked using its <code>checkWithFun<\/code> function. This is a handy function that looks at each object and expects a <code>Boolean<\/code> in return. Using this, the transaction is deemed valid if all it contains are commands of <code>GiveAway<\/code> where the Oracle is the signer and most importantly checks that the external data contained in the command is correct. If you recall the code from earlier, the correct command and signers were passed in. The only remaining validation is on the external data. If that is all fine then the Oracle will accept the transaction and send its signature back to the client that requested it.<\/p>\n<p>I chose to complete the validation via throwing exceptions (along with error messages) which are then propagated to the requesting party. I think this makes it easier on to understand what has gone wrong so it can be handled properly, rather than just a straight \u201cfailed validation\u201d message. If the validation the Oracle is performing is complex, these error messages become even more valuable.<\/p>\n<h3 class=\"wp-block-heading\">Retrieving external data<\/h3>\n<p>You should have seen the <code>StockRetriever<\/code> class pop up twice now. It was used in both the requesting party and the Oracle. I have shared this code between both types of nodes (normal nodes and Oracles) but this might not be suitable for your own use-case. Furthermore, how you choose to retrieve your external data is up to you, I am just providing a possible solution.<\/p>\n<p><p>The code can be found below:<\/p>\n<pre class=\"brush:java\">@CordaService\nclass StockRetriever(serviceHub: AppServiceHub) :\n  SingletonSerializeAsToken() {\n\n  private val client = OkHttpClient()\n  private val mapper = ObjectMapper()\n\n  fun getCurrent(symbol: String): Stock {\n    val response = client.newCall(request(symbol)).execute()\n    return response.body()?.let {\n      val json = it.string()\n      require(json != \"Unknown symbol\") { \"Stock with symbol: $symbol does not exist\" }\n      val tree = mapper.readTree(json)\n      Stock(\n        symbol = symbol,\n        name = tree[\"companyName\"].asText(),\n        primaryExchange = tree[\"primaryExchange\"].asText(),\n        price = tree[\"latestPrice\"].asDouble()\n      )\n    } ?: throw IllegalArgumentException(\"No response\")\n  }\n\n  private fun request(symbol: String) =\n    Request.Builder().url(\"https:\/\/api.iextrading.com\/1.0\/stock\/$symbol\/quote\").build()\n}<\/pre>\n<\/p>\n<p>The <code>StockRetriever<\/code> is a nice little service that uses an <code>OkHttpClient<\/code> (<a href=\"https:\/\/github.com\/square\/okhttp\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"OkHttp (opens in a new tab)\">OkHttp<\/a>) to make a HTTP request to an API (provided by <a href=\"https:\/\/iextrading.com\/developer\/docs\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"IEX Trading (opens in a new tab)\">IEX Trading<\/a> using their <a href=\"https:\/\/github.com\/WojciechZankowski\/iextrading4j\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Java library (opens in a new tab)\">Java library<\/a>) that returns stock information when a stock symbol is provided. You can use whatever client you want to make the HTTP request. I saw this one in an example CorDapp and have taken it for my own. Personally, I\u2019m too used to Spring so didn\u2019t really know any clients other than their <code>RestTemplate<\/code>.<\/p>\n<p>Once the response is returned, it is converted into a <code>Stock<\/code> object and passed back to the function\u2019s caller. That\u2019s all folks.<\/p>\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n<p>In conclusion, you should use an Oracle when your CorDapp requires frequently changing external data that needs to be validated before the transaction can be committed. Just like data held within states, external data is extremely important, probably the most important, as it is likely to determine the main contents of a transaction. Therefore all participants must feel comfortable that the data is correct and hasn\u2019t just come out of thin air.<br \/>\n&nbsp;<br \/>\nTo achieve this, an Oracle will also retrieve the external data and validate it against what the transaction says the data should be. At this point, the Oracle will either sign the transaction or throw an exception and deem it invalid. The implementation side of this is reasonably straightforward as there are not many steps that need to be taken. Retrieve the data, send a <code>FilteredTransaction<\/code> to the Oracle containing the data where it will be validated. Yes, as you have read this post, you will know there is a bit more to it. But, for a basic Flow that is pretty much it. As I said somewhere near the start, how the Oracle does its validation can be as simple or complicated as required. Although, I think most will follow the same sort of process shown here.<\/p>\n<p>Now for the main conclusion\u2026 In conclusion, you now have the knowledge to answer questions in the slack channel about Oracles or know where to send them if you can\u2019t!<\/p>\n<p>The code used in this post can be found on my <a href=\"https:\/\/github.com\/lankydan\/corda-oracle\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"GitHub (opens in a new tab)\">GitHub<\/a>.<\/p>\n<p>If you found this post helpful, you can follow me on Twitter at <a href=\"https:\/\/twitter.com\/LankyDanDev\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"@LankyDanDev (opens in a new tab)\">@LankyDanDev<\/a> to keep up with my new posts.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>\n<p>Published on Java Code Geeks with permission by Dan Newton, partner at our <a href=\"\/\/www.javacodegeeks.com\/join-us\/jcg\/\" target=\"_blank\" rel=\"noopener\">JCG program<\/a>. See the original article here: <a href=\"https:\/\/lankydanblog.com\/2019\/01\/01\/validating-external-data-with-an-oracle\/\" target=\"_blank\" rel=\"noopener\">Validating external data with an Oracle<\/a><\/p>\n<p>Opinions expressed by Java Code Geeks contributors are their own.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I hang out in the Corda Slack channel quite a lot and try to answer questions when I can. A reasonable number of questions I have attempted to answer are related to Oracles. More specifically, when to use one. I feel like I can answer that, \u201cUse an Oracle when you need to validate external &hellip;<\/p>\n","protected":false},"author":12894,"featured_media":13674,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[1646,1760,1208],"class_list":["post-85497","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-blockchain","tag-corda","tag-kotlin"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Validating external data with an Oracle - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Validating external data with an Oracle - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-01-03T11:00:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Dan Newton\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@LankyDanDev\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dan Newton\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html\"},\"author\":{\"name\":\"Dan Newton\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/00ad664c44d777ebfa4d984dcf2717e2\"},\"headline\":\"Validating external data with an Oracle\",\"datePublished\":\"2019-01-03T11:00:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html\"},\"wordCount\":1802,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2013\\\/06\\\/jetbrains-kotlin-logo.jpg\",\"keywords\":[\"Blockchain\",\"Corda\",\"Kotlin\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html\",\"name\":\"Validating external data with an Oracle - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2013\\\/06\\\/jetbrains-kotlin-logo.jpg\",\"datePublished\":\"2019-01-03T11:00:36+00:00\",\"description\":\"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2013\\\/06\\\/jetbrains-kotlin-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2013\\\/06\\\/jetbrains-kotlin-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/01\\\/validating-external-data-oracle.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Validating external data with an Oracle\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/00ad664c44d777ebfa4d984dcf2717e2\",\"name\":\"Dan Newton\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"caption\":\"Dan Newton\"},\"sameAs\":[\"https:\\\/\\\/lankydanblog.com\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/danknewton\\\/\",\"https:\\\/\\\/x.com\\\/LankyDanDev\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/dan-newton\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Validating external data with an Oracle - Java Code Geeks","description":"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html","og_locale":"en_US","og_type":"article","og_title":"Validating external data with an Oracle - Java Code Geeks","og_description":"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.","og_url":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2019-01-03T11:00:36+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg","type":"image\/jpeg"}],"author":"Dan Newton","twitter_card":"summary_large_image","twitter_creator":"@LankyDanDev","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Dan Newton","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html"},"author":{"name":"Dan Newton","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/00ad664c44d777ebfa4d984dcf2717e2"},"headline":"Validating external data with an Oracle","datePublished":"2019-01-03T11:00:36+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html"},"wordCount":1802,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg","keywords":["Blockchain","Corda","Kotlin"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html","url":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html","name":"Validating external data with an Oracle - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg","datePublished":"2019-01-03T11:00:36+00:00","description":"Interested to learn about Validating external data? Check our article explaining why to use an Oracle when you need to validate external data.","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2013\/06\/jetbrains-kotlin-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2019\/01\/validating-external-data-oracle.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Validating external data with an Oracle"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/00ad664c44d777ebfa4d984dcf2717e2","name":"Dan Newton","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","caption":"Dan Newton"},"sameAs":["https:\/\/lankydanblog.com\/","https:\/\/www.linkedin.com\/in\/danknewton\/","https:\/\/x.com\/LankyDanDev"],"url":"https:\/\/www.javacodegeeks.com\/author\/dan-newton"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/85497","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/12894"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=85497"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/85497\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/13674"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=85497"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=85497"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=85497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}