tag:blogger.com,1999:blog-211225142024-03-19T11:38:55.247+01:00Dimitri Gielis Blog (Oracle Application Express - APEX)I created this Blog to share my knowledge especially in Oracle Application Express (APEX) and my feelings ...Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.comBlogger837125tag:blogger.com,1999:blog-21122514.post-3873980073855553832022-11-11T17:00:00.000+01:002022-11-11T17:00:26.849+01:00Oracle APEX: Use saved report name of Interactive Report in Export<p></p><div class="separator" style="clear: both; text-align: left;">Recently there was a question on Twitter about how to use the saved report name in an export of an Interactive Report in <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a>. </div><div class="separator" style="clear: both; text-align: left;"> </div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjVBZgE5DCiJt6iovLiHJIdl1YKLrePx0xE6PKVYOqsA3l6WTcwb3jyDcRQPVDVDSygGgfifAPQPg-Z4EOozQ6Yx9gbFleUe6_Wt2CTLK17G78p19E4rF_H179gmQ5PYMsJdfZQWm0ZqZAsB1gX0aJ604XeS5PVOWdYD-IMM3NJ1G0UeXvz5L8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="544" data-original-width="1340" height="261" src="https://blogger.googleusercontent.com/img/a/AVvXsEjVBZgE5DCiJt6iovLiHJIdl1YKLrePx0xE6PKVYOqsA3l6WTcwb3jyDcRQPVDVDSygGgfifAPQPg-Z4EOozQ6Yx9gbFleUe6_Wt2CTLK17G78p19E4rF_H179gmQ5PYMsJdfZQWm0ZqZAsB1gX0aJ604XeS5PVOWdYD-IMM3NJ1G0UeXvz5L8=w640-h261" width="640" /></a></div><p>First, if you never heard of <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a>, or in short, <b>AOP</b>, it's the leading document generation software for <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a>. AOP allows you to create PDF, Word, Excel, PowerPoint, Text, and HTML documents with data from your database and your Oracle APEX app. AOP is unique as it's tightly integrated with Oracle APEX. You create a template in Word, Excel, PowerPoint, Text, or HTML, and tags that are included in your template will be replaced by data. In the tweet, Matic speaks about the {&interactive} tag. When you add this tag to your Word, Excel, or HTML document, AOP generates the Interactive Report in your document. AOP is even so smart that it will recognize if you have filters, highlights, groupings, etc., defined!</p><p>So I thought to create an example and see what it would take to get the <b>Saved Report name</b> in the document.</p><p>I went into the <a href="https://www.apexofficeprint.com/ords/r/aop_web/aop_menu_app_web/home" target="_blank">AOP Sample Application</a> and clicked on the example where there are Saved Reports for an Interactive Report. The way I understand the question is how to use the name of the saved report, in our case, "3. Highlight", in the export to Excel or PDF.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgbKhbtGduRRwRPCe8ze5wgj1CupL9cGAXnN4jHpprTrLtxfPKYkJJH506EzlhHsfTRCJzYSH6Lt65Nq2eaUu-ZdxneWVEjm_gN0VtQ-r8gukHS3o8dpuoFRNs5xEVjhqolJDSs1xVswAujbywsgJIfZi4IfPbwKAEiAO1LHwApCNHE7Q_5Bx8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1946" data-original-width="2554" height="488" src="https://blogger.googleusercontent.com/img/a/AVvXsEgbKhbtGduRRwRPCe8ze5wgj1CupL9cGAXnN4jHpprTrLtxfPKYkJJH506EzlhHsfTRCJzYSH6Lt65Nq2eaUu-ZdxneWVEjm_gN0VtQ-r8gukHS3o8dpuoFRNs5xEVjhqolJDSs1xVswAujbywsgJIfZi4IfPbwKAEiAO1LHwApCNHE7Q_5Bx8=w640-h488" width="640" /></a></div><p>The result when you export or download to Excel should be like this:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgModlB8cHtk2tvicDQ5ZeRBu629ds3jBjqalRAnYjmyG-uNMbE4cseCpFV-qfHSW6ASHkrhk6RNqhmvkh4pptJnMxVLyFxFBuImxx3ej0QAOsHjvA5SnThJZZXEwyNz6Ba04Y14bqZ9NmIY8ST13M-I4HK4hTV45N-J9B56V45OPJZQmCmGPo" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1276" data-original-width="1518" height="537" src="https://blogger.googleusercontent.com/img/a/AVvXsEgModlB8cHtk2tvicDQ5ZeRBu629ds3jBjqalRAnYjmyG-uNMbE4cseCpFV-qfHSW6ASHkrhk6RNqhmvkh4pptJnMxVLyFxFBuImxx3ej0QAOsHjvA5SnThJZZXEwyNz6Ba04Y14bqZ9NmIY8ST13M-I4HK4hTV45N-J9B56V45OPJZQmCmGPo=w640-h537" width="640" /></a></div><p></p><p>Here are the steps to get it done.</p>1. Create a hidden item on the page. We will use this item to store the name of the saved report.<br /><p></p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEikCupInb7s1XYCBDnY40BTSfB3PZF33JLPGEcscMrBAY1DkxzV4_eHqOel8jWo9SHIERhojgondEsN61UizFeLDBEpLEYS-_LStVXAiutzykkFkq1ew8DhyDzikDGQPJfuGBjhq9Ad-bUsEdpcXNUVQrzMzczXUKKdUsUDpfBNuV19vBATnY0" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="1860" data-original-width="1838" height="640" src="https://blogger.googleusercontent.com/img/a/AVvXsEikCupInb7s1XYCBDnY40BTSfB3PZF33JLPGEcscMrBAY1DkxzV4_eHqOel8jWo9SHIERhojgondEsN61UizFeLDBEpLEYS-_LStVXAiutzykkFkq1ew8DhyDzikDGQPJfuGBjhq9Ad-bUsEdpcXNUVQrzMzczXUKKdUsUDpfBNuV19vBATnY0=w632-h640" width="632" /></a><br /><br />2. Create a dynamic action on click of the Excel button and add a <b>Set Value </b>Action with the following JavaScript Expression:<br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhMdt5l_c0KCUHZ3jv93BA-xl3jD5wjew6sneUXqItRtL52csaJ7dEefv50Ob11V7Q-MdHV65IgvbNFN9mbTe-Ur9U-FdZsf1VarZLaJ5Hug_wRF7TI4kfmjnLd6EqSqezRDPIs11BxzV2FuAwoQp41-CwL3oADYniRVORW6PftQTwntlHl-XM" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1580" data-original-width="1838" height="551" src="https://blogger.googleusercontent.com/img/a/AVvXsEhMdt5l_c0KCUHZ3jv93BA-xl3jD5wjew6sneUXqItRtL52csaJ7dEefv50Ob11V7Q-MdHV65IgvbNFN9mbTe-Ur9U-FdZsf1VarZLaJ5Hug_wRF7TI4kfmjnLd6EqSqezRDPIs11BxzV2FuAwoQp41-CwL3oADYniRVORW6PftQTwntlHl-XM=w640-h551" width="640" /></a></div><p></p><p>3. Add the APEX Office Print Dynamic Action plug-in as another Action. We tell AOP we stored our template in Static Application Files with the name "aop_IR_template_saved_report.xlsx". Our data comes from the IR, so we define the static Id of the IR region "ireport1". As output, we took Excel, but you can also take another output like PDF, for example. It's important to add the hidden item in the "Affected Elements" section, as AOP will get the values of those items too.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgmYH75AXGEqxMNW-we2cyuoN3KwNLplx4Ci_5gpxm0jEfo3Ww4O8Kl6RfhJpcF5mjnArL7ChcDocyt40jrRb1Jdd5eGvBXeR0SkGaLfbGfaPsrb70GGvFbd2VNBRKp6xzu6D0P5exz034yNyEetheY1mVWo_IkwkILxaCJ41BojoG14MDsOu0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1772" data-original-width="1840" height="617" src="https://blogger.googleusercontent.com/img/a/AVvXsEgmYH75AXGEqxMNW-we2cyuoN3KwNLplx4Ci_5gpxm0jEfo3Ww4O8Kl6RfhJpcF5mjnArL7ChcDocyt40jrRb1Jdd5eGvBXeR0SkGaLfbGfaPsrb70GGvFbd2VNBRKp6xzu6D0P5exz034yNyEetheY1mVWo_IkwkILxaCJ41BojoG14MDsOu0=w640-h617" width="640" /></a></div><p>4. And finally, this is what our template looks like.</p><p>The hidden item is in the ireport region. You can reference the item with the following tag:<br />{ireport_items[0].P5061_SAVED_REPORT_TITLE}. An alternative, in case you have multiple items you want to reference, you can use {#ireport_items} ... define all your items with {tag} ... {/ireport_items}</p><p>And to get the Interactive Report, you define in a cell of your choice the tag {&interactive}.<br />In case you submit multiple IRs, or a combination of Classic Reports, IGs, and IRs, it would be {&interactive_1} {&interactive_2} {&classic1&} {&ig1&} etc. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiqymr_rktZgEJQBI4jFYdCcWYC5Z-2c2N5yoNY2eStW3zPRcHza2n6hTZsmuXIZftlOC5GSy3W2wuXKd3QO8cozzT1pQ1qgnipY0kXHsbxj8b96LQ6ZdmfUzerKLIklanASkST8rF2i5-DHDNm5T9RbVsYyOv-YHJfRELoMpmqEWdOJQbIhp0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="420" data-original-width="1114" height="242" src="https://blogger.googleusercontent.com/img/a/AVvXsEiqymr_rktZgEJQBI4jFYdCcWYC5Z-2c2N5yoNY2eStW3zPRcHza2n6hTZsmuXIZftlOC5GSy3W2wuXKd3QO8cozzT1pQ1qgnipY0kXHsbxj8b96LQ6ZdmfUzerKLIklanASkST8rF2i5-DHDNm5T9RbVsYyOv-YHJfRELoMpmqEWdOJQbIhp0=w640-h242" width="640" /></a></div><br /><p></p><p>And that is it! </p><p>I'm always amazed by how far we have brought AOP in the last 7 years. We have never been more committed to providing solutions to all of the reporting, exporting, and document generation needs you have ... and there is more to come 😁</p><p><br /></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1tag:blogger.com,1999:blog-21122514.post-48301761982858991302022-11-10T17:57:00.000+01:002022-11-28T19:31:23.321+01:00World Cup 2022 Challenge online!<p></p><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;">For the last 16 years, with every big football tournament (World Cup and Euro Cup), we've launched an Oracle APEX app where you can predict the scores of the games. You can find this year's app at <a href="https://wc2022.unitedcodes.com">https://wc2022.unitedcodes.com</a></div><div class="separator" style="clear: both;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgjD8FoszniAuYwcq_O11_OxzW6lflw4Rr3qkV597WLeZyQRapjsM03dpWsGQp6lpKddPEWXeX4hqZzMbDfgEM-0NQZDP059Of63gMrIu6_UYdSTL4jd1rac4PjVJ-FSozlBKDunUDtPBWz06kCGWa9KfC_zfSV2xx9PnCjG6qlk5QC9F1J6rc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1982" data-original-width="2468" height="514" src="https://blogger.googleusercontent.com/img/a/AVvXsEgjD8FoszniAuYwcq_O11_OxzW6lflw4Rr3qkV597WLeZyQRapjsM03dpWsGQp6lpKddPEWXeX4hqZzMbDfgEM-0NQZDP059Of63gMrIu6_UYdSTL4jd1rac4PjVJ-FSozlBKDunUDtPBWz06kCGWa9KfC_zfSV2xx9PnCjG6qlk5QC9F1J6rc=w640-h514" width="640" /></a></div><br /><b>Features</b><div><br /></div><div>Many people do a challenge with their friends or company, for fun, for money... Instead of using a custom-made Excel, use of email, or use of paper, you can use the World Cup 2022 Challenge site to track who's in the lead.</div><div><ul style="text-align: left;"><li>You can enter the scores of every game and see how well your predictions compare to others (overall).</li><li>You can create a group e.g. your company, or a team, etc and see how well you play within your group.</li><li>You can see statistics of predictions</li></ul></div><div><b>History</b></div><div><br /></div><div>16 years ago, I built a site to promote the use of <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a>. People loved it, so I decided to update the site with every new release of APEX. You can find some more history and screenshots of how the app looked <a href="https://wc2022.unitedcodes.com/ords/f?p=636:HISTORY:0" target="_blank">here</a>. </div><div><br /></div><div><div><b>Oracle APEX features</b></div><div><br /></div></div><div>When upgrading to the new Oracle APEX version, the Advisor and Upgrade assistant were run. This year the site runs on Oracle APEX 22.1, Universal theme got refreshed, the site is more mobile friendly and some components like the calendar where updated. Social authentication was re-enabled, so you can sign-up and log in with Email, Facebook or Google.<br /><br />Thanks to Kevin and Theo who did most of the work!</div><div><br /></div><div><b>Go and play!</b></div><div><br /></div><div>Head to the site/app and <a href="https://wc2022.unitedcodes.com/" target="_blank">start challenging your friends</a> 😀</div><p></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com0tag:blogger.com,1999:blog-21122514.post-69222795557621366372022-10-18T23:05:00.000+02:002022-10-18T23:05:18.875+02:00Oracle APEX Form: Save before Print<p>In almost every Oracle APEX application I create a <b>Report with Form</b> to edit the data.<br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhqMirdD0lowoiBrK9h0g6tq6-nvY-zAoZNbo92rH1jl-mOMck-AILE_zKlglreGOl55gLHcIq9N5nGx9ahqVXpVv9yKG3CumMgtsZMuCmAqNNuJUooldqlfHx8EOYAIaQNepm-5Y5laVqUNV5YPNVrsg0h-JunLXaS9puzXpnHBjj3i53xzoU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1366" data-original-width="2340" height="374" src="https://blogger.googleusercontent.com/img/a/AVvXsEhqMirdD0lowoiBrK9h0g6tq6-nvY-zAoZNbo92rH1jl-mOMck-AILE_zKlglreGOl55gLHcIq9N5nGx9ahqVXpVv9yKG3CumMgtsZMuCmAqNNuJUooldqlfHx8EOYAIaQNepm-5Y5laVqUNV5YPNVrsg0h-JunLXaS9puzXpnHBjj3i53xzoU=w640-h374" width="640" /></a></div><br />On this Form many people add a <b>Print button</b> to generate a document for this specific record.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEirzrUNXsiboTiiZYldPoVY73KfH2Eijr3gh-OUvjaIIjC-9rwJVito_JEp4CC5cmZW7cB2-pW9JHhF-FeVMM4ZQk2f2uRq7TVIWqwDoE_PFXnpmTeHqKPHrG7w2xvfvZ3FdYFoo8rB4vv-VrUlvR6wAUrQ9MeW6R_4UX-hRDoo5NCaEad1TWw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1326" data-original-width="2338" height="362" src="https://blogger.googleusercontent.com/img/a/AVvXsEirzrUNXsiboTiiZYldPoVY73KfH2Eijr3gh-OUvjaIIjC-9rwJVito_JEp4CC5cmZW7cB2-pW9JHhF-FeVMM4ZQk2f2uRq7TVIWqwDoE_PFXnpmTeHqKPHrG7w2xvfvZ3FdYFoo8rB4vv-VrUlvR6wAUrQ9MeW6R_4UX-hRDoo5NCaEad1TWw=w640-h362" width="640" /></a></div><br />From time to time I get the question how to <b>first save the record and next print or download </b>the document.<p></p><p>Here are the <b>5 steps</b> to do this:</p><p>1. <b>Duplicate the Save button</b> and name the button Print. Or alternatively create the Print button from scratch and make sure to set the action to Submit, the Database Action to SQL UPDATE action, and make it conditional to only show when the PK is not null. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgknqRnqvE2Xd25jOlt2cnX5PtA3-q6aGP1J9p2lU2m0oUzxuYEIWnP_8ri9JOkhyxG9uS31lYRAdnTsiljRavSiPG0Hchjvsa3HgXXYusAqKD-37iaBZmdNjp9SbQDMcsG04IZAP0Lk7AqMsc3O8rYfnxo7aZ0gptQVAHgHU_Gjyy9THoMCsM" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1284" data-original-width="1628" height="505" src="https://blogger.googleusercontent.com/img/a/AVvXsEgknqRnqvE2Xd25jOlt2cnX5PtA3-q6aGP1J9p2lU2m0oUzxuYEIWnP_8ri9JOkhyxG9uS31lYRAdnTsiljRavSiPG0Hchjvsa3HgXXYusAqKD-37iaBZmdNjp9SbQDMcsG04IZAP0Lk7AqMsc3O8rYfnxo7aZ0gptQVAHgHU_Gjyy9THoMCsM=w640-h505" width="640" /></a></div><p></p><p>This will make sure when the automatic row processing is performed the update is happening.</p><p>2. In the processing section, <b>create a Branch</b> with a Server-side Condition when button pressed PRINT. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjBxUtTGlXFw1qJN4e9vcRSBJBA4ucikkqCUkGHZskuHlBsVm1yvovy8H9YePrSQN0Qq6LqToqeBV-TGYDWky7kkpSSSpETPDrx-pEyPbtooRYes1QQqIn1zdV0hE4G03_adgArTjtINa8aRPqfsffRXQduzbbsr76q5JVtlKwCAQFxyBsw36k" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1122" data-original-width="1610" height="446" src="https://blogger.googleusercontent.com/img/a/AVvXsEjBxUtTGlXFw1qJN4e9vcRSBJBA4ucikkqCUkGHZskuHlBsVm1yvovy8H9YePrSQN0Qq6LqToqeBV-TGYDWky7kkpSSSpETPDrx-pEyPbtooRYes1QQqIn1zdV0hE4G03_adgArTjtINa8aRPqfsffRXQduzbbsr76q5JVtlKwCAQFxyBsw36k=w640-h446" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">When clicking the Target button in the Branch, link to the same page, and pass the item with the primary key and most importantly set the Request to PRINT.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj_Ta3pzsTqWxJThrPHVtswSuHdLHfP98H5PVI7DgIvNPMez-tr13jbbaqUn46ybDHoytTSGjlmfJsQv7PbwGuMp7SYiGQRru8DhwRTT5z-gHlLOeY9d-jBxc0_XBBXYrpzygtkLdtpSfXI_DQ4DE4aUZ8YrT83OaPrIRSJmS1AhbUUDSRkcvA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1012" data-original-width="1058" height="612" src="https://blogger.googleusercontent.com/img/a/AVvXsEj_Ta3pzsTqWxJThrPHVtswSuHdLHfP98H5PVI7DgIvNPMez-tr13jbbaqUn46ybDHoytTSGjlmfJsQv7PbwGuMp7SYiGQRru8DhwRTT5z-gHlLOeY9d-jBxc0_XBBXYrpzygtkLdtpSfXI_DQ4DE4aUZ8YrT83OaPrIRSJmS1AhbUUDSRkcvA=w640-h612" width="640" /></a></div><br /><p></p><p>3. Create a new <b>Dynamic Action called AOP Print</b> which runs on Page Load with a Server-side Condition that the Request value = PRINT (as we defined in the Branch).</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiXWhx13kIENbDdD6ULNWEfwxXqQbt4u9PwmZJhyr1V8vZJmfRw7ndb4rE7slb1UKMPDvMw4CAVjgrAzVg0bR8wYggr2f7CvXq9SGl3YpmUxOSXj8N3_W_4U2gu_ZhVBV1cRHU0p6fowV5qmatDel6rUFRjsNpmlOfNMJPXTXa9hUXn-ggZbb0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1272" data-original-width="1626" height="500" src="https://blogger.googleusercontent.com/img/a/AVvXsEiXWhx13kIENbDdD6ULNWEfwxXqQbt4u9PwmZJhyr1V8vZJmfRw7ndb4rE7slb1UKMPDvMw4CAVjgrAzVg0bR8wYggr2f7CvXq9SGl3YpmUxOSXj8N3_W_4U2gu_ZhVBV1cRHU0p6fowV5qmatDel6rUFRjsNpmlOfNMJPXTXa9hUXn-ggZbb0=w640-h500" width="640" /></a></div><p></p><p>4. Add as <b>True Action the <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a> </b>dynamic action (DA) plug-in. <br />Specify the template and data (SQL) and the output you want (PDF). We want the document to download into the browser.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjXSW5U5v22cPaKr33wkQupCgJV-RpM62Pv4SFRAqvV7cvw4lL7z3Xf8PoESYBYmB66WRuKNmRFz0g-EyzJkjvxQk4pbV8GnNBI-HWjOT44k8sPuBWQ2UAfLGYr3PVyOQb8USJs0ODKxAPK2mMuY5LzVjJ9SkhU-4ZBOH99dwPn58M3IuzB9Ro" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1414" data-original-width="1960" height="462" src="https://blogger.googleusercontent.com/img/a/AVvXsEjXSW5U5v22cPaKr33wkQupCgJV-RpM62Pv4SFRAqvV7cvw4lL7z3Xf8PoESYBYmB66WRuKNmRFz0g-EyzJkjvxQk4pbV8GnNBI-HWjOT44k8sPuBWQ2UAfLGYr3PVyOQb8USJs0ODKxAPK2mMuY5LzVjJ9SkhU-4ZBOH99dwPn58M3IuzB9Ro=w640-h462" width="640" /></a></div><br />Optionally, add another True action to Close the Dialog in case your Form is a dialog and you want it to automatically close.<p></p><p>5. When you download the document, it might be empty. This is because our PK isn't known to the AOP process. See my <a href="https://dgielis.blogspot.com/2022/10/no-value-of-page-item-when-using.html" target="_blank">previous blog post</a> which goes in more details. So the final step is to set <b>Maintain Session State: Per Session (Disk) for the primary key item</b>.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg9KDM3g8CxSEqWPCxSD_FZiSi0YJYbZrIqe9Z_niIUgJ--V-koUhwpm9ytO4peu2xLYOOJmltpTPnNAWlM1E6R825DdoiRYT7Zjk9tDfpGZFwnyuvdfe9xrrgfwvKNN6jfK9F9TOwDXW7YETeuHrMUtA7urTat_FDMt7a39wonUTU_buhaZRQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1184" data-original-width="1612" height="470" src="https://blogger.googleusercontent.com/img/a/AVvXsEg9KDM3g8CxSEqWPCxSD_FZiSi0YJYbZrIqe9Z_niIUgJ--V-koUhwpm9ytO4peu2xLYOOJmltpTPnNAWlM1E6R825DdoiRYT7Zjk9tDfpGZFwnyuvdfe9xrrgfwvKNN6jfK9F9TOwDXW7YETeuHrMUtA7urTat_FDMt7a39wonUTU_buhaZRQ=w640-h470" width="640" /></a></div><br />And that's it... now when you click the Print button, it will save the record first and next download the document to the browser (and optionally close the dialog of the Form).<p></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1tag:blogger.com,1999:blog-21122514.post-73153422054417448852022-10-11T16:11:00.000+02:002022-10-11T16:11:30.497+02:00No value of a page item when using a Dynamic Action<p>Sometimes you expect to see some data in your <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> application and it's not there<b>.</b>.. in this post I will describe one use case I see more often and how to solve it.</p><p>We have a <b>report</b> which shows all the employees (coming from the EMP table):</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhN2MDfl-GlJtm-0FWX2NDC2FUXpUAk1HTQdjXboYro596vuV4CtW4_YruMKA9tBAAR0ifMFEfKeiJb2IHPTOAyeA_OYkj5Ps1efl6tzyVGqSLBxYtU85HLi6fXNqAUQNNMtwlgyxqryvGQcjCIeGfb02NNpfUb7pQ6TRRgw8E5dc6lX-DLsak" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="724" data-original-width="1640" height="282" src="https://blogger.googleusercontent.com/img/a/AVvXsEhN2MDfl-GlJtm-0FWX2NDC2FUXpUAk1HTQdjXboYro596vuV4CtW4_YruMKA9tBAAR0ifMFEfKeiJb2IHPTOAyeA_OYkj5Ps1efl6tzyVGqSLBxYtU85HLi6fXNqAUQNNMtwlgyxqryvGQcjCIeGfb02NNpfUb7pQ6TRRgw8E5dc6lX-DLsak=w640-h282" width="640" /></a></div><br />Clicking the pencil icon opens up the <b>form</b> of that employee:<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgv4iCRcunWUbL1nwE4RK17klb2azptUvEt5B1tgLtq1aWEjadLpl2WJMC8VFBfw41GMCRkQjec6ChZKqP9YfvZVDXEJwi3QeVeo2m-IB-pwDCEZUJ8cHgdK2GLbHF8YoQk3o4oi_qYiJP13BDqFLDrsAzOPzf9Xpqrdh2L5D-4OA3m8l7Q-Aw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1096" data-original-width="1654" height="424" src="https://blogger.googleusercontent.com/img/a/AVvXsEgv4iCRcunWUbL1nwE4RK17klb2azptUvEt5B1tgLtq1aWEjadLpl2WJMC8VFBfw41GMCRkQjec6ChZKqP9YfvZVDXEJwi3QeVeo2m-IB-pwDCEZUJ8cHgdK2GLbHF8YoQk3o4oi_qYiJP13BDqFLDrsAzOPzf9Xpqrdh2L5D-4OA3m8l7Q-Aw=w640-h424" width="640" /></a></div><br />We added <b>two extra buttons</b>: <p></p><p></p><ul style="text-align: left;"><li>a print icon which creates a document for the employee</li><li>a bug icon which adds 10% of the salary in the commission field</li></ul><p></p><p>Let's first start to see what is behind our <b>Print button.</b> We use the <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a> Dynamic Action to generate a document, but when opening the document it's empty. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEisICu3lOqWSHG-Lhr3ksz10RpYU-m1bqPohXnQS2GZPPl1GFAJ1ao60iebPcNrgkW9vflzsbXXGzdfRmsu7JHIfNGhxcsqCVFCmLHH6CqEvDiKfHyxkg6XgtwcxkxQjq7qgnw9x6nESAqOB0vBr2O2oLVgF7OhmcfG6yvy80-JtY5g1XvMq9I" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1762" data-original-width="2038" height="553" src="https://blogger.googleusercontent.com/img/a/AVvXsEisICu3lOqWSHG-Lhr3ksz10RpYU-m1bqPohXnQS2GZPPl1GFAJ1ao60iebPcNrgkW9vflzsbXXGzdfRmsu7JHIfNGhxcsqCVFCmLHH6CqEvDiKfHyxkg6XgtwcxkxQjq7qgnw9x6nESAqOB0vBr2O2oLVgF7OhmcfG6yvy80-JtY5g1XvMq9I=w640-h553" width="640" /></a></div><br />Behind our <b>Bug button</b> we have a Dynamic Action that fires a process and sets the value of an item when P2_EMPNO is not empty, but for some reason the commission is not being filled in.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiYXrTcRqfce_-Z5us3Dunf8BnqcC2G5z09tRVSWspU5nz8Jt4T0MCBJkP0npPEVqz_6-AogyPk23nhSp-gl9zKzC3QfD4FZBEFRSSS7y25WtjxCtloOXFCqnUZqQiVyEnvXS524V6wWzfkg-SKpyrGMvbb_bPNsZfUsQI5-5uXAehcmtup4bE" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1014" data-original-width="2024" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEiYXrTcRqfce_-Z5us3Dunf8BnqcC2G5z09tRVSWspU5nz8Jt4T0MCBJkP0npPEVqz_6-AogyPk23nhSp-gl9zKzC3QfD4FZBEFRSSS7y25WtjxCtloOXFCqnUZqQiVyEnvXS524V6wWzfkg-SKpyrGMvbb_bPNsZfUsQI5-5uXAehcmtup4bE=w640-h320" width="640" /></a></div></div><p></p><p>In both cases, <b>we don't get the data</b> that we expect to see...</p><p>Whenever you have an issue like this, I turn <b>APEX debug</b> on (see APEX developer toolbar and click Debug > App Trace), click the button again and check my debug output (Debug > View Debug).</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgt3uN8ENPy1jG8TucMmPtNkv3Bzljkj_sm1M5XJ8BvT5srQ4UTs-Cw_WBe872FmPv4QmcJakUdzrcr5XXiv1DLsJSsq7Dq_k-zPRAoyLQDetmvszCD64uHoNogdaV3YDQ3ntOEe7f2MQLqlbSRkLw_BZleIQZ0UNTa8TyACXJXYJTstRgUFZU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="526" data-original-width="1498" height="224" src="https://blogger.googleusercontent.com/img/a/AVvXsEgt3uN8ENPy1jG8TucMmPtNkv3Bzljkj_sm1M5XJ8BvT5srQ4UTs-Cw_WBe872FmPv4QmcJakUdzrcr5XXiv1DLsJSsq7Dq_k-zPRAoyLQDetmvszCD64uHoNogdaV3YDQ3ntOEe7f2MQLqlbSRkLw_BZleIQZ0UNTa8TyACXJXYJTstRgUFZU=w640-h224" width="640" /></a></div><br />This is what I saw in the <b>debug output </b>after clicking the Bug icon:<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgWDAHJPZpB-xd7QO4L3Dh5A4kW71IFQdwv1QZ1NsefmsImwu07JL0YH1ZFMCGV0gZ9ngETRBO86K0MxxICNEqZOl6cUvupY-NVQTUsNjwWv_lzdaM0yV9ruBIIRXRFeWcKo5KR2YHUMhvzvKmCFAzvlhRC9v9uMsRx_vuRUVI8y4rkpvXiAIg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="446" data-original-width="1996" height="144" src="https://blogger.googleusercontent.com/img/a/AVvXsEgWDAHJPZpB-xd7QO4L3Dh5A4kW71IFQdwv1QZ1NsefmsImwu07JL0YH1ZFMCGV0gZ9ngETRBO86K0MxxICNEqZOl6cUvupY-NVQTUsNjwWv_lzdaM0yV9ruBIIRXRFeWcKo5KR2YHUMhvzvKmCFAzvlhRC9v9uMsRx_vuRUVI8y4rkpvXiAIg=w640-h144" width="640" /></a></div><p>We can see that the EMPNO item is empty, so our IF statement in our code is returning false, and the commission is not being calculated.</p><p>By default, APEX puts the primary key column as a hidden item on the page. The following two settings of the item are important: Maintain Session State is set to "Per Request (Memory Only), and Session State Protection is set to "Checksum Required - Session Level".</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjVFoppR3FLZJ8ecbSDB70TYgvut0BPf_BBnaSDex8ORvj4h18v0l3Xy8SbZaqiJkLr7XNoaCc5v3K1xZghjr0rX7ctjlqlJanuD85XN6lCej5je0FcAN84vFh78ZtGD-25_Q0QBsMEQbFlhVu5FL3NajJiMzH0A3U3Arg20V_Hh-iAs9lj71s" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1304" data-original-width="2020" height="414" src="https://blogger.googleusercontent.com/img/a/AVvXsEjVFoppR3FLZJ8ecbSDB70TYgvut0BPf_BBnaSDex8ORvj4h18v0l3Xy8SbZaqiJkLr7XNoaCc5v3K1xZghjr0rX7ctjlqlJanuD85XN6lCej5je0FcAN84vFh78ZtGD-25_Q0QBsMEQbFlhVu5FL3NajJiMzH0A3U3Arg20V_Hh-iAs9lj71s=w640-h414" width="640" /></a></div><br /></div>The error in the debug output was "<b>Access to undefined Per Request (Memory Only) variable P2_EMPNO</b>", which doesn't allow the value of the item to be known in dynamic actions (AJAX requests). One way to solve this is to change the "Maintain Session State" to "<b>Per Session (Disk)</b>". <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgpKAIDYA0mhNNMH3njXllx27Tp4m4jWAJ_EGp4CINOi1ZLHvyOsU8CdVe0tWx_FxNnFKLJzaThPesMWKJYC4poH6oGahUKZuT_ciLvqeElTYAJTRdLyQdKZ3ohhkMKtbgSgUiu-5DVZpCBxYhHN-2-2D9KQVx5UaYhw9mO5WVY0D1ZUY_MKN4" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="604" data-original-width="2030" height="190" src="https://blogger.googleusercontent.com/img/a/AVvXsEgpKAIDYA0mhNNMH3njXllx27Tp4m4jWAJ_EGp4CINOi1ZLHvyOsU8CdVe0tWx_FxNnFKLJzaThPesMWKJYC4poH6oGahUKZuT_ciLvqeElTYAJTRdLyQdKZ3ohhkMKtbgSgUiu-5DVZpCBxYhHN-2-2D9KQVx5UaYhw9mO5WVY0D1ZUY_MKN4=w640-h190" width="640" /></a></div><br /><p></p><p>And now, on the debug output, we see the value of P2_EMPNO being filled in, and the commission is being calculated.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgVR0DyBGJdgu5ZjfpG24j43hEr3Ul8iL_sZBv9uD9WQd-6Y4Q64QgDJeleDLnfNtBem0NrE_2SWUk_XbR3YYzM23uhTq4VerCKdQ39aHcGIax_8yy7Owa5K883SL8pTrrIli8Gg4yUsa1imf1bO10x24e5dy5PeBgGsSUtlKHK1wXBa85vWAc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="436" data-original-width="2000" height="140" src="https://blogger.googleusercontent.com/img/a/AVvXsEgVR0DyBGJdgu5ZjfpG24j43hEr3Ul8iL_sZBv9uD9WQd-6Y4Q64QgDJeleDLnfNtBem0NrE_2SWUk_XbR3YYzM23uhTq4VerCKdQ39aHcGIax_8yy7Owa5K883SL8pTrrIli8Gg4yUsa1imf1bO10x24e5dy5PeBgGsSUtlKHK1wXBa85vWAc=w640-h140" width="640" /></a></div><br />Also, when we Print the document, we now see that the employee is being filled in.<p></p><p><b>Yay! </b>We now see our data! 😀 </p><p>You might wonder why did this solve my issue? When session state is maintained "Per Session" the value is stored in the database and available across requests, whereas when "Per Request" is set, the value is only available during page load.</p><p>An alternative to the above solution is to define in your dynamic action the item you need the value of in "Items to Submit". But with session state protected items, depending on the use case, this might not always work, and you get a checksum error.</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1tag:blogger.com,1999:blog-21122514.post-81326193675571837752022-04-04T00:09:00.000+02:002022-04-04T00:09:23.075+02:00Export multiple tables to one Excel with different sheets in Oracle APEX<p>Today there was a question on how to export data from the <a href="https://www.oracle.com/database/" target="_blank">Oracle Database</a> and <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> into one Excel file with multiple sheets. Each sheet contains data from a different table.</p><p>With <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print</a> it's a matter of a few minutes to fulfill this request 😀</p><p>If you have never heard of APEX Office Print (AOP), here's one paragraph on it. AOP is the easiest to use product/plug-in that fully integrates with Oracle APEX to give you all the reporting and export functionality you've dreamed of. You create templates in Word, Excel, PowerPoint, HTML, or Text and AOP will merge it with the data coming from your database, APEX components, or REST Web Service and return a document to you in the output format of your choice (PDF, Word, Excel, PowerPoint, HTML, Text). If you want to get started with AOP, here's a quick <a href="https://www.youtube.com/watch?v=HJtd9Aw3zD4" target="_blank">Getting Started with AOP video</a>.</p><p>Let's get back to this example where we want to generate a single Excel file, with multiple sheets and each sheet contains data from a different table.</p><p><br /></p><p><b>Step 1: Prepare your SQL statement.</b></p><p>In this example, we want to export the data coming from our customers, products, and orders table.<br />AOP understands the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CURSOR-Expressions.html" target="_blank">CURSOR Expressions</a> of SQL. Each cursor will contain the columns of the different tables. You can have as many cursors as you want, look at them as blocks of data.</p><p><span style="font-family: courier;">select<br /></span><span style="font-family: courier;"> 'file1' as "filename", <br /></span><span style="font-family: courier;"> cursor(<br /></span><span style="font-family: courier;"> select <br /></span><span style="font-family: courier;"> cursor(<br /></span><span style="font-family: courier;"> select<br /></span><span style="font-family: courier;"> cust_first_name,<br /></span><span style="font-family: courier;"> cust_last_name,<br /></span><span style="font-family: courier;"> cust_city<br /></span><span style="font-family: courier;"> from aop_sample_customers) as "customers"<br /></span><span style="font-family: courier;"> , cursor(<br /></span><span style="font-family: courier;"> select <br /></span><span style="font-family: courier;"> order_id, <br /></span><span style="font-family: courier;"> order_total <br /></span><span style="font-family: courier;"> from aop_sample_orders) as "orders"<br /></span><span style="font-family: courier;"> , cursor(<br /></span><span style="font-family: courier;"> select <br /></span><span style="font-family: courier;"> product_name, <br /></span><span style="font-family: courier;"> product_description,<br /></span><span style="font-family: courier;"> category,<br /></span><span style="font-family: courier;"> product_avail,<br /></span><span style="font-family: courier;"> list_price<br /></span><span style="font-family: courier;"> from aop_sample_product_info) "product"<br /></span><span style="font-family: courier;"> from dual) as "data"<br /></span><span style="font-family: courier;">from dual</span></p><p>Note that with the cursor expression you can also create more nested data (as seen in the AOP Sample App on page 30). For example, if you want to see all orders and order lines of a specific customer, your SQL statement would look like this:</p><p><span style="font-family: courier;">select<br /></span><span style="font-family: courier;"> 'file1' as "filename", <br /></span><span style="font-family: courier;"> cursor(<br /></span><span style="font-family: courier;"> select<br /></span><span style="font-family: courier;"> c.cust_first_name as "cust_first_name",<br /></span><span style="font-family: courier;"> c.cust_last_name as "cust_last_name",<br /></span><span style="font-family: courier;"> c.cust_city as "cust_city",<br /></span><span style="font-family: courier;"> cursor(select o.order_total as "order_total", <br /></span><span style="font-family: courier;"> 'Order ' || rownum as "order_name",<br /></span><span style="font-family: courier;"> cursor(select p.product_name as "product_name", <br /></span><span style="font-family: courier;"> i.quantity as "quantity",<br /></span><span style="font-family: courier;"> i.unit_price as "unit_price" <br /></span><span style="font-family: courier;"> from aop_sample_order_items i, <br /> aop_sample_product_info p<br /></span><span style="font-family: courier;"> where o.order_id = i.order_id<br /></span><span style="font-family: courier;"> and i.product_id = p.product_id<br /></span><span style="font-family: courier;"> ) "product"<br /></span><span style="font-family: courier;"> from aop_sample_orders o<br /></span><span style="font-family: courier;"> where c.customer_id = o.customer_id<br /></span><span style="font-family: courier;"> ) "orders"<br /></span><span style="font-family: courier;"> from aop_sample_customers c<br /></span><span style="font-family: courier;"> where customer_id = :CUSTOMER_ID<br /></span><span style="font-family: courier;"> ) as "data"<br /></span><span style="font-family: courier;">from dual</span></p><p>So you can add the CURSOR() expressions on the same level as well as in a hierarchy.</p><p>Now that we understand this, let's get back to our example, where we wanted to export the data from the SQL statement to different sheets in Excel.</p><p><br /></p><p><b>Step 2: Create your Excel template</b></p><p>There are a few ways to create your own template:</p><p></p><ul style="text-align: left;"><li>You can start from a new empty Excel document,</li><li>or you can start from a template of your company (e.g. with the logo and some house branding),</li><li>or you can download a template you like from <a href="https://templates.office.com/en-us/templates-for-excel" target="_blank">Microsoft's Excel template</a> repository,</li><li>or you can let AOP generate a starter template for you.</li></ul><div>We will use the last option. Nothing easier than letting AOP create a template for us!</div><p></p><p>AOP has a PL/SQL API or an Oracle APEX plug-in you can use. In this example, we will use the plug-in. I won't go over how to install the Oracle APEX plug-in, you can find that in the <a href="https://www.youtube.com/watch?v=HJtd9Aw3zD4" target="_blank">getting started video</a>.</p><p>So, on our Oracle APEX page, we create a button and a dynamic action calling the APEX Office Print plug-in. We specify that we want an AOP Template, we add the SQL statement as the data source, and select an Excel file as the output type. Here's what it looks like in Oracle APEX:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhhEZP-8ibOi2wOm8rdhP6eqrkrdgss8hhlVu7KwQhQ-hyDBYsGZzGXWGossiX3oj8H4QG861azVz4By3Fjaecl-mPgHSsDTA64t9zZivUB5vKv2ypZE8hBdXRxXOytwMJklt6Wprdn4Qfu3bjg6EMoA3MckdEw7x2EFbJ7P3Wu6DlWAoTLPvc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1816" data-original-width="3014" height="386" src="https://blogger.googleusercontent.com/img/a/AVvXsEhhEZP-8ibOi2wOm8rdhP6eqrkrdgss8hhlVu7KwQhQ-hyDBYsGZzGXWGossiX3oj8H4QG861azVz4By3Fjaecl-mPgHSsDTA64t9zZivUB5vKv2ypZE8hBdXRxXOytwMJklt6Wprdn4Qfu3bjg6EMoA3MckdEw7x2EFbJ7P3Wu6DlWAoTLPvc=w640-h386" width="640" /></a></div><br />When clicking the button, this is the Excel file AOP generated:<div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiqVC8vRapwIfYaoZ0X3BgLsCYC7m063nbdnTQuKrQQBeovheHvzE8zetlhALOhYYqKw9YVO7yqISwqEkrFFX8RwH1_QaUcKzV5WBffVyNG1Sd25WLzaqwv44pJyTkMUo-bY5mErzbO2bZYDSKq2DuSNwxNV1EhVd3b4Yau1NFl1ipxFXADAic" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1754" data-original-width="2158" height="521" src="https://blogger.googleusercontent.com/img/a/AVvXsEiqVC8vRapwIfYaoZ0X3BgLsCYC7m063nbdnTQuKrQQBeovheHvzE8zetlhALOhYYqKw9YVO7yqISwqEkrFFX8RwH1_QaUcKzV5WBffVyNG1Sd25WLzaqwv44pJyTkMUo-bY5mErzbO2bZYDSKq2DuSNwxNV1EhVd3b4Yau1NFl1ipxFXADAic=w640-h521" width="640" /></a></div><br /></div><div>The AOP template will add the tags (see lines 4, 7, and 10 between {}) for the data you specified in the SQL file, and give some more explanations below to explain what is possible with AOP. For example, AOP can also generate sheets or use formulas dynamically.<br /><br />To finish our template, the only thing we need to do is to copy lines 7 and 10 and put them on their own sheets. Finally, we customize the template exactly as we want. For example, we can give it a header, make some tags bold and make it really pretty with our company logo.<br /><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjJIlsi4ADqYvDajv_eK374YrPUCU4U9Kdv6ol6HyTRPu-JhjtiekMK0YQx6xLF0HkBk_xVtS7rTdKZvqQPWivnv3bcAobGjLGlC5g-chz1CtRjjpLV-lc3ZFaLzl3eGUk6S8tHDz2I0Hq4qGWkp8RAV0-p-QROvJh758-YbkYWiGm6SrkQYzA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="956" data-original-width="1940" height="316" src="https://blogger.googleusercontent.com/img/a/AVvXsEjJIlsi4ADqYvDajv_eK374YrPUCU4U9Kdv6ol6HyTRPu-JhjtiekMK0YQx6xLF0HkBk_xVtS7rTdKZvqQPWivnv3bcAobGjLGlC5g-chz1CtRjjpLV-lc3ZFaLzl3eGUk6S8tHDz2I0Hq4qGWkp8RAV0-p-QROvJh758-YbkYWiGm6SrkQYzA=w640-h316" width="640" /></a></div><br />Once we are happy with our template, let's upload it to Static Application Files in our app. Note: you can store the template in your own table, the filesystem, online, anywhere that AOP can access.<p></p><p><br /></p><p><b>Step 3: Specify the template and Done!</b></p><p>Finally, specify the new template in the AOP Dynamic Action. The Template Type is Static Application Files and the Template Source is the filename.</p><p></p><p></p><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgPTP1ks8FULH-XLBdllljKpDaqj__WJcjfDBeyqyZ1_lnkwbY0ImLqNVyATbb2JWXJ695xdbF-3jaqj66-dlpJxyKUQ9mwGai_JoDAcOAOtaSl0rL9ebe86DEjrHbEofUQQz18xaovZqhEgMZkZAT6p0vVee2gKgvbCCJFpZYeOMCMMXL5HEE" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1778" data-original-width="3020" height="376" src="https://blogger.googleusercontent.com/img/a/AVvXsEgPTP1ks8FULH-XLBdllljKpDaqj__WJcjfDBeyqyZ1_lnkwbY0ImLqNVyATbb2JWXJ695xdbF-3jaqj66-dlpJxyKUQ9mwGai_JoDAcOAOtaSl0rL9ebe86DEjrHbEofUQQz18xaovZqhEgMZkZAT6p0vVee2gKgvbCCJFpZYeOMCMMXL5HEE=w640-h376" style="cursor: move;" width="640" /></a></div><p>And presto, you are done! Click your Excel button again and here's the output:</p><p></p></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiPZrxwX9vsHhDQ9vjzlmARqS-lH46HjBExE7xEMz9iFKG8RFmSkxflbS6xP8zvFSYNrL0L1E3GMUxPGqebVUzj-xBIm60xlhFfJ1k_L8KdyL_9muqEYybfouKqqCUKaaDmumdvRgYz_sEknuehFcfK91CArfR372_aqkPYUl0Qmrw0onDPpX0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1174" data-original-width="1944" height="386" src="https://blogger.googleusercontent.com/img/a/AVvXsEiPZrxwX9vsHhDQ9vjzlmARqS-lH46HjBExE7xEMz9iFKG8RFmSkxflbS6xP8zvFSYNrL0L1E3GMUxPGqebVUzj-xBIm60xlhFfJ1k_L8KdyL_9muqEYybfouKqqCUKaaDmumdvRgYz_sEknuehFcfK91CArfR372_aqkPYUl0Qmrw0onDPpX0=w640-h386" width="640" /></a></div><br /><p>So any time you need to create a report in Excel with data coming from Oracle APEX or the database, you know you can do it with <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a>! 😁</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1tag:blogger.com,1999:blog-21122514.post-32169352727816219942021-11-08T21:22:00.004+01:002021-11-08T21:22:48.507+01:00Oracle APEX 21.2: some things to unlearn<p>A few days ago <a href="https://apex.oracle.com" target="_blank">Oracle Application Express (APEX) 21.2</a> was released. You can now upgrade your own environment with this new release. </p><p>With every new release, it's important to look at the <a href="https://docs.oracle.com/en/database/oracle/application-express/21.2/htmrn/index.html" target="_blank">Release Notes</a>. One section I'm particularly interested in is the <a href="https://docs.oracle.com/en/database/oracle/application-express/21.2/htmrn/index.html#HTMRN-GUID-657FF369-756E-4F31-96F9-B2D92C3DE084" target="_blank">Deprecated Features</a>. Features listed in this section will still work, but sometimes in the future it might not, so it's a good time to start unlearning to use those features. Typically these features are not really necessary anymore or got replaced by something else, but it also occurs that some things get changed over time to make things more consistent or logical for new people.</p><p>One deprecated feature in APEX 21.2 got my intention... The use of the following substitution strings <b><span style="color: red;">#APP_IMAGES#</span></b> and #IMAGE_PREFIX# should from now on be avoided. Instead, make use of <b><span style="color: #38761d;">#APP_FILES#</span></b> and #APEX_FILES#. Here's a complete list of substitution strings that should not be used anymore:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-okBxoNpq954/YYmGV6SF53I/AAAAAAAALic/CE5iTcpYQVcbHWpELwc8K3-87yTw9DEEgCLcBGAsYHQ/s1098/Screenshot%2B2021-11-08%2Bat%2B19.53.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="498" data-original-width="1098" height="290" src="https://1.bp.blogspot.com/-okBxoNpq954/YYmGV6SF53I/AAAAAAAALic/CE5iTcpYQVcbHWpELwc8K3-87yTw9DEEgCLcBGAsYHQ/w640-h290/Screenshot%2B2021-11-08%2Bat%2B19.53.09.png" width="640" /></a></div><p>I will need to get used to not using #APP_IMAGES# anymore, as I used that from time to time when constructing a URL for a file in Static Application Files. </p><p>Another deprecated feature is some region positions like After Header and Before Footer, next to Body 1, Body 2, and 3.</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com2tag:blogger.com,1999:blog-21122514.post-72415579600464299812021-10-11T17:07:00.002+02:002021-10-11T17:07:47.909+02:00Oracle APEX Support from 5 years to 3 years #JoelKallmanDay<p>If you are still running <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> 5.1, it might be time to schedule an upgrade. Support is running out at the end of the year. </p><p>Does it mean you can't use Oracle APEX 5.1 after December 2011? No, not at all, if you have no need to upgrade, and all is running smoothly, it's fine... you just can't request a patch anymore.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fRUVqBbj5LA/YWQXEjq5ZaI/AAAAAAAALh0/ZSjaTsYWPMQAob7MWiGGtYX2RHq7kbsMQCLcBGAsYHQ/s1604/Screenshot%2B2021-10-11%2Bat%2B12.49.32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="902" data-original-width="1604" height="360" src="https://1.bp.blogspot.com/-fRUVqBbj5LA/YWQXEjq5ZaI/AAAAAAAALh0/ZSjaTsYWPMQAob7MWiGGtYX2RHq7kbsMQCLcBGAsYHQ/w640-h360/Screenshot%2B2021-10-11%2Bat%2B12.49.32.png" width="640" /></a></div><br /><p></p><p>Till the 20.2 release you could stay on an APEX release for 5 years, but that has changed since the 21.1 release. Oracle announced it will reduce the support for an APEX version from 5 years to 3 years. </p><p>As Oracle APEX is a web development tool and things change so fast on the internet, I would recommend upgrading faster than every 5 years anyway. From a security and browser/mobile compatibility point of view, upgrading makes all the sense. Having said that, if you run an app internally and don't upgrade browsers within your company, I can understand if you just keep what you have and don't want the hassle of upgrading. Upgrading Oracle APEX is typically a breeze, but still testing is required and some things might behave slightly different or became deprecated.</p><p>At <a href="https://www.united-codes.com" target="_blank">United Codes</a> we keep 3 instances on our main server: Oracle APEX 18.1, 19.2, and the latest version of APEX, to which we upgrade very fast. The 18.1 release we use as a base for most APEX <a href="https://www.plug-ins-pro.com" target="_blank">plug-in development</a>, unless we need some specific plug-in features for which we need to use 19.2 (e.g. for IG support). </p><p>With <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print</a> we try to support all features of APEX, e.g. when the new maps component came out, we made it so you can include it in your documents. So for that development, it's crucial to stay on top of the game. To most of our customers, I give the advice to wait for the first or second patchset, depending on our own findings.</p><p>I wrote this post for <a href="https://oracle-base.com/blog/2021/10/04/joel-kallman-day-announcement/" target="_blank">Joel Kallman Day</a>, a day we push out content as a community and try to generate a bit of buzz.</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com2tag:blogger.com,1999:blog-21122514.post-17393158800228414252021-07-24T23:57:00.000+02:002021-07-24T23:57:07.529+02:00Hiding spinning icon in APEX 21.1 Modal DialogAn AOP customer wrote us that when opening a PDF in a Modal Dialog the spinning icon didn't disappear automatically anymore in <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> 21.1, whereas it did before. <div><br /></div><div>I created a use case but saw it not only affects the AOP process but any file you want to open in the Modal Dialog. With previous versions of APEX, this didn't happen, but with APEX 21.1 the Modal Dialog keeps showing the spinning icon.</div><div><div><br /></div><div>Here's an animated gif that shows the use case:<br /><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-1cFBD8Dv8xc/YPxrmAkd7JI/AAAAAAAALgU/BRtAbye7Od8ChJNkU5xtOxvifhmg9-fqQCLcBGAsYHQ/s1280/apex211_modal_spinning.gif" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="720" data-original-width="1280" src="https://1.bp.blogspot.com/-1cFBD8Dv8xc/YPxrmAkd7JI/AAAAAAAALgU/BRtAbye7Od8ChJNkU5xtOxvifhmg9-fqQCLcBGAsYHQ/s600/apex211_modal_spinning.gif" width="600" /></a></div>I created two use cases; both buttons redirect to a modal page in the app.</div></div><div><br /></div><div>On the modal page behind the "View File" button, there's a before header process which gets a BLOB (PDF) from the database and displays it inline.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6SPR0xeB94Y/YPx1k6QdcJI/AAAAAAAALgg/Wg0gcIk9XiQE4jGHcURfhD-X4pBGqEQDACLcBGAsYHQ/s2539/Screenshot%2B2021-07-24%2Bat%2B22.11.51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1238" data-original-width="2539" height="312" src="https://1.bp.blogspot.com/-6SPR0xeB94Y/YPx1k6QdcJI/AAAAAAAALgg/Wg0gcIk9XiQE4jGHcURfhD-X4pBGqEQDACLcBGAsYHQ/w640-h312/Screenshot%2B2021-07-24%2Bat%2B22.11.51.png" width="640" /></a></div><div><br /></div>On the modal page behind the "AOP Modal" button, there's a before header AOP process which generates a PDF of a classic report on the fly.<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-kWZJiymlGrk/YPx1kxlp94I/AAAAAAAALgc/p0V6Lm4BnxQ1VRo3bGkkGanNRknG4wr2ACLcBGAsYHQ/s2048/Screenshot%2B2021-07-24%2Bat%2B22.12.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1114" data-original-width="2048" height="348" src="https://1.bp.blogspot.com/-kWZJiymlGrk/YPx1kxlp94I/AAAAAAAALgc/p0V6Lm4BnxQ1VRo3bGkkGanNRknG4wr2ACLcBGAsYHQ/w640-h348/Screenshot%2B2021-07-24%2Bat%2B22.12.22.png" width="640" /></a></div><br /><div>To work around the issue, I added a dynamic action on the page where the buttons are defined; on click of the button, it will execute the following JavaScript code:</div></div><div><br /></div><div><div><code><span style="font-family: courier;">setTimeout(function(){ </span></code></div><div><span style="font-family: courier;"> $('.ui-dialog--apex.t-Dialog-page--standard .ui-dialog-content').addClass('js-dialogReady'); </span></div><div><span style="font-family: courier;">}, 2000);</span></div></div><div><br /></div><div>After waiting 2000 milliseconds (2 seconds) it will add the js-dialogReady CSS class, which tells the icon to hide.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-3TF8inrarDc/YPyLhRMeF4I/AAAAAAAALgo/dEfxL_wdg4EUHPEbrqlGrbjQAia5AMdYwCLcBGAsYHQ/s2048/Screenshot%2B2021-07-24%2Bat%2B23.51.51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1425" data-original-width="2048" height="446" src="https://1.bp.blogspot.com/-3TF8inrarDc/YPyLhRMeF4I/AAAAAAAALgo/dEfxL_wdg4EUHPEbrqlGrbjQAia5AMdYwCLcBGAsYHQ/w640-h446/Screenshot%2B2021-07-24%2Bat%2B23.51.51.png" width="640" /></a></div><br /><div>Hope it will help you in case you need to remove the spinning icon from your modal dialog.</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com0tag:blogger.com,1999:blog-21122514.post-18594564288880235902021-06-08T19:02:00.001+02:002021-06-08T19:33:38.356+02:00Have extra EURO 2020 fun with this Oracle APEX app<p>For the last 15 years, with every big football tournament (World Cup and Euro Cup), we've launched an <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> app where you can predict the scores of the games. You can find this year's app at <a href="https://euro2020.unitedcodes.com">https://euro2020.unitedcodes.com</a></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeHXTv4KBhgidiBRfARsBo9T0gLPbnVH4oTitFwABKopn0eMaO_mLSMUPy0UD0kpleEKEZWkgL82eev4E3k37LxXzQ1Ex88W8beIXZrAkPOwzrxxjB1NjXUqmZr0af4Yi9IE390w/s2048/Screenshot+2021-06-06+at+23.02.26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1482" data-original-width="2048" height="464" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeHXTv4KBhgidiBRfARsBo9T0gLPbnVH4oTitFwABKopn0eMaO_mLSMUPy0UD0kpleEKEZWkgL82eev4E3k37LxXzQ1Ex88W8beIXZrAkPOwzrxxjB1NjXUqmZr0af4Yi9IE390w/w640-h464/Screenshot+2021-06-06+at+23.02.26.png" width="640" /></a></div><p><b>Features</b></p><p>Many people do a challenge with their friends or company, for fun, for money... Instead of using a custom-made Excel, use of email, or use of paper, you can use the Euro 2020 Challenge site to track who's in the lead.</p><p></p><ul style="text-align: left;"><li>You can enter the scores of every game and see how well your predictions compare to others (overall).</li><li>You can create a group e.g. your company, or a team, etc and see how well you play within your group.</li><li>You can see statistics of predictions</li></ul><p></p><p><b>History</b></p><p>15 years ago, I built a site to promote the use of Oracle APEX. People loved it, so I decided to update the site with every new release of APEX. You can find some more history and screenshots of how the app looked <a href="https://euro2020.unitedcodes.com/ords/f?p=636:HISTORY:0" target="_blank">here</a>. Not that many changes have been done compared to the app from 2018, but this year it runs on Oracle APEX 21.1, so it shows that upgrading APEX apps is smooth.</p><p><b>Oracle APEX features</b></p><p>When upgrading to the new Oracle APEX version, the Advisor and Upgrade assistant were run. Some plug-ins (e.g. select2) got replaced by built-in features (e.g. Inline Pop-up). Most changes were done in the Admin section, where tabular forms were replaced by Interactive Grids, native Forms regions are now being used, and other parts that showed up in the upgrade assistant were applied.</p><p>Social authentication was updated, so you can sign-up and log in with Email, Facebook or Google.</p><p>Normally with an upgrade, we also update the Universal Theme version, but as it's using a custom theme we didn't do it for this app.</p><p><b>Go and play!</b></p><p>So, now head to the site/app and <a href="https://euro2020.unitedcodes.com" target="_blank">start challenging your friends</a>!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-le6aHYp1Tk0/YL066aFOEiI/AAAAAAAALc8/juY65oY1peYtxLYvr5yEuOutlz3vluRIgCLcBGAsYHQ/s2048/Screenshot%2B2021-06-06%2Bat%2B23.15.00.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1051" data-original-width="2048" height="328" src="https://1.bp.blogspot.com/-le6aHYp1Tk0/YL066aFOEiI/AAAAAAAALc8/juY65oY1peYtxLYvr5yEuOutlz3vluRIgCLcBGAsYHQ/w640-h328/Screenshot%2B2021-06-06%2Bat%2B23.15.00.png" width="640" /></a></div><br /><p>Good luck!</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com3tag:blogger.com,1999:blog-21122514.post-57522226245094152382021-06-05T12:03:00.000+02:002021-06-05T12:03:09.912+02:00Upgrading Oracle APEX has never been easier<p>On May 12th <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> 21.1 was released. </p><p>This post is not about why Oracle APEX 21.1 is worth an upgrade. You can see for yourself if you like the improvements in the <a href="https://docs.oracle.com/en/database/oracle/application-express/21.1/htmrn/index.html#HTMRN-GUID-540B73CB-08A7-4422-B6BF-CC785EC47694" target="_blank">Release Notes</a>. Some companies upgrade once a year, some wait for the patch set bundle, and some upgrade very fast. </p><p>We upgraded our production instance this weekend. I <a href="https://dgielis.blogspot.com/2020/11/my-steps-to-upgrade-to-oracle-apex-202.html" target="_blank">blogged</a> about how we do the upgrades and try to minimize downtime in the past. But <b>upgrades have become even easier</b>!</p><p><b>While the Oracle APEX kept running; 15 minutes install which of 5 minutes downtime, and we were done!</b></p><p>Note: it's always good to read the <a href="https://docs.oracle.com/en/database/oracle/application-express/21.1/htmig/downloading-installing-apex.html" target="_blank">installation guide</a>. </p><p>Below what we did: </p><p></p><ol style="text-align: left;"><li><a href="https://www.oracle.com/tools/downloads/apex-downloads.html" target="_blank">Download Oracle APEX</a></li><li>Unzip</li><li>Go into the directory </li><li>Connect to the Oracle Database with SQLcl or SQLPlus </li><li>Run 1 command:</li></ol><div><pre class="oac_no_warn" dir="ltr" style="background-color: white; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 2px solid rgb(222, 218, 214); box-sizing: border-box; caret-color: rgb(26, 24, 22); color: #1a1816; font-family: "Courier New", Courier, monospace; font-size: 16px; font-stretch: normal; line-height: 1.44; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 18px 18px 18px 20px; word-break: normal; word-wrap: normal;" tabindex="0"><div style="box-sizing: border-box; display: inline-block;">@apexins.sql SYSAUX SYSAUX TEMP /i/</div></pre></div><p></p><div class="separator" style="clear: both; text-align: left;">That was it! ... the installation did everything for us... and again this was in a live environment!</div><div class="separator" style="clear: both; text-align: left;">ORDS knows now that an APEX install is busy and suspends traffic for a certain time and next it comes up again:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Phase 1: no downtime</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-nDhs1AsXPDY/YLtGQoTE5zI/AAAAAAAALcU/6BSSdNawRDknPYRU2KTaYmT7G8Em196jQCLcBGAsYHQ/s1420/apex_phase1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1092" data-original-width="1420" height="492" src="https://1.bp.blogspot.com/-nDhs1AsXPDY/YLtGQoTE5zI/AAAAAAAALcU/6BSSdNawRDknPYRU2KTaYmT7G8Em196jQCLcBGAsYHQ/w640-h492/apex_phase1.png" width="640" /></a></div><div><br /></div>Phase 2 and 3: small downtime during phase 3 switch:<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-GXHZX9qSgFM/YLtGQIKTW8I/AAAAAAAALcQ/t2yoJ3l-Eo0TyWXoe0eIYNNpRSr24UNdQCLcBGAsYHQ/s1662/apex_phase2_3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1100" data-original-width="1662" height="424" src="https://1.bp.blogspot.com/-GXHZX9qSgFM/YLtGQIKTW8I/AAAAAAAALcQ/t2yoJ3l-Eo0TyWXoe0eIYNNpRSr24UNdQCLcBGAsYHQ/w640-h424/apex_phase2_3.png" width="640" /></a></div><div><br /></div><div>And done:</div><div><br /></div><a href="https://1.bp.blogspot.com/-hQO7fLn1neQ/YLtGQhAnLtI/AAAAAAAALcY/xGBLHX2KvcAiGN3wZ6r0I3nQ01W8lTFmwCLcBGAsYHQ/s1574/apex_done.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1540" data-original-width="1574" height="626" src="https://1.bp.blogspot.com/-hQO7fLn1neQ/YLtGQhAnLtI/AAAAAAAALcY/xGBLHX2KvcAiGN3wZ6r0I3nQ01W8lTFmwCLcBGAsYHQ/w640-h626/apex_done.png" width="640" /></a><div><br /></div><div>During Phase 3 downtime, I copied the new images folder.</div><div><br /></div><div>I believe it wasn't really necessary as everything was working, but I did run the ORDS validate after the APEX install just to check it (while ORDS was still running):</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-THsWMSHClnY/YLtGQ-2GOBI/AAAAAAAALcc/8YdelyAy770QG-g_ZPwj3QhimHA09_XewCLcBGAsYHQ/s1462/ords_validate.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="718" data-original-width="1462" height="314" src="https://1.bp.blogspot.com/-THsWMSHClnY/YLtGQ-2GOBI/AAAAAAAALcc/8YdelyAy770QG-g_ZPwj3QhimHA09_XewCLcBGAsYHQ/w640-h314/ords_validate.png" width="640" /></a></div><div><br /></div>And the proof of the max 5 minutes downtime:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZIH0X_aDTcE/YLtJq7SBADI/AAAAAAAALcs/vjMUy2ydmOofRMtb9tqpVYBjMkghNZCOQCLcBGAsYHQ/s730/Screenshot%2B2021-06-05%2Bat%2B11.53.20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="324" data-original-width="730" src="https://1.bp.blogspot.com/-ZIH0X_aDTcE/YLtJq7SBADI/AAAAAAAALcs/vjMUy2ydmOofRMtb9tqpVYBjMkghNZCOQCLcBGAsYHQ/s320/Screenshot%2B2021-06-05%2Bat%2B11.53.20.png" width="320" /></a></div><br /><div>I'm really impressed by the install and upgrade, it's basically an autonomous process these days 😀 </div></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com20tag:blogger.com,1999:blog-21122514.post-50627353025866430012021-05-31T16:20:00.002+02:002021-05-31T16:30:23.118+02:00In memory of Joel Kallman<p>On May 26th, now a few days ago, the world stood still for a moment for me. When I read that Joel passed away, I didn't know how to deal with it. If it's already hard for me, what about his family and the APEX team... it was a storm in the whole Oracle APEX community, and all of us were shocked and wish his close family and friends the most support.</p><p>It just hurts as Joel was such an amazing person, both on a personal level and professionally. I don't know anybody else who's so unselfish, understanding, and approachable as Joel. He was a great person all-around. </p><p>After <a href="https://dgielis.blogspot.com/2008/10/why-oh-why-great-friend-amazing-apex.html" target="_blank">Carl</a> and <a href="https://dgielis.blogspot.com/2010/03/in-memory-of-scott-spadafore.html" target="_blank">Scott</a>, it's the 3rd person who leaves my Oracle APEX family too soon.</p><p>Joel was employee number 1 of Mike Hichwa, and they both created and supported APEX from day 1. </p><p>The moment I saw APEX (HTMLDB) it was love at first sight. I became passionate about this great Low Code Development Tool! When I wrote the World Cup Challenge in 2006, to promote what you could do with <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a>, Joel was one of the first to reply to my <a href="https://dgielis.blogspot.com/2006/05/world-cup-2006-score-in-apex.html " target="_blank">blog post</a>.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-dFiaf5XJRUk/YLTUfl4W6NI/AAAAAAAALbw/fGE-lyNkpXg9azOj-vsw6nGXRwKjOcB1wCLcBGAsYHQ/Screenshot%2B2021-05-31%2Bat%2B14.04.56.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="188" data-original-width="1272" height="94" src="https://lh3.googleusercontent.com/-dFiaf5XJRUk/YLTUfl4W6NI/AAAAAAAALbw/fGE-lyNkpXg9azOj-vsw6nGXRwKjOcB1wCLcBGAsYHQ/w640-h94/Screenshot%2B2021-05-31%2Bat%2B14.04.56.png" width="640" /></a></div><br />Later on that year <a href="https://dgielis.blogspot.com/2006/10/oow-tuesday-sessions-blogger-meetup.html" target="_blank">I followed his session</a> at Oracle Open World "<strong style="caret-color: rgb(25, 25, 25); color: #191919; font-family: Verdana, sans-serif; font-size: 12px;">Building Real-World Solutions with Oracle Application Express" </strong><p></p><p><strong style="caret-color: rgb(25, 25, 25); color: #191919; font-family: Verdana, sans-serif; font-size: 12px;"></strong></p><div class="separator" style="clear: both; text-align: center;"><strong style="caret-color: rgb(25, 25, 25); color: #191919; font-family: Verdana, sans-serif; font-size: 12px;"><a href="https://lh3.googleusercontent.com/-spu3vMmi5Tc/YLTIvguIZuI/AAAAAAAALbE/uqkVbU4qcvUFxpwzFD0oZ6MenFxpQ0gxgCLcBGAsYHQ/joel_giovanni-1.jpg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="480" src="https://lh3.googleusercontent.com/-spu3vMmi5Tc/YLTIvguIZuI/AAAAAAAALbE/uqkVbU4qcvUFxpwzFD0oZ6MenFxpQ0gxgCLcBGAsYHQ/w640-h480/joel_giovanni-1.jpg" width="640" /></a></strong></div><p></p><p>That Oracle Open World was legendary, as we held the <a href="https://dgielis.blogspot.com/2006/10/oow-wednesday-sessions-and-apex-meetup.html" target="_blank">first-ever Oracle APEX Meetup</a> <br /></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><a href="https://lh3.googleusercontent.com/-vGggwnH7rrc/YLTIjrHVKOI/AAAAAAAALa4/FivZ3yJuyWcUx3_kzBL2fvYbRiBe3pdbACLcBGAsYHQ/apex_meetup-1.jpg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="480" src="https://lh3.googleusercontent.com/-vGggwnH7rrc/YLTIjrHVKOI/AAAAAAAALa4/FivZ3yJuyWcUx3_kzBL2fvYbRiBe3pdbACLcBGAsYHQ/w640-h480/apex_meetup-1.jpg" width="640" /></a></div></div><p>I reread that post, and already back then I wrote: <b>"One thing is sure: Michael Hichwa and Joel Kallman really want to support us!" </b></p><div class="separator" style="clear: both; text-align: left;">And boy they did... Joel became the face of our community, a true leader.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Many more conferences followed, where APEX presentations were always successful. Kscope became a special place where not only the APEX content was at an exceptional level, it was also the place where many people from the APEX Dev team came together and mingled with the community. Not only was everybody very accessible during the conferences, even during the evening activities and parties we had so much fun, and<b> Joel went always "all-in"</b>! From serious conversations to just laughs and playing poker.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-hLmL9j5IGmI/YLTLbLlNAcI/AAAAAAAALbQ/kl_ws5p91V4fI-5buWPIAmkklkZruE11QCLcBGAsYHQ/IMG_0698.JPG" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="2048" data-original-width="1536" height="640" src="https://lh3.googleusercontent.com/-hLmL9j5IGmI/YLTLbLlNAcI/AAAAAAAALbQ/kl_ws5p91V4fI-5buWPIAmkklkZruE11QCLcBGAsYHQ/w480-h640/IMG_0698.JPG" width="480" /></a></div><p></p><p>In 2014, after a difficult time for me, I had a really nice chat with Joel. He told me he would pray for me and I will never forget his support.</p><p><span face="Trebuchet MS, Trebuchet, Verdana, sans-serif" style="color: #666666; font-size: x-small;"><span style="background-color: white; caret-color: rgb(102, 102, 102);"></span></span></p><div class="separator" style="clear: both; text-align: center;"><span face="Trebuchet MS, Trebuchet, Verdana, sans-serif" style="color: #666666; font-size: x-small;"><a href="https://lh3.googleusercontent.com/-7o7Ek8Y0FD8/YLTP_EhVzPI/AAAAAAAALbo/HL_2xo0HIh0Fv-3bgPVpN6gonkgLInz9QCLcBGAsYHQ/SpaceNeedle_Seattle-2135313-5619891-642-H.jpg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1365" data-original-width="2048" height="426" src="https://lh3.googleusercontent.com/-7o7Ek8Y0FD8/YLTP_EhVzPI/AAAAAAAALbo/HL_2xo0HIh0Fv-3bgPVpN6gonkgLInz9QCLcBGAsYHQ/w640-h426/SpaceNeedle_Seattle-2135313-5619891-642-H.jpg" width="640" /></a></span></div><p>I appreciate Joel tremendously both on a personal as professional level. He helped so many people, including me. Did you know that Joel, single handedly installed <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print</a> at Oracle in 2016? He supported us in many ways, I can not thank him enough.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-Cj-xuItiyVg/YLTr3fSNx_I/AAAAAAAALcI/dejbejk7M_sC7_6jjkSYLdba-iPJFxgAwCLcBGAsYHQ/joel_aop.jpg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="477" data-original-width="358" height="640" src="https://lh3.googleusercontent.com/-Cj-xuItiyVg/YLTr3fSNx_I/AAAAAAAALcI/dejbejk7M_sC7_6jjkSYLdba-iPJFxgAwCLcBGAsYHQ/w480-h640/joel_aop.jpg" width="480" /></a></div><br />Joel was not only a great coder and manager, but he was also a genius in marketing and community building. In 2015 he launched <b>"LetsWreckThisTogether"</b>, together with the community we would make a change in the adoption of Oracle APEX. Joel frequently gave the keynote speech at APEX World. Here Joel went with attendees that won a prize at APEX World on a boat trip.<p></p><span face=""Trebuchet MS", Trebuchet, Verdana, sans-serif" style="background-color: white; caret-color: rgb(102, 102, 102); color: #666666; font-size: 13.2px;"><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-6pAvznDz6U8/YLTO7hee7BI/AAAAAAAALbg/wrVAqdsRfsgSwhR9kWgO2ayi6U_OigbiwCLcBGAsYHQ/Screenshot%2B2021-05-31%2Bat%2B13.55.29.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="622" data-original-width="826" height="482" src="https://lh3.googleusercontent.com/-6pAvznDz6U8/YLTO7hee7BI/AAAAAAAALbg/wrVAqdsRfsgSwhR9kWgO2ayi6U_OigbiwCLcBGAsYHQ/w640-h482/Screenshot%2B2021-05-31%2Bat%2B13.55.29.png" width="640" /></a></div><div><br /></div></span>In 2018 there was Joel's legendary keynote to<b> "Make Oracle Cool Again"</b><div><br /></div><div><a href="https://lh3.googleusercontent.com/-uslWnIQqeI0/YLTMCcnzsoI/AAAAAAAALbY/JZyf8ETzFToAHkn6Hd7EvccGzRenIPYLwCLcBGAsYHQ/Screenshot%2B2021-05-31%2Bat%2B13.43.38.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="896" data-original-width="1428" height="402" src="https://lh3.googleusercontent.com/-uslWnIQqeI0/YLTMCcnzsoI/AAAAAAAALbY/JZyf8ETzFToAHkn6Hd7EvccGzRenIPYLwCLcBGAsYHQ/w640-h402/Screenshot%2B2021-05-31%2Bat%2B13.43.38.png" width="640" /></a><br /><br />In 2020, when COVID hit, he sent us an email that the day had come :</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-q1jlc7WZojA/YLTlEVv1ZSI/AAAAAAAALb8/-BBlclPAhwQm5P46EfgZ_jXjMUCzEWuCACLcBGAsYHQ/s1830/Screenshot%2B2021-05-31%2Bat%2B15.30.06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="728" data-original-width="1830" height="254" src="https://1.bp.blogspot.com/-q1jlc7WZojA/YLTlEVv1ZSI/AAAAAAAALb8/-BBlclPAhwQm5P46EfgZ_jXjMUCzEWuCACLcBGAsYHQ/w640-h254/Screenshot%2B2021-05-31%2Bat%2B15.30.06.png" width="640" /></a></div><br /><div>We are now in 2021, and <b>we made it</b>... Oracle APEX has never had more attention from inside and outside of Oracle. There have never been more people using Oracle APEX, almost all companies using Oracle are now investing in Oracle APEX and the APEX community has never been so big.</div><div><br /></div><div>I love Mike's words: "Joel set the tone for how we could all work together. Such a great legacy. Such a great community. So international, no BS, just the way things should be. I think everyone knew that Joel was about community success and he had your back."</div><div><br /></div><div><b>Let us continue with our Oracle APEX community and share our knowledge and help others.</b></div><div><br /></div><div>Thank you, Joel, you were not only a great community member, but you were also a great friend. </div><div><br /></div><div>The link to the official page of <a href="https://apex.oracle.com/pls/apex/apex_pm/r/joel/memories" target="_blank">Remembering Joel</a>.</div><p></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com5tag:blogger.com,1999:blog-21122514.post-87190912333245002442021-04-29T23:57:00.001+02:002021-04-30T00:00:31.500+02:00Setup the APEX Office Print (AOP) Server with the Oracle Cloud APEX Service<div class="separator"><a href="https://www.blogger.com/#" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="200" src="https://1.bp.blogspot.com/-SdLYP3esMrw/YIsKUKlsJHI/AAAAAAAALWU/kQckTzNgt-0oPwEfa2dZlQv1384HW78pgCLcBGAsYHQ/w200-h200/office-print-icon-color.png" width="200" /></a></div><p><span face="Verdana, sans-serif" style="caret-color: rgb(25, 25, 25); color: #191919; font-size: 12px;"></span></p><br />This post is part of the series <a href="https://dgielis.blogspot.com/2021/01/my-spin-on-new-oracle-apex-application.html">My spin on the new Oracle APEX Application Development Service</a>.<br /><br />To print and export data from the APEX Service in the Oracle Cloud, you can use <a href="https://www.blogger.com/#">APEX Office Print (AOP)</a>.<br /><br />AOP allows you to generate documents based on templates created in Word, Excel, PowerPoint, HTML, and Text.<br />For example, people use AOP to create an invoice, send a packaging slip, export an Excel spreadsheet with multiple sheets, or have a monthly PowerPoint presentation with the latest sales numbers.<br /><br />AOP the go-to print engine for Oracle APEX and the Oracle database and it offers both a cloud service and an on-premises solution. Having your APEX Service talk to the AOP Cloud is straightforward as there's really no installation to do. You can find more info about that in <a href="https://dgielis.blogspot.com/2019/09/free-oracle-cloud-8-setup-apex-office.html" target="_blank">this blog post.</a> But, what if you want your own dedicated AOP server for your APEX Service? Many people actually like to have their own instance so they can print as much as they want, have full control, and maximum speed - as it's closest to your database. In this post, I will show one way to set up your own APEX Office Print (AOP) Server which works with the <a href="https://www.oracle.com/news/announcement/oracle-apex-application-development-service-011321.html" target="_blank">Oracle APEX Application Development Service.</a><div><br /></div><div>The special bit with the Oracle APEX Service is that it's a fully managed service, which means the database, ORDS, and APEX are pre-configured, auto-patched, auto-scalable, and optimized. I think it's awesome, but the downside is that you don't have direct access to the machine and the network. </div><div><br /><b>The installation is a 3 step process</b>:<br />1. Import the AOP Server image in your own Oracle Cloud<br />2. Create a Compute instance based on this image<br />3. Create a Gateway to this instance<br /><br />The following is a step-by-step guide:<div><br /></div><div>(1) Login into <a href="https://www.apexofficeprint.com">apexofficeprint.com</a>, go to the Downloads section, and click <b>AOP Gateway with Compute</b> </div><div>This will copy the URL of the AOP image, which we will import in your own Oracle Cloud. <i>(FYI we are focussing heavily on the ability to let you run your own AOP instance in the Oracle Cloud, so in the Oracle Cloud section on our website, you will find more ways to run AOP).</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-5fdYL1mp4dI/YIsbh510mAI/AAAAAAAALYk/lK0Q0nB-krsqmBma4ZHt1NErafJyo0ZowCLcBGAsYHQ/s1262/Screenshot%2B2021-04-29%2Bat%2B22.47.51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1182" data-original-width="1262" height="600" src="https://1.bp.blogspot.com/-5fdYL1mp4dI/YIsbh510mAI/AAAAAAAALYk/lK0Q0nB-krsqmBma4ZHt1NErafJyo0ZowCLcBGAsYHQ/w640-h600/Screenshot%2B2021-04-29%2Bat%2B22.47.51.png" width="640" /></a></div><div><br /></div><div>Go to your own Oracle Cloud dashboard and click <b>Compute - Custom Images</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ev-TfCpe8rE/YIsTMm94zUI/AAAAAAAALYQ/BgbyaWehfaUzuLtKdeBTGyKG_OfIig94QCLcBGAsYHQ/s1972/Screenshot%2B2021-04-29%2Bat%2B22.03.16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="738" data-original-width="1972" height="240" src="https://1.bp.blogspot.com/-ev-TfCpe8rE/YIsTMm94zUI/AAAAAAAALYQ/BgbyaWehfaUzuLtKdeBTGyKG_OfIig94QCLcBGAsYHQ/w640-h240/Screenshot%2B2021-04-29%2Bat%2B22.03.16.png" width="640" /></a></div><br /><div>Click the <b>Import Image </b>button:<br /><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-3JxdMyNy_nI/YIsSzSI85gI/AAAAAAAALWc/DyFqEHFp8EMcdIBisFaiiF967HJ7plYkACLcBGAsYHQ/s2464/Screenshot%2B2021-04-23%2Bat%2B21.55.03.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="924" data-original-width="2464" height="240" src="https://1.bp.blogspot.com/-3JxdMyNy_nI/YIsSzSI85gI/AAAAAAAALWc/DyFqEHFp8EMcdIBisFaiiF967HJ7plYkACLcBGAsYHQ/w640-h240/Screenshot%2B2021-04-23%2Bat%2B21.55.03.png" width="640" /></a></div><div><br /></div><div>Give it a name and copy the link that is in the clipboard to the <b>Object Storage URL</b>:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-NK2HpCdk7Z8/YIsSzaPGzAI/AAAAAAAALWg/QAhHRCmtz2Eu4VSwC8mcvBaaD0pXvy5gwCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B21.56.02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1456" data-original-width="2048" height="456" src="https://1.bp.blogspot.com/-NK2HpCdk7Z8/YIsSzaPGzAI/AAAAAAAALWg/QAhHRCmtz2Eu4VSwC8mcvBaaD0pXvy5gwCLcBGAsYHQ/w640-h456/Screenshot%2B2021-04-23%2Bat%2B21.56.02.png" width="640" /></a></div><div><br /></div>Hit the <b>Import Image</b> button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-JWMXGDsm0ws/YIsSzU0d_fI/AAAAAAAALWk/dpN5Dc6SFNAbhE5a70X2fekd3V07CvnZgCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B21.56.53.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1495" data-original-width="2048" height="468" src="https://1.bp.blogspot.com/-JWMXGDsm0ws/YIsSzU0d_fI/AAAAAAAALWk/dpN5Dc6SFNAbhE5a70X2fekd3V07CvnZgCLcBGAsYHQ/w640-h468/Screenshot%2B2021-04-23%2Bat%2B21.56.53.png" width="640" /></a></div><div><br /></div>(2) It might take a few minutes in order for it to create the image, but once it's green, we can <b>Create Instance</b> from this image:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-H876d9AbYF0/YIsSz6UuUmI/AAAAAAAALWo/OX53Dsh3q5w4m-DZh14Q4rb3rZQqn60QgCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.08.51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1495" data-original-width="2048" height="468" src="https://1.bp.blogspot.com/-H876d9AbYF0/YIsSz6UuUmI/AAAAAAAALWo/OX53Dsh3q5w4m-DZh14Q4rb3rZQqn60QgCLcBGAsYHQ/w640-h468/Screenshot%2B2021-04-23%2Bat%2B22.08.51.png" width="640" /></a></div><div><br /></div><div>Give the instance a <b>name</b>, select where you want the Compute instance to be, and select an Image and <b>shape</b>:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-IGdEqLvNKQ4/YIsS0N5DOII/AAAAAAAALWs/Q1SwGnaMNiYhQo40WAOAayAFiKh6UJ2VQCLcBGAsYHQ/s1766/Screenshot%2B2021-04-23%2Bat%2B22.10.32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1224" data-original-width="1766" height="444" src="https://1.bp.blogspot.com/-IGdEqLvNKQ4/YIsS0N5DOII/AAAAAAAALWs/Q1SwGnaMNiYhQo40WAOAayAFiKh6UJ2VQCLcBGAsYHQ/w640-h444/Screenshot%2B2021-04-23%2Bat%2B22.10.32.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-hAFbeMA7Fac/YIsS0PmtKoI/AAAAAAAALWw/7RGVvmsTZGsnxS2MjeUU-45k3UQ7eK3IQCLcBGAsYHQ/s1714/Screenshot%2B2021-04-23%2Bat%2B22.11.09.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1162" data-original-width="1714" height="434" src="https://1.bp.blogspot.com/-hAFbeMA7Fac/YIsS0PmtKoI/AAAAAAAALWw/7RGVvmsTZGsnxS2MjeUU-45k3UQ7eK3IQCLcBGAsYHQ/w640-h434/Screenshot%2B2021-04-23%2Bat%2B22.11.09.png" width="640" /></a></div><div><br /></div><div>The selection of the shape really depends on how much you print. I like, for example, the flexible shape</div><div><div>AMD Rome: VM.Standard.E3.Flex (2 OCPU, 20GB Mem) which will cost around $60 a month.</div></div><div><br /></div>Select the <b>network</b> and assign a public IP address. Note that the public IP is not really necessary, but it just makes the activation of AOP easier as you can connect directly to the Compute instance:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ff-6saqxBaU/YIsS0q_kreI/AAAAAAAALW0/k9m_FKS_WqwuitLyUONL15WGSuY_T_cUQCLcBGAsYHQ/s1926/Screenshot%2B2021-04-23%2Bat%2B22.11.26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1926" data-original-width="1722" height="640" src="https://1.bp.blogspot.com/-ff-6saqxBaU/YIsS0q_kreI/AAAAAAAALW0/k9m_FKS_WqwuitLyUONL15WGSuY_T_cUQCLcBGAsYHQ/w572-h640/Screenshot%2B2021-04-23%2Bat%2B22.11.26.png" width="572" /></a></div><div><br /></div>Finally hit the Create button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-mS2TYiyccrw/YIsS09UN1OI/AAAAAAAALW4/QB4LmlUbg_cFgBIHwHj0IfQfGAAwiAN4ACLcBGAsYHQ/s1718/Screenshot%2B2021-04-23%2Bat%2B22.11.36.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="836" data-original-width="1718" height="312" src="https://1.bp.blogspot.com/-mS2TYiyccrw/YIsS09UN1OI/AAAAAAAALW4/QB4LmlUbg_cFgBIHwHj0IfQfGAAwiAN4ACLcBGAsYHQ/w640-h312/Screenshot%2B2021-04-23%2Bat%2B22.11.36.png" width="640" /></a></div><div><br /></div>Now the Compute Instance will be created:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bO_sWqQpA1M/YIsS0-MygII/AAAAAAAALW8/5vb-8xjpJjsjNdQrEMxPSoVidMJVfDeJACLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.12.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1655" data-original-width="2048" height="518" src="https://1.bp.blogspot.com/-bO_sWqQpA1M/YIsS0-MygII/AAAAAAAALW8/5vb-8xjpJjsjNdQrEMxPSoVidMJVfDeJACLcBGAsYHQ/w640-h518/Screenshot%2B2021-04-23%2Bat%2B22.12.22.png" width="640" /></a></div><div><br /></div>A few minutes later, the pre-configured AOP instance is up and running. </div><div>Write down the Private IP Address and Click on Subnet:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-v8XsfVSTjZ0/YIsS1E2jbJI/AAAAAAAALXA/ECQOzMUSk5sZHjXNY3k5zjsmTmI_0S41gCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.12.56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1652" data-original-width="2048" height="516" src="https://1.bp.blogspot.com/-v8XsfVSTjZ0/YIsS1E2jbJI/AAAAAAAALXA/ECQOzMUSk5sZHjXNY3k5zjsmTmI_0S41gCLcBGAsYHQ/w640-h516/Screenshot%2B2021-04-23%2Bat%2B22.12.56.png" width="640" /></a></div><div><br /></div>Next click on the name of the <b>Security Lists</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-IBR7V0lqdqo/YIsS1SmqWDI/AAAAAAAALXE/nn2UOCMBHVwLqu0RxXRoW2L2mmqTT5ZTwCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.14.24.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1243" data-original-width="2048" height="388" src="https://1.bp.blogspot.com/-IBR7V0lqdqo/YIsS1SmqWDI/AAAAAAAALXE/nn2UOCMBHVwLqu0RxXRoW2L2mmqTT5ZTwCLcBGAsYHQ/w640-h388/Screenshot%2B2021-04-23%2Bat%2B22.14.24.png" width="640" /></a></div><div><br /></div>And <b>Add Ingress Rules:</b></div><div><b><br /></b><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-nioDdbncWkY/YIsS1WO2RqI/AAAAAAAALXI/max2H3hYV2A1KavQmz5hU-am9BIlVcEQQCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.14.40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1859" data-original-width="2048" height="580" src="https://1.bp.blogspot.com/-nioDdbncWkY/YIsS1WO2RqI/AAAAAAAALXI/max2H3hYV2A1KavQmz5hU-am9BIlVcEQQCLcBGAsYHQ/w640-h580/Screenshot%2B2021-04-23%2Bat%2B22.14.40.png" width="640" /></a></div><div><br /></div><div>Add the port AOP is running on. By default, AOP is running on <b>port 8010</b>, but you could change that in the instance if you wanted, and hit Save Changes:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/--CfwryCy3oc/YIsS1sTBY0I/AAAAAAAALXM/Lh9MshU_2KE6VgDijMl8wZPdSevG7mYmACLcBGAsYHQ/s1396/Screenshot%2B2021-04-23%2Bat%2B22.15.07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1202" data-original-width="1396" height="552" src="https://1.bp.blogspot.com/--CfwryCy3oc/YIsS1sTBY0I/AAAAAAAALXM/Lh9MshU_2KE6VgDijMl8wZPdSevG7mYmACLcBGAsYHQ/w640-h552/Screenshot%2B2021-04-23%2Bat%2B22.15.07.png" width="640" /></a></div><div><br /></div><div><b>The Compute instance is now fully configured.</b></div><div><br /></div><div>(3) The issue with the APEX Service is that it only allows HTTPS calls. Instead of dealing with SSL certificates, we will make use of the Gateways feature in the Oracle Cloud which you find under <b>Developer Services - API Management - Gateways</b></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-TTLlnPx01QI/YIsTjrapHaI/AAAAAAAALYc/jiW_9QdizRY-ykFV65ZVsKSZbD4TNe7dgCLcBGAsYHQ/s2088/Screenshot%2B2021-04-29%2Bat%2B22.13.51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="888" data-original-width="2088" height="272" src="https://1.bp.blogspot.com/-TTLlnPx01QI/YIsTjrapHaI/AAAAAAAALYc/jiW_9QdizRY-ykFV65ZVsKSZbD4TNe7dgCLcBGAsYHQ/w640-h272/Screenshot%2B2021-04-29%2Bat%2B22.13.51.png" width="640" /></a></div><div><br /></div><b>Create Gateway:</b><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Ae8Sgmgx-mg/YIsS2em6QDI/AAAAAAAALXQ/XPRUkEY9LjwYREQje53o7muyXckj2R9hQCLcBGAsYHQ/s2666/Screenshot%2B2021-04-23%2Bat%2B22.15.54.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="860" data-original-width="2666" height="206" src="https://1.bp.blogspot.com/-Ae8Sgmgx-mg/YIsS2em6QDI/AAAAAAAALXQ/XPRUkEY9LjwYREQje53o7muyXckj2R9hQCLcBGAsYHQ/w640-h206/Screenshot%2B2021-04-23%2Bat%2B22.15.54.png" width="640" /></a></div><div><br /></div><div>Give it a name and hit <b>Create</b>:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-wK1P30LoJoI/YIsS20mMmUI/AAAAAAAALXU/rINsl6axXDkvwd1twx5SFFRHdz19jHdBgCLcBGAsYHQ/s2564/Screenshot%2B2021-04-23%2Bat%2B22.17.07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1226" data-original-width="2564" height="306" src="https://1.bp.blogspot.com/-wK1P30LoJoI/YIsS20mMmUI/AAAAAAAALXU/rINsl6axXDkvwd1twx5SFFRHdz19jHdBgCLcBGAsYHQ/w640-h306/Screenshot%2B2021-04-23%2Bat%2B22.17.07.png" width="640" /></a></div><div><br /></div>Once the Gateway is created go to the Deployments section:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CQXfC7s9q1I/YIsS3p1LffI/AAAAAAAALXY/2HhLGxqNbLAz8BYLa05Hv_MAFafSVJOQACLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.18.28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1161" data-original-width="2048" height="362" src="https://1.bp.blogspot.com/-CQXfC7s9q1I/YIsS3p1LffI/AAAAAAAALXY/2HhLGxqNbLAz8BYLa05Hv_MAFafSVJOQACLcBGAsYHQ/w640-h362/Screenshot%2B2021-04-23%2Bat%2B22.18.28.png" width="640" /></a></div><div><br /></div><b>Create Deployment:</b></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-O6HlrIJBJPs/YIsS4CKmvII/AAAAAAAALXc/p0_NAAoOFAQNjPevUB1rPZtHvr0KZf_HACLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.18.37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1118" data-original-width="2048" height="350" src="https://1.bp.blogspot.com/-O6HlrIJBJPs/YIsS4CKmvII/AAAAAAAALXc/p0_NAAoOFAQNjPevUB1rPZtHvr0KZf_HACLcBGAsYHQ/w640-h350/Screenshot%2B2021-04-23%2Bat%2B22.18.37.png" width="640" /></a></div><div><br /></div><div>Give it the name AOP and path prefix /aop and hit the <b>Next</b> button</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZYjRf-GDJ5o/YIsS4gtXKpI/AAAAAAAALXg/0Z7dpXqHX6wtuM9Oj-f1pZPHWKtOgdBXACLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.21.18.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1653" data-original-width="2048" height="516" src="https://1.bp.blogspot.com/-ZYjRf-GDJ5o/YIsS4gtXKpI/AAAAAAAALXg/0Z7dpXqHX6wtuM9Oj-f1pZPHWKtOgdBXACLcBGAsYHQ/w640-h516/Screenshot%2B2021-04-23%2Bat%2B22.21.18.png" width="640" /></a></div><div><br /></div>The path can be / and for the URL use the <b>Private URL</b> of the Compute instance.</div><div>Make sure to check the "Disable SSL Verification". Our Compute doesn't have SSL, but the Gateway does and the APEX Service will only talk to the Gateway.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-wIXX2SHiQTc/YIsS5UO3veI/AAAAAAAALXk/Byd3faZQKG8GeYZNk8NPC9_pVJrk7JxQQCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.21.43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1650" data-original-width="2048" height="516" src="https://1.bp.blogspot.com/-wIXX2SHiQTc/YIsS5UO3veI/AAAAAAAALXk/Byd3faZQKG8GeYZNk8NPC9_pVJrk7JxQQCLcBGAsYHQ/w640-h516/Screenshot%2B2021-04-23%2Bat%2B22.21.43.png" width="640" /></a></div><div><br /></div>In the overview screen hit the <b>Create</b> button</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-TJRTMgPGBOI/YIsS6HPhomI/AAAAAAAALXo/xTZxI3YmKo06_p8tzsMg5xitO2R8g4NVACLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.21.50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1661" data-original-width="2048" height="520" src="https://1.bp.blogspot.com/-TJRTMgPGBOI/YIsS6HPhomI/AAAAAAAALXo/xTZxI3YmKo06_p8tzsMg5xitO2R8g4NVACLcBGAsYHQ/w640-h520/Screenshot%2B2021-04-23%2Bat%2B22.21.50.png" width="640" /></a></div><div><br /></div>And you will see that AOP is being deployed and becomes Active:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YYyjv--5Nk0/YIsS7ftBzHI/AAAAAAAALXw/cgurFibgNR4cFlGpw2HeR0ngETxXCZ1qgCLcBGAsYHQ/s2048/Screenshot%2B2021-04-23%2Bat%2B22.22.50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1093" data-original-width="2048" height="342" src="https://1.bp.blogspot.com/-YYyjv--5Nk0/YIsS7ftBzHI/AAAAAAAALXw/cgurFibgNR4cFlGpw2HeR0ngETxXCZ1qgCLcBGAsYHQ/w640-h342/Screenshot%2B2021-04-23%2Bat%2B22.22.50.png" width="640" /></a></div><br /><div>Click the Copy Endpoint in the Deployments section - this is your AOP Server URL!</div></div></div><div><br /></div><div>Those are basically the steps to get your own AOP Server running with the APEX Service.</div><div>In fact, it's not only linked to the APEX Service, you can use this technique for any Oracle Cloud service, like Autonomous Database or your database on another Compute instance.</div><div><br /></div><div>To manage the AOP Server here are some commands you can use when connected to the AOP Server:</div><div><br /></div><div><span style="background-color: #f8f8f8; caret-color: rgb(51, 51, 51); color: #333333; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre;">start aop : systemctl start aop
stop aop : systemctl stop aop
status aop : systemctl status aop
autostart at boot : systemctl </span><span class="hljs-built_in" style="background-color: #f8f8f8; box-sizing: border-box; color: #0086b3; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre;">enable</span><span style="background-color: #f8f8f8; caret-color: rgb(51, 51, 51); color: #333333; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre;"> aop
remove autostart at boot: systemctl </span><span class="hljs-built_in" style="background-color: #f8f8f8; box-sizing: border-box; color: #0086b3; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre;">disable</span><span style="background-color: #f8f8f8; caret-color: rgb(51, 51, 51); color: #333333; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre;"> aop</span></div><div><br /></div>
Happy printing!</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com2tag:blogger.com,1999:blog-21122514.post-27876323160677802562021-04-22T22:56:00.000+02:002021-04-22T22:56:09.597+02:00Which one to pick: Free APEX Service vs Free Oracle Autonomous DB<p>I'm a big fan of the Free Oracle Cloud as it allows Oracle APEX, Oracle Database, web developers, or more generally, everybody, to get started doing their thing. If you want to get going, I previously did a series you may want to read called <a href="https://dgielis.blogspot.com/2019/09/best-and-cheapest-oracle-apex-hosting.html" target="_blank">Best and Cheapest Oracle APEX hosting: Free Oracle Cloud</a>.</p><p>A few days ago Oracle <a href="https://blogs.oracle.com/developers/oracle-cloud-adds-free-apex-and-json-services" target="_blank">announced</a> the free offering for the Oracle APEX Service. I previously started on a series on this new APEX service <a href="https://dgielis.blogspot.com/2021/01/my-spin-on-new-oracle-apex-application.html" target="_blank">My spin on the new Oracle APEX Application Development Service</a>. I still have to continue that series, but I first thought to write now that it's available for free, about which one to pick. The Free Oracle Autonomous DB which comes with APEX or the Free APEX Service which comes with the Oracle DB?</p><p>All-in-all both services are very similar, but the decision is very easy for me. Ask these two questions to yourself:</p><p><b><span style="color: red;">Do I want to have SQL*net access (e.g. connect with SQLcl, SQL Developer, or Visual Studio Code)?</span></b></p><p>If the answer is yes, you need to go with the Oracle Autonomous Database as of the time of writing SQL*net access isn't available for the APEX Service.</p><p><b><span style="color: red;">Do I want to upgrade my free service to a paid service at some point?</span></b></p><p>The APEX Service is unbelievable value for money, and 1/3 of the price of the Autonomous Database, so if you ever want to upgrade in one click to a paid version of the APEX Service, you want to start from the free APEX Service, You can't go from the Autonomous DB to the APEX Service, so the one you pick decides where you upgrade to.</p><p><b>Combining both ...</b></p><p>If you don't mind a bit of hassle, you could start with the Always Free Autonomous Database, export the database and APEX apps, and import them into the APEX Service. It will take a bit of effort to do this, but it's definitely a good choice if you don't mind doing that. But from that moment onwards you will work with the APEX Service... or you treat the APEX service as your production environment and your Always Free Oracle Autonomous DB as your development environment.</p><p>If you wonder why do you even care about SQL*net access... I work file-based, e.g. all my PL/SQL objects (packages, procedures, ...) are in files in Git and I edit them, I see very nicely what I changed, I can easily commit, etc. I won't mess up other people's code and I can always go back to a previous version. So, I really like to work in Visual Studio Code linked to my Git. Now I could just copy/paste when I'm done editing and compile it in SQL Workshop of SQL Developer Web, but it's one extra step.</p><p><b>Starting with the Always Free APEX Service and upgrading to Paid.</b></p><p>For most smaller projects I will probably educate people to go with the Always Free APEX Service. Most time is spent in APEX anyway and SQL Workshop or SQL Developer Web is good enough for those small projects to maintain the database objects as typically not many people are working on the same package at the same time. So I thought to see how well upgrading from Free to Paid would work... and I must say I was impressed! It took about 15 minutes to do. Here's what I did:</p><p>In the Oracle Cloud console, go to the APEX Application Development - APEX Instances and hit the <b>Create APEX Service</b> button:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-sT0Ee9bAwkk/YIHb0675HdI/AAAAAAAALVw/_aQ6Pn8AfkoyQlpjUg47WrnCZZ2b4hpswCLcBGAsYHQ/s2048/Screenshot%2B2021-04-22%2Bat%2B22.24.57.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1434" data-original-width="2048" height="448" src="https://1.bp.blogspot.com/-sT0Ee9bAwkk/YIHb0675HdI/AAAAAAAALVw/_aQ6Pn8AfkoyQlpjUg47WrnCZZ2b4hpswCLcBGAsYHQ/w640-h448/Screenshot%2B2021-04-22%2Bat%2B22.24.57.png" width="640" /></a></div><p>Follow the wizard to Create the APEX Service; give it a name</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6jSfhIWAXwI/YIHbDZ5BxDI/AAAAAAAALU0/IF_3QZYJ1d0OIiUvk4usnoZlUM-FQDmzQCLcBGAsYHQ/s2048/Screenshot%2B2021-04-22%2Bat%2B15.28.34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1696" data-original-width="2048" height="530" src="https://1.bp.blogspot.com/-6jSfhIWAXwI/YIHbDZ5BxDI/AAAAAAAALU0/IF_3QZYJ1d0OIiUvk4usnoZlUM-FQDmzQCLcBGAsYHQ/w640-h530/Screenshot%2B2021-04-22%2Bat%2B15.28.34.png" width="640" /></a></div><div><br /></div>Add a password and provide the email addresses of people you want to be notified of maintenance. This notification part is new and really useful!<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-InWEX8s8MDw/YIHbDehVUbI/AAAAAAAALU4/8PYYD4bkcjUiuj1YzYO1hkrk-c_ZfPU7QCLcBGAsYHQ/s2048/Screenshot%2B2021-04-22%2Bat%2B15.29.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1616" data-original-width="2048" height="504" src="https://1.bp.blogspot.com/-InWEX8s8MDw/YIHbDehVUbI/AAAAAAAALU4/8PYYD4bkcjUiuj1YzYO1hkrk-c_ZfPU7QCLcBGAsYHQ/w640-h504/Screenshot%2B2021-04-22%2Bat%2B15.29.22.png" width="640" /></a></div><div><br /></div><div>The Always Free APEX Service is ready and you can play with it. Now, let's hope at some point you are so successful with your APEX app, that you will switch to a Paid instance. Here's what it takes to upgrade.</div><div>Click the More Actions : Upgrade Instance to Paid:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-W60B5vSrtBA/YIHbDdxZedI/AAAAAAAALUw/dkjN1OoqH4seJq-DiUUoz1kdop_YWF2RwCLcBGAsYHQ/s2530/Screenshot%2B2021-04-22%2Bat%2B15.30.36.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1116" data-original-width="2530" height="282" src="https://1.bp.blogspot.com/-W60B5vSrtBA/YIHbDdxZedI/AAAAAAAALUw/dkjN1OoqH4seJq-DiUUoz1kdop_YWF2RwCLcBGAsYHQ/w640-h282/Screenshot%2B2021-04-22%2Bat%2B15.30.36.png" width="640" /></a></div><div><br /></div>Confirm you want to upgrade:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-gwjnbf3aO_w/YIHbDxUmJyI/AAAAAAAALU8/JXID7vHI3gQXn0jq-2KVOvkV-My4Y48oQCLcBGAsYHQ/s1770/Screenshot%2B2021-04-22%2Bat%2B15.30.45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="702" data-original-width="1770" height="254" src="https://1.bp.blogspot.com/-gwjnbf3aO_w/YIHbDxUmJyI/AAAAAAAALU8/JXID7vHI3gQXn0jq-2KVOvkV-My4Y48oQCLcBGAsYHQ/w640-h254/Screenshot%2B2021-04-22%2Bat%2B15.30.45.png" width="640" /></a></div><div><br /></div>It will take a few minutes to update:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ImQ6FN8mHb4/YIHbEaBaGwI/AAAAAAAALVA/9Lip_WruEsIYgh3xre-NqIBYsX4eNR-iwCLcBGAsYHQ/s2514/Screenshot%2B2021-04-22%2Bat%2B15.31.23.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1128" data-original-width="2514" height="288" src="https://1.bp.blogspot.com/-ImQ6FN8mHb4/YIHbEaBaGwI/AAAAAAAALVA/9Lip_WruEsIYgh3xre-NqIBYsX4eNR-iwCLcBGAsYHQ/w640-h288/Screenshot%2B2021-04-22%2Bat%2B15.31.23.png" width="640" /></a></div><div><br /></div>And presto, there it becomes available:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-nxv2OmyKXys/YIHbEu7y2_I/AAAAAAAALVE/5uFN-oXs5KsxPeB76NjRhYG51ZQqk9IbQCLcBGAsYHQ/s2376/Screenshot%2B2021-04-22%2Bat%2B15.36.32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1076" data-original-width="2376" height="290" src="https://1.bp.blogspot.com/-nxv2OmyKXys/YIHbEu7y2_I/AAAAAAAALVE/5uFN-oXs5KsxPeB76NjRhYG51ZQqk9IbQCLcBGAsYHQ/w640-h290/Screenshot%2B2021-04-22%2Bat%2B15.36.32.png" width="640" /></a></div><div><br /></div>Easy! Now one of the best features of the APEX Service is that it can Auto Scale, which means that on heavy traffic the service can take up to 3 times the OCPU you have. I find that super cool :) You pay for it, but you don't have to do anything, and it's only for the time it needs more resources.</div><div><br /></div><div>When you upgrade from a free tier, the auto-scaling is not enabled by default. Here's how to enable it: Click More Actions > Scale:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-n_CB7OYoa3s/YIHbFcfuMXI/AAAAAAAALVI/Q-dx4nDkLSwBpWTA3DIleq0T5qQJeAzqwCLcBGAsYHQ/s1454/Screenshot%2B2021-04-22%2Bat%2B15.36.48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="626" data-original-width="1454" height="276" src="https://1.bp.blogspot.com/-n_CB7OYoa3s/YIHbFcfuMXI/AAAAAAAALVI/Q-dx4nDkLSwBpWTA3DIleq0T5qQJeAzqwCLcBGAsYHQ/w640-h276/Screenshot%2B2021-04-22%2Bat%2B15.36.48.png" width="640" /></a></div><div><br /></div>Hit the Auto Scaling checkbox:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-H0e37ESoeCQ/YIHbF8uNbjI/AAAAAAAALVM/VJzC6yAvWzwF5rBhrhnbeTMnvBwa4yjiwCLcBGAsYHQ/s2188/Screenshot%2B2021-04-22%2Bat%2B15.36.56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="868" data-original-width="2188" height="254" src="https://1.bp.blogspot.com/-H0e37ESoeCQ/YIHbF8uNbjI/AAAAAAAALVM/VJzC6yAvWzwF5rBhrhnbeTMnvBwa4yjiwCLcBGAsYHQ/w640-h254/Screenshot%2B2021-04-22%2Bat%2B15.36.56.png" width="640" /></a></div><div><br /></div>This takes a bit of time and for me, it didn't automatically tell me it was done....</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uPN6rXCyaxw/YIHbGR37ayI/AAAAAAAALVQ/HatXpLSjpE0h1yamVyUw84_69LfIu_YggCLcBGAsYHQ/s2398/Screenshot%2B2021-04-22%2Bat%2B15.37.06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1072" data-original-width="2398" height="286" src="https://1.bp.blogspot.com/-uPN6rXCyaxw/YIHbGR37ayI/AAAAAAAALVQ/HatXpLSjpE0h1yamVyUw84_69LfIu_YggCLcBGAsYHQ/w640-h286/Screenshot%2B2021-04-22%2Bat%2B15.37.06.png" width="640" /></a></div><div><br /></div>... at some point I refreshed the browser and saw it was done:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tHqvSC1tHDQ/YIHbG_WleQI/AAAAAAAALVU/SV6N92BoxXUcZw9wJnbAndrIhePl4iC_wCLcBGAsYHQ/s2372/Screenshot%2B2021-04-22%2Bat%2B16.12.09.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="2372" height="292" src="https://1.bp.blogspot.com/-tHqvSC1tHDQ/YIHbG_WleQI/AAAAAAAALVU/SV6N92BoxXUcZw9wJnbAndrIhePl4iC_wCLcBGAsYHQ/w640-h292/Screenshot%2B2021-04-22%2Bat%2B16.12.09.png" width="640" /></a></div><p>I like the APEX Service a lot. It's missing a few features before I can move a few customers <br />e.g. the ability to have custom domain names to name one. </p><p>But since January 13th I'm actually using the new APEX Service and hosting a public website on it.<br />It's a fun app to predict the curve of the COVID-19 cases in Belgium. There's a static page in front of it, so the custom domain name <a href="http://toogviroloog.be">toogviroloog.be</a> is there, but once you click on Predict (Voorspel zelf), you will see the APEX app hosted on the APEX Service.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-qpGYVX4BqVQ/YIHgGMagrDI/AAAAAAAALWA/6w3j3b-aVHgr7ET03ty2qCtpRcMat0zlwCLcBGAsYHQ/s2048/Screenshot%2B2021-04-22%2Bat%2B22.43.44.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1359" data-original-width="2048" height="424" src="https://1.bp.blogspot.com/-qpGYVX4BqVQ/YIHgGMagrDI/AAAAAAAALWA/6w3j3b-aVHgr7ET03ty2qCtpRcMat0zlwCLcBGAsYHQ/w640-h424/Screenshot%2B2021-04-22%2Bat%2B22.43.44.png" width="640" /></a></div><br /><p>Hope this post helps to pick the Free Oracle Cloud service you need.</p></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com6tag:blogger.com,1999:blog-21122514.post-43930131831377587922021-02-02T16:01:00.004+01:002021-03-16T23:08:31.745+01:00The Best Rich Text / HTML Editor for Oracle APEX<p>One of the first bigger public applications I built in <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> was the website and backend for a flight school (in 2006). It was a little Content Management System (CMS), so the secretary of the flight school could update the website and the trainers could create their online course material and exams straight from an administration page. I used a Rich Text (HTML) Editor, so they could make some text bold, include pictures, add some color and add tables to the text.</p><p>In many other applications, I started to use the Rich Text Editor so people could write their own emails and send them straight from their APEX apps. </p><p>In the last 5 years, I didn't only come across the use of a Rich Text Editor in our own applications, but we saw that many people use it when they use <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a> to generate documents. AOP has the unique feature that it understands HTML and converts this to native Word/PDF styling. For example, the bold tag in HTML or the use of a span with a certain style is translated as real bold and, for example, that color in the generated document. People love it as they can make very dynamic documents.</p><p>Although we and many others are using the Rich Text Editor in our Oracle APEX apps, there were two things that were hard to do (read not native and you have to write extra code):</p><p></p><ul style="text-align: left;"><li>dealing with over 32K of data</li><li>upload, manipulate, and include images in the text </li></ul><p></p><p>As part of our <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a> offering, we wanted to create the best Rich Text Editor (RTE) possible for Oracle APEX. So, a year ago, <a href="https://twitter.com/bostrowsk1" target="_blank">Bartosz</a> and I did some research on what would be the best way to address this. We thought about enhancing the current RTE of APEX, but while doing the research we found the component was quite old (based on CKEditor 4 in APEX 20.1 and before). So we looked at <a href="https://handsontable.com/blog/articles/2017/8/11-best-rich-text-editors" target="_blank">many different RTEs</a>, and ended up with our top 3:</p><p></p><ul style="text-align: left;"><li><a href="https://www.tiny.cloud/features" target="_blank">TinyMCE</a>: an open-source editor, with which Bartosz had done a lot of work</li><li><a href="https://ckeditor.com/ckeditor-5/demo/" target="_blank">CKEditor</a>: this is what is included in Oracle APEX. Before APEX 20.2 it was CKEditor 4, from 20.2 onwards the default one is CKEditor 5. The new editor is also open-source, looks nice but was still undergoing a lot of changes and enhancements, and wasn't backward compatible.</li><li><a href="https://froala.com" target="_blank">Froala</a>: used a lot by AOP customers, I have always been impressed by their offering, but it's paid.</li></ul><div>They are all good, and although we needed to pay to use this editor in an APEX Plug-in and have the rights to distribute it without people needing to have their own license, we went with the <a href="https://froala.com/wysiwyg-editor/" target="_blank">Froala WYSIWYG Editor</a>. </div><div><br /></div><div>And, I couldn't be happier with what Bartosz came up with and how easy it is now to use the RTE Editor.</div><div>Here's an animated gif to give you an idea of how it looks:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-QNZp8TiJZSw/YBlpAaALoHI/AAAAAAAALSo/lnBiF8xHuJwCsTgDyNy1TjcQPq4EhHv7wCLcBGAsYHQ/s1280/plugins_pro_rte_editor.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://1.bp.blogspot.com/-QNZp8TiJZSw/YBlpAaALoHI/AAAAAAAALSo/lnBiF8xHuJwCsTgDyNy1TjcQPq4EhHv7wCLcBGAsYHQ/w640-h360/plugins_pro_rte_editor.gif" width="640" /></a></div><br /><div><br /></div><div>To implement a plug-in in your own app, you can follow <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">this step-by-step guide</a>, which will cover how to download the Oracle APEX plug-ins from the <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro website</a> and import and register the plug-in.</div><div><br /></div><div>In short, the steps to use the Rich Text Editor Pro plug-in in your own app are:</div><div><ol style="text-align: left;"><li>Login, download, and unzip the <b>Rich Text Editor Pro</b> plug-in from <a href="https://www.plug-ins-pro.com">plug-ins-pro.com</a></li><li>Upload and run from SQL Workshop > <b>SQL Scripts</b> > ddl_unitedcodes_rich_text_editor_pro.sql and ddl_unitedcodes_rich_text_editor_pro_sample_rest.sql</li><li>Import the Plug-ins in your app (the RTE Editor exists out of 3 plug-ins): Shared Components > <b>Plug-ins</b> > Import: dynamic_action_plugin_unitedcodes_froala_rte_da_conf.sql and item_type_plugin_unitedcodes_froala_rte.sql and process_type_plugin_unitedcodes_froala_rte_process.sql<br /><br /><a href="https://1.bp.blogspot.com/-13Q9Al60WZE/YBkeZkJCOvI/AAAAAAAALRM/asZwChrmLS012XuiK4G5w1UcN4CpEV2GACLcBGAsYHQ/s2606/Screenshot%2B2021-02-02%2Bat%2B10.37.51.png" style="clear: left; display: inline; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1114" data-original-width="2606" height="274" src="https://1.bp.blogspot.com/-13Q9Al60WZE/YBkeZkJCOvI/AAAAAAAALRM/asZwChrmLS012XuiK4G5w1UcN4CpEV2GACLcBGAsYHQ/w640-h274/Screenshot%2B2021-02-02%2Bat%2B10.37.51.png" width="640" /></a><br /><br /></li><li>Register the plug-in by going to SQL Workshop > SQL Commands and copy from the README.md file the script and enter your API key which you find in the Plug-ins Pro Portal<br /><br /><img border="0" data-original-height="968" data-original-width="1630" height="381" src="https://1.bp.blogspot.com/-blpFJwqCGTE/YBkeZsrSg_I/AAAAAAAALRQ/E4mWNbsDM8UzB0wwiNzGsVLlX8xnJJoRACLcBGAsYHQ/w640-h381/Screenshot%2B2021-02-02%2Bat%2B10.41.22.png" style="caret-color: rgb(0, 0, 238); color: #0000ee; text-align: center; text-decoration: underline;" width="640" /><br /></li></ol></div><div>Now we are ready to use it in our application. I will use the Sample Database Application that comes with Oracle APEX, and change the Product description item on Page 6, which is a Textarea, to be the new Rich Text Editor Pro:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-mnbtLbQLLZc/YBkguNgMYXI/AAAAAAAALRc/_XhTUXueC4sCjtDw4ndJv_8gXAHlW17AgCLcBGAsYHQ/s2048/Screenshot%2B2021-02-02%2Bat%2B10.51.10.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1415" data-original-width="2048" height="442" src="https://1.bp.blogspot.com/-mnbtLbQLLZc/YBkguNgMYXI/AAAAAAAALRc/_XhTUXueC4sCjtDw4ndJv_8gXAHlW17AgCLcBGAsYHQ/w640-h442/Screenshot%2B2021-02-02%2Bat%2B10.51.10.png" width="640" /></a></div><br /><div>Edit page 6, click the P6_PRODUCT_DESCRIPTION item and:</div><div>- <b>change the item type</b> to be the <b>United Codes Rich Text Editor Pro [Plug-in]</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-IJxSONCLLOA/YBkikUVrGOI/AAAAAAAALRo/3miwc37UVGUHWo_wJ7F0wKpGxWxo28ClwCLcBGAsYHQ/s2344/Screenshot%2B2021-02-02%2Bat%2B10.58.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1148" data-original-width="2344" height="314" src="https://1.bp.blogspot.com/-IJxSONCLLOA/YBkikUVrGOI/AAAAAAAALRo/3miwc37UVGUHWo_wJ7F0wKpGxWxo28ClwCLcBGAsYHQ/w640-h314/Screenshot%2B2021-02-02%2Bat%2B10.58.22.png" width="640" /></a></div><br /><div>- give it a height of 300px</div><div>- change the Appearance - Template: Optional - Above</div><div>- change the Source - Form Region: - Select - </div><div><br /></div><div>The reason we unselect the Form Region and the item becomes Null is because Oracle APEX doesn't support more than 32K in an item. So we have to fill the item in another way. This is why the Rich Text Editor Pro comes with its own process which supports CLOBs and data over 32K.</div><div><br /></div><div>We will <b>add a Process</b> by going to Pre-Rendering - After Header - Process - Right Click and Create Process. Call the process Fetch RTE and as Type select <b>United Codes Rich Text Editor Pro (Process) [Plug-in]</b>. The process supports three different ways of loading the CLOB value into the item: SQL Query, Function Returning CLOB, and Table. The most declarative one is the Table, so we will go with that. Select the item and fill in the columns:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWc3ETDMkeg8qeQ0dOPzTBpwdpr5dqFdzv3qg1WF0X9cMkN8MyN4vp5vBzlNSFFgIp2fjOFP_2k-FiugQfxFaE5-VY-Ia0PEywviQxTX5xzYDH1xREu1AvbNGfuPftc87OSwiSTQ/s2350/Screenshot+2021-02-02+at+11.13.27.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1132" data-original-width="2350" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWc3ETDMkeg8qeQ0dOPzTBpwdpr5dqFdzv3qg1WF0X9cMkN8MyN4vp5vBzlNSFFgIp2fjOFP_2k-FiugQfxFaE5-VY-Ia0PEywviQxTX5xzYDH1xREu1AvbNGfuPftc87OSwiSTQ/w640-h308/Screenshot+2021-02-02+at+11.13.27.png" width="640" /></a></div><br /><div>In order to save the value back to the database, we also need a custom process, because of the same reason we had to fetch the value, to circumvent the 32K limit.</div><div><br /></div><div>So, go to Processing - Processes - Right Click and Create Process which will <b>add a new Process</b>.</div><div>Move it after the Process Row process. Call the new process Process RTE and select as Type <b>United Codes Rich Text Editor Pro (Process) [Plug-in]</b>. The process supports two different ways of saving the item value into the CLOB column in the table: PL/SQL Code and Table. The most declarative one is the Table, so we will go with that. Select the item and fill in the columns:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CxPZPkjqFBI/YFEsUWOrjMI/AAAAAAAALTs/My7xs9I6Masd1z98dVk89SdKx8ANcPxsgCLcBGAsYHQ/s2906/Screenshot%2B2021-03-16%2Bat%2B23.07.56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1082" data-original-width="2906" height="238" src="https://1.bp.blogspot.com/-CxPZPkjqFBI/YFEsUWOrjMI/AAAAAAAALTs/My7xs9I6Masd1z98dVk89SdKx8ANcPxsgCLcBGAsYHQ/w640-h238/Screenshot%2B2021-03-16%2Bat%2B23.07.56.png" width="640" /></a></div><br /><div>That's it! </div><div><br /></div><div>Finally, I changed the height of the Modal to be 750px and changed the Labels of the other items to use the Floating template. When you open a product now, the result looks like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-614I4IbMycA/YBkoEX505jI/AAAAAAAALSI/oXLgmZEmOCMJH_eX8LpILQxULMgQNouvgCLcBGAsYHQ/s2048/Screenshot%2B2021-02-02%2Bat%2B11.22.40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1465" data-original-width="2048" height="458" src="https://1.bp.blogspot.com/-614I4IbMycA/YBkoEX505jI/AAAAAAAALSI/oXLgmZEmOCMJH_eX8LpILQxULMgQNouvgCLcBGAsYHQ/w640-h458/Screenshot%2B2021-02-02%2Bat%2B11.22.40.png" width="640" /></a></div><br /><div>Now you can make the text bold, upload, drag-drop and manipulate pictures, add videos to the product description, etc. A plethora of options are now available through this new Rich Text Editor!</div><div><br /></div><div>So our Rich Text Editor Pro exists out of 3 plug-ins: an item type plug-in, a process plug-in which we saw both being used above. But this plug-in also comes with a dynamic action plug-in. The dynamic action plug-in allows you to further customize the Rich Text Editor. Here are a couple of things you can do with the DA plug-in:</div><div><ul style="text-align: left;"><li>ability to change the toolbar: add and remove buttons</li><li>change settings: allow spell checker, copy/paste images, image resizing, configure the sticky toolbar</li><li>enable/disable image as base64</li><li>upload CLOB</li></ul><div>You can customize the RTE editor also via JavaScript, but having this extra DA plug-in makes the life of a low-code developer easier 😀</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-lE177EWvCs4/YBk1_Mvq_jI/AAAAAAAALSY/d4DrP6TL2zs4WkVou5XQOmm6YSzEW2bRgCLcBGAsYHQ/s2048/Screenshot%2B2021-02-02%2Bat%2B12.21.57.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1997" data-original-width="2048" height="624" src="https://1.bp.blogspot.com/-lE177EWvCs4/YBk1_Mvq_jI/AAAAAAAALSY/d4DrP6TL2zs4WkVou5XQOmm6YSzEW2bRgCLcBGAsYHQ/w640-h624/Screenshot%2B2021-02-02%2Bat%2B12.21.57.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>To see the full power of this amazing plug-in, I strongly recommend installing the sample application that comes with it. You also find the <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/rich_text_editor_pro/home" target="_blank">sample application on the Plug-ins Pro website</a>.</div><p></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1tag:blogger.com,1999:blog-21122514.post-72861641692243275762021-01-24T18:10:00.002+01:002021-04-30T21:58:04.423+02:00Import an existing database and APEX app into the Oracle APEX Application Development ServiceThis post is part of the series <a href="https://dgielis.blogspot.com/2021/01/my-spin-on-new-oracle-apex-application.html">My spin on the new Oracle APEX Application Development Service</a>. <div><br /></div><div>In the <a href="https://dgielis.blogspot.com/2021/01/setup-and-configure-apex-application.html">previous post</a>, we set up the environment which provided us everything to start building <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> apps. In this post, I want to take the Oracle APEX apps I've built before and move them to this new service.</div><div><br /></div><div>There are different ways of accomplishing this. Here are the steps I will follow:</div><div><ol style="text-align: left;"><li>In the current environment</li><ol><li>Export the database (schema)</li><li>Export the APEX app</li></ol><li>On the new Oracle APEX Application Development Service</li><ol><li>Import the database (schema)</li><li>Import/Deploy the APEX app</li></ol></ol></div><div>I will start by moving a very small app I built a few years ago; the reservation of meeting rooms we use in the Innovation and Incubation center in which our office is located.</div><div><br /></div><div>In our current environment, we will export the data and the APEX app as explained below.</div><div><br /></div><div><b>Export the database schema</b></div><div><br /></div><div>There are different ways to get your data: export to flat files, make your data available through REST web services or use some other tools to move data. We export all our apps every night to a different location with <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sutil/oracle-data-pump-export-utility.html#GUID-5F7380CE-A619-4042-8D13-1F7DDE429991" target="_blank">Oracle Data Pump</a>. In case you are new to Data Pump, here's the command you can use to export a specific schema:</div><div><br /></div><div><div><span style="font-family: courier;">expdp apex_backup/xxx@apex_pdb directory=DATAPUMP dumpfile=db_20210121_ini.dmp logfile=db_20210121_ini.log schemas=INI exclude=statistics</span></div></div><div><br /></div><div>or export the entire database:</div><div><br /></div><div><span style="font-family: courier;">expdp apex_backup/xxx@apex_pdb directory=DATAPUMP dumpfile=db_20210121_full.dmp logfile=db_20210121_full.log full=y exclude=statistics </span></div><div><br /></div><div>I like to use Data Pump as it will export everything in one .dmp file and it's really fast to do.</div><div><br /></div><div><br /></div><div><b>Export the APEX application</b></div><div><br /></div><div>There are different ways to export the APEX app. You can <a href="https://docs.oracle.com/en/database/oracle/application-express/20.2/htmdb/exporting-an-application.html#GUID-CA08D090-882F-4745-87D9-149373F285F1" target="_blank">export through the GUI</a> in Oracle APEX, use the external <a href="https://docs.oracle.com/en/database/oracle/application-express/20.2/aeadm/exporting-from-a-command-line.html#GUID-7C70BD79-3AA0-4B70-A386-D611D3CB12AC" target="_blank">APEX Export tool</a>, or use <a href="https://www.oracle.com/database/technologies/appdev/sqlcl.html" target="_blank">SQLcl</a>.</div><div><br /></div><div>Just like with the data, we also export all APEX workspaces and applications every night. We use the APEX Export tool. This is especially useful if you want to move your entire environment to the cloud as you don't have to export workspaces and apps one by one.</div><div><br /></div><div>The command to export all workspaces:</div><div><br /></div><div><div><span style="font-family: courier;">/usr/bin/java oracle.apex.APEXExport -db localhost:1521/APEX_PDB -user apex_backup -password xxx -expWorkspace > workspaces.txt</span></div><div><br /></div><div>The command to export all applications:</div><div><br /></div><div><span style="font-family: courier;">/usr/bin/java oracle.apex.APEXExport -db localhost:1521/APEX_PDB -user apex_backup -password xxx -instance > applications.txt</span></div></div><div><br /></div><div><br /></div><div>Now that we have the database data pump file (.dmp) and the APEX export file (.sql), we are ready to go to the new APEX Application Development Service to import the database and Oracle APEX app.</div><div><br /></div><div><b>Import the database schema</b></div><div><br /></div><div>The first thing we will do is import the database into the new service.</div><div><br /></div><div>Log in to the Oracle Cloud and go to the APEX Application Development > APEX Instances.</div><div>From there click on the database link:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyO0UPO_Bij8HC7AtmTH2_QEoM9LgWq6l3U_PHhboaVhMcB4zu2qvTklNwmXIsDSsP7pey4DJOgVHITAVnQ-JZL5PVJSl9cQnbfTJP1jxQWpkCRjutUFiJEOLQrlXlXnnYQE5W6g/s2722/Screenshot+2021-01-24+at+12.40.06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1112" data-original-width="2722" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyO0UPO_Bij8HC7AtmTH2_QEoM9LgWq6l3U_PHhboaVhMcB4zu2qvTklNwmXIsDSsP7pey4DJOgVHITAVnQ-JZL5PVJSl9cQnbfTJP1jxQWpkCRjutUFiJEOLQrlXlXnnYQE5W6g/w640-h262/Screenshot+2021-01-24+at+12.40.06.png" width="640" /></a></div><br /><div>Here you arrive in the database. There's a DB Connection button:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8Hupha_9M4bWNGfnzLYYkALasFEjROROS-GYhARbKLOFciD5fm9Vqkqazq3DrZlg9vJ3k8yVmAtYSgdVYyGCU8kC8LcHvhyphenhyphenIofUC1u2xmIPGR1-aX8UTB8LRPW1LljFm_ydM_aQ/s2482/Screenshot+2021-01-24+at+12.25.21.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1144" data-original-width="2482" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8Hupha_9M4bWNGfnzLYYkALasFEjROROS-GYhARbKLOFciD5fm9Vqkqazq3DrZlg9vJ3k8yVmAtYSgdVYyGCU8kC8LcHvhyphenhyphenIofUC1u2xmIPGR1-aX8UTB8LRPW1LljFm_ydM_aQ/w640-h294/Screenshot+2021-01-24+at+12.25.21.png" width="640" /></a></div><div><br /></div>Here you normally can download the connection details (credentials/wallet) to your database, which would mean we could follow the same technique as I described in my blog series on the Always Free Oracle Cloud, more specifically on <a href="https://dgielis.blogspot.com/2019/10/free-oracle-cloud-10-running-sqlcl-and.html" target="_blank">how to use SQLcl and Data Pump with the Oracle ATP</a>. Although this Oracle APEX Service is based on the same technology as the Always Free ATP, there are some limitations, one is, you can't connect directly to the database from external tools e.g. SQLcl. <div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_qjP-Ppsa4pDL_IiabEH1n3sqg6Y9OBqRiHO5icVpHehtZeRB_76JwEHkOkJtyqzY0ZSSoqtJgzVa916HWJQVI2MB_5Skxa1agTN2uj9LSYKTAuGQOFTRAzt97CF8zBzyh39CyQ/s2048/Screenshot+2021-01-24+at+12.25.32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1184" data-original-width="2048" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_qjP-Ppsa4pDL_IiabEH1n3sqg6Y9OBqRiHO5icVpHehtZeRB_76JwEHkOkJtyqzY0ZSSoqtJgzVa916HWJQVI2MB_5Skxa1agTN2uj9LSYKTAuGQOFTRAzt97CF8zBzyh39CyQ/w640-h370/Screenshot+2021-01-24+at+12.25.32.png" width="640" /></a></div><div><br /></div>I thought as a workaround I would upgrade the service, import the data and downgrade again, but it seems that is not going to fly. Once you upgrade it's irrevocable.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhvngZm8_HOZsXAKKNNmhNdVYOoajU1-r6wv99ayiRLHyXowOnWvPH0pAZREpeE99_rTRmthxj4KoXRg4DDkkWPtzzX40QuuDCFeHUspl6gESvl_4jlvN9ouNR0eMv4IpFglVIqA/s2478/Screenshot+2021-01-24+at+12.26.08.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1052" data-original-width="2478" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhvngZm8_HOZsXAKKNNmhNdVYOoajU1-r6wv99ayiRLHyXowOnWvPH0pAZREpeE99_rTRmthxj4KoXRg4DDkkWPtzzX40QuuDCFeHUspl6gESvl_4jlvN9ouNR0eMv4IpFglVIqA/w640-h272/Screenshot+2021-01-24+at+12.26.08.png" width="640" /></a></div><br /><div>Luckily there's another way to load our data, we can use the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sutil/using-oracle_datapump-api.html#GUID-22D4851C-4057-4BBB-B7F0-DB9091A30641" target="_blank">Oracle Data Pump API</a> from PL/SQL.</div></div><div><br /></div><div>First, we will make the dump file available to the Data Pump API. The database in the Oracle Cloud can not read a file from your filesystem directly, so you have to make the file available so the database can read it. In the Oracle Cloud, we can use Object Storage to store our dump file. In my blog post <a href="https://dgielis.blogspot.com/2019/09/free-oracle-cloud-9-setup-object.html" target="_blank">Setup Object Storage and use for File Share and Backups</a>, you find step-by-step instructions both to upload through the GUI as from the command line.</div><div><br /></div><div>As this is a very small database, I will just use the GUI. For anything that is less than 500MB you can most likely use the OCI Console, but for large data pumps the GUI will time out. In case your dump file is bigger, use the OCI REST API or CLI, or SDK.</div><div><br /></div><div>Go to Object Storage :</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0fb3engxKJaIlRE723lEwfxMlTuGNsz8pXx6qPnPhnsC_VeLDlC9BzeQ8kG-GHU2GTAfhw7Bah7jfdLhE7-stfkVTb5P3MBsjhHTEnQcHpyXR24bNGgMJA4TsuoO0E6WILGjKA/s1086/Screenshot+2021-01-20+at+11.46.07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="590" data-original-width="1086" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0fb3engxKJaIlRE723lEwfxMlTuGNsz8pXx6qPnPhnsC_VeLDlC9BzeQ8kG-GHU2GTAfhw7Bah7jfdLhE7-stfkVTb5P3MBsjhHTEnQcHpyXR24bNGgMJA4TsuoO0E6WILGjKA/w400-h217/Screenshot+2021-01-20+at+11.46.07.png" width="400" /></a></div><div><br /></div><div>Create a Bucket:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdCI7Laiatf7PrZdoKHCCiBHQtKIHMsHWN8w-L7TavXtUg1sQP1znqL8Uyk5mWgU7c7__-zdm2x_dgwYs0NeZC6o11Vl-IfPRtUAn_5lLuLDEhse6zfeRphzCo5rqzw1VmDrVHQw/s2720/Screenshot+2021-01-20+at+11.16.10.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="904" data-original-width="2720" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdCI7Laiatf7PrZdoKHCCiBHQtKIHMsHWN8w-L7TavXtUg1sQP1znqL8Uyk5mWgU7c7__-zdm2x_dgwYs0NeZC6o11Vl-IfPRtUAn_5lLuLDEhse6zfeRphzCo5rqzw1VmDrVHQw/w640-h212/Screenshot+2021-01-20+at+11.16.10.png" width="640" /></a></div><div><br /></div>I call it db_import:<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7mKJhgnycUiG0dtoPRLrDApI-yI9LONGkkyuCxhmtee73N5bB5Q1krQPTq8YkQ09N42IXxBpOin2er3MKLKEim6BYJMx8nHu1UNc62PVPR54Mw3KfCKy6mX467a63lm2ipwTwGA/s1812/Screenshot+2021-01-20+at+11.16.49.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1500" data-original-width="1812" height="530" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7mKJhgnycUiG0dtoPRLrDApI-yI9LONGkkyuCxhmtee73N5bB5Q1krQPTq8YkQ09N42IXxBpOin2er3MKLKEim6BYJMx8nHu1UNc62PVPR54Mw3KfCKy6mX467a63lm2ipwTwGA/w640-h530/Screenshot+2021-01-20+at+11.16.49.png" width="640" /></a></div><div><br /></div>Click on the new bucket, db_import:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPXC5W5EJrHh-a0DPyjwYb21DSZu9Z5pSyoEnThaeD74sCFZ0FPWpQdbWLkz3nN2ihyphenhyphenUKy4SjgePwvG1GieGrgZR-iphQjh-2Fn3BbACSslunjfDJPiG3lc5J6BPk6dFoCk_Otug/s2726/Screenshot+2021-01-20+at+11.17.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="908" data-original-width="2726" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPXC5W5EJrHh-a0DPyjwYb21DSZu9Z5pSyoEnThaeD74sCFZ0FPWpQdbWLkz3nN2ihyphenhyphenUKy4SjgePwvG1GieGrgZR-iphQjh-2Fn3BbACSslunjfDJPiG3lc5J6BPk6dFoCk_Otug/w640-h214/Screenshot+2021-01-20+at+11.17.04.png" width="640" /></a></div><div><br /></div>In the bucket, click the Upload button:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirVSURT4tpHQ-iotS7_ZyV7bUAGhOPVWQWK7p6ph94N2xg5GBIheQBojVbetii_nSY3vKjMNX-OsveTT-LpLcznxuwJ9fA4mD4Bpsrpne7NW2XuCS31t80objVTQ4ybOBzUUcQ5w/s2048/Screenshot+2021-01-20+at+11.17.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1271" data-original-width="2048" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirVSURT4tpHQ-iotS7_ZyV7bUAGhOPVWQWK7p6ph94N2xg5GBIheQBojVbetii_nSY3vKjMNX-OsveTT-LpLcznxuwJ9fA4mD4Bpsrpne7NW2XuCS31t80objVTQ4ybOBzUUcQ5w/w640-h398/Screenshot+2021-01-20+at+11.17.22.png" width="640" /></a></div><div><br /></div>Drag-drop the files you want to upload. In my case I will just upload one file db_20210119_ini.dmp:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAhB9uSMbsA4V8v5meAkIWAUG6eTYQatP8gGY2wlGJFglpInPWw-4v5mWdmTPrnWnk131lu628yGJSvOi6obzWGOGuql9IGQf7gNe6hA_X8MXlU78e8iDDTQSujCFyfo99BKE_og/s1794/Screenshot+2021-01-20+at+11.17.32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="536" data-original-width="1794" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAhB9uSMbsA4V8v5meAkIWAUG6eTYQatP8gGY2wlGJFglpInPWw-4v5mWdmTPrnWnk131lu628yGJSvOi6obzWGOGuql9IGQf7gNe6hA_X8MXlU78e8iDDTQSujCFyfo99BKE_og/w640-h192/Screenshot+2021-01-20+at+11.17.32.png" width="640" /></a></div><div><br /></div>The uploaded files will appear in the bucket under Objects:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8PrWUaU5uNbO2S6WVVHwDAbO8IPt5gGCM1IcGPPQpCN4Y7AHDPmHBW-aJqSI3nHPg_v7Tr8QyqPoj77QHeI95C0ted9Se2vRLy4bI4vT4tces3ijvsfkaXot3jL_6pR546uqbog/s2048/Screenshot+2021-01-20+at+11.22.14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1288" data-original-width="2048" height="402" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8PrWUaU5uNbO2S6WVVHwDAbO8IPt5gGCM1IcGPPQpCN4Y7AHDPmHBW-aJqSI3nHPg_v7Tr8QyqPoj77QHeI95C0ted9Se2vRLy4bI4vT4tces3ijvsfkaXot3jL_6pR546uqbog/w640-h402/Screenshot+2021-01-20+at+11.22.14.png" width="640" /></a></div><div><br /></div><div>Make sure to copy the URL of the dump file. In order to do so, click the three dots next to the file and click View Object Details</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIbAIV2i70YvqJP3uhSHrJLq6Y66vkBSovcktxPh-7SZZy_PuqBoiT6mLkdfMYvV8QQShFyZzHWhg_Nbo6mkrBUWEULpGhH1MdTmY-8OP6zs5BboUNaqH5tj1ZovS7ZGLljP3yHg/s2048/Screenshot+2021-01-24+at+15.49.37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1222" data-original-width="2048" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIbAIV2i70YvqJP3uhSHrJLq6Y66vkBSovcktxPh-7SZZy_PuqBoiT6mLkdfMYvV8QQShFyZzHWhg_Nbo6mkrBUWEULpGhH1MdTmY-8OP6zs5BboUNaqH5tj1ZovS7ZGLljP3yHg/w640-h382/Screenshot+2021-01-24+at+15.49.37.png" width="640" /></a></div><div><br /></div>And copy the URL Path (URI):</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_ZI2Y8MrwrrQPgkXe6Bywtu0gnBgTzGe3lFN-saItA8jzPw7OCYtkD5fhGg7AEX59xhpYfhRB-_ueP4-HYlapq-JqOwaOaD6lN3BtUZR0CU25bLZY87Hb9CwSAMgl32tHJ6Sk2A/s2621/Screenshot+2021-01-24+at+15.49.50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="2621" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_ZI2Y8MrwrrQPgkXe6Bywtu0gnBgTzGe3lFN-saItA8jzPw7OCYtkD5fhGg7AEX59xhpYfhRB-_ueP4-HYlapq-JqOwaOaD6lN3BtUZR0CU25bLZY87Hb9CwSAMgl32tHJ6Sk2A/w640-h294/Screenshot+2021-01-24+at+15.49.50.png" width="640" /></a></div><div><br /></div><div>Now that the file is available, let's create the database (schema).</div></div><div><br /></div><div>First, I typically create the user with a script:</div><div><br /></div><div><div><span style="font-family: courier;">create user ini identified by Thisisrealsecure123;</span></div><div><span style="font-family: courier;">grant connect to ini;</span></div><div><span style="font-family: courier;">grant create job to ini;</span></div><div><span style="font-family: courier;">grant create dimension to ini;</span></div><div><span style="font-family: courier;">grant create indextype to ini;</span></div><div><span style="font-family: courier;">grant create operator to ini;</span></div><div><span style="font-family: courier;">grant create type to ini;</span></div><div><span style="font-family: courier;">grant create materialized view to ini;</span></div><div><span style="font-family: courier;">grant create trigger to ini;</span></div><div><span style="font-family: courier;">grant create procedure to ini;</span></div><div><span style="font-family: courier;">grant create sequence to ini;</span></div><div><span style="font-family: courier;">grant create view to ini;</span></div><div><span style="font-family: courier;">grant create synonym to ini;</span></div><div><span style="font-family: courier;">grant create cluster to ini;</span></div><div><span style="font-family: courier;">grant create table to ini;</span></div><div><span style="font-family: courier;">grant create session to ini;</span></div><div><span style="font-family: courier;">grant execute on ctxsys.ctx_ddl to ini;</span></div><div><span style="font-family: courier;">grant execute on dbms_crypto to ini;</span></div><div><span style="font-family: courier;">alter user ini quota unlimited on data;</span></div></div><div><span style="font-family: courier;"><br /></span></div>On the APEX Service dashboard, click the Launch SQL Developer Web, log in and copy and run the above script:<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLT-YKNadu1Ahiws0ZNuyF037fMjfahNu533pylchLKAkV00b7LtTk_BSsrXGEJBF2TaVxsKmTKHrvBCjEQvBSR3nTCN5osANusZMiur_gy3j4riP-afN_XOcrMTkyBHT4Atbqzw/s2598/Screenshot+2021-01-24+at+13.48.45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1211" data-original-width="2598" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLT-YKNadu1Ahiws0ZNuyF037fMjfahNu533pylchLKAkV00b7LtTk_BSsrXGEJBF2TaVxsKmTKHrvBCjEQvBSR3nTCN5osANusZMiur_gy3j4riP-afN_XOcrMTkyBHT4Atbqzw/w640-h298/Screenshot+2021-01-24+at+13.48.45.png" width="640" /></a></div><br /><div>Next, import the data pump file which we stored earlier in Object Storage.</div><div><br /></div><div>In order to connect to Object Storage from SQL Dev Web we need some Cloud Credentials. Just like in the first post where we created the SMTP credentials, we will now go to that screen to create some Auth Credentials.</div><div><br /></div><div>Go to Identity > Users and select your user and click the Auth Tokens:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmzAAVetLspWrLyqptJxNbcCJjcCbBxkKpdmz4e2BkP99JJlI1ipw54dYAm9SvJpqysgvtunn7jrgK8liemvKkungD1_czSSOybIKz5LwB9vdcswoMdzrvNK2f8NgO6Ucl-25TuA/s2048/Screenshot+2021-01-24+at+15.11.11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1168" data-original-width="2048" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmzAAVetLspWrLyqptJxNbcCJjcCbBxkKpdmz4e2BkP99JJlI1ipw54dYAm9SvJpqysgvtunn7jrgK8liemvKkungD1_czSSOybIKz5LwB9vdcswoMdzrvNK2f8NgO6Ucl-25TuA/w640-h364/Screenshot+2021-01-24+at+15.11.11.png" width="640" /></a></div><div><br /></div>Click the Generate Token button, give it a name and click the Generate Token button:<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlB6TCSGMLpMltv1h55cJXFJSi0S9wNAKL9A8BYq-MkF8r4v664FZAlkkK-N4ccwhY1wntP9SHHlHLvgZ3ibXAmmRhBht4pruaB9O2f45bMzXeYwUQQ0IQqnmdok0rfUDwnBAktg/s2626/Screenshot+2021-01-24+at+15.11.48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="796" data-original-width="2626" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlB6TCSGMLpMltv1h55cJXFJSi0S9wNAKL9A8BYq-MkF8r4v664FZAlkkK-N4ccwhY1wntP9SHHlHLvgZ3ibXAmmRhBht4pruaB9O2f45bMzXeYwUQQ0IQqnmdok0rfUDwnBAktg/w640-h194/Screenshot+2021-01-24+at+15.11.48.png" width="640" /></a></div><div><br /></div>Copy the created token and hit the close button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMYJvAFf4BvfETSr-Hicd30-0qrgd8q8t0a8bWZ6nxgciuSPWNMlLDfaBnlmOwXP0-uX6gp1b-4I_7XhqTMZ-Xr0ZQa4T18Ya4o2Pt-vb-JUnsV46QAMkQO7H7d8pDf3B0NmjVBg/s2096/Screenshot+2021-01-24+at+15.11.58.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="648" data-original-width="2096" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMYJvAFf4BvfETSr-Hicd30-0qrgd8q8t0a8bWZ6nxgciuSPWNMlLDfaBnlmOwXP0-uX6gp1b-4I_7XhqTMZ-Xr0ZQa4T18Ya4o2Pt-vb-JUnsV46QAMkQO7H7d8pDf3B0NmjVBg/w640-h198/Screenshot+2021-01-24+at+15.11.58.png" width="640" /></a></div><div><br /></div>Note that if you lost your token, you can create another token from this screen (and delete the old one):</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZ_0wgEx6wX9HsTTQmnd-mAunZYfu088wl2mESthM705led81FAvfX6w-eykMebKW12Iz06dsnQfrRZ0GcVy4XUz4xsmKY7vE05W-Upq3zC8zirrarS_ahPwkm_uwYeTPbfj6cg/s2048/Screenshot+2021-01-24+at+15.12.25.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1171" data-original-width="2048" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZ_0wgEx6wX9HsTTQmnd-mAunZYfu088wl2mESthM705led81FAvfX6w-eykMebKW12Iz06dsnQfrRZ0GcVy4XUz4xsmKY7vE05W-Upq3zC8zirrarS_ahPwkm_uwYeTPbfj6cg/w640-h366/Screenshot+2021-01-24+at+15.12.25.png" width="640" /></a></div><div><br /></div>Go back to SQL Developer Web and create the credentials. This will allow us to connect to other cloud services like the Object Storage:</div><div><br /></div><div><div><span style="font-family: courier;">begin</span></div><div><span style="font-family: courier;"> dbms_cloud.create_credential(</span></div><div><span style="font-family: courier;"> credential_name => 'YourName',</span></div><div><span style="font-family: courier;"> username => 'YourUser',</span></div><div><span style="font-family: courier;"> password => 'YourPassword');</span></div><div><span style="font-family: courier;">end;</span></div><div><span style="font-family: courier;">/</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="text-align: center;">In my case it looks like this:</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiarsGg-9WuJQYxKI6UGJMn28X8krQIw0eCipyEaKnPHpnovyRfNT60ct8kHkTwR-sc3GJ78pRdLljfrCSH1RWfomqoWo3F9VIAXdxoRFCv1eexoXHKfTTp0wYKjzWv6jBoCDJ4YQ/s2094/Screenshot+2021-01-24+at+15.15.31.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="952" data-original-width="2094" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiarsGg-9WuJQYxKI6UGJMn28X8krQIw0eCipyEaKnPHpnovyRfNT60ct8kHkTwR-sc3GJ78pRdLljfrCSH1RWfomqoWo3F9VIAXdxoRFCv1eexoXHKfTTp0wYKjzWv6jBoCDJ4YQ/w640-h290/Screenshot+2021-01-24+at+15.15.31.png" width="640" /></a></div><div><br /></div>Now we load the file from our Object Storage into the DATA_PUMP_DIR directory where Data Pump can find the dump file to finally do the import. We use the <a href="https://docs.oracle.com/en/cloud/paas/autonomous-database/adbsa/dbms-cloud.html" target="_blank">DBMS_CLOUD</a> package. Use the credentials you created before, use the URL you copied and the directory name should be DATA_PUMP_DIR</div><div><div><br /></div><div><span style="font-family: courier;">begin</span></div><div><span style="font-family: courier;"> DBMS_CLOUD.GET_OBJECT(</span></div><div><span style="font-family: courier;"> credential_name => 'dgielis',</span></div><div><span style="font-family: courier;"> object_uri => 'https://objectstorage.eu-amsterdam-1.oraclecloud.com/n/ax54uj3ardud/b/db_import/o/db_20210119_ini.dmp',</span></div><div><span style="font-family: courier;"> directory_name => 'DATA_PUMP_DIR'); </span></div><div><span style="font-family: courier;">end;</span></div></div><div><br /></div><div>I took a screenshot of some more commands I used to check my environment:</div><div><ul style="text-align: left;"><li>The first command to check I had credentials (dba_credentials)</li><li>The second to query the Object Storage bucket</li><li>The third to put the object from the Object Storage onto the database machine</li><li>The fourth command to make sure the dump file was in the directory</li></ul></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtw6HKDgucnRuawF7FOtWPq4q_cv8rVCkf50h1DhiMr2LZ6kR9BP0wY4DK-xTPl2pqEMbtF4ac3d7Zzafz6vjjuzYdfSeaAzktUObWtVD9UkC65mshPUfLnGI23_gRhXIOyR5LA/s2048/Screenshot+2021-01-24+at+15.47.40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1307" data-original-width="2048" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtw6HKDgucnRuawF7FOtWPq4q_cv8rVCkf50h1DhiMr2LZ6kR9BP0wY4DK-xTPl2pqEMbtF4ac3d7Zzafz6vjjuzYdfSeaAzktUObWtVD9UkC65mshPUfLnGI23_gRhXIOyR5LA/w640-h408/Screenshot+2021-01-24+at+15.47.40.png" width="640" /></a></div><div><br /></div>Ok - now we can start our Data Pump import by using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sutil/using-oracle_datapump-api.html" target="_blank">DBMS_DATAPUMP</a> API.</div><div><br /></div><div><div><span style="font-family: courier; font-size: x-small;">declare</span></div><div><span style="font-family: courier; font-size: x-small;"> ind NUMBER; -- Loop index</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 NUMBER; -- Data Pump job handle</span></div><div><span style="font-family: courier; font-size: x-small;"> percent_done NUMBER; -- Percentage of job complete</span></div><div><span style="font-family: courier; font-size: x-small;"> job_state VARCHAR2(30); -- To keep track of job state</span></div><div><span style="font-family: courier; font-size: x-small;"> le ku$_LogEntry; -- For WIP and error messages</span></div><div><span style="font-family: courier; font-size: x-small;"> js ku$_JobStatus; -- The job status from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> jd ku$_JobDesc; -- The job description from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> sts ku$_Status; -- The status object returned by get_status</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> -- Create a Data Pump job to do a "full" import (everything in the dump file without filtering).</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 := DBMS_DATAPUMP.OPEN('IMPORT','FULL',NULL,'INI');</span></div><div><span style="font-family: courier; font-size: x-small;"> </span></div><div><span style="font-family: courier; font-size: x-small;"> -- Add the file to the job handler</span></div><div><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.ADD_FILE(h1,'db_20210119_ini.dmp','DATA_PUMP_DIR');</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- As on the previous system the tablespace was different, I remap the tablespace </span></div><div><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.METADATA_REMAP(h1,'REMAP_TABLESPACE','INI','DATA');</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> -- In case you migrate from a legacy Schema Service, in addition, to remap the </span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> -- tablespace, you may also want to remap the schema to a more user-friendly name </span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> --</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.METADATA_REMAP(h1,'REMAP_SCHEMA','DBPTTTBDEG1JF','MYNEWSCHEMA');</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Start the job. An exception is returned if something is not set up properly.</span></div><div><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.START_JOB(h1);</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- The import job should now be running. In the following loop, the job is </span></div><div><span style="font-family: courier; font-size: x-small;"> -- monitored until it completes. In the meantime, progress information is displayed. </span></div><div><span style="font-family: courier; font-size: x-small;"> percent_done := 0;</span></div><div><span style="font-family: courier; font-size: x-small;"> job_state := 'UNDEFINED';</span></div><div><span style="font-family: courier; font-size: x-small;"> while (job_state != 'COMPLETED') and (job_state != 'STOPPED') </span></div><div><span style="font-family: courier; font-size: x-small;"> loop</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_datapump.get_status(h1,</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_job_error +</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_job_status +</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_wip,-1,job_state,sts);</span></div><div><span style="font-family: courier; font-size: x-small;"> js := sts.job_status;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- If the percentage done changed, display the new value.</span></div><div><span style="font-family: courier; font-size: x-small;"> if js.percent_done != percent_done</span></div><div><span style="font-family: courier; font-size: x-small;"> then</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_output.put_line('*** Job percent done = ' || to_char(js.percent_done));</span></div><div><span style="font-family: courier; font-size: x-small;"> percent_done := js.percent_done;</span></div><div><span style="font-family: courier; font-size: x-small;"> end if;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- If any work-in-progress (WIP) or Error messages were received for the job, display them.</span></div><div><span style="font-family: courier; font-size: x-small;"> if (bitand(sts.mask,dbms_datapump.ku$_status_wip) != 0)</span></div><div><span style="font-family: courier; font-size: x-small;"> then</span></div><div><span style="font-family: courier; font-size: x-small;"> le := sts.wip;</span></div><div><span style="font-family: courier; font-size: x-small;"> else</span></div><div><span style="font-family: courier; font-size: x-small;"> if (bitand(sts.mask,dbms_datapump.ku$_status_job_error) != 0)</span></div><div><span style="font-family: courier; font-size: x-small;"> then</span></div><div><span style="font-family: courier; font-size: x-small;"> le := sts.error;</span></div><div><span style="font-family: courier; font-size: x-small;"> else</span></div><div><span style="font-family: courier; font-size: x-small;"> le := null;</span></div><div><span style="font-family: courier; font-size: x-small;"> end if;</span></div><div><span style="font-family: courier; font-size: x-small;"> end if;</span></div><div><span style="font-family: courier; font-size: x-small;"> if le is not null</span></div><div><span style="font-family: courier; font-size: x-small;"> then</span></div><div><span style="font-family: courier; font-size: x-small;"> ind := le.FIRST;</span></div><div><span style="font-family: courier; font-size: x-small;"> while ind is not null loop</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_output.put_line(le(ind).LogText);</span></div><div><span style="font-family: courier; font-size: x-small;"> ind := le.NEXT(ind);</span></div><div><span style="font-family: courier; font-size: x-small;"> end loop;</span></div><div><span style="font-family: courier; font-size: x-small;"> end if;</span></div><div><span style="font-family: courier; font-size: x-small;"> end loop;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Indicate that the job finished and gracefully detach from it. </span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_output.put_line('Job has completed');</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_output.put_line('Final job state = ' || job_state);</span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_datapump.detach(h1);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;">/</span></div></div><div><br /></div><div>And here's the result, everything nicely imported:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-k8HMJM2DwMRFQTsjVjPYA69Zy7pfKvRl5juOasN18OtPZf6OOX5bXxcfvNvk1XjVxyhE2P2h9fAzy8yJj3kAmfqzRRFhLJMpdR-1Wg-Yhf9PFtiR1Y-Z4mfV7I8hJE6Mlm_geA/s2048/Screenshot+2021-01-24+at+16.13.41.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1309" data-original-width="2048" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-k8HMJM2DwMRFQTsjVjPYA69Zy7pfKvRl5juOasN18OtPZf6OOX5bXxcfvNvk1XjVxyhE2P2h9fAzy8yJj3kAmfqzRRFhLJMpdR-1Wg-Yhf9PFtiR1Y-Z4mfV7I8hJE6Mlm_geA/w640-h410/Screenshot+2021-01-24+at+16.13.41.png" width="640" /></a></div><div><br /></div>I switch users and see the tables, and querying the data of a table gives me the data:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJKH_3iYam_8HMAcXLVSq8My2C-RfqivIcpTxmZK5lqc22d9EtPsv1DFx5x0nqm2kuMdvIuLep6A6BQWB-WpwNaG5xwQdKSScGMWDuCVj94FwiDAtQsb8Dwupdd8wO5fSXnyUcKw/s3081/Screenshot+2021-01-24+at+16.15.36.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1021" data-original-width="3081" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJKH_3iYam_8HMAcXLVSq8My2C-RfqivIcpTxmZK5lqc22d9EtPsv1DFx5x0nqm2kuMdvIuLep6A6BQWB-WpwNaG5xwQdKSScGMWDuCVj94FwiDAtQsb8Dwupdd8wO5fSXnyUcKw/w640-h212/Screenshot+2021-01-24+at+16.15.36.png" width="640" /></a></div><br /><div>Pretty neat 😃</div></div><div><br /></div><div><div>When executing the import script in SQL Developer Web (SDW), for large imports, it is possible you will be timed out of SDW before the import job finishes. To monitor the status of the job, you can open another SDW instance and monitor the job. </div><div><br /></div><div><div><span style="font-family: courier; font-size: x-small;">declare</span></div><div><span style="font-family: courier; font-size: x-small;"> ind NUMBER; -- Loop index</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 NUMBER; -- Data Pump job handle</span></div><div><span style="font-family: courier; font-size: x-small;"> percent_done NUMBER; -- Percentage of job complete</span></div><div><span style="font-family: courier; font-size: x-small;"> job_state VARCHAR2(30); -- To keep track of job state</span></div><div><span style="font-family: courier; font-size: x-small;"> le ku$_LogEntry; -- For WIP and error messages</span></div><div><span style="font-family: courier; font-size: x-small;"> js ku$_JobStatus; -- The job status from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> jd ku$_JobDesc; -- The job description from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> sts ku$_Status; -- The status object returned by get_status</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> -- Attach to the Data Pump job</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 := DBMS_DATAPUMP.ATTACH('IMPORT','INI');</span></div></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Get the Job Status</span></div><div><span style="font-family: courier; font-size: x-small;"><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> dbms_datapump.get_status(h1,</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_job_error +</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_job_status +</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> dbms_datapump.ku$_status_wip,-1,job_state,sts);</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> js := sts.job_status;</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"><br /></span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> -- check percent done and output to console</span></div><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> percent_done := js.percent_done;</span></div></span></div><div><span style="font-family: courier; font-size: x-small;"> dbms_output.put_line('*** Job percent done = ' || to_char(percent_done));</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Detach</span></div><div><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.DETACH(h1);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div>In case the status is going bananas, here's a short script you can execute to kill the job if needed. </div><div><br /></div><div><div><div><span style="font-family: courier; font-size: x-small;">declare</span></div><div><span style="font-family: courier; font-size: x-small;"> ind NUMBER; -- Loop index</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 NUMBER; -- Data Pump job handle</span></div><div><span style="font-family: courier; font-size: x-small;"> percent_done NUMBER; -- Percentage of job complete</span></div><div><span style="font-family: courier; font-size: x-small;"> job_state VARCHAR2(30); -- To keep track of job state</span></div><div><span style="font-family: courier; font-size: x-small;"> le ku$_LogEntry; -- For WIP and error messages</span></div><div><span style="font-family: courier; font-size: x-small;"> js ku$_JobStatus; -- The job status from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> jd ku$_JobDesc; -- The job description from get_status</span></div><div><span style="font-family: courier; font-size: x-small;"> sts ku$_Status; -- The status object returned by get_status</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> -- Attach to the Data Pump job</span></div><div><span style="font-family: courier; font-size: x-small;"> h1 := DBMS_DATAPUMP.ATTACH('IMPORT','INI');</span></div></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Stop the job</span></div><div><span style="font-family: courier; font-size: x-small;"><div style="font-family: -webkit-standard;"><span style="font-family: courier; font-size: x-small;"> dbms_datapump.stop_job(h1, 1</span><span style="font-family: courier;">);</span></div></span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> -- Detach</span></div><div><span style="font-family: courier; font-size: x-small;"> DBMS_DATAPUMP.DETACH(h1);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div></div><div><br /></div></div><div><b>Credit to Todd Bottger (update on 30-APR-2021):</b></div><div><b>-- //start</b></div><div><div>There are two different ways to get the actual import job done in PL/SQL. Each has tradeoffs. </div><div> </div><div>1) Use of DBMS_CLOUD.GET_OBJECT followed by DBMS_DATAPUMP import from the local file as described above: this approach probably will be the fastest one for large data sets. </div><div>The downsides are slightly more complex script (more lines of script) and it consumes extra storage space due to GET_OBJECT making a full local copy first. Note that customers pay for this storage space as part of their storage bill. Of course, the price per TB in APEX Service is quite low, so perhaps it will not be a big concern for most folks.</div><div><br /></div><div>2) Alternative approach using DBMS_DATAPUMP *only*. </div><div>Note that DBMS_DATAPUMP in ADB-S now supports importing directly from OCI Object Storage. </div><div>This was implemented in DB 21c and backported to DB 19c for internal patch applied to ADB-S services (including APEX service). <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_DATAPUMP.html#GUID-876AA583-35DC-46B4-97FD-8F02AC1AB3A8" target="_blank">Here</a> and <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sutil/using-oracle-data-pump-api.html#GUID-21E2D775-8EF1-4E66-8E91-AE84F25729CC" target="_blank">here</a> are some DB 21c docs that cover it. </div><div>I have on good authority from folks here at Oracle that this operation reads data over the network and imports in real-time. There are some internal optimizations like read-ahead caching, but it does not make an additional copy to local disk, which is nice. This approach results in simpler script (fewer lines of code – no need for DBMS_CLOUD.GET_OBJECT) and also avoids consuming the extra storage space. </div><div>However, there are performance points to be aware of – i.e. network latencies and some overheads in object storage itself – that probably make it slower than Option A. </div><div>It still might be a good approach for when users want the simplest possible PL/SQL script and they are importing a small data set: </div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">DBMS_DATAPUMP.ADD_FILE(h1, 'https://swiftobjectstorage.us-phoenix-1.oraclecloud.com/v1/<objectstoragenamespace>/<bucketname>/<dumpfilename>', 'MYCREDENTIAL', NULL, dbms_datapump.ku$_file_type_uridump_file);</span></div><div><br /></div><div>Side note: I believe you can use the <filename>_%U.dmp syntax at the end of such URLs when the export was split across multiple files like export_01.dmp, export_02.dmp, etc. to automatically import them all</div></div><div><b>-- //end</b></div><div><br /></div><div>Now that we have our database (all objects and data), let's import the Oracle APEX app.</div><div><br /></div><div>First, we have to create the workspace. I tried to find an easy way to run my workspace sql file, but couldn't. For example in SQL Developer on the desktop, I can just run files from a URL, but in SQL Dev Web this is not available yet:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbZHUJS_Q8qhblj2OhR79NWrLgnkDT7jKtuz5e6cSiC5wbIOhMlvqzXclbv7z3cP3YYcy51cTEweiqBVvm_41yJaBO4SW0_Hz9wKdy6qyOLEcbzWGdCQNdI_Go3v96l0SADBg1Fw/s2704/Screenshot+2021-01-20+at+12.19.25.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="884" data-original-width="2704" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbZHUJS_Q8qhblj2OhR79NWrLgnkDT7jKtuz5e6cSiC5wbIOhMlvqzXclbv7z3cP3YYcy51cTEweiqBVvm_41yJaBO4SW0_Hz9wKdy6qyOLEcbzWGdCQNdI_Go3v96l0SADBg1Fw/w640-h210/Screenshot+2021-01-20+at+12.19.25.png" width="640" /></a></div><br /><div>So, I went with the conventional way of importing my APEX Workspace through APEX itself.</div><div>Log in to the INTERNAL workspace and click on Manage Workspace - Import Workspace:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt1B3R92xtvGZhyphenhyphenE1cfwn6ho1M8a7qTU2_iyCvsIUurK70_VGIK0qPsMGKsHekBccMq9E7o8sCba_dnTXkr3NFMv42Vv7n8JIPYxTAaUaaxx1inLBSfNRhL3vQct61VlS0wCwkqA/s2048/Screenshot+2021-01-24+at+16.28.02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1130" data-original-width="2048" height="354" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt1B3R92xtvGZhyphenhyphenE1cfwn6ho1M8a7qTU2_iyCvsIUurK70_VGIK0qPsMGKsHekBccMq9E7o8sCba_dnTXkr3NFMv42Vv7n8JIPYxTAaUaaxx1inLBSfNRhL3vQct61VlS0wCwkqA/w640-h354/Screenshot+2021-01-24+at+16.28.02.png" width="640" /></a></div><div><br /></div>Select the workspace file and hit next:<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVhtNMedCjVwdoqMN3ymNgBwNBbz14xdWZzoYliM7sgxLZwk1dxjcrkbkWD-4me08dku-8mC0oeK_yw-M42LvOqUTjdrn9rBzjN-6JocuOYAHGSANPNq0G1KI7MxE_2eBtJy5tyg/s2048/Screenshot+2021-01-24+at+16.29.14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1128" data-original-width="2048" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVhtNMedCjVwdoqMN3ymNgBwNBbz14xdWZzoYliM7sgxLZwk1dxjcrkbkWD-4me08dku-8mC0oeK_yw-M42LvOqUTjdrn9rBzjN-6JocuOYAHGSANPNq0G1KI7MxE_2eBtJy5tyg/w640-h352/Screenshot+2021-01-24+at+16.29.14.png" width="640" /></a></div><div><br /></div>Follow the wizard and select to reuse the schema we already created when we imported the database objects:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFjZbOVzyiQcCgmt4HT-K_8qH-eM6hQt8GjE0OeI5iSUo6p7TcQXR6Ba7dih2MaY4_vNttf188W57JpH-HzAsoZMEoC4LfOFJIWsGx_OAAIvQsf8It2QQ9G9hNpR2j8_B1_DUi1w/s2048/Screenshot+2021-01-24+at+16.29.31.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1127" data-original-width="2048" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFjZbOVzyiQcCgmt4HT-K_8qH-eM6hQt8GjE0OeI5iSUo6p7TcQXR6Ba7dih2MaY4_vNttf188W57JpH-HzAsoZMEoC4LfOFJIWsGx_OAAIvQsf8It2QQ9G9hNpR2j8_B1_DUi1w/w640-h352/Screenshot+2021-01-24+at+16.29.31.png" width="640" /></a></div><div><br /></div>Enable the checkbox:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD_Dum_iA1Y5Ab4wPG3Xy2sJ5r49OD7NpiTVcQ35Nmk1Dib4gvwxUrHZFWay3ckWe-ckmwVh8cKo7sL8ackS4fQYpwMC6wYAJtl-H1cZ8iRqVkIz_yvvg0TzclF9T1dZchfmKUEw/s2048/Screenshot+2021-01-24+at+16.29.50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1121" data-original-width="2048" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD_Dum_iA1Y5Ab4wPG3Xy2sJ5r49OD7NpiTVcQ35Nmk1Dib4gvwxUrHZFWay3ckWe-ckmwVh8cKo7sL8ackS4fQYpwMC6wYAJtl-H1cZ8iRqVkIz_yvvg0TzclF9T1dZchfmKUEw/w640-h350/Screenshot+2021-01-24+at+16.29.50.png" width="640" /></a></div><div><br /></div>Finally hit the Install Workspace button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT4Bs-ZrD3C6Dfg7ncCvy9DJdTc96-VYVVdIlZOS37DZ1zHw36otJDLTZBccTuEtAKdOmnBWgcZk7t316YJEGUMAfQZ5jqYU1eImeftBr0IB1Y5K43BeRELPTRI17fXd0rmELgLA/s2048/Screenshot+2021-01-24+at+16.29.59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1123" data-original-width="2048" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT4Bs-ZrD3C6Dfg7ncCvy9DJdTc96-VYVVdIlZOS37DZ1zHw36otJDLTZBccTuEtAKdOmnBWgcZk7t316YJEGUMAfQZ5jqYU1eImeftBr0IB1Y5K43BeRELPTRI17fXd0rmELgLA/w640-h350/Screenshot+2021-01-24+at+16.29.59.png" width="640" /></a></div><div><br /></div>And there we go, done:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMY8og1BjMPS6Czsu_5myia8rQ8EQ480R3RJ56rnh-A8x14Vf2miCpY25iKMvGRVB9cev5S3Cv55LBQxPCk88VGjAwq4kiAd-bXpQA-Wmh1pGrqZERczYgIIB_KQwWQjysajrRHw/s2852/Screenshot+2021-01-24+at+16.30.14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="772" data-original-width="2852" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMY8og1BjMPS6Czsu_5myia8rQ8EQ480R3RJ56rnh-A8x14Vf2miCpY25iKMvGRVB9cev5S3Cv55LBQxPCk88VGjAwq4kiAd-bXpQA-Wmh1pGrqZERczYgIIB_KQwWQjysajrRHw/w640-h174/Screenshot+2021-01-24+at+16.30.14.png" width="640" /></a></div><div><br /></div>The reason I don't create a new workspace, is because I want to take all workspace settings and users from the other system.</div><div><br /></div><div>Log in to the workspace we just imported. Note that you log in with the ADMIN user, same as INTERNAL:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ0DOq60auUULOhbPn6I8ZCqUeDOQ06YtO7xihW_c4I5oGiSbcs_b4a9l3ZD94ZY4HVYi_hy_1WQ6YsZUj5zzCOh8FeusOup3UZezV8pEd9HCw96tt_t3GyPZHdOpmvnKg-Qh5uA/s1244/Screenshot+2021-01-24+at+16.31.29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1244" data-original-width="962" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ0DOq60auUULOhbPn6I8ZCqUeDOQ06YtO7xihW_c4I5oGiSbcs_b4a9l3ZD94ZY4HVYi_hy_1WQ6YsZUj5zzCOh8FeusOup3UZezV8pEd9HCw96tt_t3GyPZHdOpmvnKg-Qh5uA/w309-h400/Screenshot+2021-01-24+at+16.31.29.png" width="309" /></a></div><div><br /></div>APEX recognizes it's the first time you log in and it asks to set a password in this workspace:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5eAHkxZTI0nf3IVxXazcxuXi3By_3Aa0GSxP0GrSrgKZ0BTF8DSN9oZnmTmdP-h5imM5YHCZagOlNxWQ76fBjJ438WJBL_MoteoaYIg4PCASUJObpGk7-ADPSKW_jhucjKDGP-w/s2752/Screenshot+2021-01-24+at+16.31.43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1142" data-original-width="2752" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5eAHkxZTI0nf3IVxXazcxuXi3By_3Aa0GSxP0GrSrgKZ0BTF8DSN9oZnmTmdP-h5imM5YHCZagOlNxWQ76fBjJ438WJBL_MoteoaYIg4PCASUJObpGk7-ADPSKW_jhucjKDGP-w/w640-h266/Screenshot+2021-01-24+at+16.31.43.png" width="640" /></a></div><div><br /></div>You can chose one and hit Apply Changes:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYYQmozs7U63vvJV1Q4mhYxZkIxm6r_Nd7DQTP7xyZSrrDQmNLUsHc2q3MHGdQlNhH3kliBYKTp8dbha0HFm-4mioEdlle_s-q9Z7i1SlyELo4nIfNTpcrOrD4OEmWXH5SH72vHA/s1500/Screenshot+2021-01-24+at+16.31.58.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1214" data-original-width="1500" height="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYYQmozs7U63vvJV1Q4mhYxZkIxm6r_Nd7DQTP7xyZSrrDQmNLUsHc2q3MHGdQlNhH3kliBYKTp8dbha0HFm-4mioEdlle_s-q9Z7i1SlyELo4nIfNTpcrOrD4OEmWXH5SH72vHA/w400-h324/Screenshot+2021-01-24+at+16.31.58.png" width="400" /></a></div><div><br /></div>And that is it, we are now in our imported Workspace.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB2TcNabGl4JjJU_bHJBu1Tc8ZHE25t_0aEm20dxBrizOvrE74hyphenhyphenQJXZ0XtiC6bhBH_3DSGQbWHYZZkdGhtlepphgRDMDcReqrJUCjse7BgcGZz_7fV8h2AdCcBE6hWfUzf-cufw/s2846/Screenshot+2021-01-24+at+16.32.20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="946" data-original-width="2846" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB2TcNabGl4JjJU_bHJBu1Tc8ZHE25t_0aEm20dxBrizOvrE74hyphenhyphenQJXZ0XtiC6bhBH_3DSGQbWHYZZkdGhtlepphgRDMDcReqrJUCjse7BgcGZz_7fV8h2AdCcBE6hWfUzf-cufw/w640-h212/Screenshot+2021-01-24+at+16.32.20.png" width="640" /></a></div><div><br /></div><div>Next up, import the APEX application. We could go to App Builder and follow the import wizard.</div><div>If you have only a handful of applications, this is definitely a good way. However, if you are moving hundreds of apps to this environment you probably more want to script it.</div><div><br /></div><div>Here's a way you could do it. I uploaded the APEX app export files also to Object Storage.</div><div>In order to use this file in APEX, we create a Pre-Authenticated Request, so basically for a specific amount of time, we can access our file without the need for a password and other credentials.</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXGf4oOBNLeOoObXFcrFttKw0KNuKZqTHu8GeyeG2DFxR83a_VDgK_jGH1bELeE3RPOcHAihRBQoKNB29zeISLrgQLWgXXo1YnXK057chuFBcGrDqJJ0LqtNYOWllXGCvclt9HQ/s2048/Screenshot+2021-01-24+at+16.35.20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1303" data-original-width="2048" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXGf4oOBNLeOoObXFcrFttKw0KNuKZqTHu8GeyeG2DFxR83a_VDgK_jGH1bELeE3RPOcHAihRBQoKNB29zeISLrgQLWgXXo1YnXK057chuFBcGrDqJJ0LqtNYOWllXGCvclt9HQ/w640-h408/Screenshot+2021-01-24+at+16.35.20.png" width="640" /></a></div><div><br /></div>Follow the wizard and set for example the expiration of the pre-authentication request to 1 extra day:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnkU_UXf4LS2JEDUfyazwdCfsara-sA-6CKM3y7DukfM7AiX7ei13SHCnuFlaxQ-RpRi3yNGbvWoBfVsDFhZZVGsTjmansb3bztXVcH-Rp6O6CWvbtJbBm_Tf4nh53xGu4l4d4vg/s2539/Screenshot+2021-01-24+at+16.36.37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1239" data-original-width="2539" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnkU_UXf4LS2JEDUfyazwdCfsara-sA-6CKM3y7DukfM7AiX7ei13SHCnuFlaxQ-RpRi3yNGbvWoBfVsDFhZZVGsTjmansb3bztXVcH-Rp6O6CWvbtJbBm_Tf4nh53xGu4l4d4vg/w640-h312/Screenshot+2021-01-24+at+16.36.37.png" width="640" /></a></div><div><br /></div>Copy the URL:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfiBKRxkKvBJIWvpSubQab7Hoa_DoPfPG3-Lo9QesRdSHhFvOfpdwD46X-KG6SVhYclY4jFFzNPDavwLnIekHXNygFdInjZ6Bp24i96Y5BrKCZgu8cjjd-K_Dc3F-smF2-DM3gWw/s1858/Screenshot+2021-01-24+at+16.36.49.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="926" data-original-width="1858" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfiBKRxkKvBJIWvpSubQab7Hoa_DoPfPG3-Lo9QesRdSHhFvOfpdwD46X-KG6SVhYclY4jFFzNPDavwLnIekHXNygFdInjZ6Bp24i96Y5BrKCZgu8cjjd-K_Dc3F-smF2-DM3gWw/w640-h318/Screenshot+2021-01-24+at+16.36.49.png" width="640" /></a></div><div><br /></div>Now, go back to your APEX workspace and click SQL Workshop > SQL Commands and use the following script:</div><div><br /></div><div><div><span style="font-family: courier; font-size: x-small;">declare</span></div><div><span style="font-family: courier; font-size: x-small;"> l_source apex_t_export_files;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> l_source := apex_t_export_files (</span></div><div><span style="font-family: courier; font-size: x-small;"> apex_t_export_file (</span></div><div><span style="font-family: courier; font-size: x-small;"> name => 'f263.sql',</span></div><div><span style="font-family: courier; font-size: x-small;"> contents => apex_web_service.make_rest_request (</span></div><div><span style="font-family: courier; font-size: x-small;"> p_url => 'https://objectstorage../f263.sql',</span></div><div><span style="font-family: courier; font-size: x-small;"> p_http_method => 'GET' )));</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> apex_application_install.install(p_source => l_source );</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><br /></div><div>And presto, the APEX app is installed:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQRwMhep5hfjYdPNOtZyX79iHPySXSuSPZ5oVSj3caE7aHT2Anc-AhAiaQI733NS_hxVXwFOleF2fdymj3V23VH6xOZiFYP-RfIExQsDnqeZn2lzua59ggXtLdZr6pab47c7cjyg/s2560/Screenshot+2021-01-24+at+16.41.59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1229" data-original-width="2560" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQRwMhep5hfjYdPNOtZyX79iHPySXSuSPZ5oVSj3caE7aHT2Anc-AhAiaQI733NS_hxVXwFOleF2fdymj3V23VH6xOZiFYP-RfIExQsDnqeZn2lzua59ggXtLdZr6pab47c7cjyg/w640-h308/Screenshot+2021-01-24+at+16.41.59.png" width="640" /></a></div><div><br /></div>Go to the App Builder, and enjoy seeing the APEX app</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK0akHn16yzHd5px_uVefolwMDEE-A5wKEcf0pCd2gfVLstaqjtLnvW2-6S1NAW2JTwbjmnQbr1gJxGJSx3myYbRc0WlMBfJV3L3AeyviNGfhb_dvPRWMHRs4fs6Cotbef8U924A/s2976/Screenshot+2021-01-24+at+16.42.15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="950" data-original-width="2976" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK0akHn16yzHd5px_uVefolwMDEE-A5wKEcf0pCd2gfVLstaqjtLnvW2-6S1NAW2JTwbjmnQbr1gJxGJSx3myYbRc0WlMBfJV3L3AeyviNGfhb_dvPRWMHRs4fs6Cotbef8U924A/w640-h204/Screenshot+2021-01-24+at+16.42.15.png" width="640" /></a></div><br /><div>It turns out to be quite a long blog post to move my database and APEX app to this new environment.</div></div><div>There are probably more ways to do it, so feel free to comment on this blog post with an improved flow.</div><div><br /></div><div>I also expect in the future it becomes easier. One of the focus points of Oracle APEX 21.1 and further is to make the integration with other Oracle Cloud services easier. If for example Object Storage was known by APEX_APPLICATION_INSTALL or other we would have fewer steps. </div><div><br /></div><div>That's it for now, next up, configure printing and exporting.</div><div><br /></div><div><b>Update 30-APR-2021</b>: </div><div>Todd Bottger sent me a few commands which I incorporated in the blog post. Thank you, Todd!</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com7tag:blogger.com,1999:blog-21122514.post-71522643823767244582021-01-18T15:23:00.000+01:002021-01-18T15:23:19.855+01:00Setup and configure the APEX Application Development Service (including email) in the Oracle Cloud<p>This post is part of the series <a href="https://dgielis.blogspot.com/2021/01/my-spin-on-new-oracle-apex-application.html">My spin on the new Oracle APEX Application Development Service</a>.</p><p>In this post, we will set up everything you need to build an Oracle APEX application that is able to also send emails.</p><p>I expect you already have an <a href="https://www.oracle.com" target="_blank">Oracle Cloud</a> account. If not, it's easy to sign up for one by following the wizards. This post starts when you enter the <b>Oracle Cloud Getting Started page</b>.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-R-VKBR2FMSU/YASGnOeH4GI/AAAAAAAALGs/fI_HxSCdWJQSlqycqs0r3Bq19MX2PamtwCLcBGAsYHQ/s2048/Screenshot%2B2021-01-17%2Bat%2B19.48.34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1094" data-original-width="2048" height="342" src="https://1.bp.blogspot.com/-R-VKBR2FMSU/YASGnOeH4GI/AAAAAAAALGs/fI_HxSCdWJQSlqycqs0r3Bq19MX2PamtwCLcBGAsYHQ/w640-h342/Screenshot%2B2021-01-17%2Bat%2B19.48.34.png" width="640" /></a></div><div><br /></div>Click the menu icon on the top left, select <b>APEX Application Development</b>, and click on <b>APEX Instances</b>:<div><br /><div class="separator" style="clear: both; text-align: center;"><table><tbody><tr><td><a href="https://1.bp.blogspot.com/-Tq_2_NcCsTE/YASMYaupooI/AAAAAAAALG4/Mcu3sa_UCLM_ub02VTxwyx-fuK_vUEp5ACLcBGAsYHQ/s1538/start01.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1538" data-original-width="944" height="320" src="https://1.bp.blogspot.com/-Tq_2_NcCsTE/YASMYaupooI/AAAAAAAALG4/Mcu3sa_UCLM_ub02VTxwyx-fuK_vUEp5ACLcBGAsYHQ/s320/start01.png" /></a></td><td><a href="https://1.bp.blogspot.com/-iK4Qb-mszIg/YASMYdJBDZI/AAAAAAAALG8/Q2FQho0E19wdwHbE4PWG3kiRkpbbRXKMQCLcBGAsYHQ/s2296/start02.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="776" data-original-width="2296" height="216" src="https://1.bp.blogspot.com/-iK4Qb-mszIg/YASMYdJBDZI/AAAAAAAALG8/Q2FQho0E19wdwHbE4PWG3kiRkpbbRXKMQCLcBGAsYHQ/w640-h216/start02.png" width="640" /></a></td></tr></tbody></table></div>Click the <b>Create APEX Service</b> button and fill out the details.</div><div><br /></div><div>The database name can only be 14 characters and at the moment you can only choose a 19c database.</div><div>Behind the APEX Service is an Autonomous Oracle Database, optimized for APEX. </div><div><br /></div><div><b>I love this APEX Service (and in general the Autonomous Oracle Database) because it can auto-scale</b>. We select 1 OCPU and 1TB of storage, but with Autoscaling it can go up to 3 OCPUs depending on the load. This is a major feature as in almost all the projects I'm involved in, you need, from time to time, just a little extra power (e.g. end-of-month calculations or heavy traffic to your app after an event). In my World Cup Football betting app, for example, every time a game was finished I had a huge spike in visitors as people wanted to know their scores and rank. And <b>the cool thing is that it doesn't require downtime and happens automatically</b>! Note that when it effectively auto-scales you pay for the extra OCPU and potential extra storage, but only for the time it auto-scaled.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-U-ehTCgdWfs/YASMYc7nlJI/AAAAAAAALHA/BG3Irmm3qH4YEFVl0bedj7gABvAKQTBRQCLcBGAsYHQ/s1760/start03.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1646" data-original-width="1760" height="598" src="https://1.bp.blogspot.com/-U-ehTCgdWfs/YASMYc7nlJI/AAAAAAAALHA/BG3Irmm3qH4YEFVl0bedj7gABvAKQTBRQCLcBGAsYHQ/w640-h598/start03.png" width="640" /></a></div><div><br /></div><div>Furthermore, <b>define the password for the ADMIN user</b>, which is needed to login to SQL Developer Web and Oracle APEX. And finally, define the network access. As I want the Oracle APEX apps accessible from anywhere in the world, I chose "Allow secure access from everywhere". Note that you can always change the access and define access control rules later.</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-QBqnsXfwC-I/YASMY61k9LI/AAAAAAAALHE/72j2C8F5dYw_o6qnkF1QYqWrUR77x6I3ACLcBGAsYHQ/s1512/start04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1396" data-original-width="1512" height="592" src="https://1.bp.blogspot.com/-QBqnsXfwC-I/YASMY61k9LI/AAAAAAAALHE/72j2C8F5dYw_o6qnkF1QYqWrUR77x6I3ACLcBGAsYHQ/w640-h592/start04.png" width="640" /></a></div><div><br /></div>Hit the <b>Create APEX Service</b> and the magic will start!</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-GuBN5FtWgh4/YASMZF3XHqI/AAAAAAAALHI/-s6TDK2Y1dAz9aWKdMG39l-4yapwRa6HwCLcBGAsYHQ/s2048/start05.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1049" data-original-width="2048" height="328" src="https://1.bp.blogspot.com/-GuBN5FtWgh4/YASMZF3XHqI/AAAAAAAALHI/-s6TDK2Y1dAz9aWKdMG39l-4yapwRa6HwCLcBGAsYHQ/w640-h328/start05.png" width="640" /></a></div><div><br /></div>A few minutes later the <b>APEX Instance is ready to be used</b>. Behind the scenes, there's an Oracle Database, APEX (20.2 at the time of writing), and ORDS (20.3 at the time of writing) fully configured.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KJiK1lacGqA/YASMZQjHNeI/AAAAAAAALHM/-5bdK0oOq9EDfGdx5umdPv7iTS5-u4sYgCLcBGAsYHQ/s2572/start06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1100" data-original-width="2572" height="274" src="https://1.bp.blogspot.com/-KJiK1lacGqA/YASMZQjHNeI/AAAAAAAALHM/-5bdK0oOq9EDfGdx5umdPv7iTS5-u4sYgCLcBGAsYHQ/w640-h274/start06.png" width="640" /></a></div><div><br /></div><div>We can now access APEX by clicking on the "<b>Launch APEX</b>" button and create REST services and get into the Oracle database by clicking the "<b>Launch SQL Developer Web</b>" button.</div><div><br /></div><div>But before we build an Oracle APEX app, we need to do one extra thing: <b>configure the Oracle Cloud and APEX to allow to send emails</b>. It's a two-step process: create SMTP credentials and enter the email addresses from which emails are allowed to be sent.</div><div><br /></div><div>To get the SMTP credentials, go to Identity > Users and click on a user</div><div><br /></div><table> <tbody><tr> <td><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CR_n3gQV2fg/YASMZXw7bzI/AAAAAAAALHQ/EVWO6GUZHR8qiHP-6hWTgrjG2gJOCBm2ACLcBGAsYHQ/s1504/start10.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1504" data-original-width="992" height="320" src="https://1.bp.blogspot.com/-CR_n3gQV2fg/YASMZXw7bzI/AAAAAAAALHQ/EVWO6GUZHR8qiHP-6hWTgrjG2gJOCBm2ACLcBGAsYHQ/s320/start10.png" /></a></div></td><td><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-3vLBns2eAIU/YASMZjLLAdI/AAAAAAAALHU/QzaD-8i8V2EbcrjS79XTjupkpy_zSs87wCLcBGAsYHQ/s3291/start11.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="956" data-original-width="3291" height="186" src="https://1.bp.blogspot.com/-3vLBns2eAIU/YASMZjLLAdI/AAAAAAAALHU/QzaD-8i8V2EbcrjS79XTjupkpy_zSs87wCLcBGAsYHQ/w640-h186/start11.png" width="640" /></a></div><div><br /></div></td></tr></tbody></table>In the details of the user, click the link <b>SMTP Credentials</b></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-b3xA-q_kj0k/YASMavmmkwI/AAAAAAAALHY/pzW87-tPnQsvWI6B1qzNVSPhO8daQviywCLcBGAsYHQ/s2048/start12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1163" data-original-width="2048" height="364" src="https://1.bp.blogspot.com/-b3xA-q_kj0k/YASMavmmkwI/AAAAAAAALHY/pzW87-tPnQsvWI6B1qzNVSPhO8daQviywCLcBGAsYHQ/w640-h364/start12.png" width="640" /></a></div><div><br /></div>Click the <b>Generate SMTP Credentials</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-GcRg7vCXQkc/YASMazCfqAI/AAAAAAAALHc/a01ybnzcUJMLfpUynM-bbcx87-iS0eajwCLcBGAsYHQ/s3322/start13.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="542" data-original-width="3322" height="104" src="https://1.bp.blogspot.com/-GcRg7vCXQkc/YASMazCfqAI/AAAAAAAALHc/a01ybnzcUJMLfpUynM-bbcx87-iS0eajwCLcBGAsYHQ/w640-h104/start13.png" width="640" /></a></div><div><br /></div>Enter a description and click the Generate SMTP Credentials button:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-9tM0JDhXeUA/YASMbD4IB8I/AAAAAAAALHg/mRYiOZIjAkIP0tv02UwYmInhsEOUoiovgCLcBGAsYHQ/s1760/start14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="398" data-original-width="1760" height="144" src="https://1.bp.blogspot.com/-9tM0JDhXeUA/YASMbD4IB8I/AAAAAAAALHg/mRYiOZIjAkIP0tv02UwYmInhsEOUoiovgCLcBGAsYHQ/w640-h144/start14.png" width="640" /></a></div><div><br /></div>A <b>username and password </b>are created. Make sure to <b>copy both</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-C5sx8VgBLmc/YASMbK_2bNI/AAAAAAAALHk/gmYr85wexUg9Ec9ocOJkn7TpD_W39PB5gCLcBGAsYHQ/s1826/start15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="738" data-original-width="1826" height="258" src="https://1.bp.blogspot.com/-C5sx8VgBLmc/YASMbK_2bNI/AAAAAAAALHk/gmYr85wexUg9Ec9ocOJkn7TpD_W39PB5gCLcBGAsYHQ/w640-h258/start15.png" width="640" /></a></div><div><br /></div><div>Next, we will add the email addresses from which emails can be sent.</div><div><br /></div><div>Go to <b>Email Delivery</b> and click on <b>Email Approved Senders </b>and hit the <b>Create Approved Sender</b> button.</div><table> <tbody><tr> <td><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-4K9dXVmaYOs/YASMbU9Q8PI/AAAAAAAALHo/cRDD75bjOTg9mt3hsF3kNNuHaX_vU6puQCLcBGAsYHQ/s1102/start17.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="680" data-original-width="1102" src="https://1.bp.blogspot.com/-4K9dXVmaYOs/YASMbU9Q8PI/AAAAAAAALHo/cRDD75bjOTg9mt3hsF3kNNuHaX_vU6puQCLcBGAsYHQ/s320/start17.png" width="320" /></a></div></td><td><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-N8GDG08SE48/YASMbnPCa8I/AAAAAAAALHs/49752n2ENrI--gb3qkDCgFzyeVr1q9nKACLcBGAsYHQ/s3338/start18.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="854" data-original-width="3338" height="165" src="https://1.bp.blogspot.com/-N8GDG08SE48/YASMbnPCa8I/AAAAAAAALHs/49752n2ENrI--gb3qkDCgFzyeVr1q9nKACLcBGAsYHQ/w640-h165/start18.png" width="640" /></a></div></td></tr></tbody></table></div><div>Enter the Email Address and hit the <b>Create Approved Sender</b> button.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YjvklETZSBc/YASMb3kNvmI/AAAAAAAALHw/OMkTxNG-YekJPXAUttBeUXRuzvDSQ_vVACLcBGAsYHQ/s2619/start19.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="2619" height="294" src="https://1.bp.blogspot.com/-YjvklETZSBc/YASMb3kNvmI/AAAAAAAALHw/OMkTxNG-YekJPXAUttBeUXRuzvDSQ_vVACLcBGAsYHQ/w640-h294/start19.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>Repeat the same for other email addresses you want to send from.</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CQhg4aueDSA/YASMb-bCXRI/AAAAAAAALH0/qhjjYkU_7rcqFrXjhULDx1mQAxC-YonugCLcBGAsYHQ/s3346/start20a.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="852" data-original-width="3346" height="162" src="https://1.bp.blogspot.com/-CQhg4aueDSA/YASMb-bCXRI/AAAAAAAALH0/qhjjYkU_7rcqFrXjhULDx1mQAxC-YonugCLcBGAsYHQ/w640-h162/start20a.png" width="640" /></a></div><div><br /></div><div>With United Codes we own both domains: united-codes.com and unitedcodes.com, so I enabled both my email addresses. </div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-48CqvcSlq9I/YASMcN1R_1I/AAAAAAAALH4/zw3iFfJpcPESVcNKRAIUyPELkEVvmvoewCLcBGAsYHQ/s2536/start20b.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="850" data-original-width="2536" height="214" src="https://1.bp.blogspot.com/-48CqvcSlq9I/YASMcN1R_1I/AAAAAAAALH4/zw3iFfJpcPESVcNKRAIUyPELkEVvmvoewCLcBGAsYHQ/w640-h214/start20b.png" width="640" /></a></div><div><br /></div>Click the<b> Email Configuration</b> and copy the <b>Public Endpoint (smtp.email....)</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-PDCfywXg__g/YASMcXhTKOI/AAAAAAAALH8/LqR69283uMoYom3PhJOK5b72MXLRjxy9ACLcBGAsYHQ/s2132/start20c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="738" data-original-width="2132" height="222" src="https://1.bp.blogspot.com/-PDCfywXg__g/YASMcXhTKOI/AAAAAAAALH8/LqR69283uMoYom3PhJOK5b72MXLRjxy9ACLcBGAsYHQ/w640-h222/start20c.png" width="640" /></a></div><div><br /></div>Finally, we will configure the Oracle APEX instance with the SMTP credentials.</div><div><br /></div><div>Head back to the <b>APEX Instance Details</b></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KJiK1lacGqA/YASMZQjHNeI/AAAAAAAALHM/-5bdK0oOq9EDfGdx5umdPv7iTS5-u4sYgCLcBGAsYHQ/s2572/start06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1100" data-original-width="2572" height="274" src="https://1.bp.blogspot.com/-KJiK1lacGqA/YASMZQjHNeI/AAAAAAAALHM/-5bdK0oOq9EDfGdx5umdPv7iTS5-u4sYgCLcBGAsYHQ/w640-h274/start06.png" width="640" /></a></div><div><br /></div><div>Click the <b>Launch SQL Developer Web</b> button and login with ADMIN and the password which was defined during the creation of the service</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ocaAe2PaglY/YASsNAskK4I/AAAAAAAALIo/uY1ssmYA7BY965Z4vdEwm7TOwDuQ57P_QCLcBGAsYHQ/s2048/sqldevw01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1081" data-original-width="2048" height="338" src="https://1.bp.blogspot.com/-ocaAe2PaglY/YASsNAskK4I/AAAAAAAALIo/uY1ssmYA7BY965Z4vdEwm7TOwDuQ57P_QCLcBGAsYHQ/w640-h338/sqldevw01.png" width="640" /></a></div><div><br /></div>The first time you open <b>SQL Developer Web</b>, there's a nice guided tour that explains the functionality in SQL Developer Web. (<i>Note: in case you are interested in a Guided Tour for your own Oracle APEX app, have a look at <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a>, we've built a Guided Tour APEX Plug-in which makes it very easy to provide your users with a nice interactive guide.</i>)<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-oFq5wQg-Qi0/YASsNItMg9I/AAAAAAAALIg/zr4z7-WDc2A_q2NNE5-9KGIn7mcz5vF6QCLcBGAsYHQ/s2048/sqldevw02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="2048" height="334" src="https://1.bp.blogspot.com/-oFq5wQg-Qi0/YASsNItMg9I/AAAAAAAALIg/zr4z7-WDc2A_q2NNE5-9KGIn7mcz5vF6QCLcBGAsYHQ/w640-h334/sqldevw02.png" width="640" /></a></div><div><br /></div>Finally, we arrive at a SQL Worksheet, in which you can type any SQL or PL/SQL statement:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-pXhzIV5Y7Mo/YASsNP66xTI/AAAAAAAALIk/iUF8u8ImREoeuyOW_dfBVhkSNV2iFS-fACLcBGAsYHQ/s2048/sqldevw03.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1074" data-original-width="2048" height="336" src="https://1.bp.blogspot.com/-pXhzIV5Y7Mo/YASsNP66xTI/AAAAAAAALIk/iUF8u8ImREoeuyOW_dfBVhkSNV2iFS-fACLcBGAsYHQ/w640-h336/sqldevw03.png" width="640" /></a></div><div><br /></div><div>By using the APEX_INSTANCE_ADMIN package we can define the SMTP configuration:</div><div><br /></div><div><div><span style="font-family: courier;">set define off</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">BEGIN</span></div><div><span style="font-family: courier;"> APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_HOST_ADDRESS', 'smtp...');</span></div><div><span style="font-family: courier;"> APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_USERNAME', 'o...');</span></div><div><span style="font-family: courier;"> APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_PASSWORD', 'k...');</span></div><div><span style="font-family: courier;"> COMMIT;</span></div><div><span style="font-family: courier;">END;</span></div><div><span style="font-family: courier;">/</span></div></div><div><br /></div>Click the green arrow with the paper, which runs the commands as a script:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-cWDGxy9N5zc/YASsN7YuDWI/AAAAAAAALIs/LQnUYMFLYt4qeEqRuJKTfh20xvvF22LIACLcBGAsYHQ/s2048/sqldevw03a.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1257" data-original-width="2048" height="392" src="https://1.bp.blogspot.com/-cWDGxy9N5zc/YASsN7YuDWI/AAAAAAAALIs/LQnUYMFLYt4qeEqRuJKTfh20xvvF22LIACLcBGAsYHQ/w640-h392/sqldevw03a.png" width="640" /></a></div><div><br /></div><div>That's it, now <b>we are ready to send emails from our APEX instance.</b></div><div><br /></div>Before we login into APEX, I looked a bit more around in SQL Developer Web. For example, I saw that the previous versions of Oracle APEX are still there:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-MR5Fx7hg4ig/YASsOKybORI/AAAAAAAALIw/YiJdgufj5ikEiuToqxRd5ADeeR50DCcdQCLcBGAsYHQ/s1146/sqldevw04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="926" data-original-width="1146" height="518" src="https://1.bp.blogspot.com/-MR5Fx7hg4ig/YASsOKybORI/AAAAAAAALIw/YiJdgufj5ikEiuToqxRd5ADeeR50DCcdQCLcBGAsYHQ/w640-h518/sqldevw04.png" width="640" /></a></div><div><br /></div><div>Trying to delete the older versions or some objects gave me insufficient privileges. This is good, as it means you can't accidentally do something bad:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-gGij2EP57K4/YASsOTXfPfI/AAAAAAAALI4/7ffPee_q4BoWxWsc-QCJhadFWqNNgo9fACLcBGAsYHQ/s1658/sqldevw07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="928" data-original-width="1658" height="358" src="https://1.bp.blogspot.com/-gGij2EP57K4/YASsOTXfPfI/AAAAAAAALI4/7ffPee_q4BoWxWsc-QCJhadFWqNNgo9fACLcBGAsYHQ/w640-h358/sqldevw07.png" width="640" /></a></div><div><br /></div><div>There are also some rules to follow, for example when I wanted to create a new Oracle database user, it has to fulfill some rules. It took me a bit to figure out which ones:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-q6hicrtVPmg/YASsOH33UnI/AAAAAAAALI0/dGjLkkuJnIkTcBpXjbPrlB0-runuxMrXgCLcBGAsYHQ/s2048/sqldevw06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1124" data-original-width="2048" height="352" src="https://1.bp.blogspot.com/-q6hicrtVPmg/YASsOH33UnI/AAAAAAAALI0/dGjLkkuJnIkTcBpXjbPrlB0-runuxMrXgCLcBGAsYHQ/w640-h352/sqldevw06.png" width="640" /></a></div><div><br /></div><div>Anyway, I really like SQL Developer Web. It has many great features and gives you access to your database by just using a browser.</div><div><br /></div><div>So now, <b>let's get started with APEX.</b> From the <b>APEX Instance Details </b>click the <b>Launch APEX</b> button.</div><div><br /></div><div>The first time we try to login into APEX, we need to provide the password we defined during the creation of the service. Hit <b>Sign in to Administration</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-TUVFtXD3qiY/YASw0LucrcI/AAAAAAAALJc/sGFxh40a5JEOfvD43hvXMPPqigik-_swQCLcBGAsYHQ/s2048/apex01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1119" data-original-width="2048" height="350" src="https://1.bp.blogspot.com/-TUVFtXD3qiY/YASw0LucrcI/AAAAAAAALJc/sGFxh40a5JEOfvD43hvXMPPqigik-_swQCLcBGAsYHQ/w640-h350/apex01.png" width="640" /></a></div><div><br /></div><div>We get a nice welcome message and it asks us to create a new <a href="https://docs.oracle.com/en/database/oracle/application-express/20.2/htmdb/understanding-workspace-management.html#GUID-05BA697E-2C9C-4FCB-89FF-B7A6AECD0CD3" target="_blank">Workspace</a>. Hit the<b> Create Workspace</b> button:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-azn7cT1qBms/YASw0C8WDHI/AAAAAAAALJU/JblqoTF-7vYHrZA_F5Lqo0NxW4VlbdqUACLcBGAsYHQ/s2048/apex02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1070" data-original-width="2048" height="334" src="https://1.bp.blogspot.com/-azn7cT1qBms/YASw0C8WDHI/AAAAAAAALJU/JblqoTF-7vYHrZA_F5Lqo0NxW4VlbdqUACLcBGAsYHQ/w640-h334/apex02.png" width="640" /></a></div><div><br /></div>Define a new database user, a password, and a workspace name and hit the <b>Create Workspace</b> button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-_d7TqCqpnG0/YASw0AimOmI/AAAAAAAALJY/V1pdQhWi5wEc16ny3ruTKUGolIC81b0sgCLcBGAsYHQ/s2048/apex03.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1064" data-original-width="2048" height="332" src="https://1.bp.blogspot.com/-_d7TqCqpnG0/YASw0AimOmI/AAAAAAAALJY/V1pdQhWi5wEc16ny3ruTKUGolIC81b0sgCLcBGAsYHQ/w640-h332/apex03.png" width="640" /></a></div><div><br /></div>A few seconds later the workspace is created and we can log in to that Workspace to create our first Oracle APEX application. <b>Click the workspace name link</b>:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-61D2ZxzKF8M/YASw00hN_DI/AAAAAAAALJg/ZjT697M5uaUUafsA-iPm9pKiFLGt6pxGACLcBGAsYHQ/s2048/apex04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1059" data-original-width="2048" height="330" src="https://1.bp.blogspot.com/-61D2ZxzKF8M/YASw00hN_DI/AAAAAAAALJg/ZjT697M5uaUUafsA-iPm9pKiFLGt6pxGACLcBGAsYHQ/w640-h330/apex04.png" width="640" /></a></div><div><br /></div>Enter the workspace name, the username (which is the database user), and the password and hit the <b>Sign In</b> button:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-573_TC8DpWw/YASw1cl1uMI/AAAAAAAALJk/A7c8HxtqsewzYUBQ6vt1g_f6OPOnTj7hQCLcBGAsYHQ/s2048/apex05.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1054" data-original-width="2048" height="330" src="https://1.bp.blogspot.com/-573_TC8DpWw/YASw1cl1uMI/AAAAAAAALJk/A7c8HxtqsewzYUBQ6vt1g_f6OPOnTj7hQCLcBGAsYHQ/w640-h330/apex05.png" width="640" /></a></div><div><br /></div>And here we are in Oracle APEX. Now we are ready to build APEX applications. </div><div>If you are new to Oracle APEX you can follow the <a href="https://docs.oracle.com/en/cloud/paas/apex/gsadd/learn-about-oracle-application-express.html#GUID-EB2427F5-BCEC-4260-82D5-9D4CCDC1A447" target="_blank">Getting started with Oracle APEX Application Development</a> guide, follow <a href="https://devgym.oracle.com/pls/apex/dg/workout/low-code-development-with-oracle-autonomous-database.html" target="_blank">this Oracle Dev Gym tutorial</a>, or <a href="https://www.youtube.com/watch?v=fI0zXKga-6U" target="_blank">watch this video from Todd Bottger</a>.</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uV0J16SBEoA/YASw1-orx3I/AAAAAAAALJo/CZKgU-9FiEAiCX8XOZQswRop0MOqWPcUgCLcBGAsYHQ/s2048/apex06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1074" data-original-width="2048" height="336" src="https://1.bp.blogspot.com/-uV0J16SBEoA/YASw1-orx3I/AAAAAAAALJo/CZKgU-9FiEAiCX8XOZQswRop0MOqWPcUgCLcBGAsYHQ/w640-h336/apex06.png" width="640" /></a></div><div><br /></div>To test if the sending of emails work, head over to SQL Workshop > SQL Commands and enter the following code:</div><div><br /></div><div><div><span style="font-family: courier;">begin</span></div><div><span style="font-family: courier;"> apex_mail.send(</span></div><div><span style="font-family: courier;"> p_to => 'xxx',</span></div><div><span style="font-family: courier;"> p_from => 'xxx',</span></div><div><span style="font-family: courier;"> p_body => 'Testing email from Oracle APEX Cloud service',</span></div><div><span style="font-family: courier;"> p_subj => 'APEX_MAIL Package - Plain Text message');</span></div><div><span style="font-family: courier;"> apex_mail.push_queue; </span></div><div><span style="font-family: courier;">end;</span></div></div><div><br /></div><div>It should run fine:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6GidN6NqM_s/YASw18kTsNI/AAAAAAAALJs/frW_qYs6Nec3jI3unuzhxW9hcWyMCDuMQCLcBGAsYHQ/s1478/apex07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1478" height="442" src="https://1.bp.blogspot.com/-6GidN6NqM_s/YASw18kTsNI/AAAAAAAALJs/frW_qYs6Nec3jI3unuzhxW9hcWyMCDuMQCLcBGAsYHQ/w640-h442/apex07.png" width="640" /></a></div><div><br /></div><div>Check APEX_MAIL_LOG to see if the email was effectively sent:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-N1mLqhN1k_k/YASw2JyxxwI/AAAAAAAALJw/6_AaIY4AXusZdUhTg0IjX3ACrvYxj6lqgCLcBGAsYHQ/s3318/apex08.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="948" data-original-width="3318" height="182" src="https://1.bp.blogspot.com/-N1mLqhN1k_k/YASw2JyxxwI/AAAAAAAALJw/6_AaIY4AXusZdUhTg0IjX3ACrvYxj6lqgCLcBGAsYHQ/w640-h182/apex08.png" width="640" /></a></div><div><br /></div>In case you don't see an entry, it probably means the email is hanging in the mail queue. Check the APEX_MAIL_QUEUE for possible errors:</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Y96LIQc-R9E/YASw2oM4DyI/AAAAAAAALJ0/1qlgMO6Ih04bg9oM0VxsLgcWt4AxPAU3wCLcBGAsYHQ/s2647/apex09.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1188" data-original-width="2647" height="288" src="https://1.bp.blogspot.com/-Y96LIQc-R9E/YASw2oM4DyI/AAAAAAAALJ0/1qlgMO6Ih04bg9oM0VxsLgcWt4AxPAU3wCLcBGAsYHQ/w640-h288/apex09.png" width="640" /></a></div><p>The errors that I've come across are the following:</p><p></p><ul style="text-align: left;"><li>ORA-29278: SMTP transient error: 421 Service not available</li><li>ORA-29279: SMTP permanent error: 535 Authorization failed: Envelope From address <...> not authorized</li></ul><p></p><p>The first error most likely means the SMTP credentials are not entered correctly (see SMTP credentials).<br />The second error most likely means that the email from the address is not allowed to send emails (see Email Delivery).</p><p>Before I finish this blog post I want to highlight that from the APEX Service, you can also see the details of the Autonomous Oracle Database that was created behind the scenes.</p><div>When you are in the <b>APEX Instance Details</b>, click on the link of the <b>Database Name</b>.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-NTCXIqlxcBk/YAS4JBNuRQI/AAAAAAAALKQ/HSxPl78dY7gn0SmrukupRE2Uco_-6RXyQCLcBGAsYHQ/s2572/start06db.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1100" data-original-width="2572" height="274" src="https://1.bp.blogspot.com/-NTCXIqlxcBk/YAS4JBNuRQI/AAAAAAAALKQ/HSxPl78dY7gn0SmrukupRE2Uco_-6RXyQCLcBGAsYHQ/w640-h274/start06db.png" width="640" /></a></div><br /><div>We will now get the details of the <b>Autonomous Database</b></div></div></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-U1S5ZI7CysM/YAS42V_A4jI/AAAAAAAALKY/RsgmJ1tOV1UmM1uttQx4X1Nkqg4ms6EZgCLcBGAsYHQ/s2048/Screenshot%2B2021-01-17%2Bat%2B23.21.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1025" data-original-width="2048" height="320" src="https://1.bp.blogspot.com/-U1S5ZI7CysM/YAS42V_A4jI/AAAAAAAALKY/RsgmJ1tOV1UmM1uttQx4X1Nkqg4ms6EZgCLcBGAsYHQ/w640-h320/Screenshot%2B2021-01-17%2Bat%2B23.21.04.png" width="640" /></a></div><div><br /></div>In case you want to stop the APEX instance or terminate it, you have to go to the database to do this. See the <b>More Actions</b> button. Also when you want to <b>manually Scale Up or Down</b>, you do it from this database screen and not the APEX instance screen. As some might search for it, I thought to point it out in this post. In my series where we set up an <a href="https://dgielis.blogspot.com/2019/09/best-and-cheapest-oracle-apex-hosting.html" target="_blank">Always Free Oracle Cloud</a>, we get a free Oracle Autonomous Database with APEX and SQL Developer Web too, so you might wonder, what is the difference with setting up an APEX instance? The components look identical, but I did notice one difference, the workload type is now called APEX instead of, for example, Transaction Processing:<br /><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bHTsTuCnXhg/YAS8CdDC-cI/AAAAAAAALKs/L_JXwpTAfEwf5OElhPqgHDRqCc2kKDOTgCLcBGAsYHQ/s3111/Screenshot%2B2021-01-17%2Bat%2B23.33.44.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1011" data-original-width="3111" height="208" src="https://1.bp.blogspot.com/-bHTsTuCnXhg/YAS8CdDC-cI/AAAAAAAALKs/L_JXwpTAfEwf5OElhPqgHDRqCc2kKDOTgCLcBGAsYHQ/w640-h208/Screenshot%2B2021-01-17%2Bat%2B23.33.44.png" width="640" /></a></div><div><br /></div>But regardless of the workload type, you will see all the Autonomous Databases also in the APEX Instances screen:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-vfl7N0CDu-o/YAS8CARypWI/AAAAAAAALKk/B49d4C1GOqswuiqYKHGh45buWLJ8_TpIwCLcBGAsYHQ/s3358/Screenshot%2B2021-01-17%2Bat%2B23.35.14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="848" data-original-width="3358" height="162" src="https://1.bp.blogspot.com/-vfl7N0CDu-o/YAS8CARypWI/AAAAAAAALKk/B49d4C1GOqswuiqYKHGh45buWLJ8_TpIwCLcBGAsYHQ/w640-h162/Screenshot%2B2021-01-17%2Bat%2B23.35.14.png" width="640" /></a></div><div><br /></div>When clicking on an APEX instance name, you see metrics of the APEX instance:<br /><div style="text-align: center;"><br /></div><div style="text-align: center;"><img border="0" data-original-height="1217" data-original-width="2048" height="380" src="https://1.bp.blogspot.com/-ccXfP17P5NQ/YAS8CBFHTMI/AAAAAAAALKo/WcaU5AQUea48gCSVbcM6NdCXuwPsqdh0gCLcBGAsYHQ/w640-h380/Screenshot%2B2021-01-17%2Bat%2B23.34.52.png" style="caret-color: rgb(0, 0, 238); color: #0000ee; text-align: center; text-decoration: underline;" width="640" /></div><div><div style="text-align: center;"><br /></div><div>Now, you could also set up the APEX instance through the Autonomous Database wizard and select the APEX workload type:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2AMZua9cwfY/YATAkcSS80I/AAAAAAAALLA/__aMryrMl_4GCMBeyqKOVGOzdha8J2TRQCLcBGAsYHQ/s2048/Screenshot%2B2021-01-17%2Bat%2B23.40.08.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1520" data-original-width="2048" height="476" src="https://1.bp.blogspot.com/-2AMZua9cwfY/YATAkcSS80I/AAAAAAAALLA/__aMryrMl_4GCMBeyqKOVGOzdha8J2TRQCLcBGAsYHQ/w640-h476/Screenshot%2B2021-01-17%2Bat%2B23.40.08.png" width="640" /></a></div><div><br /></div>The difference is that when you follow the APEX Application Development, settings are pre-set or hidden, so it's a more seamless experience. But I hope that in the future when you select to use this new wizard, the wizard will also guide you to set up the email delivery and SMTP credentials automatically, so all those steps are done for you. Object Storage would be another good candidate to set up automatically, for example, create a bucket with the same name as the APEX instance. This would also differentiate it more from using the Create Autonomous Database wizard.</div></div><div><br /></div><div>That's it for now... next up, I will import an existing database (schema) and Oracle APEX app into the environment we just created.</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com5tag:blogger.com,1999:blog-21122514.post-44361405938957262112021-01-15T16:25:00.005+01:002021-04-30T00:01:17.080+02:00My spin on the new Oracle APEX Application Development Service<p>I believe there have never been bigger announcements surrounding <a href="https://apex.oracle.com" target="_blank">Oracle Application Express</a> (APEX) than in the last weeks (or actually months). <b>Oracle is really putting cannons on the marketing of Oracle APEX now!</b></p><p>In the Oracle APEX community, we typically come together at the many APEX conferences in the world. Things changed with COVID and while all the conferences got canceled, the awareness of Oracle APEX rose significantly. Oracle setup special forces to build COVID apps (including Larry Ellison himself!)... and used Oracle APEX to do so. Those apps were mentioned in the White House and many different articles around the world. Not only on the outside things changed, but also on the inside at Oracle, the view towards APEX changed a lot. Oracle APEX finally received the recognition of the leadership team we already knew it deserved for 15 years. And once Larry Ellison, Safra Catz, and the entire management and marketing team get behind something, it's unstoppable. </p><p>It started on December 8th through the 10th, 2020, with the Build Low Code Apps using APEX - Partner Technical Council 2020, where Joel Kallman and many people of the APEX Development team gave an update and did Q&A with the audience. </p><p>December 16th, 2020, with the Virtual Summit <a href="https://www.oracle.com/events/virtual-summits/cloud-platform/build-applications-with-low-code/" target="_blank">Build Applications Faster with Low Code</a>. There were different presentations, but the biggest impact came from Michael Hichwa, the father of Oracle APEX, who announced the new Oracle APEX Application Development Service.</p><p>On January 13th, 2021, Andrew Mendelsohn, executive vice president of Oracle database server technologies, presented <a href="https://www.oracle.com/events/live/new-database-innovations/" target="_blank">the latest announcements about Oracle Database 21c and the new Oracle Application Express (APEX) low-code application development service</a>. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CfHzK1sg7jw/YAFyDO2PoHI/AAAAAAAALGU/g3B85SCbxP8Pd5Cdr4_wzAfdCwZhR2MCQCLcBGAsYHQ/s2533/Screenshot%2B2021-01-13%2Bat%2B18.19.26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1242" data-original-width="2533" height="314" src="https://1.bp.blogspot.com/-CfHzK1sg7jw/YAFyDO2PoHI/AAAAAAAALGU/g3B85SCbxP8Pd5Cdr4_wzAfdCwZhR2MCQCLcBGAsYHQ/w640-h314/Screenshot%2B2021-01-13%2Bat%2B18.19.26.png" width="640" /></a></div><div><br /></div>This was followed by a <a href="https://www.oracle.com/news/announcement/oracle-apex-application-development-service-011321.html" target="_blank">press release</a> the same day.<br /><p></p><p>Today when you go to <a href="http://oracle.com">oracle.com</a>, Oracle APEX is front and center.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bUzaOj6vYhI/YAF_HQ7TSpI/AAAAAAAALGg/R-0NZCeXnjAbSdU7jDrAbfsXFHtFt822wCLcBGAsYHQ/s2048/Screenshot%2B2021-01-15%2Bat%2B12.38.52.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1344" data-original-width="2048" height="420" src="https://1.bp.blogspot.com/-bUzaOj6vYhI/YAF_HQ7TSpI/AAAAAAAALGg/R-0NZCeXnjAbSdU7jDrAbfsXFHtFt822wCLcBGAsYHQ/w640-h420/Screenshot%2B2021-01-15%2Bat%2B12.38.52.png" width="640" /></a></div> <p></p><p>So things changed a bit compared to a few years ago... so let's go back to why I am writing this blog post.</p><p><b>This new Oracle APEX Application Development Service is an interesting spin on the Oracle Cloud.</b> Where before you would set up an Oracle Database and Oracle APEX came with it, with this service it's the other way around! You sign up for a Low Code Development Platform called Oracle APEX, and you get an Oracle Database with it!</p><p>I really like this service, because for a relatively low price (360 USD all costs included) you get a<b> fully managed Oracle APEX instance running on unbeatable hardware (Exadata)</b>, which is able to autoscale based on your needs!</p><p>And what is even better, it looks like this service will also come in the Oracle Cloud Free Tier! I wonder if the disk space is the same as the ATP free tier... remains to be seen. At the moment you can either buy it or try it with the free credits when you sign up.</p><p>Just like <a href="https://dgielis.blogspot.com/2019/09/best-and-cheapest-oracle-apex-hosting.html" target="_blank">my blog series when Oracle launched the Always Free Oracle Cloud</a>, I thought to write a few posts while I set up and test this new service myself.</p><p>Here's my agenda for the upcoming blog posts (subject to change based on my experiences and questions raised by you):</p><p></p><ol style="text-align: left;"><li><a href="https://dgielis.blogspot.com/2021/01/setup-and-configure-apex-application.html" target="_blank">Setup Oracle APEX Application Development Service (include configure of email sending)</a></li><li><a href="https://dgielis.blogspot.com/2021/01/import-existing-database-and-apex-app.html">Import an existing Oracle APEX app and Oracle database schema</a></li><li><a href="https://dgielis.blogspot.com/2021/04/setup-apex-office-print-aop-server-with.html" target="_blank">Configure printing and exporting</a></li><li>Configure media conversion</li><li>Create a custom domain name</li><li>Setup and test automated scaling</li><li>Configure, running and using backups</li><li>Connecting from external tools e.g. Visual Studio Code and SQL Developer</li><li>Monitor your Oracle APEX instance</li><li>Final thoughts</li></ol><div>I will update this post with the links to the new blog posts.</div><p></p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com3tag:blogger.com,1999:blog-21122514.post-33456127930458599632020-11-22T17:49:00.000+01:002020-11-22T17:49:53.791+01:00My steps to upgrade to Oracle APEX 20.2, ORDS 20.3 and AOP 20.3<div>In the last month, the <b>three major components of an Oracle APEX environment </b>got new versions:</div><div>- on October 21, 2020, <a href="https://www.oracle.com/tools/downloads/apex-downloads.html" target="_blank">Oracle Application Express (APEX) 20.2</a> </div><div>- on October 29, 2020, <a href="https://www.oracle.com/database/technologies/appdev/rest-data-services-downloads.html" target="_blank">Oracle REST Data Services (ORDS) 20.3</a> </div><div>- on November 15, 2020, <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP) 20.3</a> </div><div><br /></div><div>In general, the <b>releases are as follows</b> (based on findings from 2018 onwards):</div><div>- APEX has two releases a year, around March/April and one around September/October.</div><div>- ORDS brings out one release per quarter, but from time to time they might skip a quarter.</div><div>- AOP has three major releases per year and some smaller releases in between.</div><div><br /></div><div>Do we <b>upgrade our production environment </b>with every new release? </div><div>- APEX: yes, we upgrade typically once the patchset bundle is available, so every 6 months</div><div>- ORDS: no, we upgrade ORDS once a year, unless we need a specific feature</div><div>- AOP: yes, at least the major releases are followed for the on-premises AOP release. AOP Cloud always has the latest release by default.</div><div><br /></div><div>When I look at our customers, many don't upgrade that fast. The bigger the corporation the slower the uptake, going from every 4 years to yearly upgrades.</div><div><br /></div><div>This weekend we upgraded an environment to bring everything to the latest release. Here's a <b>breakdown of my tasks and some tips</b>.</div><div><div><br /></div></div><div><b>1. Download all the latest software</b></div><div><b><br /></b></div><div><div>- Go to the website <a href="https://www.oracle.com/tools/downloads/apex-downloads.html" target="_blank">Oracle Application Express (APEX) 20.2</a>, click the download link, once you log in the download starts. If you want to be on the latest patch set, then also click the link to download Patch Set Bundle for Oracle APEX 20.2 (32006852). You will need to have a valid support contract with Oracle in order to download the patchset bundle.</div><div><br /></div><div>- Go to the website <a href="https://www.oracle.com/database/technologies/appdev/rest-data-services-downloads.html" target="_blank">Oracle REST Data Services (ORDS) 20.3</a>, click the download link, once you log in the download starts. </div><div><br /></div><div>- Go to the website <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP) 20.3</a>, login (or signup if you don't have an account yet), go to the downloads section, and download the on-premise version of Linux or Windows.</div></div><div><br /></div><div><br /></div><b>2. Prepare installs</b><div><br /></div><div>- Copy all the zip files from step 1 to the server(s). In our case, all of the above software is running on the same server, but many people have separate servers for the DB (where APEX is), ORDS, and AOP.</div><div><br /></div><div>- Prepare the directories and unzip</div><div><br /></div><div>- I typically export all Workspaces and APEX apps before doing the upgrade, in the case of APEX 20.1, and store them somewhere. This way I always have a copy of the app in that APEX version. Here's the command to do so:</div><div><br /></div><div><div><span style="font-family: courier;">/usr/bin/java oracle.apex.APEXExport -db localhost:1521/APEX_PDB -user xxx -password xxx -expWorkspace > workspaces.txt</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">/usr/bin/java oracle.apex.APEXExport -db localhost:1521/APEX_PDB -user xxx -password xxx -instance > applications.txt</span></div></div><div><br /></div><div><br /><div><b>3. Install Oracle APEX</b></div><div><br /></div><div>Just as with the upgrade to Oracle APEX 20.1 I blogged about <a href="https://dgielis.blogspot.com/2020/04/oracle-apex-201-installed-with-only-2.html" target="_blank">previously</a>, I followed the same steps to <a href="https://docs.oracle.com/en/database/oracle/application-express/20.2/htmig/maximizing-uptime-during-apex-upgrade.html#GUID-DE1EEE34-E79A-4937-8B5E-B405BE23F1B5" target="_blank">maximize uptime</a> during the APEX upgrade.</div><div><br /></div><div><div>During the first two phases, the Oracle APEX apps were still running:</div><div><br /></div><div><span style="font-family: courier;">SQL> @apexins1.sql sysaux sysaux temp /i/</span></div><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-lpQkQzZIxvw/X7peTps3tRI/AAAAAAAALEg/Kp9Ef3_xV14NY9xQMH7B1SNlEWNeeGJCgCLcBGAsYHQ/s1344/apex202_phase1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1344" data-original-width="1192" height="400" src="https://1.bp.blogspot.com/-lpQkQzZIxvw/X7peTps3tRI/AAAAAAAALEg/Kp9Ef3_xV14NY9xQMH7B1SNlEWNeeGJCgCLcBGAsYHQ/w355-h400/apex202_phase1.png" width="355" /></a></div><div><br /></div><span style="font-family: courier;">SQL> @apexins2.sql sysaux sysaux temp /i/</span></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZGgiKXXHFnk/X7peTkvtL_I/AAAAAAAALEk/9kyPQW7iuN4yE_AWFi_-je4BI6byDFucgCLcBGAsYHQ/s816/apex202_phase2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="612" data-original-width="816" height="300" src="https://1.bp.blogspot.com/-ZGgiKXXHFnk/X7peTkvtL_I/AAAAAAAALEk/9kyPQW7iuN4yE_AWFi_-je4BI6byDFucgCLcBGAsYHQ/w400-h300/apex202_phase2.png" width="400" /></a></div><div><br /></div><div>The first two phases took about 7 minutes.</div><div><br /></div><div>After phase 2, I stopped ORDS as specified in the doc, but which is not necessary anymore as ORDS is smart and knows APEX is upgrading and automatically suspends activity by itself. </div><div>(As I wanted to upgrade ORDS too I stopped it - read more in ORDS install about that)</div><div><br /></div><div><span style="font-family: courier;">SQL> @apexins3.sql sysaux sysaux temp /i/</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-AZYvvDFojgE/X7peThkcSYI/AAAAAAAALEc/SvA-FwbIqk4XoSC3SM4ZDRkTuCHeb2OogCLcBGAsYHQ/s1448/apex202_phase3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1448" data-original-width="1366" height="400" src="https://1.bp.blogspot.com/-AZYvvDFojgE/X7peThkcSYI/AAAAAAAALEc/SvA-FwbIqk4XoSC3SM4ZDRkTuCHeb2OogCLcBGAsYHQ/w378-h400/apex202_phase3.png" width="378" /></a></div><div><br /></div><div>It completed in about 3.30 minutes.</div><div><br /></div><div>At the same time, phase 3 was running, I copied the images folder.</div><div>Note: you can also use the CDN by running @reset_image_prefix.sql after phase 3 and specifying: https://static.oracle.com/cdn/apex/20.2.0.00.20/</div><div><br /></div><div>With the above steps, the APEX 20.2 install completed. Now, I applied the patchset bundle, which took about 1 minute.</div><div><br /></div><div><span style="font-family: courier;">SQL> @catpatch</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-AWQAltiP_2I/X7peUtv__kI/AAAAAAAALEo/QlHwETl1bNAwsBYNox9Oql5OySFkmPXMACLcBGAsYHQ/s1304/apex202_phase4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1210" data-original-width="1304" height="371" src="https://1.bp.blogspot.com/-AWQAltiP_2I/X7peUtv__kI/AAAAAAAALEo/QlHwETl1bNAwsBYNox9Oql5OySFkmPXMACLcBGAsYHQ/w400-h371/apex202_phase4.png" width="400" /></a></div><br /><div>Finally, I ran the following command to allow APEX apps to access web services:</div><div><div><br /></div><div><span style="font-family: courier;">SQL> BEGIN</span></div><div><span style="font-family: courier;"> DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(</span></div><div><span style="font-family: courier;"> host => '*',</span></div><div><span style="font-family: courier;"> ace => xs$ace_type(privilege_list => xs$name_list('connect'),</span></div><div><span style="font-family: courier;"> principal_name => 'APEX_200200',</span></div><div><span style="font-family: courier;"> principal_type => xs_acl.ptype_db));</span></div><div><span style="font-family: courier;">END;</span></div><div><span style="font-family: courier;">/ </span></div></div><div><br /></div><div>That was pretty much it to upgrade our Oracle APEX 20.1 to 20.2 release.</div><div><br /></div><div><br /></div><div><b>4. Install ORDS</b></div><div><br /></div><div>Every pluggable database and APEX version has its own ORDS. Whenever I upgrade ORDS, I unzip it in a new directory. I copy the config of the previous ORDS version (the whole ords directory) in the new directory where I unzipped ORDS. In my case, I unzipped ORDS 20.3 in /u01/apex202/ords.</div><div>Next to the config, I also copy the start and stop scripts and create a logs directory.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-iQCxxqHHTus/X7po4Df5kvI/AAAAAAAALE8/Iw-27UONBoM0PUxxvB068wo8I3xDykwnACLcBGAsYHQ/s1740/ords_203_dir.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="244" data-original-width="1740" height="90" src="https://1.bp.blogspot.com/-iQCxxqHHTus/X7po4Df5kvI/AAAAAAAALE8/Iw-27UONBoM0PUxxvB068wo8I3xDykwnACLcBGAsYHQ/w640-h90/ords_203_dir.png" width="640" /></a></div><br /><div>Next, I run the ORDS command to set the config directory in the new ords.war file.</div><div><br /></div><div><span style="font-family: courier;">java -jar ords.war configdir /u01/apex202/ords</span></div><div><br /></div><div>To upgrade ORDS I run: </div><div><br /></div><div><span style="font-family: courier;">java -jar ords.war </span></div><div><br /></div><div>This will connect to the database, identify the meta-data, upgrade it, and run ORDS.</div><div>Once it's complete, I stop ORDS and run it with the start_ords.sh script, so proper logging is done. </div><div>Note, in this environment we run ORDS in standalone mode.</div><div><br /></div><div>Now, with the install of ORDS, I made a mistake... I thought to be smart, and upgrade ORDS at the same time when APEX was doing the final install step (see in APEX, when I stopped ORDS).</div><div>This wasn't so smart to do! It looks like ORDS is looking at the APEX version to generate some repository views. It messed up things, as ORDS saw still APEX 20.1 as the flip of APEX versions was still going on. Anyway, I got an error. So I decided to wait until the APEX upgrade was finished, then I ran the ORDS command again and it completed fine. All things were validated ok, start ORDS and we were up-and-running in APEX 20.2 and ORDS 20.3. Tested the apps, all ok... but for one domain, after a few minutes, I saw an error in the ORDS logs:</div><div><br /></div><div><div><span style="font-family: courier; font-size: x-small;">2020-11-21T11:19:38.182Z INFO <CaNhATfOdgVPIOr6aSAtzw> GET www.xxxx.com /ords/f?p=XXXX:LOGIN:0 403</span></div><div><span style="font-family: courier; font-size: x-small;">ProcedureForbiddenException [statusCode=403, logLevel=INFO, reasons=[Access to the procedure named: f is denied. ]]</span></div></div><div><br /></div><div>I still can't explain why it happened. I solved it by running ORDS validate again and restarting ORDS.</div><div><div><br /></div><div><span style="font-family: courier;">java -jar ords.war validate</span></div></div><div><span style="font-family: courier;"><br /></span></div><div>My guess is, that the connection pool was messed up by running ORDS while APEX was not finished yet installing. So my recommendation is to always install APEX first and only once that is complete upgrade ORDS (if you want to do it at the same moment), or the other way around, install ORDS first and once complete upgrade APEX.</div><div><br /></div><div><br /></div><div><b>5. Install AOP</b></div></div><div><br /></div><div>Upgrading AOP is the most simple of the three components, as it doesn't have a repository. Unzip the download in a new directory, copy the config (aop_config.json) of the running AOP to the new folder and activate AOP:</div><div><br /></div><div><span style="font-family: courier;">./APEXOfficePrintLinux64 -a</span></div><div><br /></div><div>Stop the old version of AOP, start the new version of AOP, and done.</div><div><br /></div><div><br /></div><div>Happy upgrading!</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com5tag:blogger.com,1999:blog-21122514.post-11406082342897748572020-11-14T17:50:00.000+01:002020-11-14T17:50:02.738+01:00Oracle APEX 20.2: APEX Office Print (AOP) vs native PDF, Excel and HTML<p>One of the most loved features of <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a> is the ability to export an Interactive Report or Grid exactly as you see it on the screen to Excel and PDF. AOP takes into account highlighting, filters, and more as defined by the end-user. This feature has been available since AOP 1.5 (2015) on APEX 5.0 and any higher version of APEX.</p><p>With the release of <a href="https://apex.oracle.com">Oracle APEX 20.2</a>, APEX provides this capability out-of-the-box. Because of this, we have received a few questions like: "Is this AOP functionality?", "How does the native APEX functionality compare with AOP?", "What's the roadmap of AOP?" and I thought the best way to answer would be to write about the differences between APEX Office Print and the native printing functionality in APEX 20.2.</p><p>Let's go back to the start... <b>AOP</b>'s mission has always been to make the printing and exporting of data in Oracle APEX in the format you want as easy as possible. We really believe that business users should be able to create a template in a tool they know (Word, Excel, Powerpoint) and let AOP merge it with data from the database. From day 1, APEX Office Print has been a <b>template-based reporting engine</b>. In your template, you use tags, which AOP replaces with data. When no custom template is selected AOP will use a default AOP Template. AOP is the most integrated printing solution for Oracle APEX out there and provides some unique features like the ability to print and export different regions by providing a single tag. For example, to print an Interactive Report as you see it on the screen you put {&interactive} in your template, to print a chart you use {$chart}, an image you use {%image}, etc.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEispuwfxgMWzIoEgYXcSUz2Tlq9RLH1GmS4nqEJo6LXPonkFZ3rhr7kf4UkQa0XX8vMAyX4xKAxheLm7YanTigT-ewXdtVxWIkvLjJZjHOt35URLcoXq7lHyPzTwKGGq-KJzLuL_A/s1968/Screenshot+2020-11-11+at+23.12.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1022" data-original-width="1968" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEispuwfxgMWzIoEgYXcSUz2Tlq9RLH1GmS4nqEJo6LXPonkFZ3rhr7kf4UkQa0XX8vMAyX4xKAxheLm7YanTigT-ewXdtVxWIkvLjJZjHOt35URLcoXq7lHyPzTwKGGq-KJzLuL_A/w640-h332/Screenshot+2020-11-11+at+23.12.04.png" width="640" /></a></div><p>The built-in exporting solution of <b>Oracle APEX</b> started from a different angle. The APEX development team wanted a<b> PL/SQL only solution</b> to allow people to export data/regions in different formats. Oracle APEX 20.2 is a big advancement to what was already available previously. For example, before you could download a report to CSV, but now APEX allows you to download to native Excel. Also, for Interactive Reports and Grids, you can choose to get the export as you have it on the screen with breaks, etc. In addition to the built-in download of a region, they now expose APIs (APEX_REGION and APEX_DATA_EXPORT packages) to export programmatically. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOrP8mkIfMU-Htj2pJ177spin2xPERRgfsi2jr7iKONh3IO8CvCQhKrspF4iJD2kTJsIs7_uGtxRRSC5VtPjfasMdt_-oScwzci22TGC9sjzY9tv4I_J-wWhkSak_Vc1RBMJuww/s1962/Screenshot+2020-11-11+at+23.07.46.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1034" data-original-width="1962" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOrP8mkIfMU-Htj2pJ177spin2xPERRgfsi2jr7iKONh3IO8CvCQhKrspF4iJD2kTJsIs7_uGtxRRSC5VtPjfasMdt_-oScwzci22TGC9sjzY9tv4I_J-wWhkSak_Vc1RBMJuww/w640-h338/Screenshot+2020-11-11+at+23.07.46.png" width="640" /></a></div><p>Let's look at the questions people ask: </p><p><b>Is this AOP functionality?</b></p><p>No, it's not, in the sense that the creation of the file happens completely in PL/SQL in native APEX, whereas AOP reads the APEX meta-data, creates a JSON, and sends it to the AOP Server which creates the file and serves it back to the database. Of course, reading the meta-data is the same and the output for a single report is very similar when you don't define a custom template in AOP. </p><p>Although AOP is super fast in creating files (< 0.5 seconds!), the native APEX functionality will be the fastest solution to export data as it stays within the database. This is why from AOP 20.3 onwards we also now provide the option to select APEX Report, which will use the native APEX functionality behind the scenes.</p><p><b>How does the native APEX functionality compare with AOP? </b></p><p>The native functionality in Oracle APEX 20.2 focuses on exporting a single region or some flat data (single select statement). This is vastly different from AOP, which focuses on printing and exporting as a whole. AOP is a full templating and printing engine with hundreds of features to create pixel-perfect PDFs and export the data out of your database in the format you want. If you need to create custom letters, bills of lading, documents with images and charts, perform some PDF manipulations like merging, splitting, signing or want to print directly to a printer, for example, AOP is what you need to use. </p><p>When we don't look at general exporting and printing but focus on exporting of APEX regions and data, the native APEX functionality does a great job on basic functionalities. If you want more flexibility and advanced features, AOP is what you want to use. Here are a few examples where AOP shines:</p><p></p><ul style="text-align: left;"><li>put your logo on top of the export (PDF/Excel/HTML)</li><li>export multiple reports with some custom titles and text to PDF</li><li>export different Interactive Report, Interactive Grid, Classic Reports, and some custom data to different sheets in Excel</li><li>keep the styling (e.g. defined in HTML expressions) when exporting to PDF and Excel </li><li>have complete freedom as to how the export looks and define your own template</li><li>support for many different languages</li><li>export the charts of Interactive Reports and Grids</li><li>reference APEX Items in your export</li><li>use a percent graph in your reports</li><li>export a specific saved private or public report</li><li>conditionally hide a specific column when you export</li><li>export Master-Detail(-Detail) Interactive Grids</li><li>export your reports to Word, Open Document Format, or Markdown</li><li>export hierarchical data and different blocks of data </li></ul><p></p><p>I think its great people can create some custom exports and prints with built-in tools and use AOP when more customization, flexibility, and features are needed. In fact, the new API functionality that is exposed in APEX 20.2 will make AOP even better, but more about that in my answer to the next question.</p><p><b>What's the roadmap of AOP?</b></p><p>We shipped the first version of AOP in March 2015 and since that day we have <a href="https://www.apexofficeprint.com/ords/uc/r/aop_portal/release_history" target="_blank">constantly invested in the product</a>. We typically have 3 major releases per year and some smaller releases between them.</p><p>In fact, every year <b>we have invested more in the product than the year before</b>. 2020 is not any different. On the AOP 20.3 release, we have worked for 6 months with 8 people! It was one of the biggest and most challenging releases we have ever done, but it has made it our best release ever! A huge shout-out to the entire team who pulled it together: Sunil, Recep, Gibresh, Niyam, Kelvin, Inias, Jackie, and ... myself 😀</p><p>Two years ago it was announced that <b>AOP will be more integrated into Oracle APEX</b>. In APEX 20.1 and above, you can define <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print</a> as your Print Server on the Instance Level, which replaced the functionality that was deprecated in ORDS. In APEX 20.2 the foundation of further integration of AOP is made available by providing the awesome APEX_REGION and APEX_DATA_EXPORT packages. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTQzWPi_n_-S1ZmgRgPrfxp6__Omn-qERXaJnhbqcyZAo7z3-un__zrBF5RmTBoxF7PQZG6Luml_Zt9toZ8E7S0CQU9_TlPLDpeEK-abJ0fyx2RoJaogOhIr8qj_8cY25bXdUW3A/s2552/Screenshot+2020-11-11+at+22.53.07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1232" data-original-width="2552" height="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTQzWPi_n_-S1ZmgRgPrfxp6__Omn-qERXaJnhbqcyZAo7z3-un__zrBF5RmTBoxF7PQZG6Luml_Zt9toZ8E7S0CQU9_TlPLDpeEK-abJ0fyx2RoJaogOhIr8qj_8cY25bXdUW3A/w640-h309/Screenshot+2020-11-11+at+22.53.07.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p>If you've ever wondered why there's a '<b>PJSON</b>' format in the APEX_DATA_EXPORT package... it's because we worked with the APEX Development team on this. In the last years, we've spent a lot of time understanding the meta-data of APEX and for every new component and release, we've had to put a lot of effort into supporting and testing it. The new packages provide us with a built-in way to get the region meta-data, so we are set up to support any future component.</p><p><b>The Oracle Database and APEX are in our hearts and we do everything we can to provide you with the best printing and exporting solution out there.</b> Just like the APEX Development team, we are dedicated to making you successful. We also understand you might be using additional technologies to Oracle APEX and PL/SQL, and although, today, AOP can already be used from any technology by doing a REST call, we will begin providing SDKs for other technologies too.</p><p>I hope the above addresses some of your questions and I'm happy to answer any other you might ask in the comments section below or by emailing our AOP Support team.</p><p>Happy printing and exporting! 😀</p>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com0tag:blogger.com,1999:blog-21122514.post-27308771438947837902020-11-02T15:23:00.003+01:002020-11-02T15:45:40.637+01:00Create, Read, Fill and Flatten PDF Forms with APEX Office Print 20.3In the last three years, we've put a lot of effort into the PDF capabilities of <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a>.<div><br /></div><div>With AOP 20.3 we are releasing an additional sample app focussed just on PDF generation and manipulation. Here's an overview of the main page, highlighting our many features:<div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbtGMaZLD-GSdkTLNXjrrAUUrZvyKgb6FqCeZx_3S3sLezNmL4Cqkc2eI2I50inuT2E3KHtKn3p4UzFnWHJv7Tbe9KXFSB1pNPSkhM_IwDCeLIlRCBNeoBHt4CU74-pdRad79Y4g/s2048/aop_203_pdf_form.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1751" data-original-width="2048" height="547" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbtGMaZLD-GSdkTLNXjrrAUUrZvyKgb6FqCeZx_3S3sLezNmL4Cqkc2eI2I50inuT2E3KHtKn3p4UzFnWHJv7Tbe9KXFSB1pNPSkhM_IwDCeLIlRCBNeoBHt4CU74-pdRad79Y4g/w640-h547/aop_203_pdf_form.png" width="640" /></a></div><div><br /></div><div>In this blog post, I want to cover <b>PDF Forms</b>. PDF Forms have been around for a long time. My guess is that everybody has had to fill in at least one PDF Form already. An example we as a company have to fill in a lot is the <a href="https://www.irs.gov/pub/irs-pdf/fw8ben.pdf" target="_blank">W-8BEN</a> form, another example is <a href="https://www.irs.gov/pub/irs-pdf/f941.pdf" target="_blank">Form 941</a> Federal Tax Return. </div><div><br /></div><div>Before I go into how you can fill such a PDF Form automatically, let's first look at how you can <b>create a PDF Form yourself with AOP</b>! It looks like COVID increased the requirement to create such forms directly from the database, at least we received many more requests for such a feature lately.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLO0EGRhQZhq-vCqkv1p8IEdoeGVNRHB6LvISeRbFnhOz7xh0QwmLpKXLbE1jj21Ds95mh5g6CehhEWdzA8RJnGofd4kMCyM-UmJcn6otZun3_hB1nTY0gh_C3qCebRGdfAeKCTg/s2048/Screenshot+2020-10-20+at+20.15.11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1399" data-original-width="2048" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLO0EGRhQZhq-vCqkv1p8IEdoeGVNRHB6LvISeRbFnhOz7xh0QwmLpKXLbE1jj21Ds95mh5g6CehhEWdzA8RJnGofd4kMCyM-UmJcn6otZun3_hB1nTY0gh_C3qCebRGdfAeKCTg/w640-h438/Screenshot+2020-10-20+at+20.15.11.png" width="640" /></a></div><div><br /></div><div>First, you create a template in Word (docx), and anywhere you want a form item (text box, radio group, checkbox) you specify the tag <b>{?form</b> name<b>}.</b></div><div><br /></div><div>Next, for every form item you need to specify how it should look in the data you send with the template.</div><div>You can specify the item details in AOP by defining the JSON, a SQL, or PL/SQL statement for example. Here's how the definition looks in a SQL Statement and in JSON:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh-oLVxeqSn4j0Unl3kc6SrGKlQxfj_1hWnOqw9YsN1G4jIFBcW2l2aAiOlk2HP87uDrLsDPMC9OPkDbIlVFsSAEC9pgoTb4wBSNI9dMs9eJbW0j2lw1XfduQ-Mhe4ta4nBOnrZg/s608/Screenshot+2020-10-20+at+20.37.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="296" data-original-width="608" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh-oLVxeqSn4j0Unl3kc6SrGKlQxfj_1hWnOqw9YsN1G4jIFBcW2l2aAiOlk2HP87uDrLsDPMC9OPkDbIlVFsSAEC9pgoTb4wBSNI9dMs9eJbW0j2lw1XfduQ-Mhe4ta4nBOnrZg/w400-h195/Screenshot+2020-10-20+at+20.37.04.png" width="400" /></a></div><br /><div>You define your template and data source in the AOP APEX Plug-in (or PL/SQL API).</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGpeXTV_3CCuidUDxFwmwX2iKw-WFgmiAWGqyIzdztAhnmqWW6S_iB6G0Zaxxg8IRoEkG8LMy0IV3mJMw3t_mOnK-ipn74ehMGfBv_wxkCERrNjiPwId74LpNYm_C-NTML4yzQg/s1706/Screenshot+2020-10-20+at+20.41.54.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1064" data-original-width="1706" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGpeXTV_3CCuidUDxFwmwX2iKw-WFgmiAWGqyIzdztAhnmqWW6S_iB6G0Zaxxg8IRoEkG8LMy0IV3mJMw3t_mOnK-ipn74ehMGfBv_wxkCERrNjiPwId74LpNYm_C-NTML4yzQg/w640-h400/Screenshot+2020-10-20+at+20.41.54.png" width="640" /></a></div><br /><div>That's it, AOP will do the rest and create your beautiful PDF Form automagically! :)</div><div><br /></div><div>Now let's see what AOP can do with PDF Forms we received? E.g. the W-8BEN Form.</div><div>Our dream was to <b>read the PDF Form, identify the fields, and fill it automatically</b> and get a filled-in PDF back... and we nailed it! 😀</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA4RFSLgd3Bw6w6b0aWupkSl6K4nfIj6wzI4y0p02fgZVTKuCeHFmtpD5UVRkOwSrkZ2useWs2Xb9do46aU4cSBX4n2zBuyiwgLiYDF2wdbRyyaatvgFE5Ty4iwTL9VpkjfmZ42A/s2048/Screenshot+2020-10-20+at+20.47.54.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1421" data-original-width="2048" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA4RFSLgd3Bw6w6b0aWupkSl6K4nfIj6wzI4y0p02fgZVTKuCeHFmtpD5UVRkOwSrkZ2useWs2Xb9do46aU4cSBX4n2zBuyiwgLiYDF2wdbRyyaatvgFE5Ty4iwTL9VpkjfmZ42A/w640-h444/Screenshot+2020-10-20+at+20.47.54.png" width="640" /></a></div><div><br /></div>Use the AOP plug-in to tell which PDF you want to read, and set the global variable g_identify_form_fields to true. AOP generates <b>a new PDF that identifies every field and shows what the name is</b>.<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEE_NIToA_r_0zZuVdTFwliNWJPx8Wsc7_RmW1-MG0SgUMW4E6UklNiRwzeN551uIKPWhNyghQjcqgG5T4nBQvO0zJLiajHsY_nU0Iy6wYpCVYci8te27JgFnQiUTRGKy4NVAKZQ/s1698/Screenshot+2020-10-20+at+20.58.25.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="982" data-original-width="1698" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEE_NIToA_r_0zZuVdTFwliNWJPx8Wsc7_RmW1-MG0SgUMW4E6UklNiRwzeN551uIKPWhNyghQjcqgG5T4nBQvO0zJLiajHsY_nU0Iy6wYpCVYci8te27JgFnQiUTRGKy4NVAKZQ/w640-h370/Screenshot+2020-10-20+at+20.58.25.png" width="640" /></a></div><br /><div>If you want <b>all the fields in a JSON</b>, use the AOP PL/SQL API and specify FORM_FIELDS as output type:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Xb10fIk4FGfx3Ea3ByUgz9zar_0K5m2kNyp2KZDqbvHCcvsc6eFUMFq7Y_bn-hErcyi6ynYZv4ETgTtuzekyEHXBOTWYpq9hUKkWOYdVQmt0jhe0a6MorxjeywkiR13U7y2KHw/s1190/Screenshot+2020-10-20+at+21.03.44.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="1190" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Xb10fIk4FGfx3Ea3ByUgz9zar_0K5m2kNyp2KZDqbvHCcvsc6eFUMFq7Y_bn-hErcyi6ynYZv4ETgTtuzekyEHXBOTWYpq9hUKkWOYdVQmt0jhe0a6MorxjeywkiR13U7y2KHw/w640-h352/Screenshot+2020-10-20+at+21.03.44.png" width="640" /></a></div><br /><div>You get back a nice JSON with all the different form fields, the type, and the value, in case it's filled in.</div><div><br /></div><div>To fill the items, you call AOP and specify in "aop_pdf_form_data" the data to <b>fill in the PDF Form</b>.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEireJcnNBLmPTIosCR4x4DdzfBhoRRlS0wd9kDDp5Cb8U6ZBip7GTj-qGIWCsi6XmlRg-kK55b1f34yMl1gVo-i1sgAyQ8NtuClZJgWvBGC_G2FHZ1EW8rBZgxaSod7qzdD7-vfug/s1704/Screenshot+2020-10-20+at+21.12.59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1680" data-original-width="1704" height="630" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEireJcnNBLmPTIosCR4x4DdzfBhoRRlS0wd9kDDp5Cb8U6ZBip7GTj-qGIWCsi6XmlRg-kK55b1f34yMl1gVo-i1sgAyQ8NtuClZJgWvBGC_G2FHZ1EW8rBZgxaSod7qzdD7-vfug/w640-h630/Screenshot+2020-10-20+at+21.12.59.png" width="640" /></a></div><div><br /></div><div>Finally, in case you filled in the PDF Form and now want to make sure other people can't change the fields anymore, you would <b>flatten the PDF</b>. Again, use the AOP PL/SQL API or APEX Plug-in, set the global variable g_output_lock_form to true and you are done!</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiML_mB0VPkIwYtlaJJ1g6phiZc9xZWG9n9McOOxD3MQ4yOl5UqO9XLXhRkS1ne3ZVb1jNlAMDXEBOiR1At5V7V6uoBf900NsIGX_tkubdCUuWzm3bw8JSS7IzNe5Z6u8lCfcGb3A/s1722/Screenshot+2020-10-20+at+21.16.47.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="914" data-original-width="1722" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiML_mB0VPkIwYtlaJJ1g6phiZc9xZWG9n9McOOxD3MQ4yOl5UqO9XLXhRkS1ne3ZVb1jNlAMDXEBOiR1At5V7V6uoBf900NsIGX_tkubdCUuWzm3bw8JSS7IzNe5Z6u8lCfcGb3A/w640-h340/Screenshot+2020-10-20+at+21.16.47.png" width="640" /></a></div><div><br /></div>In the AOP PDF Sample App you will see that the PDF on the left you can still edit, while on the right, you can't:<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmlWqnxCvnsQ_AOQlk0QkR6xPP1zBHg0peFh7q1rVfZyKmBcVDbIEZ75zPTa6yT5BdgL2diFxEytojXcwVx6Ax7mWJq6KmPAMqLq9uZhw-fctKWX3w4oVkGBUF6OmzST-Cg2_r1g/s2048/Screenshot+2020-10-20+at+21.26.40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1155" data-original-width="2048" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmlWqnxCvnsQ_AOQlk0QkR6xPP1zBHg0peFh7q1rVfZyKmBcVDbIEZ75zPTa6yT5BdgL2diFxEytojXcwVx6Ax7mWJq6KmPAMqLq9uZhw-fctKWX3w4oVkGBUF6OmzST-Cg2_r1g/w640-h360/Screenshot+2020-10-20+at+21.26.40.png" width="640" /></a></div><br /><div>It's not going to be any easier than this!</div><div><br /></div><div>In case you need to generate PDF Forms, or you need to fill in forms or you want to process and read those filled-in PDF Forms, AOP can really help. It was a tough nut to crack, but I'm super proud the team was able to pull it together.</div><div><br /></div><div>Be on the lookout for APEX Office Print 20.3, it's coming to you very soon!</div></div></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com8tag:blogger.com,1999:blog-21122514.post-79845579986996740452020-09-28T15:54:00.000+02:002020-09-28T15:54:43.354+02:00More Advanced File Uploads in Oracle APEX<p>This post is part of the <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Getting Started with Plug-ins Pro APEX plug-ins</a> series.</p><p>In many <a href="https://apex.oracle.com" target="_blank">Oracle Application Express</a> projects, there's a requirement that people can upload files. Typically the end-users want the ability to drag-and-drop images, PDFs, or other file types in their application. </p><p>For example, if you use <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print</a>, you might have added in your application the ability for end-users to upload their own templates which typically are docx, xlsx, pptx, html and text files. </p><p>Those files are then stored in the database in a BLOB column or they might be stored on a file server or cloud storage.</p><p>In order to add this capability in your app, <b>APEX provides a File Browse item</b>.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-l5VDGNiXtBY/X3BhnPPvsOI/AAAAAAAAK8g/Dsqff0cPA3EGmCozuUnQQu1hYFRTYT3VQCLcBGAsYHQ/s1296/Screenshot%2B2020-09-27%2Bat%2B11.54.50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="1296" height="158" src="https://1.bp.blogspot.com/-l5VDGNiXtBY/X3BhnPPvsOI/AAAAAAAAK8g/Dsqff0cPA3EGmCozuUnQQu1hYFRTYT3VQCLcBGAsYHQ/w640-h158/Screenshot%2B2020-09-27%2Bat%2B11.54.50.png" width="640" /></a></div><div><br /></div>There are a few <b>settings</b> for this item type; where do you want to store those files (in a BLOB column or in a TEMP table), if you want to allow multiple file uploads at once, and which types of file you want to accept.<div><br /><div style="text-align: center;"><img border="0" data-original-height="974" data-original-width="796" height="400" src="https://1.bp.blogspot.com/-UXRgi6yx5LE/X3BhzC10VpI/AAAAAAAAK8k/TSUT7fx7m5ccYYtG7pTBURArGFzbOTrBwCLcBGAsYHQ/w328-h400/Screenshot%2B2020-09-26%2Bat%2B21.24.20.png" style="caret-color: rgb(0, 0, 238); color: #0000ee; text-align: center; text-decoration: underline;" width="328" /></div><div><p>But be careful with the accepted File Types feature. You can define image/* if you want your browser to only allow selecting of images. BUT specifying the file type doesn't prevent users from dragging-and-dropping other file types! So you can't rely on this feature to keep other file types out of your database. </p><p>As this is a native HTML File Browse item, you can <a href="https://www.benmarshall.me/styling-file-inputs/" target="_blank"><b>customize</b> it with CSS</a> (and HTML and JavaScript). For example, you can make it look like what APEX provides in the APEX Builder itself:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uHRma1UITpM/X3Bj1fYhPmI/AAAAAAAAK80/U9laF6OxNBUPruzwP1MoCP_nB5nBe9HGQCLcBGAsYHQ/s1506/Screenshot%2B2020-09-26%2Bat%2B22.11.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="452" data-original-width="1506" height="192" src="https://1.bp.blogspot.com/-uHRma1UITpM/X3Bj1fYhPmI/AAAAAAAAK80/U9laF6OxNBUPruzwP1MoCP_nB5nBe9HGQCLcBGAsYHQ/w640-h192/Screenshot%2B2020-09-26%2Bat%2B22.11.04.png" width="640" /></a></div><p>In most of the projects I'm involved in, <b>the end-users want more than the standard HTML File Browse that Oracle APEX provides out-of-the-box</b>. </p><p>The <b>most requested features</b> are:</p><p></p><ul style="text-align: left;"><li>Show which files were selected when adding multiple files</li><li>A visual indicator of the progress of uploading</li><li>Save files directly to the cloud (Oracle Cloud Object Storage, Amazon S3) instead of the database</li><li>Limit the file types that will be accepted</li><li>Only allow files with a size less than x MB</li><li>Specific to upload of images: resize and compress images and add watermarks automatically</li><li>Rename files</li></ul><div>There are some excellent open-source JavaScript libraries that bring these features, one of the most known is <a href="https://www.dropzonejs.com/">Dropzone.js</a>. Five years ago, Daniel Hochleitner even created an <a href="https://github.com/Dani3lSun/apex-plugin-dropzone" target="_blank">APEX Plug-in</a> on top of it (with the last update 2 years ago). As this plug-in was really well written, we decided to use it as the starting point for our <b>File & Image Uploader plug-in</b>. You can see our plug-in as a <b>supported version of Dropzone for Oracle APEX</b>, with some extra features.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Wg1yVpi0esg/X3BvLs9glKI/AAAAAAAAK9A/7zXa4jXOfB4n-jYqVRBwM8fgpMd70RExwCLcBGAsYHQ/s1300/Screenshot%2B2020-09-27%2Bat%2B11.55.22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="484" data-original-width="1300" height="238" src="https://1.bp.blogspot.com/-Wg1yVpi0esg/X3BvLs9glKI/AAAAAAAAK9A/7zXa4jXOfB4n-jYqVRBwM8fgpMd70RExwCLcBGAsYHQ/w640-h238/Screenshot%2B2020-09-27%2Bat%2B11.55.22.png" width="640" /></a></div><br /><div>To use this plug-in, you first have to <b>download and install it</b>. I've covered that in my blog posts <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Plug-ins Pro: Getting started: Sign-up and install your first Oracle APEX Plug-in</a>. So if you didn't import the File & Image Uploader Pro plug-in yet, read that post first.</div><div><br /></div><div>I'll cover <b>two use cases</b> where we used our File & Image Uploader plug-in.</div><div><br /></div><div>The<b> first use case</b> is for our RentMaster Platform software which assists in the renting of student homes. We have a form with the information of the contract, and a region which allows people to upload multiple files (up to 3, with a max file size of 5MB) that are linked to this contract. This information is stored in the CONTRACTS table and another <b>CONTRACT_FILES table which has an FK</b> to the CONTRACTS table. Here's a simplified version of the use case in action:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-iuO6NtT0Gng/X3DySMefq2I/AAAAAAAAK98/oit8cDYSvtcUgun_wVytAD5KzUSYUQIxgCLcBGAsYHQ/s1076/upload1.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="436" data-original-width="1076" height="260" src="https://1.bp.blogspot.com/-iuO6NtT0Gng/X3DySMefq2I/AAAAAAAAK98/oit8cDYSvtcUgun_wVytAD5KzUSYUQIxgCLcBGAsYHQ/w640-h260/upload1.gif" width="640" /></a></div><br /><div>In order to create the above, we add a region with our plug-in on the left and a normal classic report on the right. We also have a Dynamic Action that fires when the files are uploaded so that the report on the right is refreshed.</div><div><br /></div><div>The attributes of our plug-in region look like this. As storage type we use <b>Custom Table</b>:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bOe93XmaWzc/X3DzHaxVo0I/AAAAAAAAK-E/H9n_cPewCHAPEMjek33db1gFPLefpm8nQCLcBGAsYHQ/s1782/Screenshot%2B2020-09-27%2Bat%2B22.16.07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1358" data-original-width="1782" height="488" src="https://1.bp.blogspot.com/-bOe93XmaWzc/X3DzHaxVo0I/AAAAAAAAK-E/H9n_cPewCHAPEMjek33db1gFPLefpm8nQCLcBGAsYHQ/w640-h488/Screenshot%2B2020-09-27%2Bat%2B22.16.07.png" width="640" /></a></div><br /><div>The only thing we have to do is define the table in which we want to store the files and the relation (FK) with the parent (ID).</div><div><br /></div><div>The plug-in exposes many dynamic action events, so you know exactly in which state the upload is in. We specified when Dropzone File Upload was successful:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-7vKOdrrDil8/X3Dz-_t8Y6I/AAAAAAAAK-Q/OOI7APOnTvAvhl8OcYb5hOsVOnSNIdyWQCLcBGAsYHQ/s1916/Screenshot%2B2020-09-27%2Bat%2B22.19.20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="664" data-original-width="1916" height="222" src="https://1.bp.blogspot.com/-7vKOdrrDil8/X3Dz-_t8Y6I/AAAAAAAAK-Q/OOI7APOnTvAvhl8OcYb5hOsVOnSNIdyWQCLcBGAsYHQ/w640-h222/Screenshot%2B2020-09-27%2Bat%2B22.19.20.png" width="640" /></a></div><br /><div>Pretty simple and low code :)</div><div><br /></div><div>In the <b>second use case</b>, our customer does auctions. With every auction, multiple images are included of the goods that are for sale. As there are so many images, all those images are resized and watermarked and put outside the database, on a file server and cloud storage. In this example, I will show <b>how to do the image manipulation and save the files directly in the <a href="https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Concepts/objectstorageoverview.htm" target="_blank">Object Storage</a> of the <a href="https://cloud.oracle.com" target="_blank">Oracle Cloud</a></b>.</div><div><br /></div><div><i>Note: if you are interested in <a href="https://dgielis.blogspot.com/2019/09/free-oracle-cloud-9-setup-object.html" target="_blank">how to set up the Object Storage in the Oracle Cloud</a>, read my <a href="https://dgielis.blogspot.com/2019/09/best-and-cheapest-oracle-apex-hosting.html" target="_blank">series</a> on the Always FREE Oracle Cloud.</i></div><div><br /></div><div>In the next animated gif, you see again a simplified version in action. On the left the APEX application with the File & Image Uploader plug-in, on the right, the Oracle Cloud - Object Storage:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Rx1G2O7cKns/X3EGlbqakUI/AAAAAAAAK-k/NISbGrp1wo82oM96Fzl2n47y5cvii1iOgCLcBGAsYHQ/s1617/upload2.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="895" data-original-width="1617" height="354" src="https://1.bp.blogspot.com/-Rx1G2O7cKns/X3EGlbqakUI/AAAAAAAAK-k/NISbGrp1wo82oM96Fzl2n47y5cvii1iOgCLcBGAsYHQ/w640-h354/upload2.gif" width="640" /></a></div><br /><div>The attributes of our plug-in region look like this. As storage type we use this time <b>Web Service</b>:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-p8wpUhetz1o/X3EIoifwEII/AAAAAAAAK-4/nwNz8E7ktLMUOF7QfS-NjvkfH75LwIsWQCLcBGAsYHQ/s1916/Screenshot%2B2020-09-27%2Bat%2B23.47.14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1888" data-original-width="1916" height="630" src="https://1.bp.blogspot.com/-p8wpUhetz1o/X3EIoifwEII/AAAAAAAAK-4/nwNz8E7ktLMUOF7QfS-NjvkfH75LwIsWQCLcBGAsYHQ/w640-h630/Screenshot%2B2020-09-27%2Bat%2B23.47.14.png" width="640" /></a></div><br /><div>Furthermore, in the attributes, we defined that we should only accept images with max size 3MB and only 10 files.</div><div><br /></div><div>This time we also defined <b>transformation</b> parameters, a w<b>atermark</b> and we <b>rename</b> the files on the fly.</div><div><br /></div><div>In the <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/image_uploader_pro/" target="_blank">United Codes File & Image Uploader Pro Sample Application</a>, you will find an Attribute Builder, which makes it very easy to define what your transformations and watermark need to be, so you can just copy and paste in the attributes:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-AnSjagJ3LNk/X3EJmL07YeI/AAAAAAAAK_A/sI8aPB2rQjIVVhGgS48JyUGFESXTnb-3wCLcBGAsYHQ/s2048/Screenshot%2B2020-09-27%2Bat%2B23.52.09.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2048" data-original-width="1862" height="640" src="https://1.bp.blogspot.com/-AnSjagJ3LNk/X3EJmL07YeI/AAAAAAAAK_A/sI8aPB2rQjIVVhGgS48JyUGFESXTnb-3wCLcBGAsYHQ/w582-h640/Screenshot%2B2020-09-27%2Bat%2B23.52.09.png" width="582" /></a></div><br /><div>So we defined a Web Service... this web service can be anything. In my example, I created a web service in <a href="https://www.oracle.com/database/technologies/appdev/rest.html" target="_blank">ORDS</a>. In this web service, I make a call to the Object Storage REST API of the Oracle Cloud. The plug-in will pass some parameters to the web service: file, filename, mimetype, sessionid and appid:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-aMdG1eDKD9w/X3EGaIuWcBI/AAAAAAAAK-c/UK9LsbVUSc0W7hGLFYnbRWtrWubEoz0tQCLcBGAsYHQ/s2048/Screenshot%2B2020-09-27%2Bat%2B23.35.28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1764" data-original-width="2048" height="552" src="https://1.bp.blogspot.com/-aMdG1eDKD9w/X3EGaIuWcBI/AAAAAAAAK-c/UK9LsbVUSc0W7hGLFYnbRWtrWubEoz0tQCLcBGAsYHQ/w640-h552/Screenshot%2B2020-09-27%2Bat%2B23.35.28.png" width="640" /></a></div><br /></div><div>When you look at the above, you might think... hmm, Dimitri is not doing any authentication to his Object Storage... that is correct. To simplify my example I setup <a href="https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/usingpreauthenticatedrequests.htm" target="_blank">Pre-Authenticated Requests</a> for my bucket in the Object Storage. This provides me with a secure URL people can use to put files in my bucket.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-WCwbxJwoF38/X3EGgW8E_II/AAAAAAAAK-g/64TtlrunjI8VmDFvrHbAesDKIY2wi_wkQCLcBGAsYHQ/s2560/Screenshot%2B2020-09-27%2Bat%2B23.01.48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1228" data-original-width="2560" height="308" src="https://1.bp.blogspot.com/-WCwbxJwoF38/X3EGgW8E_II/AAAAAAAAK-g/64TtlrunjI8VmDFvrHbAesDKIY2wi_wkQCLcBGAsYHQ/w640-h308/Screenshot%2B2020-09-27%2Bat%2B23.01.48.png" width="640" /></a></div><br /><div>I believe that most people will do proper authentication, which means you first do an extra call to get the authentication token. You may want to read <a href="https://www.jmjcloud.com/blog/-using-oracle-storage-cloud-service-for-apex-blobs" target="_blank">JMJ Cloud's blog post</a> if you want an example of how to do that from APEX. Adrian Png also did another <a href="https://blogs.oracle.com/oraclemagazine/better-file-storage-in-oracle-cloud" target="_blank">blog post</a> on how to deal with Object Storage from APEX.</div><div><br /></div><div>Now back to the example... this is what the result looks like; the large image was scaled down, the quality was set to 80%, a watermark was added and the file was renamed - all on the fly and automatically!</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-mtw7fEHNal4/X3EPbPE2V9I/AAAAAAAAK_M/AQd2HZyE3NsO0059C6c-8pdDiWlR6l-igCLcBGAsYHQ/s300/1601244951716_nice.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="300" src="https://1.bp.blogspot.com/-mtw7fEHNal4/X3EPbPE2V9I/AAAAAAAAK_M/AQd2HZyE3NsO0059C6c-8pdDiWlR6l-igCLcBGAsYHQ/s0/1601244951716_nice.jpeg" /></a></div><div><br /></div><div>So to recap this example: you add our region plug-in, you specify the actions you want to happen (transform, watermark, rename), define a web service which does the call to your cloud of choice and that's it, now whenever somebody uploads files in your Oracle APEX app, it will go straight to the cloud and all manipulations are done in the background!</div><div><br /></div><div>There are many more use cases you can come up with. This plug-in is also part of our <a href="https://www.apexmediaextension.com" target="_blank">APEX Media Extension (AME)</a>. Using the Plug-ins Pro File & Image Uploader plug-in is great when you want things to happen on the client-side. When you already have images in your database, and you want to manipulate those images, you definitely want to check out AME, as it provides a PL/SQL API to do all that, and more (e.g. read meta-data of photos!). We built AME as a replacement for Oracle Intermedia (see <a href="https://dgielis.blogspot.com/2020/03/apex-media-extension-ame-publicly.html" target="_blank">blog post</a> and <a href="https://dgielis.blogspot.com/2020/03/apex-media-extension-ame-publicly.html" target="_blank">here</a>), we are even featured in the official <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/upgrd/behavior-changes-deprecated-desupport-oracle-database.html#GUID-BABC1C60-EA07-4EBE-8C67-B69B59E4F742" target="_blank">Oracle documentation</a> as a replacement.</div><div><br /></div></div><div><div><div>Ok back, to this plug-in... just like any other <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a> plug-in, there's extensive <a href="https://www.plug-ins-pro.com/plug-ins/UNITEDCODES_IMAGE_UPLOADER/doc/index.html" target="_blank">documentation</a> and a great <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/image_uploader_pro/" target="_blank">sample app</a> that showcases the different features.</div><div><br /></div><div>You can try the plug-in yourself for 1 month for free in your own APEX applications, so you can see what it can do for you. I also want to highlight that through the end of September 2020, there's a special running. You can find all the details on the <a href="https://www.plug-ins-pro.com">Plug-ins Pro</a> website!</div></div><p></p></div></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com3tag:blogger.com,1999:blog-21122514.post-84703608320030210452020-09-21T15:10:00.000+02:002020-09-21T15:10:21.759+02:00Power to the end-user! Create Interactive JET Charts in Oracle APEX<p>This post is part of the <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Getting Started with Plug-ins Pro APEX plug-ins</a> series.</p><p>Charts and visualizations become very important when talking about data. Businesses are using these visualizations to make an appealing story. You will find many <a href="https://visme.co/blog/data-storytelling-tips/" target="_blank">tips and tricks</a> on the internet when you search for <a href="http://www.storytellingwithdata.com" target="_blank">Data Storytelling</a>. One of the most important tips is to <a href="https://infogram.com/page/choose-the-right-chart-data-visualization" target="_blank">use the right chart</a> for your data. </p><p>So as a developer, will you figure out what type of chart to include in your <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> app? <br />Or do you include a complete dashboard with every possible way to look at the data?</p><p><b>The issue is that the perfect chart depends on the story the business wants to tell!</b></p><p>Let's look at an example of that is pertinent to today: COVID data.</p><p>The table below shows the number of positive cases in the last 4 months for two different countries and a total.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fJuLxBe5Z-c/X2ZI-SF-dsI/AAAAAAAAK6E/OapdcNgWvqknPdp9z-_VSjiDllmAzM-ZwCLcBGAsYHQ/s1572/Screenshot%2B2020-09-19%2Bat%2B20.06.56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="376" data-original-width="1572" height="154" src="https://1.bp.blogspot.com/-fJuLxBe5Z-c/X2ZI-SF-dsI/AAAAAAAAK6E/OapdcNgWvqknPdp9z-_VSjiDllmAzM-ZwCLcBGAsYHQ/w640-h154/Screenshot%2B2020-09-19%2Bat%2B20.06.56.png" width="640" /></a></div><div><br /></div>Most likely, people would like to look at this data where the months go from left to right, so let's pivot the data:<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-1Cqz-scCI1E/X2ZI-P6WBFI/AAAAAAAAK6A/Ofi4FxNw5rwkQ_NL9sn5wiixbBpG6FAigCLcBGAsYHQ/s1566/Screenshot%2B2020-09-19%2Bat%2B20.07.03.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="1566" height="122" src="https://1.bp.blogspot.com/-1Cqz-scCI1E/X2ZI-P6WBFI/AAAAAAAAK6A/Ofi4FxNw5rwkQ_NL9sn5wiixbBpG6FAigCLcBGAsYHQ/w640-h122/Screenshot%2B2020-09-19%2Bat%2B20.07.03.png" width="640" /></a></div><div><br /></div><b>How do we visualize this data?</b></div><div><br /></div><div>If I add a Chart region in APEX, providing the data source, adding sorting and a Legend, it looks like this: </div><div> </div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSMIlNex0K9OtbGnCQKWiGg3oDcrFtTRz5nVYyjFNby7cEhz559xco7GUqZXn3f2bxS1NyThbFkKpmUWfOQHIoRKgXLKmOuEOMrtnceD1FwNDsyvBHJzj2RWUBN89NKtx3DgOM4Q/s2722/Screenshot+2020-09-19+at+20.29.33.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="980" data-original-width="2722" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSMIlNex0K9OtbGnCQKWiGg3oDcrFtTRz5nVYyjFNby7cEhz559xco7GUqZXn3f2bxS1NyThbFkKpmUWfOQHIoRKgXLKmOuEOMrtnceD1FwNDsyvBHJzj2RWUBN89NKtx3DgOM4Q/w640-h230/Screenshot+2020-09-19+at+20.29.33.png" width="640" /></a></div><div><br /></div><div>We can now customize the chart further, but without knowing what the business wants to talk about, it's hard, no? We can use different colors, move the legend to the bottom, change the bars to be stacked, use a different chart type, etc..</div><div><br /></div><div>When you look at the history of<b> Oracle APEX, one of the most significant and breathtaking features has been Interactive Reports</b>. As a developer, we specify just the SQL query, but the business user is able to look at the data in different ways.</div><p>With <a href="https://www.united-codes.com" target="_blank">United Codes</a>, we wanted to provide the developer and business user the same functionality as the Interactive Report but with charts. So I'm happy to introduce you to one of the most astonishing <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro APEX plug-ins</a>: <b>Interactive JET Charts Pro</b>. </p><p>Let's look at what this plug-in can bring to your end-users:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-oAYREAoZsYU/X2ZVddxyGmI/AAAAAAAAK6o/njmaqy9cY1IebTsENMqix16HoiajJKDdQCLcBGAsYHQ/s1029/jet_charts_pro.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="1029" height="524" src="https://1.bp.blogspot.com/-oAYREAoZsYU/X2ZVddxyGmI/AAAAAAAAK6o/njmaqy9cY1IebTsENMqix16HoiajJKDdQCLcBGAsYHQ/w640-h524/jet_charts_pro.gif" width="640" /></a></div><div><br /></div>Did you see <b>your end-users can save the customized charts</b>, just like with Interactive Reports? They can add as many charts as they want, so they can<b> quickly change to different views</b> and even share those charts with colleagues! </div><div><b><br /></b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xDzklQOqryY/X2hqLUKJZPI/AAAAAAAAK8Q/a-nRcFZQYk4dkBtFS6yjkIuSbLo1CV63gCLcBGAsYHQ/s2054/Screenshot%2B2020-09-21%2Bat%2B10.53.43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="984" data-original-width="2054" height="306" src="https://1.bp.blogspot.com/-xDzklQOqryY/X2hqLUKJZPI/AAAAAAAAK8Q/a-nRcFZQYk4dkBtFS6yjkIuSbLo1CV63gCLcBGAsYHQ/w640-h306/Screenshot%2B2020-09-21%2Bat%2B10.53.43.png" width="640" /></a></div><br /></div><div><b>Mindblowing</b>? Well, it was for me when I saw how far we got with this 😀<p>Before I show you how to add a customize button to your own charts, I want to continue the data story...</p><p>All of the charts I created in the animated gif are on the same data, but they all support a different story.</p><p>The <b>line chart</b> shows whether lines are going up, going down, or holding steady. You can clearly see that country 2 numbers decline and country 1’s take an upswing.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CV1uu22J1hE/X2aK_GqK4rI/AAAAAAAAK70/2h0lo109D2ksQS7o-ZzqgJZ6Wk_0BXLHACLcBGAsYHQ/s2020/Screenshot%2B2020-09-20%2Bat%2B00.47.56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="834" data-original-width="2020" height="264" src="https://1.bp.blogspot.com/-CV1uu22J1hE/X2aK_GqK4rI/AAAAAAAAK70/2h0lo109D2ksQS7o-ZzqgJZ6Wk_0BXLHACLcBGAsYHQ/w640-h264/Screenshot%2B2020-09-20%2Bat%2B00.47.56.png" width="640" /></a></div><p>The <b>clustered column chart</b> directly compares the two columns. This is perfect when I want to focus on the difference between both countries: the orange column vs the green column. I changed the colors of the charts as they better represent the country and the difference is shown more clearly.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-qF-ILlq7hTQ/X2aLQ2SHOtI/AAAAAAAAK78/lLcISGktDxcWCE1WP90NoMj7_R7iRh2YQCLcBGAsYHQ/s2006/Screenshot%2B2020-09-20%2Bat%2B00.49.00.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="836" data-original-width="2006" height="266" src="https://1.bp.blogspot.com/-qF-ILlq7hTQ/X2aLQ2SHOtI/AAAAAAAAK78/lLcISGktDxcWCE1WP90NoMj7_R7iRh2YQCLcBGAsYHQ/w640-h266/Screenshot%2B2020-09-20%2Bat%2B00.49.00.png" width="640" /></a></div><p></p><p><strong>The stacked column chart focuses on part-to-whole patterns, </strong>how the gold segment and the green segment add up to a total. If I wanted to tell the story about the combined numbers of the countries I would pick the stacked bar chart.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-25MpQ2Cy-3k/X2aLHmug88I/AAAAAAAAK74/g4jZ7RgzJxIH9EMTdikRWyxyNgPsSwsEACLcBGAsYHQ/s2004/Screenshot%2B2020-09-20%2Bat%2B00.48.40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="798" data-original-width="2004" height="254" src="https://1.bp.blogspot.com/-25MpQ2Cy-3k/X2aLHmug88I/AAAAAAAAK74/g4jZ7RgzJxIH9EMTdikRWyxyNgPsSwsEACLcBGAsYHQ/w640-h254/Screenshot%2B2020-09-20%2Bat%2B00.48.40.png" width="640" /></a></div></div><p>So which one to pick, it all depends on the message you want to get across. <b>The Interactive JET Chart APEX Plug-in is ideal if you need to brainstorm on several possible charts, to finally find the perfect chart to support your message.</b> And the cool thing is that as a developer you don't have to make decisions about which type will be most suitable, you <b>give the power to the end-user!</b></p><p>Ok, now that we have a bit more background as to why we built this plug-in, let me walk you through <b>step-by-step how to get started in your own app</b>.</p><div><div><div>The first step is to <b>download and install the plug-in</b>. I covered that in my blog post <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Plug-ins Pro: Getting started: Sign-up and install your first Oracle APEX Plug-in</a>. So if you didn't import the Interactive JET Chart Pro plug-in or one of the other awesome Plug-ins Pro plug-ins yet, read that post first.</div></div><div><br /></div><div>One point of attention, in the last step, when you install the plug-in it will prompt the <b>Component Settings</b> and you have to define which Procedure you want to use to save the charts. This plug-in will save the end-user settings in a table. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-NPHvGjKyI5E/X2aAWwpsLII/AAAAAAAAK60/U7Wvfw2sD4EOju6bpK6JX8V7Yn6y6uS1QCLcBGAsYHQ/s1140/component_settings.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="373" data-original-width="1140" height="210" src="https://1.bp.blogspot.com/-NPHvGjKyI5E/X2aAWwpsLII/AAAAAAAAK60/U7Wvfw2sD4EOju6bpK6JX8V7Yn6y6uS1QCLcBGAsYHQ/w640-h210/component_settings.png" width="640" /></a></div><div><br /></div>I would recommend installing the Sample App that comes with the plug-in. This will install everything you need.</div><div>The <b>procedure</b> is called UC_JET_CHART_API.SAVEREPORT. You can look at that package and can customize it to your needs. As you have full control over the procedures to save, fetch, and delete charts, you can hook up authorization schemes or any rules you like.</div><div><div><br /></div><div>In your application, go to a page where you have a <b>JET Chart</b>. Add a <b>Button</b>, right-click on it and add a <b>Dynamic Action</b> that fires on Click of the button. As Action, you specify <b>United Codes Interactive JET Charts [Plug-in] </b>and you select in <b>Affected Elements</b> the JET Chart Region.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-T0VITIXqnWA/X2aCDyDapqI/AAAAAAAAK7A/YiFifAPkMTorz7w4zo99d7CRbidCnmOlwCLcBGAsYHQ/s1894/Screenshot%2B2020-09-20%2Bat%2B00.10.48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1242" data-original-width="1894" height="420" src="https://1.bp.blogspot.com/-T0VITIXqnWA/X2aCDyDapqI/AAAAAAAAK7A/YiFifAPkMTorz7w4zo99d7CRbidCnmOlwCLcBGAsYHQ/w640-h420/Screenshot%2B2020-09-20%2Bat%2B00.10.48.png" width="640" /></a></div><br /><div>That's it!</div><div><br /></div><div>In the animated gif, I only did a few customizations, but there are so many more things in this plug-in! In the next example I hide and show a series, so you can focus on a single data set and I <b>change a series chart type and color</b>.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-XA26jIzWFR0/X2aEFBOAUZI/AAAAAAAAK7Y/If0k-ApxziIOrhpSeKbjoBg4s6TGMDfvACLcBGAsYHQ/s991/jet_charts_pro2.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="724" data-original-width="991" height="468" src="https://1.bp.blogspot.com/-XA26jIzWFR0/X2aEFBOAUZI/AAAAAAAAK7Y/If0k-ApxziIOrhpSeKbjoBg4s6TGMDfvACLcBGAsYHQ/w640-h468/jet_charts_pro2.gif" width="640" /></a></div><br /><div>Another important feature is that you can <b>download the JET chart</b> you customized to a PNG file.</div><div>This way it's super easy to include the chart in a presentation or document.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-NbAz69ieXkk/X2aDMOFZu5I/AAAAAAAAK7M/A6lgharOpqQvMuzs7SwTo9pH4_m5kErBgCLcBGAsYHQ/s1728/Screenshot%2B2020-09-20%2Bat%2B00.16.02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1008" data-original-width="1728" height="374" src="https://1.bp.blogspot.com/-NbAz69ieXkk/X2aDMOFZu5I/AAAAAAAAK7M/A6lgharOpqQvMuzs7SwTo9pH4_m5kErBgCLcBGAsYHQ/w640-h374/Screenshot%2B2020-09-20%2Bat%2B00.16.02.png" width="640" /></a></div><br /><div>Finally, just like any other <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a> plug-in, there's extensive <a href="https://www.plug-ins-pro.com/plug-ins/UNITEDCODES_INTERACTIVE_JET_CHARTS/doc/index.html" target="_blank">documentation</a> and a great <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/interactive_jet_charts_pro/home" target="_blank">sample app</a> that showcases the different features. I would strongly encourage you to look at the <b>Live Demo</b> in the sample app. The plug-in exposes many events, something I didn't even touch on in this blog post!</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2uTvP2SFaRQ/X2aF_HotK0I/AAAAAAAAK7o/CB405t3nudI5nz4ThHlc4l1hEGK4Qc0uQCLcBGAsYHQ/s2048/Screenshot%2B2020-09-20%2Bat%2B00.27.00.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1457" data-original-width="2048" height="456" src="https://1.bp.blogspot.com/-2uTvP2SFaRQ/X2aF_HotK0I/AAAAAAAAK7o/CB405t3nudI5nz4ThHlc4l1hEGK4Qc0uQCLcBGAsYHQ/w640-h456/Screenshot%2B2020-09-20%2Bat%2B00.27.00.png" width="640" /></a></div><br /><div>You can try the plug-in yourself for 1 month for free in your own APEX applications, so you can see what it can do for you. I also want to highlight that through the end of September 2020, there's a special running. You can find all the details on the <a href="https://www.plug-ins-pro.com">Plug-ins Pro</a> website!</div></div><div><br /></div><div>I'm a big fan of charts and visualizations and I believe your end-users will love this plug-in! </div><div><br /></div><div>In 2008 I did a chart presentation at Kscope and I joked that using charts in your Oracle APEX apps is the shortest way to get a raise (as every manager loves pretty pictures). Our goal is to make you even more successful by providing you extra tools, if this plug-in also gives you a raise, it makes us full of joy. We wish for your success (and raises) 😀</div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com0tag:blogger.com,1999:blog-21122514.post-14218306740033407052020-09-16T15:50:00.000+02:002020-09-16T15:50:39.763+02:00Adding a download (blob) link and context menu to your Interactive Grid in Oracle APEX<p>This post is part of the <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Getting Started with Plug-ins Pro APEX plug-ins</a>.</p><p>In this blog post, I want to highlight another Interactive Grid plug-in we've built: the <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/ig_download_file_pro/home?session=7635238027201" target="_blank">United Codes Interactive Grid Download File Plug-in</a>.</p><p>When you buy any of the <a href="https://www.united-codes.com" target="_blank">United Codes</a> products, when you go to your Account on the website, you can click on View Invoices and have the ability to download them. Those invoices were created with <a href="https://www.apexofficeprint.com" target="_blank">APEX Office Print (AOP)</a> and stored in a <b>BLOB column</b> of a table.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-II7kXbkUIlU/X1_vwZoYhdI/AAAAAAAAK4A/5ABl1OACi1ktnk9vfORTdxypnqfCVCw8QCLcBGAsYHQ/s1672/Screenshot%2B2020-09-15%2Bat%2B00.33.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1380" data-original-width="1672" height="516" src="https://1.bp.blogspot.com/-II7kXbkUIlU/X1_vwZoYhdI/AAAAAAAAK4A/5ABl1OACi1ktnk9vfORTdxypnqfCVCw8QCLcBGAsYHQ/w625-h516/Screenshot%2B2020-09-15%2Bat%2B00.33.04.png" width="625" /></a></div><p>Behind the scenes, we use a <b>Classic Report</b> with a Download BLOB column.</p><p>You have the same feature with an <b>Interactive Report</b>, you can go to any column, and make it a Download BLOB column as in the screenshot below. You tell from which table you want the file to be downloaded and give some extra info like mime type etc.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrLZZ3YGopbZet1956mWc83K4yKd5HdvKXCz0BiMaQyS6xNo4EzOwjgnxnwAeh20tIKOHbhk_Q1cH7co9HNKr3jpCvWK71NIjaggug0lJ6PSZu0sELlDVGUQxBVbWPlFS56qeUXQ/s2048/ir_download_blob.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2048" data-original-width="1477" height="976" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrLZZ3YGopbZet1956mWc83K4yKd5HdvKXCz0BiMaQyS6xNo4EzOwjgnxnwAeh20tIKOHbhk_Q1cH7co9HNKr3jpCvWK71NIjaggug0lJ6PSZu0sELlDVGUQxBVbWPlFS56qeUXQ/w705-h976/ir_download_blob.png" width="705" /></a></div><p>Jackie redid our entire backend system and used many more <b>Interactive Grids</b> (IG). When she tried to include a <b>Download BLOB link</b>, to her surprise there was <b>no such option in an IG</b>. And that is how our IG Download File Plug-in came to live!</p><p><a href="https://twitter.com/mcilroyjackie" target="_blank">Jackie</a>, <a href="https://twitter.com/bostrowsk1" target="_blank">Bartosz</a>, and I did some brainstorming on what such a plug-in would look like and it became a bit <b>more than just a Download Link</b> 😉</p><p>Although this plug-in is probably one of the smaller plug-ins of <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a>, we love it and use it a lot in our own applications. Let me first show it in action!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-X14eV9VG9RI/X1_5fhAM0_I/AAAAAAAAK4U/TYi5UIGtpxE3QOCyLW4o2kn9xApC2uL9gCLcBGAsYHQ/s1067/ig_downloadfile2.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="597" data-original-width="1067" height="350" src="https://1.bp.blogspot.com/-X14eV9VG9RI/X1_5fhAM0_I/AAAAAAAAK4U/TYi5UIGtpxE3QOCyLW4o2kn9xApC2uL9gCLcBGAsYHQ/w625-h350/ig_downloadfile2.gif" width="625" /></a></div><br /><p>As you can see, it's not just a bleeding fast download link, but you can customize what happens when you click. You can show a context menu on right-click or on a normal click and have full control over it. You can preview files and so much more!</p><div>Let's move on <b>integrating this awesome download link into our Interactive Grid</b>. </div><div><br /></div><div>The first step is to <b>download and install the plug-in</b>. I covered that in my blog posts <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Plug-ins Pro: Getting started: Sign-up and install your first Oracle APEX Plug-in</a>. So if you didn't import the IG Download File Pro plug-in yet, read that post first.</div><div><br /></div><div>Once it's installed it's pretty simple to use the plug-in. Go to your Interactive Grid and right-click on the Columns and <b>add a new column</b> called "DOWNLOAD" from <b>type Link</b>. Give it a CSS Class of "download", specify the target of the link as "javascript:///" and finally give it a link text. You could just give it plain text "Download" or you could specify for example an icon by using:</div><div><span style="font-family: courier;"><i class="fa fa-download"></i></span></div><div><br /></div><div>The above step created a Download link column in our Interactive Grid. Now we will hook up the UC IG Download File Dynamic Action Plug-in to this column. <b>Create a Dynamic Action</b>, Event: Click, Selection: jQuery Selector with .download. As Action, we specify the <b>United Codes IG Download File [Plug-In] </b>and enter the requested details of the BLOB. That's it!</div><div><br /></div><div>Here a quick screen-recording of me doing all those steps in a few seconds:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-aAdGDEycVcM/X2COTONxyGI/AAAAAAAAK4g/qHm84nK4OFUXDVzkZ_iGx5Qn698yASKOgCLcBGAsYHQ/s902/ig_downloadfile_create.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="829" data-original-width="902" height="588" src="https://1.bp.blogspot.com/-aAdGDEycVcM/X2COTONxyGI/AAAAAAAAK4g/qHm84nK4OFUXDVzkZ_iGx5Qn698yASKOgCLcBGAsYHQ/w640-h588/ig_downloadfile_create.gif" width="640" /></a></div><div><br /></div>You also find the all steps completely documented in the <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/ig_download_file_pro/5">Usage Guide > </a><a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/ig_download_file_pro/5" target="_blank">Implementation Guide</a>.<div><br /><div>Now, let's look a bit closer to the settings you can enter:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsaFavuD5E2Wob4mFxjBjTDuibQtmHq7RV2U7DJwwLL_eJ-WKb-zPVT6gXW2XvaJDZY1ogUkfAksgzBzYxfi4UGeM3WtUTVl6P00R5TqeZmIAZkUW12xcDnJt1zTnBbFMnUuGvTw/s1730/Screenshot+2020-09-15+at+11.58.18.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1730" data-original-width="1624" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsaFavuD5E2Wob4mFxjBjTDuibQtmHq7RV2U7DJwwLL_eJ-WKb-zPVT6gXW2XvaJDZY1ogUkfAksgzBzYxfi4UGeM3WtUTVl6P00R5TqeZmIAZkUW12xcDnJt1zTnBbFMnUuGvTw/w600-h640/Screenshot+2020-09-15+at+11.58.18.png" width="600" /></a></div><br /><div>You specify the (ID) column in the Interactive Grid and the details of the table where the BLOB is found, like the name of the BLOB column, the mime type, and file name columns.</div><div><br /></div><div>There are also some cool <b>settings</b>. You can keep a normal Download link, or you can extend it so the default behavior is not a download but a menu showing different options. In our own back-end, for example, we quickly wanted to see the preview of a PDF invoice. You just check the checkbox that you want the Context Menu and that is it. This <b>Context Menu</b> by default is enabled on right-click and has some predefined settings like Preview and Download, but you can customize it however you want and even make it the default action.</div><div><br /></div><div><b>Events</b></div><div><br /></div><div>This plug-in wouldn't be a Pro plug-in if it wouldn't expose events. Events allow you to interfere with the download process at any time. Here are the events you can use in your When of the Dynamic Action:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-leFUqTJ02WM/X2DOIDJfWyI/AAAAAAAAK44/KcCtKS8VHww-K799iisHNMy07qoua2P1gCLcBGAsYHQ/s912/Screenshot%2B2020-09-15%2Bat%2B16.19.04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="912" height="162" src="https://1.bp.blogspot.com/-leFUqTJ02WM/X2DOIDJfWyI/AAAAAAAAK44/KcCtKS8VHww-K799iisHNMy07qoua2P1gCLcBGAsYHQ/w640-h162/Screenshot%2B2020-09-15%2Bat%2B16.19.04.png" width="640" /></a></div><br /><div>A typical use case of an event is showing a spinner while the download is transferring data. You find an example in the sample app that comes with the plug-in. Here's what it looks like:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-8nStmjW7T38/X2DQ4ZUdXBI/AAAAAAAAK5U/ZUUdBybjLMQjyBR2ZeZGLo2ny7sLfXaHwCLcBGAsYHQ/s603/ig_downloadfile_event4.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="555" data-original-width="603" height="590" src="https://1.bp.blogspot.com/-8nStmjW7T38/X2DQ4ZUdXBI/AAAAAAAAK5U/ZUUdBybjLMQjyBR2ZeZGLo2ny7sLfXaHwCLcBGAsYHQ/w640-h590/ig_downloadfile_event4.gif" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b>And more ...</b></div><div><br /></div><div>As we want our plug-ins to be used over the entire world, the plug-in supports <b>translations</b> and exposes many more <b>customizations</b>. Here's an example of a custom entry opening a modal window and showing more info of the file.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-PUr51hgOQs4/X2DeKgFxC1I/AAAAAAAAK5g/oi7l7kOSlXYm88C1KDsybKGHkFNexUD_wCLcBGAsYHQ/s1118/ig_downloadfile_custom.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="708" data-original-width="1118" height="406" src="https://1.bp.blogspot.com/-PUr51hgOQs4/X2DeKgFxC1I/AAAAAAAAK5g/oi7l7kOSlXYm88C1KDsybKGHkFNexUD_wCLcBGAsYHQ/w640-h406/ig_downloadfile_custom.gif" width="640" /></a></div><br /><div><br /></div><div>And of course, just like any other <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a> plug-in, there's extensive <a href="https://www.plug-ins-pro.com/plug-ins/UNITEDCODES_IG_DOWNLOAD_FILE/doc/index.html" target="_blank">documentation</a> and a great <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/ig_download_file_pro/" target="_blank">sample app</a> that showcases the different features.</div><div><br /></div><div>You can try the plug-in yourself for 1 month for free in your own APEX applications, so you can see what it can do for you. I also want to highlight that through the end of September 2020, there's a special running. You can find all the details on the <a href="https://www.plug-ins-pro.com">Plug-ins Pro</a> website!</div><div><br /></div></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com0tag:blogger.com,1999:blog-21122514.post-13574679938953483392020-09-14T15:20:00.000+02:002020-09-14T15:20:19.686+02:00Add awesome checkboxes and status fields in an Interactive Grid in Oracle APEX<p>This post is part of the <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Getting Started with Plug-ins Pro APEX plug-ins</a>.</p><div>I don't know about you, but I had a <b>love/hate relationship with Interactive Grids</b> in <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a>.</div><div><br /></div><div>I love it because it's really powerful and very useful and fast to insert, update, and delete multiple records at once. It was also the basis of many new things in APEX linked to modern web development.</div><div><br /></div><div>But I also disliked it<i> </i>a bit, because to me it felt different than any other component in APEX. Especially in the beginning IGs just didn't work for me. Whenever I wanted to do something, I found myself writing multiple lines of JavaScript. Things have changed, IG is much more stable, and more built-in features have been introduced, and extending it has become easier, or I now have a better understanding of how things work. Today, in every project I do, Interactive Grids are part of it...</div><div><br /></div><div>Interactive Grids follow the Model View Controller (MVC) model, which is typically used in JavaScript projects. Here's a diagram which shows the (<b>complex)</b> <b>architecture</b> of this component:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipqhZdBQT2o6Wgt8JstaxcIfiFoLGhwDcrH-d1Sr_zGO4dqlVuMZTU2bhK0_pCQKLmKXayD4wxvmgMt3VJTr7QXXjop8HLlXVUY6XkuyPa3ZxWQ6CXvA-N4hqr_eUJmALxuRru8Q/s1056/IG_arch.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="816" data-original-width="1056" height="483" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipqhZdBQT2o6Wgt8JstaxcIfiFoLGhwDcrH-d1Sr_zGO4dqlVuMZTU2bhK0_pCQKLmKXayD4wxvmgMt3VJTr7QXXjop8HLlXVUY6XkuyPa3ZxWQ6CXvA-N4hqr_eUJmALxuRru8Q/w625-h483/IG_arch.jpg" width="625" /></a></div><br /><div>John Snyders, one of the architects behind IG, wrote a nice <a href="https://hardlikesoftware.com/weblog/2016/06/08/interactive-grid-under-the-hood/" target="_blank">blog post</a> in 2016 which explains Interactive Grids. When you look at John's blog, you will find many more posts about Interactive Grids. He also has an excellent <a href="https://hardlikesoftware.com/weblog/2019/11/04/apex-ig-cookbook-update-for-19-2/" target="_blank">IG cookbook app</a> that shows different use cases of Interactive Grids.</div><div><br /></div><div><div>In this blog post, I want to focus on how to <b>represent a status field</b>, I typically call it a flag field. The most common values of such a field are 'Yes' and 'No', 'On' and 'Off', 'Active' and 'Inactive', 'True' and 'False'.</div></div><div><br /></div><div>Your native choices in Oracle APEX at the moment of writing are:</div><div><ul style="text-align: left;"><li>a checkbox</li><li>a radio group</li><li>a switch (which depending the component settings can look like a Switch, Pill Button or Select List)</li></ul></div><div>And here's an animated gif showing how these options look. Changing the first row values from Yes to No and the second row from No from Yes.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-zRdZ5MOlBEU/X19Zg5tnpOI/AAAAAAAAK30/xw3wY2SjLEcPaLFIL432sjzedUfB4KbagCLcBGAsYHQ/s1007/checkbox_pro_native3.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="381" data-original-width="1007" height="236" src="https://1.bp.blogspot.com/-zRdZ5MOlBEU/X19Zg5tnpOI/AAAAAAAAK30/xw3wY2SjLEcPaLFIL432sjzedUfB4KbagCLcBGAsYHQ/w625-h236/checkbox_pro_native3.gif" width="625" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>The native implementation in APEX is that you have to click in the cell to make it editable, then you see the checkbox, and once selected it shows the display value. When I show those options to my customers, many of them tell me: "<b>Can I not just have a checkbox?</b>" They mean they always want to see the checkbox visible and selected or unselected, like you have with the Row Selector (first column in the IG). </div><div><br /></div><div>Although Interactive Grids have evolved over the last 4 years, in case you want such a <b>checkbox, it's not as easy</b> as it should be and you need to write custom JavaScript. When the question was asked on Twitter why it wasn't there yet, you see John's reply:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-psZBPmU-VhY/X1o1JsL8_CI/AAAAAAAAK2I/V_KYvOBkp104K9S_BDwGcL6Oodl20QN_QCLcBGAsYHQ/s1176/Screenshot%2B2020-09-10%2Bat%2B16.07.06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="436" data-original-width="1176" height="186" src="https://1.bp.blogspot.com/-psZBPmU-VhY/X1o1JsL8_CI/AAAAAAAAK2I/V_KYvOBkp104K9S_BDwGcL6Oodl20QN_QCLcBGAsYHQ/w500-h186/Screenshot%2B2020-09-10%2Bat%2B16.07.06.png" width="500" /></a></div><div><br /></div><div>I told <a href="https://twitter.com/bostrowsk1" target="_blank">Bartosz</a>, who is our lead developer at <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a>, that I would love to have an <b>Interactive Grid Checkbox Pro plug-in</b>, to make it very easy to add a "simple checkbox"... but it turned out John was absolutely right... this is not an easy plug-in to do! After multiple iterations, Bartosz finally cracked it and he came back with a <b>checkbox on steroids</b>! 😉</div><div><br /></div><div>When I think about a checkbox, I don't think about two values, but three:</div><div><ul style="text-align: left;"><li>null (untouched)</li><li>unchecked (not selected)</li><li>checked (selected)</li></ul><div>So, we wanted to give people the choice of what they like: a checkbox with two values or three.</div></div><div>When we discussed the look of a checkbox it turns out that people like the HTML5 checkbox, which personally looks more 'old school' to me, but of course it's very known. But we wanted to give people more choice, so they have <b>full freedom on the look-and-feel of the different states</b>. In some applications it's more intuitive to have a switch look or a check icon or a smiley to name a few.</div><div><br /></div><div>Here's a quick <b>example of our plug-in in action</b> 😀</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Lx_bioE1qWQ/X1p4XXU1-TI/AAAAAAAAK2g/4AgnSjc45bo5KDY7CBZ0K58Z2VDHojFegCLcBGAsYHQ/s1220/checkbox_pro_plugin.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="345" data-original-width="1220" height="176" src="https://1.bp.blogspot.com/-Lx_bioE1qWQ/X1p4XXU1-TI/AAAAAAAAK2g/4AgnSjc45bo5KDY7CBZ0K58Z2VDHojFegCLcBGAsYHQ/w625-h176/checkbox_pro_plugin.gif" width="625" /></a></div><div><br /></div><div>Let's move on <b>integrating this awesome checkbox into our Interactive Grid</b>. </div><div><br /></div><div><div>The first step is to <b>download and install the plug-in</b>. I covered that in my blog posts <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Plug-ins Pro: Getting started: Sign-up and install your first Oracle APEX Plug-in</a>. So if you didn't import the Checkbox Pro plug-in yet, read that post first.</div></div><div><br /></div><div>Once it's installed it's pretty simple to use the plug-in. Go to a column of the Interactive Grid and <b>change the Type of the column to the United Codes IG Checkbox [Plug-in]</b>.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-chzijSp6z-o/X1o1u5K1NkI/AAAAAAAAK2Q/tRRueP9L2OkCwu7YBTT98jRPnfrSSurRgCLcBGAsYHQ/s1496/Screenshot%2B2020-09-10%2Bat%2B16.18.12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1238" data-original-width="1496" height="518" src="https://1.bp.blogspot.com/-chzijSp6z-o/X1o1u5K1NkI/AAAAAAAAK2Q/tRRueP9L2OkCwu7YBTT98jRPnfrSSurRgCLcBGAsYHQ/w625-h518/Screenshot%2B2020-09-10%2Bat%2B16.18.12.png" width="625" /></a></div><div><br /></div><div>You can <b>customize the look and feel of the plug-in in the Settings area</b>. The Type can be the <b>HTML5</b> implementation or a checked and not checked <b>icon</b>. So if you want thumbs-up and thumbs-down, or you want a square and checkbox, you name it, you are free to define the icon of your choice.</div><div>Next, you define the <b>value</b> it should have when checked and not checked and whether you want to see an empty column or the not checked value when you add a <b>new row</b>.</div><div>Finally, you can define if you want to see a title on <b>hover</b> and if people should be able to click the checkbox in the <b>read mode</b> of the IG or only when Edit mode is on (which is default IG behaviour). </div><div>The last bit is really what makes this checkbox such a nice user experience. People don't have to be in the cell first to change the checkbox or icon! <i>You don't hear or see my body language when I tell you that sentence, but I'm super excited (!) about this feature! T</i><i>he edit and read mode of the IG, made this plug-in so hard to make.</i></div><div><br /></div><div><b>Events</b></div><div><br /></div><div>What is really cool about this plug-in, it's not just a visual checkbox, but it also behaves like a native item and column in APEX. So if you want to <b>dynamically set the value of the checkbox</b>, the plug-in understands that. In the below example, when we change the First name to DIMI, it will set the value of the IS_ACTIVE4 checkbox column.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tNw3lMTYKGE/X15v3_u7sXI/AAAAAAAAK3M/Tvao3QjLma0qbj-ofxTCGoa5XxKR1a9NgCLcBGAsYHQ/s1716/set_value_of_ig_checkbox.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1152" data-original-width="1716" height="420" src="https://1.bp.blogspot.com/-tNw3lMTYKGE/X15v3_u7sXI/AAAAAAAAK3M/Tvao3QjLma0qbj-ofxTCGoa5XxKR1a9NgCLcBGAsYHQ/w625-h420/set_value_of_ig_checkbox.png" width="625" /></a></div><div><br /></div><div>Also when you want to detect a change of the state of the checkbox, you can hook up a dynamic action to that. In the below example, we have a <b>change event</b> on the checkbox on column IS_ACTIVE1 and IS_ACTIVE4. Whenever we change that column (meaning when we check/uncheck the checkbox) the salary will change.</div><div><br /></div><div><img border="0" data-original-height="1288" data-original-width="1710" height="470" src="https://1.bp.blogspot.com/-hcdv2qOnB1I/X15vdYIl18I/AAAAAAAAK3A/C4Za4c1qFQgVk56X0l0qc4C6ZymFyldrgCLcBGAsYHQ/w625-h470/change_ig_checkbox.png" style="caret-color: rgb(0, 0, 238); color: #0000ee; text-align: center; text-decoration: underline;" width="625" /></div><div><br /></div><div>And this is what it looks like:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-SJkUZRObiWY/X15waB0JN_I/AAAAAAAAK3U/ihtniaUiuDE6-cNCUQyD9zkqpMn3ATYXACLcBGAsYHQ/s1007/checkbox_pro_plugin_change2.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="369" data-original-width="1007" height="229" src="https://1.bp.blogspot.com/-SJkUZRObiWY/X15waB0JN_I/AAAAAAAAK3U/ihtniaUiuDE6-cNCUQyD9zkqpMn3ATYXACLcBGAsYHQ/w625-h229/checkbox_pro_plugin_change2.gif" width="625" /></a></div><div><br /></div><div><b>And there is more...</b></div><div><br /></div><div>The checkbox is accessible, supports validations, and you can style it however you want.</div><div><br /></div><div>And just like any other <a href="https://www.plug-ins-pro.com" target="_blank">Plug-ins Pro</a> plug-in, there's extensive <a href="https://www.plug-ins-pro.com/plug-ins/UNITEDCODES_IG_CHECKBOX/doc/index.html" target="_blank">documentation</a> and a great <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/ig_checkbox_pro/home?session=4028820518697" target="_blank">sample app</a> that showcases the different features.</div><div><br /></div><div><div>You can try the plug-in yourself for 1 month for free in your own APEX applications, so you can see what it can do for you. I also want to highlight that through the end of September 2020, there's a special running. You can find all the details on the <a href="https://www.plug-ins-pro.com">Plug-ins Pro</a> website!</div></div><div><br /></div><div><b>I use this plug-in in every Oracle APEX project and I strongly believe anybody using Interactive Grids will benefit from this plug-in!</b> This plug-in works from Oracle APEX 19.2 and above.</div><div><br /></div><div><i>Note:</i> depending on when you read this article, the plans are that from <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> 20.2 a more advanced checkbox item is native available, but it's unclear if it has all of the features our checkbox plug-in has. I will update this post once APEX 20.2 comes out. </div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com3tag:blogger.com,1999:blog-21122514.post-49702438182801296822020-09-07T16:25:00.000+02:002020-09-07T16:25:34.265+02:00Building a better Form in Oracle APEX: Instant validation and feedback on items<p>This post is part of the <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Getting Started with Plug-ins Pro APEX plug-ins</a>.</p><p>Creating a form with some items in <a href="https://apex.oracle.com" target="_blank">Oracle APEX</a> is fast and easy... Here's <b>an example of a sign-up form</b> I created in my APEX app, heavily inspired on the <a href="https://github.com" target="_blank">Github</a> sign-up form. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEVd5WaK7JxxMnTRJf5ABwakrc5mvmhBbJ2TnInn4PoaIW5Ia9wZt70RpxyvAy5XUM44lxVQ5qggD0ac3nmePQRcvGaNeOv8edGRvqe_XD6m218Oh5tQWaiC3-BDsaVtBKV9C-Og/s2048/Screenshot+2020-09-07+at+10.02.37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1131" data-original-width="2048" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEVd5WaK7JxxMnTRJf5ABwakrc5mvmhBbJ2TnInn4PoaIW5Ia9wZt70RpxyvAy5XUM44lxVQ5qggD0ac3nmePQRcvGaNeOv8edGRvqe_XD6m218Oh5tQWaiC3-BDsaVtBKV9C-Og/w625-h345/Screenshot+2020-09-07+at+10.02.37.png" width="625" /></a></div><p>I added a region, a couple of items, and a button to a page. Here's how it looks behind the scenes:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYEMQbKEroDWd87q7E1sQH13LovKcKrID9tpL-X7vM1yY4Y-xmobiR6Z5V5LPqH2S8xehEg-JK-NS5c_L00m84mev2jJB2C8Z4slseLlKgpSDGOd41uV_TTR11Sn7qqUn3Ay3cxQ/s2048/Screenshot+2020-09-06+at+17.57.48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1750" data-original-width="2048" height="533" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYEMQbKEroDWd87q7E1sQH13LovKcKrID9tpL-X7vM1yY4Y-xmobiR6Z5V5LPqH2S8xehEg-JK-NS5c_L00m84mev2jJB2C8Z4slseLlKgpSDGOd41uV_TTR11Sn7qqUn3Ay3cxQ/w625-h533/Screenshot+2020-09-06+at+17.57.48.png" width="625" /></a></div><p>In order for us to get good data we will need to specify some validations, so end-users can't type just anything. If we don't then, for example, when entering a username that already exists they'll get a unique key violation error.</p><p>Here are <b>the validations</b> we will specify:</p><p></p><ul style="text-align: left;"><li>username doesn't exist yet</li><li>valid email</li><li>password must comply with our complexity rules</li><li>username, email, and password are required</li><li>when registering as a company the company name must be entered</li><li>only allow valid VAT number when entered</li></ul><div>And this is how these validations look on our APEX page. You will see we use different types of validations: PL/SQL, no rows returned, regular expressions, etc.:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRijLWGjHxq_G4C4ZbB2rq28-m4D3NfKJr8SAhOTW0ngLW4jWdqAhy-JjY02h6iZCS2-2TTGNfib3DvzAb2Jd0_9r-R_gpZWwcVMvH_m4tNh6mh6q4elqE3E432uqQUKygr-DxvQ/s937/client_side_requirements2.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="890" data-original-width="937" height="594" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRijLWGjHxq_G4C4ZbB2rq28-m4D3NfKJr8SAhOTW0ngLW4jWdqAhy-JjY02h6iZCS2-2TTGNfib3DvzAb2Jd0_9r-R_gpZWwcVMvH_m4tNh6mh6q4elqE3E432uqQUKygr-DxvQ/w625-h594/client_side_requirements2.gif" width="625" /></a></div><br /><div>When we do nothing else on our APEX page and leave the form as is, it will cause <b>frustrations for many end-users</b>, because:</div><p></p><ul style="text-align: left;"><li>When a typo is made in the email field, they will only be notified after they hit the sign up button</li><li>When the password doesn't comply, again, only after hitting the button they are notified</li><li>When the username is already taken, only after hitting the sign up button they find out about it</li></ul><p></p><p>As a developer, I strive to make my forms as user-friendly as possible in the time I have. We are responsible for the apps we put out there and we love our customers, so the last thing we want is to cause any type of frustration.</p><p>So if we want to<b> improve our Oracle APEX page</b>, what does it take? </p><p>We want to have our validations be user friendly, context-aware, and responsive, meaning the end-user should see the issues live, relevant for what they are doing at that moment.</p><p>And here's the <b>problem for the developer</b>... it takes a lot of effort and different skillsets: native APEX skills, PL/SQL skills, JavaScript. This is what we already have:</p><p></p><ul style="text-align: left;"><li>There's a PL/SQL process, which handles the sign-up and spits back errors in case things go wrong</li><li>We already created APEX validations that are run before the sign-up process</li><li>We already have some items where the value required field set to Yes </li><li>For the email item, we also specified the correct type of item</li></ul><div>All those validations are being fired when you hit the Sign Up button. In the case of a value being required and email type specified on an email item, the check is done before the page is submitted, but for all the validations we specified in the processing section, those only get fired when the page is submitted. </div><div><br /></div><div>When we want to <b>give the end-user immediate feedback</b> while they are entering something in an item that is not correct, this <b>requires manual coding. </b>You end-up writing many dynamic actions and potentially some custom JavaScript and AJAX calls.</div><div><br /></div><div>Some developers might think to only include the dynamic action validations, but that is even worse. You have to have the APEX (server-side) validations, as you can't rely on JavaScript being fired. So you end up duplicating the logic in the validation portion of the processing section and your own dynamic action code. Whenever something changes, you have to change twice... </div><div><br /></div><div>It's an understatement when I say<b> I don't like to write code to tackle the same thing twice</b>!</div><div><br /></div><div>So instead of all this manual development, what is the <b>solution</b>? Use the <b><a href="https://www.plug-ins-pro.com/ords/uc/r/plug-ins-pro/home" target="_blank">Plug-ins Pro Client-side Validation Plug-in</a></b>! I will show you exactly how to do that now 😃</div><div><br /></div><div>The <b>first step</b> is to download and install the plug-in. I covered that in my blog posts <a href="https://dgielis.blogspot.com/2020/09/plug-ins-pro-getting-started-sign-up.html" target="_blank">Plug-ins Pro: Getting started: Sign-up and install your first Oracle APEX Plug-in</a>. So if you didn't import the Client-side Validation plug-in yet, read that post first.</div><div><br /></div><div>Next, create a <b>Dynamic Action</b> on the page which will fire on change or on <b>key release</b> for the <b>items</b> we want to check. Now, you can specify all items, or even cooler (!) you can specify the region, and all items in that region will be validated! So whenever the user enters something in the fields of that region, the dynamic action will fire.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-354Rl30Wll8/X1VEJn0L81I/AAAAAAAAKzg/6rjHIHMCaTcbAfJqNpY0LLd3IfuAvwBcACLcBGAsYHQ/s1980/Screenshot%2B2020-09-06%2Bat%2B22.18.15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1176" data-original-width="1980" height="373" src="https://1.bp.blogspot.com/-354Rl30Wll8/X1VEJn0L81I/AAAAAAAAKzg/6rjHIHMCaTcbAfJqNpY0LLd3IfuAvwBcACLcBGAsYHQ/w625-h373/Screenshot%2B2020-09-06%2Bat%2B22.18.15.png" width="625" /></a></div><br /><div>And as <b>Action</b>, we specify the <b>Client-side Validation Pro [Plug-In]</b> and for Affected Elements, we leave it blank. The plug-in is super smart and will show the notification for the item you are on, but if you specify the items that are affected, it will validate all of those items.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-aBBWt6ul7QU/X1VEQKgGkdI/AAAAAAAAKzk/SljRLQ7SLtYoLDRtR5PWhasAPd-DiFrIgCLcBGAsYHQ/s1968/Screenshot%2B2020-09-06%2Bat%2B22.18.26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1670" data-original-width="1968" height="531" src="https://1.bp.blogspot.com/-aBBWt6ul7QU/X1VEQKgGkdI/AAAAAAAAKzk/SljRLQ7SLtYoLDRtR5PWhasAPd-DiFrIgCLcBGAsYHQ/w625-h531/Screenshot%2B2020-09-06%2Bat%2B22.18.26.png" width="625" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b>That's it!!</b> When you run the page, the end-user gets instant feedback!</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-wLiaNqStrgs/X1XqJuWs1iI/AAAAAAAAK08/-kwpaxtRC3Up7y4h_9wo_MZmd87OKgBRQCLcBGAsYHQ/s1036/client_side_val.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="686" data-original-width="1036" height="414" src="https://1.bp.blogspot.com/-wLiaNqStrgs/X1XqJuWs1iI/AAAAAAAAK08/-kwpaxtRC3Up7y4h_9wo_MZmd87OKgBRQCLcBGAsYHQ/w625-h414/client_side_val.gif" width="625" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>The above implementation of the plug-in barely scratches the surface. I always specified in the validation to show the notification inline with the item, but the plug-in also supports showing a notification on top of the page or both. This plug-in is a real powerhouse! </div><div><br /></div><div>It even <b>supports validations for Interactive Grids</b>! If you are interested in live IG validations, check out <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/client_side_validation_pro/" target="_blank">the Sample App</a> (under Triggering Elements) that ships with the plug-in. Normally it would require a lot of (hardcoded) JavaScript, but not when using the plug-in. One client-side validation and native APEX validations do the job! Here's a quick screen recording with an example:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xB8VuAidcvQ/X1YuWuFc39I/AAAAAAAAK1Y/l50hwhtdHrgs-zcApQfZi76O0DJhLOmuQCLcBGAsYHQ/s815/client_side_ig.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="757" data-original-width="815" height="580" src="https://1.bp.blogspot.com/-xB8VuAidcvQ/X1YuWuFc39I/AAAAAAAAK1Y/l50hwhtdHrgs-zcApQfZi76O0DJhLOmuQCLcBGAsYHQ/w625-h580/client_side_ig.gif" width="625" /></a></div><br /><div>I can't stop telling how amazing this plug-in is! It's <b>*really* smart</b>. APEX has many validations built-in (HTML5 and Server-side validations) but this plug-in will combine them all together with client-side validations in a seamless user experience. If the plug-in can do the validation without a round-trip to the database, it will. There's no duplication of code, it's super easy to implement and very maintainable and it will save you hours or even days of development. </div><div><br /></div><div>This blog post would become really long if I would go over all the features of the plug-in, but I do want to highlight one other implementation that takes so much manual code without this plug-in.</div><div><br /></div><div><b>What if we wanted to give a soft warning?</b> So when the validation fails, the user can still say to move on. Here's an example: I have a form where you can enter 3 numbers. Number 1 and Number 2 and the sum of both. On submit it will validate the result and do some processing.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Xi_RqOJOiJg/X1VTnNkpb8I/AAAAAAAAK0A/8i3-kIRY1DIrzYfzOUv1-JujxY4ZpYHOQCLcBGAsYHQ/s898/Screenshot%2B2020-09-06%2Bat%2B23.24.28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="898" data-original-width="798" height="500" src="https://1.bp.blogspot.com/-Xi_RqOJOiJg/X1VTnNkpb8I/AAAAAAAAK0A/8i3-kIRY1DIrzYfzOUv1-JujxY4ZpYHOQCLcBGAsYHQ/w444-h500/Screenshot%2B2020-09-06%2Bat%2B23.24.28.png" width="444" /></a></div><div><br /></div>So when I enter 1 + 2 = 3, the page should submit fine. But when I enter 1 + 2 = 4, I should get a question if I want to continue or not. If I say no, it should stay on the page. When I say yes, it should submit nevertheless. Here's a quick gif to explain what I mean:<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdkM7gjddtGAoyXVj7A6qqHJnrj9XN9pGUUwwr549J_E1Si4NYV8pZyXnYhCvBLKW31Lq5-EDCzkqBLmHpQVQBe9F-gVmYD_oIvA6gjLQMGnQnF-iSVOX7k701BPtxZObZWPTHgQ/s500/client_side_valsum10.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="477" height="500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdkM7gjddtGAoyXVj7A6qqHJnrj9XN9pGUUwwr549J_E1Si4NYV8pZyXnYhCvBLKW31Lq5-EDCzkqBLmHpQVQBe9F-gVmYD_oIvA6gjLQMGnQnF-iSVOX7k701BPtxZObZWPTHgQ/w476-h500/client_side_valsum10.gif" width="476" /></a></div><br /><div>So let's look at what we did <b>behind the scenes</b> to do this.</div><div><br /></div><div>We have a region, with 3 items and a button. The button is defined by a dynamic action. The Dynamic Action is called Client-side Validation and it fires on click of the Submit button.</div><div>As a true action we specified the <b>Client-side Validation Pro [Plug-in]</b> with the following settings:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-x0on-B6tdzs/X1VXJisWAqI/AAAAAAAAK0g/211mIC0SObg1FSC4RRefy0BtU_jbyM7egCLcBGAsYHQ/s2048/Screenshot%2B2020-09-06%2Bat%2B23.38.27.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1265" data-original-width="2048" height="388" src="https://1.bp.blogspot.com/-x0on-B6tdzs/X1VXJisWAqI/AAAAAAAAK0g/211mIC0SObg1FSC4RRefy0BtU_jbyM7egCLcBGAsYHQ/w625-h388/Screenshot%2B2020-09-06%2Bat%2B23.38.27.png" width="625" /></a></div><div><br /></div><div>Note that we defined a success callback and failure callback and this is what <b>makes our validation conditional</b>! This is something that is not possible with Oracle APEX out-of-the-box. When the validation is successful we submit the page. But when it fails, we ask for confirmation if the end-user wants to continue even with an invalid result. If yes, we will give a hidden item on the page the value 'Y'.</div><div><br /></div><div>Our Validation is a normal APEX validation defined in the processing section of our page:</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Ky8N_YiSFr4/X1VXJkhfNHI/AAAAAAAAK0k/5gLHTmlbyQImqnexuvfWId_m2E5qtO2hACLcBGAsYHQ/s2048/Screenshot%2B2020-09-06%2Bat%2B23.39.29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1814" data-original-width="2048" height="554" src="https://1.bp.blogspot.com/-Ky8N_YiSFr4/X1VXJkhfNHI/AAAAAAAAK0k/5gLHTmlbyQImqnexuvfWId_m2E5qtO2hACLcBGAsYHQ/w625-h554/Screenshot%2B2020-09-06%2Bat%2B23.39.29.png" width="625" /></a></div><div><br /></div><div>Pretty powerful, right? 😉</div><div><br /><div><div>I mentioned in a previous blog post we don't take things lightly. We spend a huge amount of time on the development to make the plug-in act as a real component, so it knows about universal theme and translations to name a few. We try to make it as easy as possible for you to use, along with writing detailed documentation and creating a sample application that shows the different features of the plug-in. This all together took over 400 hours to do for this plug-in, but every time I use the plug-in myself, I'm happy we did. I'm super excited that I can just use it without me needing to write all this code and maintain it and there is great documentation and a sample app to get me going fast. </div></div><div><br /></div><div>There's nothing that comes even close to what this plug-in can do. If you read the <a href="https://www.plug-ins-pro.com/plug-ins/UNITEDCODES_CLIENT_SIDE_VALIDATION/doc/index.html" target="_blank">documentation</a> of this plug-in and look at the <a href="https://www.plug-ins-pro.com/ords/pluginspro_web/r/client_side_validation_pro/home" target="_blank">sample app</a>, you will understand 😉</div><div><br /></div><div>You can try the plug-in yourself for 1 month for free in your own APEX applications, so you can see what it can do for you. I also want to highlight that through the end of September 2020, there's a special running. You can find all the details on the <a href="https://www.plug-ins-pro.com">Plug-ins Pro</a> website!</div><div><br /></div><div>It may not be the sexiest plug-in, but heck, it works!</div><p></p></div>Dimitri Gielishttp://www.blogger.com/profile/16295721159626839167noreply@blogger.com1