Welcome to the OPA Hub!

Blog

Temporal Reasoning in Oracle Policy Automation #1 : Time Travel

Temporal Reasoning in Oracle Policy Automation #1 : Time Travel

A while ago I was asking a friend what was the most frustrating and complicated thing when they started working with Oracle Policy Automation. Temporal reasoning came up pretty quickly, and after speaking with other friends and colleagues it definitely ranks highly on the list of most people’s bugbears. There have been lots of excellent articles and posts about this subject on other sites, and in the final part of the series I will share a set of useful links. But we are going to examine the topic over the course of the next few posts on the OPA Hub Website.

But now, into the subject. Let’s first of all consider some of the basics. What is all this about. Consider the following situation: I ask you for your date of birth, so that I can find out how old you are.

If I ask you the question this time next year, then the answer will be of course, different. But nothing has changed in my input data. You still have the same date of birth. But the nature of the response is that it changes over time. If that didn’t make sense, then my favourite is definitely the most obvious one for many people. How much money do you have in your bank account? And did you have the same amount in there last week?

This bank account example usually does it for most people! And what is more, the bank account example allows us to consider the next part of the temporal puzzle. Open a new Project in Oracle Policy Automation and create a new attribute called the temporal bank balance, of type Currency. Start the Debugger. Enter a value of 1200 for the bank balance.

Temporal Reasoning in Oracle Policy Automation Introduction

But what does that value actually mean? When did you have that money in your account?

Let’s add some more data to our Debugger session. Open the Change points >> dialog and add three lines. This is where the magic happens. This data will help us begin to see the concept of temporal reasoning.

Temporal Reasoning in Oracle Policy Automation Change Points Debugger

Add three change points, for the first, second and third of July (1000, 1100, 1500) . Looking at the data, we can use some Oracle Policy Automation Functions to understand how this data is actually represented.

In a Word document, enter the following rules (note that the dates are based on the ones I suggested):

Temporal Reasoning in Oracle Policy Automation Rules 1

Return to the Debugger and let’s look at the values.

Temporal Reasoning in Oracle Policy Automation Debug Result

Observe the values for the  three days in July are perhaps exactly what you are expecting. The ValueAt function has provided you the value on the date you specified. The surprises perhaps are from the other two. The bank balance today (assuming today is a date after the third of July and that you used the same data as my example ) is listed as 1500. In this case, Oracle Policy Automation has found that the last change point was July 3rd, and gives you that value. In summary – according to the data you entered, there was no change after the 3rd. Finally, the amount on June 30th, outside the data points you gave, is the amount you entered in the debugger right at the beginning.

If you right-click the temporal bank balance, and select Temporal Visualisation, then click the Temporal Visualisation tab on the left, the data is displayed visually:

Temporal Reasoning in Oracle Policy Automation Final

So in this first post, we have learned how to enter temporal data, and we have used a new temporal reasoning function to get the value on a specific date. In the second part of the post series, we will look at some more typical cases using temporal data and some more functions. More details can be found online of course.

Thanks for reading and see you soon!

 

OPA Hub - Deployment REST API VB Debug 1

Deployment REST API : Uploading Zip Files #2

Deployment REST API : Uploading Zip Files #2

Following on from the previous post, we are now in a position to begin putting together the different elements and actually working out how to use the Deployment REST API to upload a Zip File programatically. As I have said on many occasions I’m most definitely not a coder, but I like to explore and often it helps me in my day job : if I can piece together a plan and show that it works, other more intelligent people can get behind it. All of that means that any code I share (and you are welcome to post a comment and I will forward it to you) is strictly for entertainment and educational purposes only.

Back to our challenge, and here is our strategy.

  1. Ask the user for a Zip File
  2. Base64 encode the Zip File
  3. Use the Authentication mechanism from last time, log the user in to the Oracle Policy Automation Hub
  4. POST the request
  5. Observe the Response in the Oracle Policy Automation Hub and in our code
  6. Debug any issues

Building the Solution

The only thing to remember is that you need a snapshot file from the Deployment page, but even I know how to display a Windows Dialog and grab the file name.

OPA Hub - Deployment REST API Get File

2. Base64 encode the Zip File, as we mentioned in the previous post.

3. Use the authentication mechanism as we did in the original post. If you are struggling with the concepts behind it, read the section about debugging further on in this article.

4. POST the Request. Nothing much to see here, except the need to instantiate all the different elements of your Visual Basic Class before you serialize the whole thing into JSON. In the image below, I’m using the Classes generated in JSONUtils and building my structure before serializing it into JSON.

OPA Hub - Dep;loyment REST API example code

The actual POST comes from the Stack Exchange code I linked to in the previous article, with a few minor modifications.

OPA Hub - Deployment REST API POST Request

5. Observing the response is pretty easy, since you should now have a new Deployment in your Oracle Policy Automation Hub. Can you guess which ones in the screenshot below came from my code?

OPA Hub - Deployment REST API Result

6. Debugging

Of course, this is going to be the place where you might spend a lot of time. And of course, the Visual Studio debugger is your friend. But part of the challenge is the lack of detail. For example, it’s good to know you have a 409 Error, or a 400 Error. But what the heck does it mean. This is where your toolset will come in very handy.

a. Use SOAP UI

SOAP UI can be used to make and debug REST API calls. The process is a little different to the SOAP calls of the past, and it is important to note that you will need to create an Authentication Profile with your Oracle Policy Automation integration user account, and check that you have a valid token before you begin. If you are new to this, the OPA Hub Website has some good news for you. In our series of articles about Web Services and integrating with other applications, we videoed a typical scenario of using SOAP UI for deployment REST API calls. Scroll down to the video labelled “REST API Services”.

b. Grab your base64

Using your Visual Studio debugger and the variable content viewer for example, grab the encoded Zip File from your session:

OPA Hub - Deployment REST API VB Debug 1

Then paste it into a REST request in SOAP UI that has a valid token, and observe the response. Way more useful and a good guide to coding your error handling in Visual Studio.

OPA Hub - Deployment REST API SOAP UI Debug 1

So what about a self-congratulatory video to finish. If you want the code, just leave a comment and I will happily provide it to you.

OPA Hub - REST API Generate Class

Deployment REST API : Uploading Zip Files #1

Deployment REST API : Uploading Zip Files

Following on from a post in the not too distant past, where we looked sideways at the Deployment REST API and the ability to download the Zip File of a deployment snapshot programatically, this new post answers a request from one of our readers regarding the “other side of the coin” ; specifically how to take a Zip File that needs to be uploaded into an Oracle Policy Automation Hub, and get the file to load up into the Deployments, using code. I must thank the commenter on the previous article for sharing his question, since it is one that comes up quite a lot and this is a good opportunity to hopefully show how you might do it.

The starting point of the process is that you have previously downloaded a snapshot file from a Deployments page of your Hub in environment A, and you now want to copy it across to environment B.

With your Zip File in hand, what can you do to automate this process? Of course, you turn your attention to the REST API and the deployment REST API in particular. Find the page that matches your version and let’s have a look.

{
    "name": "Example",
    "description": "Description of Example Project",
    "compatibilityMode": "latest",
    "services":
    [
        "interview",
        "webservice",
        "mobile",
        "javaScriptSessions"
    ],
    "collections":
    [
        "Default Collection"
    ],
    "versions":
    {
        "items":
        [
            {
                "description": "The initial version",
                "activeVersionFlag": true,
                "snapshot":
                {
                    "base64": "...base64 value..."
                }
            }
        ]
    }
}

How to get a class out of that? If only I could find a way to turn that into something easy to use in Visual Studio, I could create my own…wait a minute! Enter JSONUtils – the perfect site for converting JSON into C# or Visual Basic Classes.

OPA Hub - Deployment REST API Generate Class

How easy is that?

  1. Choose your language
  2. Give your new Class a name
  3. Paste the sample from the Oracle REST API documentation
  4. Press this button
  5. There’s your class, ready to use in your Visual Studio project.

Armed with this, we are ready to continue our research. We also need to be able to POST our request to the Oracle Policy Automation Hub. Thankfully somebody else has already asked about POSTing JSON to a specific URL millions of times, and there is a good starter function on Stack Exchange. At the bottom of that question is a great example.

Checklist – REST API Deployment

We can step back a moment and review a checklist

  1. We have Class to model our request
  2. We have a function to use HTTPWebRequest send things to the Oracle Policy Automation Hub
  3. We have an integration user and password, and the url of the Oracle Policy Automation Hub

So what else do we need? We need to be able to turn the Zip File into an encoded string as per the example given on the Oracle Policy Automation website : something like this:

 

Public Function ConvertFileToBase64(ByVal fileName As String) As String
        Return Convert.ToBase64String(System.IO.File.ReadAllBytes(fileName))
    End Function

In the second part of this post, we will put it all together and see the result!

OPA Quizzes : Helping you learn Oracle Policy Automation

OPA Quizzes : Helping you learn Oracle Policy Automation

We are always looking for ways to help you learn Oracle Policy Automation, so that’s why  we came up with our OPA Quizzes.

Whether it is for your next interview, or even as a preparation for your upcoming certification examination if you are planning on taking one, we hope that our range of free quizzes can help you get ready. If you are not familiar with the examination find out about it here  OPA Quizzes

In any case we hope that you enjoy them and have fun with them. Share them with your friends as you learn Oracle Policy Automation.

And while you are at it, reward yourself with a mug from the Shop. Maybe we will give away a few mugs at the end of the year to the Leaderboard Winners.

Yes, that’s a nice idea and this time we are organised enough to do it.

At the following page you will find all the OPA Quizzes and the links to the OPA Quiz Leaderboards. Check your results against the top scores and enjoy the stress of answering questions against the clock.

We recently began the process of building another’s two sets of questions so stay tuned and watch out for them in the coming weeks. In the meantime keeping smiling and have a good day!

What’s New in Oracle Policy Automation 18B #2 Relationship Control Extensions

What’s New in Oracle Policy Automation 18B #2

The main thrust of this post first came into my head when I was writing one of the recent Back to Basics posts about Relationships. And as if by magic, Oracle Policy Automation went ahead and improved the product with something I felt was lacking. I should ruminate more often, perhaps they have telepathic powers over there. So in this post, What’s New in Oracle Policy Automation 18B #2, we are going to look at the new feature of the Control Extensions : the ability to customise the Relationship experience.

What’s New in Oracle Policy Automation 18B #2

The relationship above is a good example. In the course of a prototype, I designed the car and the passenger entities for a car-sharing enterprise. A car can have many potential passengers. For each journey, however, your passenger can only be in one car at a time. And yes, I understand that I could build a many-to-many and intersection the car and passengers or infer the current passengers or what have you, but this is just an example.

What’s New in Oracle Policy Automation 18B #2

So in the above example, you can see that I am in the process of selecting the passengers for each car. Putting aside the discussion about how best to model the data, there is a challenge here. The checkbox (which is the only display offered) is fine, but due to the lack of dynamism (?) in the display, the choices remain static. I mean by that you are able to choose an incoherent selection, with the same passenger being in multiple cars.

Of course, when you do so, the engine (correctly) gives you an error and you must correct your data entry. But what if we did it another way?

The core of this is the fact that now, in Oracle Policy Automation 18B, you can use the following in your Extensions:

control.getControlType() – which now will return “OneToMany” or “ManyToMany” and so forth for relationship controls. So your code could adapt the User Experience based on the cardinality.

control.getOptions() – returns an array of the different choices for the user ( the passengers in my case above). So you can retrieve the list of choices.

To help manage this kind of extension, control.getValue() returns an array of the selected values for your relationship (the instances that have been selected). So you can examine the selected values.

Let’s look at this code. It is, as always provided for educational and entertainment purposes (indeed, many will find my stream of consciousness code amusing). It is also available on the OPA Hub Website Shop page as a free PDF download. So let’s see What’s New in Oracle Policy Automation 18B #2 : Relationship Controls with an example.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
(c) 2018 Richard Napier The OPA Hub Website May 2018
Educational Example of Relationship Input Controls
I will remember this is for demonstration and educational purposes only
 */
 
OraclePolicyAutomation.AddExtension({
	customInput: function (control, interview) {
		if (control.getProperty("name") == "xPassengerSelect") {
			return {
				mount: function (el) {
					//console.log("Control " + control.getProperty("name") + " is a " + control.getDataType() + ", originally a " + control.getControlType());
					var myValues = [];
					//Previous values
					myValues = control.getValue();
					var myOptions = control.getOptions();
					//console.log("Obtained list of instances for control " + control.id);
					var myDropDown = document.createElement('select');
					myDropDown.setAttribute('id', control.instance.toString());
					myDropDown.setAttribute('data-instance', control.instance.toString());
					myDropDown.setAttribute('data-entity', control.entity.toString());
					myDropDown.setAttribute('multiple', 'true');
					for (j = 0; j < myOptions.length; j++) {
						var myoption = new Option(myOptions[j].text, myOptions[j].value)
							myoption.setAttribute("data-instance", control.instance.toString());
						myoption.setAttribute("data-entity", control.entity.toString());
						myDropDown.options.add(myoption)
						//console.log("Added list option " + myOptions[j].text);
					}
					for (i = 0; i < myDropDown.length; i++) {
						currentOption = myDropDown[i];
 
						if (myValues.indexOf(currentOption.value) != -1) {
							$("select [data-instance='" + myDropDown.getAttribute('data-instance') + "']").filter("option[value='" + currentOption.value + "']").attr("selected", "selected");
						}
 
					}
					$(myDropDown).change(function () {
 
						//New Values Selected
 
						for (i = 0; i < myDropDown.length; i++) {
							currentOption = myDropDown[i];
 
							if (currentOption.selected == true) {
								myValues.push(currentOption.value);
 
								//Disable All Values Matching Selected in other instances
								$("select [data-instance!='" + myDropDown.getAttribute('data-instance') + "']").filter("option[value='" + currentOption.value + "']").attr("disabled", "true")
 
							} 
 
						}
					});
					var deselectbutton = document.createElement("button");
					deselectbutton.setAttribute("type", "button");
					deselectbutton.setAttribute('data-instance', control.instance.toString());
					var deselectbuttontext = document.createTextNode("Deselect All");
					deselectbutton.appendChild(deselectbuttontext);
 
					el.appendChild(myDropDown);
					$(myDropDown).after(deselectbutton);
 
					$(deselectbutton).click(
 
						function () {
						$("select [data-instance='" + this.getAttribute('data-instance') + "']").filter(":selected").prop("selected", false);
						control.setValue("");
							$("select [data-instance!='" + this.getAttribute('data-instance') + "']").attr("disabled", false);
					});
 
					for (i = 0; i < myDropDown.length; i++) {
						currentOption = myDropDown[i];
 
						if (myValues.indexOf(currentOption.value) != -1) {
							$("select [data-instance='" + myDropDown.getAttribute('data-instance') + "']").filter("option[value='" + currentOption.value + "']").attr("selected", "selected")
 
						}
 
					}
				},
				update: function (el) {},
				unmount: function (el) {}
			}
		}
	}
});

So what are we looking at. There are probably four key areas in this rough prototype.

Lines 18 to 27 build a multiple-select drop-down instead of the check-boxes. Using HTML 5 data attributes, each option and each drop-down (there will be  drop-downs, one for each of the car ) is tagged with the instance name and the entity name. This is useful if you intend to have a page with lots of entity-related things on it , and it was useful in the Entity Collect example from a few weeks ago as well.

Lines  29 to 33 look through the existing values of the Control (maybe the user has already been working on this page, and has now come back to it for further editing) and selects programatically all those values that were chosen previously. Otherwise when you click the Next button and then the Previous button, you will no longer “see” your selections even though they actually have been selected.

Lines 38 to 58 handle the Change event if the user selects other items in the multi-select, and ensures that the corresponding items are deactivated in the other drop-downs.

Lines 58 to 78 create the Deselect All button for each drop-down, which removes all the selected items both from the drop-down and from the underlying control values, and re-enables the values in the other drop-downs.

Once again, I state for the record that this was just a “stream of consciousness” which became a bare-bones prototype. There are lots of holes in the code, and lots of repetition because I just wrote it in a single shot. So you have been warned.

It does, however, demonstrate the new functionality, so our post title What’s New in Oracle Policy Automation 18B #2 is fulfilled. This is something you could not really do in previous versions.


Have fun!

What’s New in Oracle Policy Automation 18B #1

What’s New in Oracle Policy Automation 18B #1

The team that creates and updates Oracle Policy Automation have once again been very busy indeed, and the latest and greatest release can be downloaded from the usual Oracle Technology Network pages, and the link to the documentation follows the usual schema, just with the new 18B tag in it. So What’s New in Oracle Policy Automation 18B ?

In this first post in a short series, we are going to be looking at the new features of this release, and there certainly are some crackingly good ones. Let’s get started with the integration-related changes and what they mean for Oracle Policy Automation 18B:

  • A new Integration Cloud Service OPA assessment Adapter

What's New in Oracle Policy Automation 18B ICS

A massively important piece of the integration architecture for Oracle Policy Automation just got a whole lot better. An Oracle Policy Automation assessment can now be called as a step in your integration Workflow built on Oracle Integration Cloud Service. The Oracle Policy Automation assessment adapter has been available as a pre-release version but by the time you read this, or shortly afterwards, it should be available from the list of Adapters on the Oracle Integration Cloud Service site.

  • Embeddable JavaScript Models

An embedded JavaScript model is essentially a completely self-contained rulebase which can run, therefore, in a disconnected scenario. This will be a game-changer for Internet of Things devices, as well as situations where you need to have lightweight, client-side rule execution. This feature does not support Interviews, and is license-based.

  • Inline Customer Portal interview widget

Service Cloud customers can now take advantage of the new IFRAMEless integration capability that we enjoy with Siebel CRM already.

  • New REST API Batch Assessment Licensing Options

The Batch Assess REST API can now be called if you are licensed for Oracle RightNow Universal Policy Automation Tier 3 sessions, even if you are not also licensed for Oracle Policy Automation Enterprise Assessment API. For more information on the licensing and restrictions contact your Oracle representative.

  • Cookie-less interviews

A real boon for Safari users (but not only Safari) : Embedded Interviews no longer require a Browser cookie, which potentially could stop the Interview from functioning in certain environments. CORS still applies for resources shared across domains but basic embedding should now be possible whatever the browser security settings.

  • New Inline API Interview

The new API is OraclePolicyAutomationInterview and it uses the same methods as in previous versions (StartInterview, ResumeInterview, BatchStartOrResume). This new API version enforces all interview element styles. Styles won’t inherit from the parent stylesheet, and interview extensions can be used to modify interview appearance.  Awesome news for customers looking to render a a transparent experience to their users.

  • Relationship Control Customization

In the second part of our What’s New in Oracle Policy Automation 18B post series, we will look at the new Relationship Control extension capability which I was wishing for only a few weeks ago!

Custom Entity Collect Extension in Oracle Policy Automation #2

Custom Entity Collect Extension in Oracle Policy Automation

In this second part of the series, we continue to investigate building a Custom Entity Collect Extension in Oracle Policy Automation, and complete the basic example of a working collector. The code is once again focused on pointing out big ideas, traps, suggestions and the details are left to you, dear readers. Everything you see here is free and you can use it anywhere but it is for educational and entertainment purposes only. The PDF version of the code is available in the OPA Hub Shop for free.

Building the User Interface

The next big chunk of code is all about continuing the work begun previously, specifically building the User Interface by adding input boxes and other User Interface elements to the page. We switch according to data type, and as before we add a number of valuable extra HTML attributes to our elements.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//GET KEY INFORMATION
									var theinstancename = myrecords[i][j].instance.toString();
									var theentityname = myrecords[i][j].entity.toString();
									var theattributename = myrecords[i][j]._source.config.attributeId;
 
									var myname = myrecords[i][j].id.toString();
 
									attrInput.setAttribute('id', myId);
									attrInput.setAttribute('data-entityname', theentityname);
									attrInput.setAttribute('data-instancename', theinstancename);
									attrInput.setAttribute('data-attributename', theattributename);
									attrInput.setAttribute('data-rownumber', j.toString());
									attrInput.setAttribute('name', myname);
 
									// CONVERT ATTRIBUTES OBJECT TO ARRAY
									var myAttributeObject = myrecords[i][j]._source.screen.clientState[theentityname];
									myAttributeObject = myAttributeObject[theinstancename];
									var myAttributeArray = $.map(myAttributeObject, function (value, index) {
											return [value];
										});
 
									//DISPLAY THE CORRECT VALUE IN THE INPUT BOX
 
									switch (myattributedatatype) {
									case "boolean":
										var response;
										switch (myAttributeArray[j].toString()) {
 
										case "true":
											response = true;
											break;
										default:
											response = false;
										}
										attrInput.checked = response;
										rowdiv.appendChild(attrLabel);
										$(attrLabel).after(attrInput);
 
										break;
 
									case "number":
										attrInput.setAttribute('value', Number(myAttributeArray[j]));
										rowdiv.appendChild(attrLabel);
										$(attrLabel).after(attrInput);
										break;
 
									case "text":
										attrInput.setAttribute('value', myAttributeArray[j].toString());
										rowdiv.appendChild(attrLabel);
										$(attrLabel).after(attrInput);
										break;
									case "date":
										if ($(attrInput).attr("data-datepicker") === 'true') {
											$(attrInput).datepicker();
											$(attrInput).datepicker("option", "dateFormat", "yy-mm-dd");
											$(attrInput).val( myAttributeArray[j]);
											rowdiv.appendChild(attrLabel);
											$(attrLabel).after(attrInput);
 
 
 
										}
										break;
 
									}

Whoa, easy there! So what is all of that about? The different kinds of data (Boolean, text, numbers, dates) need to be handled slightly differently, to display correctly.

Error Display

What happens if the Interview cannot continue (note that this example Entity Collect only handles errors on navigate, the default for Oracle Policy Automation Interviews) because of an issue? The user needs to know what they have done wrong, so they can correct it. Thankfully the errors are available to us (if they exist).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//HANDLE DATA ENTRY ERRORS AND ERROR DISPLAY
var myerrorobject = myrecords[i][j]._source.screen.errors[theentityname]
if (myerrorobject) {
var myerrorinstance = myerrorobject[theinstancename];
if (myerrorinstance) {
var myerrorattribute = myerrorinstance[theattributename]
if (myerrorattribute) {
var errorrow = document.createElement("div");
errorrow.id = "rowcontainer" + i.toString();
errorrow.setAttribute('data-entityname', theentityname);
errorrow.setAttribute('data-instancename', theinstancename);
errorrow.setAttribute('data-attributename', theattributename);
$("#errordiv").append(errorrow);
 
$(errorrow).append("Attribute : " + myerrorattribute.attributeId.toString() + " - " + myerrorattribute.message);
$("input[data-entityname='" + theentityname + "'][data-instancename='" + theinstancename + "'][data-attributename='" + theattributename + "']").css("border", "3px solid red");
}
}
}

In this section we build a small DIV for the errors, and add any errors that exist as rows within it. At the same time, the relevant attribute is highlighted with a red border.

Updating the User Interface

When the user makes changes, we need to handle them and ensure they are passed on. The last part of the code for today concentrates on handling each of the data types, and making sure the data is correctly passed to Oracle Policy Automation. This is quite tricky, and can necessitate quite a bit of review of the Investigate JSON to try and understand what it does not like, as the error in the Browser will most likely be a generic 500 error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
var inputtype = $(attrInput).attr("type");
var datepicker = $(attrInput).attr("data-datepicker")
 
switch (inputtype) {
case "checkbox":
$(attrInput).change(function () {
interview.setInputValue(event.target.attributes["data-attributename"].value, this.checked, event.target.attributes["data-entityname"].value, event.target.attributes["data-instancename"].value);
 
interview.saveData();
event.stopImmediatePropagation();
 
});
break;
case "input":
 
if (datepicker === 'true') {
$(attrInput).change(function () {
var mydate = $(this).datepicker('getDate');
mydate = new Date(mydate);
var mydateinstance = $(this).attr("data-instancename");
var mydateattribute = $(this).attr("data-attributename");
var mydateentity = $(this).attr("data-entityname");
var myisodate = mydate.toString();
function formatDate(mydate) {
var d = new Date(mydate),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
 
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
 
return [year, month, day].join('-');
}
interview.setInputValue(mydateattribute, formatDate(mydate), mydateentity, mydateinstance);
 
interview.saveData();
event.stopImmediatePropagation();
 
});
 
} else {
$(attrInput).change(function () {
interview.setInputValue(event.target.attributes["data-attributename"].value, event.target.value.toString(), event.target.attributes["data-entityname"].value, event.target.attributes["data-instancename"].value);
 
interview.saveData();
event.stopImmediatePropagation();
 
});
 
}
 
break;
case "number":
$(attrInput).change(function () {
interview.setInputValue(event.target.attributes["data-attributename"].value, Number(event.target.value), event.target.attributes["data-entityname"].value, event.target.attributes["data-instancename"].value);
 
interview.saveData();
event.stopImmediatePropagation();
 
});
break;
}
 
}

And so this pretty much leaves us with a row builder, and an error builder. But the final part of the code is very important, specifically the Delete Button to delete the row you don’t want any more.

Delete Rows

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//ADD A DELETE ROW BUTTON  AFTER EACH ROW
								var deletebutton = document.createElement("button");
								deletebutton.setAttribute("type", "button");
								var deletebuttontext = document.createTextNode(control.getRemoveButtonText());
								deletebutton.appendChild(deletebuttontext);
								//SET UP THE CLICK EVENT OF THE DELETE BUTTON
								$(deletebutton).click(function () {
									var myliveinstances = control._source.instances.slice();
									// FIND THE ROW THAT CONTAINS THE DELETED INSTANCE
									var found = myliveinstances.indexOf(event.target.parentElement.getAttribute("data-instancename"));
									control.removeRow(found);
 
									drawrows();
								});
								rowdiv.appendChild(deletebutton);

Delete the Right Row

The delete row feature needs to find the row in the live set of instances (the _source.instances) using the HTML element that is the parent of the button. So if you click the Button, which is on the third row of the HTML User Interface, then using the instance name we can find the correct row and remove it. This is because the control.removeRow() uses the zero-indexed array in control._source.instances, not the user interface you are building. For example, if you have four instances on screen, then you delete one, the HTML will show that instance 1, instance 3 and instance 4 remain for example. But the Array members are now marked as rows 0,1 and 2.

The code closes out with the standard stuff :

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
update: function (el) {$("#errordiv").empty();	drawrows();},
				unmount: function (el) {
 
					if (control.getProperty("name") == "xEntity") {
 
						$("#entitycollector").remove();
					}
				}
			}
		}
	}
})
 
 

And so, what remains to be done? Well, of course, reorganize all that code written as a stream of consciousness!

But seriously, the obvious ones are

  • Ensure that when an instance is created, but the user has not yet entered any data, that the error checking is fired ( you can actually advance to the next page and come back to see the errors, because of the way the error object is handled only on the mount , not on the update.
  • Ensure that errors are removed from the page when they relate to an instance that was deleted by the user.
  • Ensure that the HTML building includes CSS class information to facilitate a new look
  • Build out date-time input and currency input and saving

But I’m sure you will find time for that. Have a nice day and enjoy building your own Custom Entity Collect Extension in Oracle Policy Automation!

We’ll leave you with a short video.

Custom Entity Collect Extension in Oracle Policy Automation #1

Custom Entity Collect Extension in Oracle Policy Automation

The idea behind this post, as is often the case, came from a conversation with a customer about something unrelated to the actual result. Suffice to say we were discussing data collection in Oracle Policy Automation and the idea of Custom Entity Collect Extension in Oracle Policy Automation came up, vaguely. The difficulty with demonstrating such an Extension is that every situation will be different, and every extension will have lots of styling to “make it look like something different”.

Perhaps the most important thing therefore is to demonstrate a Custom Entity Collect Extension in Oracle Policy Automation without any custom functionality and without any styling, so you can use it as the basis for your own discovery sessions. Of course, as always (and in particular in this case, as the example is necessarily longer than most), the code is totally for prototype and demonstration purposes only, and I will leave it to you to take the ideas and run with them.

Custom Entity Collect Extension in Oracle Policy Automation Result Final

Alright let’s get started. The Project looks like the following screenshot; namely a single entity called the accident and a variety of input attributes. There are no rules in this Project at the moment.

Custom Entity Collect Extension in Oracle Policy Automation Result 1

The screenshot shows a number of things we will need to think about:

  1. The code will try to be generic
  2. The code needs to read Screen items like the text here
  3. The code needs to offer deletion of instances as well
  4. The code needs to display Boolean data as well as text or numbers
  5. The code needs to display dates with a date picker

The Project also has, for completeness’ sake, an entity container on the final Screen to review the data to make sure that what the user has done has been saved correctly. Of course, you can also check the Data tab in the debugger.

The basic principle of the code is common to all the different examples seen around the Web, namely the Entity Collect has a custom Property whose name identifies it to the JavaScript extension code. I won’t include it here but you can find it in the PDF version at the end of this series.

NOTE : The Code Viewer on this website eats some characters, so be careful (especially less than and greater than symbols)

Getting Started : Make a Container

The first part of our mouncode will build the infrastructure for our container. Fittingly enough, it will be a DIV.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
return {
				mount: function (el) {
 
					// ADD ROW BUTTON THE TOP OF THE ELEMENT
					var button = document.createElement("BUTTON");
					button.setAttribute("type", "button");
					var buttontext = document.createTextNode(control.getAddButtonText());
					button.appendChild(buttontext);
					$(button).click(function () {
						control.addNewRow();
						drawrows();
					});
					el.appendChild(button);
 
					//CREATE DIV CONTAINER FOR ENTITY COLLECT
					var div = document.createElement("div");
					div.id = "entitycollector";
					el.appendChild(div);

As you can see, there was a little more than just a DIV. The code added an “Add Row” Button to the top of the Container, add set a click event to add a row to the Control with control.addNewRow(). The rest of the code adds the button to the page, and then adds an empty DIV.

1
2
3
4
5
6
7
8
9
10
11
12
var myattributelist = control._source.config.templateControl.controls
					function drawrows() {
						$('#entitycollector').empty();
						// CREATE AN ARRAY OF LABELS FROM THE ATTRIBUTES
						var mylabels = [];
 
						for (i = 0; i < myattributelist.length; i++) {
							mylabels.push({
								caption: myattributelist[i].caption.toString(),
								name: myattributelist[i].attributeId.toString()
							});
						}

The code above gets a reference to the list of attributes that are on the Control (essentially, what the designer has added to the Screen in Oracle Policy Modelling. Then it creates an array of label texts for each attribute. This set of labels will be used in the next part of the code. The function drawrows() will perform almost all of the setup of the control.

1
2
3
4
5
6
7
8
9
10
11
12
var myrecords = control.getRows();
 
						if (myrecords.length > 0) {
							for (i = 0; i < myrecords.length; i++) {
								// CREATE A CONTAINING DIV FOR EACH ROW
 
								var rowdiv = document.createElement("div");
								rowdiv.id = "rowcontainer" + i.toString();
								rowdiv.setAttribute('data-rownumber', i.toString());
								rowdiv.setAttribute('style', 'background-color: lightblue;');
								rowdiv.setAttribute('data-instancename', myrecords[i][0].instance.toString());
								$("#entitycollector").append(rowdiv);

This section creates a new DIV for each row of the “records” or instances of the entity. The rowdiv also uses HTML attributes to store useful information about the row such as the instance name, which makes it easy to find things later on either in the HTML source or in jQuery.

Drawing the Inputs

The final part of the code for today looks at drawing the input boxes, check-boxes and other data entry items.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var attrLabel = document.createElement('label');
// FOR EACH LABEL
for (j = 0; j < mylabels.length; j++) {
var myId = myrecords[i][j].id.toString();
var attrLabel = document.createElement('label');
attrLabel.setAttribute('for', myId)
var attrLabelTextNode = document.createTextNode(mylabels[j].caption);
attrLabel.appendChild(attrLabelTextNode);
 
//ADD PROPERTIES TO THE HTML INPUT
var myattributedatatype = myrecords[i][j]._source.config.dataType;
 
switch (myattributedatatype) {
 
case "boolean":
var attrInput = document.createElement('input');
attrInput.setAttribute('type', 'checkbox');
break;
 
case "number":
var attrInput = document.createElement('input');
attrInput.setAttribute('type', 'number');
break;
 
case "text":
var attrInput = document.createElement('input');
attrInput.setAttribute('type', 'input');
attrInput.setAttribute('data-datepicker', 'false');
break;
 
case "date":
var attrInput = document.createElement('input');
attrInput.setAttribute('type', 'input');
attrInput.setAttribute('data-datepicker', 'true');
break;
 
}

So what is happening here? In the first part of the code, we are setting up the labels by adding the text node to build the appropriate UI. Then we switch through a variety of different data types – note that we have not covered them all, just the core types – and how they will be built in HTML. The date type, for example, is going to use jQuery UI date picker so the type is set to input not date as you might have thought (to take advantage of modern browser support for that input type) but the support is patchy and the limitations many. So it is going to be a simple input but with a jQuery UI element bound to it.

The Boolean uses a check-box and the Number uses number : so we can experiment with that UI experience.

Continues in part two of our Custom Entity Collect Extension in Oracle Policy Automation investigation. If you are looking for more information, the official documentation is to be found here.

Oracle Policy Automation Embed Website in Interview End

Oracle Policy Automation Embed Website in Interview

Oracle Policy Automation Embed Website in Interview

This request comes up quite often, at least often enough that I feel the need to mention it today. The example we are going to use is to embed the OPA Hub Website in an Oracle Policy Automation Interview. In addition we are going to pass an attribute to the website so that it performs a search for us. So, let us start our tutorial “Oracle Policy Automation Embed Website in Interview”.

Now, I am sure many of you are old enough to have spent years trying to avoid IFRAME integrations in applications : Siebel, SAP, they all do it or have done it at some point in time, and they are awful for the most part – whether it be from an accessibility, SEO, browser restriction or other perspective. So here are our goals for this mission:

  • Don’t use an IFRAME
  • Add the Website in a way that does not destroy the look and feel of the Interview
  • The Website must actually function properly

The steps to create this Project are shown below. You should be aware (and not be surprised) that this will not work well in the built-in embedded Browser in Debug Mode, so run Debug mode using Ctrl+Debug or deploy the Project to see the final results.

Oracle Policy Automation Embed Website in Interview Pre-requisites:

A New Project called “Oracle Policy Automation Embed Website in Interview” or something shorter.

Create a global attribute with the text the subject with a name of subject.

Create a new Screen to ask what is the subject. I suggest a Drop-down list with the Values “Siebel Integration, JavaScript Extensions,Service Cloud”.

Create a second Screen to display the Website.

  1. Create a label, using the name  of  the subject to display the chosen subject.
  2. Place this inside a Container
  3. Make sure you add a Property for the Container, naming the Object.

By now the Screen should look like this:

Oracle Policy Automation Embed Website in Interview Design

Now we come to the code. This is quite simple,although we will also need some CSS to make it look right. Add a JavaScript file and a CSS file to your resources folder for this Project. The explanation is after this code, which is as always provided for educational and investigative purposes only:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * Richard Napier The OPA Hub Website April 2018
 * Educational Example of Custom Container with a Website inside
 * I will remember this is for demonstration and educational purposes only
 */
 
OraclePolicyAutomation.AddExtension({
	customContainer: function (control,interview) {
		if (control.getProperty("name") === "xWebsite") {
 
			return {
				mount: function (el) {
					var myDiv = document.createElement("div");
					myDiv.setAttribute("id", "mySpecialDIV");
					document.body.appendChild(myDiv);
					$("#mySpecialDIV").width(900);
					$("#mySpecialDIV").height(600);
					var mySubject = interview.getValue("subject");
					$("#mySpecialDIV").html('XXXXXX'+ mySubject + '">');
				},
				update: function (el) {},
				unmount: function (el) {
					var myDiv = $("#mySpecialDIV");
					myDiv.remove();
 
				}
 
			}
		}
	}
});

Oracle Policy Automation Embed Website in Interview Code

In the code above, here are the salient points.

Lines 13 to 17 create a DIV and insert it into DOM, appending it to the body of the document.

Line 18 retrieves the value selected by the user on the previous page that is present in the Container as a label.

Line 19 is the most important one. Notice the “XXXXX”. Replace this with the website and any URL construct you need. For example, replace it with the following:

<object data="https://theopahub.com/main/?s=

The code viewer didn’t correctly display that part. Insert it exactly as shown, so that you are concatenating the URL with the user selected subject. The key point here is the use of the object tag rather than an nasty IFRAME. Thanks to Stackoverflow!

The rest of the code just tidies up when the unmount happens.

Oracle Policy Automation Embed Website in Interview CSS

The CSS is quite important here, to ensure that the embedding is seamless. Add this CSS code to your CSS file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
object {
    height: 100%;
    width: 100%;
}
#mySpecialDIV {
	float: left;
    margin: 0px;
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	border-radius: 10px;
	background-color: #404040;
}
html
{
    border: 0px;
    margin: 0px;
    overflow: hidden;
    padding: 0px;
}
body
{
    border: 0px;
    margin: 0px;
    overflow: hidden;
    padding: 0px;
}

Let’s take a look at the CSS. We use styling to position the DIV, as well as styling to ensure the object tag uses all of the available DIV. Finally we use some tricks to eliminate overflowing content and remove the horizontal scrollbar.

Oracle Policy Automation Embed Website in Interview Debugging

As mentioned earlier, this may be best tested in the Browser, not in the Debug Embedded Browser, so make sure you start with Ctrl+Debug.

The first screen will be straightforward:

Oracle Policy Automation Embed Website in Interview 1

The second screen will display and if your Internet connection is slow, you may have time to witness the two stages of display:

Stage 1 : Show the styled DIV that has been added to the Screen. Of course you don’t have to use this colour, I just wanted to use it for positioning and effect.

Oracle Policy Automation Embed Website in Interview DIV

Stage 2 : The embedded Website is displayed. The embedding is seamless (nice colour scheme!).

Oracle Policy Automation Embed Website in Interview End

  1. Notice that the attribute value has been passed to the OPA Hub Website and a search has been performed for you. The site is fully functional and can be accessed from the Interview Window.

Have a nice day! (The PDF is in the OPA Hub Shop).

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling

One of the most interesting questions I have been asked during my current assignment in beautiful Madrid has been the following :

“How can I make a Chart”

Well, that’s easy I said : pick your Charting platform (for example, you might choose D3 as the charting library as it is well-known and incredibly powerful. Or alternatively you could manipulate SVG arcs and lines yourself if you want to, to achieve the same thing.

“How can I make a Chart based on Oracle Policy Automation data”

Well, that’s easy I said : you even have an example in the Oracle Policy Automation Example Projects, called the Loan Advisor. You can see a screenshot from that project, right here:

JavaScript Extensions with a Live Entity-based Chart : Intro

Digging deeper into that Project, we discover that the attributes that are used to create the chart are global :

JavaScript Extensions with a Live Entity-based Chart : Intro 2

“How can I make a Chart that uses Entity data”

Well that’s easy I said, you could hook up the D3 library to the entity, and use a similar system to our custom Entity Container example to retrieve the data. After all, the Pie Chart in D3  accepts any array of data organized into labels and values. You may remember in that example, we sought the name of the entity using EntityId and then iterated through the instances in the Entity to display them.

But upon investigation this is not really satisfactory. Adding an instance to the entity container does not refresh the Chart. In fact, you have to navigate forward and then backwards to get the Chart to refresh. That’s because, of course, your new “instance” does not actually exist yet. It does not get added into the entity.instances[i] list until you leave the current screen.

“How Can I make JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling”

You will have guessed by now that my entourage here is pretty demanding! So here goes. Firstly, the scenario. I have created an Entity called the payment. It has two attributes, the identifier, a text attribute, and the payment amount, a currency or number as you wish.

The goal : on ONE Screen, enter data and view a live chart that updates live, without changing Screens, as data is added or removed.

To experiment further with this, I also decided to create another Entity called the shadow payment. This is a copy of the original, created by the simple rule in Word that follows:

JavaScript Extensions with a Live Entity-based Chart Intro 3

The idea was to test if it would work both on inferred and normal entity instances. It seemed to, so you could probably use the code with either. To enable my shadow entities, I set up the relationship for the above Word rules to function properly.

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling Intro 5

The Code Concept

Now we come to the code itself. This is, as I always state clearly, just code that I have hacked together to see if a concept had the ability to be taken further. It is in no way production or even unit test ready. That’s your problem. But I hope you find it interesting and inspiring.

Another note, I have seen that this “code view” messes with some characters. The OPA Hub Shop has a PDF version which you can use to compare and correct anything that looks wrong, notably the > and < characters don’t show up correctly here.

The code uses D3 for the pie chart, and the explanation follows after the code. Pop D3 in a JS file in the resources folder, as well as the D3 library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
 * Richard Napier The OPA Hub Website April 2018
 * Educational Example of Custom D3 Chart Extension with live refresh on a screen
 * I will remember this is for demonstration and educational purposes only
 */
 
OraclePolicyAutomation.AddExtension({
	customContainer: function (control) {
		if (control.getProperty("name") === "xChart") {
 
			return {
				mount: function (el) {
 
				},
				update: function (el) {
 
					if (document.readyState == "complete") {
 
						var entity = control._source.screen.serverState.shadowpayment;
						var myFlatList = [];
						var myObject;
 
						var width = 300, //width
						height = 300, //height
						radius = 150, //radius
 
						color = d3.scaleOrdinal(d3.schemeCategory10);
						var size = Object.keys(entity).length;
 
						for (i = 1; i &lt; size+1; i++) {
							myObject = new Object();
							myObject.label =control._source.screen.serverState.shadowpayment["@_@opa-rel-target={payment[the payment" + i + "]}/global[global]"].shadow_payment;
							myObject.value = control._source.screen.serverState.shadowpayment["@_@opa-rel-target={payment[the payment" + i + "]}/global[global]"].shadow_amount;
							myFlatList.push(myObject);
							//console.log(" Flattened the list - item " + i);
						}
						data = myFlatList;
						var vis = d3.select(el);
						vis.select("svg").remove();
						var vis = d3.select(el)
						.append("svg")
							.data([data])
							.attr("width", width)
							.attr("height", height)
							.append("g")
							.attr('transform', 'translate(' + (width / 2) +
								',' + (height / 2) + ')'); 
						var arc = d3.arc().outerRadius(radius)
							.innerRadius(0); ;
						var pie = d3.pie()
							.value(function (d) {
								return d.value;
							});
						var arcs = vis.selectAll("g.slice")
							.data(pie)
							.enter()
							.append("svg:g")
							.attr("class", "slice");
						arcs.append("svg:path")
						.attr("fill", function (d, i) {
							return color(i);
						})
						.attr("d", arc);
						arcs.append("svg:text")
						.attr("transform", function (d) {
							d.innerRadius = 0;
							d.outerRadius = radius;
							return "translate(" + arc.centroid(d) + ")";
						})
						.attr("text-anchor", "middle")
						.text(function (d, i) {
							return data[i].label;
						});
					}
				}
			}
		}
	}
});

Review of JavaScript Extensions with a Live Entity-based Chart

Line 8 : This is a Custom Container. So make sure that you drop a container into your Screen, and in the container make sure you add your Entity. In my example, I displayed both the original the payment entity, for the user to add or delete records, as well as the shadow payment which I leveraged to draw the pie chart.

Line 19 ; This example uses control._source.screen.serverState.shadowpayment. This JavaScript object contains the instances of your entity, and is updated as new instances are added, before you leave the page. Of course the name is the technical name  of your entity so don’t forget to add that to your Data tab.

Line 27 : Selecting a standard set of colors from the D3 color categories

Line 28: Finding how many objects are inside the control._source.screen.serverState.shadowpayment object. Each instance is a child object.

Lines 32 and 33 : Creating dynamically the identifiers of each row to select the label and the value using the names of the attributes in your entity, and copying them into a flat object with values and labels

Line 37 : Set the flat list as the data source for the Pie Chart

Line 40 : Add the Chart into the Container

Line 41 : Add the pie chart, setting the origin to the center of the Container, and hooking up to the data we created

Line 50 and beyond : Using D3, draw the arcs and fills that make the Pie Chart by going through the total set of data and dividing the pie into the right number of pieces.

This is the result, in full Hollywood glory, of JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling.

The PDF version is on the OPA Hub Shop, just search for the Pie Chart example.

We will of course be revisiting this to investigate making it more robust, but it’s a good starting point. Have fun and see you soon!