Sunday, 15 November 2015

32 vs 64 bit app determination and windows which–two bugbears of mine (what’s a bugbear?)

 

I’ve struggled for this for a while too, in this modern day of transition from 32 to 64 bit, why is not HEAPS easier to tell if a file is 64 bit?  Give me the unix file command any day of the week.  While I’m on a rant, the other thing I dislike about windows is that there is no where command.  If I’m running sqlplus – I want to know which one in the path is being called – not just guess.  This is a common problem on deployment servers where you have e1local that is 64 bit and then you have the 32 bit client component.

Note that one of my prayers have been answered:  which is a command that I use on linux all of the time.  Handy to know what version of sqlplus is being used and therefore what tnsnames to change.  modern windows you can now use where!

C:\Oracle\E1Local\BIN>where sqlplus
C:\Oracle\E1Local\BIN\sqlplus.exe
D:\oracle\product\11.2.0\client_1\BIN\sqlplus.exe

It seems that the consensus online us using dumpbin, this is crap.  No everyone has visual studio just lying around for this purpose.  We don’t want to download noddy little tools to do this stuff.

Wait, both rants might be over.  Thanks to this post:  http://superuser.com/questions/358434/how-to-check-if-a-binary-is-32-or-64-bit-on-windows

clip_image002

64bit

clip_image004

32bit

This is really cool, so I can use the tools that are installed on my machine to determine 64 and 32 bit applications by a simple notepad interrogation.

Note that you can also use findstr if you don’t want to involve notepad:

C:\Oracle\E1Local\BIN>findstr /C:"PE" D:\oracle\product\11.2.0\client_1\BIN\sqlplus.exe |more

clip_image006

See the PE then L in the 2nd page of the results.  Remember that the L means 32 bit

Note that after considering the wikipedia definition of bugbear, I might stop using the word.  It does not seem to make a lot of sense the way I use it…  unless you look right to the end of the actual definition In a modern context, the term bugbear may also mean pet peeve

Wednesday, 11 November 2015

JD Edwards and IOT

Exciting

This is a pretty exciting enhancement, it’s exciting for a number of reasons.  Although to be honest, technically – it’s not that exciting.  It’s the change of thinking that is truly exciting.  Can I write the word exciting anymore, let’s see.

Why do I say that technically it’s not exciting, well most of the cool stuff has already been released in AIS, so the generic ability to call E1 functionality via rest based calls is totally awesome.  This must be the way you choose to integrate anything with JD Edwards moving forward.  It seems to be lighter and easier to develop in than BSSV, error handling is better and more forgiving, especially for a human based interface (mobile, website etc).  Don’t get me wrong, BSSV has it’s place – but it’s no longer that cool.

The technology that is doing the rules based filtering is nice, but fairly rudimentary at this stage, lets wait for some graphical tool to assist us.  Something nice with flows and drag and drop parameters  that’d be nice.  Don’t stop with the flow and the rules either, how about making AIS development graphical – come on – there is a challenge.  I’d like some nice tool to drop 3 XML documents into the associated directories and allow me to call them!  True, I’m getting old.  Although let’s be honest – who calls writing a well formed XML document “cutting code”?

Change of thinking, business opportunity:

So this is where I think that the true value is, I don’t think that you need to look too hard for a use case either – especially if you take inputs from anything and enter them into JD Edwards,

JD Edwards is not going to be a great data warehouse, it’s not going to store 100000’s of rows of asset location data well, of course it will – but it’ll slow everything else down.  You need to design your inputs so that they are meaningful in JD Edwards.  Don’t misinterpret what I’m saying, SAVE ALL DATA – you’ll never know what it’s actually worth.  I’m just saying that saving it into your production JD Edwards database might not not be the most efficient place.  Save the triggering event, raise the work order when the temperature device reads too high….  But don’t save the normal 1 minute trend data for the last year in JD Edwards.  Save this in a data warehouse and show it with CAFE1 if you really need to see it in JD Edwards.  Choose the right place for your data.

Remember, IOT is going to create a lot of data…  More sensors, more data.  keep your data and save your data for a rainy and strategic day for the use case that you cannot visualise today.

I think some fantastic opportunities for this is:

  • weighbridge interfaces
  • quality readings from products – steel / food etc
  • RFID for shipping and identification
  • anything PLC related
  • temperature, moisture (agri business), location, angle, speed, noise,

I think there are fantastic opportunities with CAM and with HS&E, this data could be vital when trying to predict incidents that cause harm and report over them.  Remember you’ll get true data from IOT, no mistakes, always entered on time – accurately.

We’re prototyping some IOT for clients at the moment, if you think that you’ve got a winning use case – we have a winning team that might be able to implement the solution for you at the right price. 

Here are a couple of learning's from my recent adventures in IOT.

image

The general section of your AIS server needs to point to quite a specific directory – this one:

/U01/jde_home1/sampleOrchestrations/SampleOrchestrations/JDE_IOT_Orchestrator_XML

For me, it’s above.  But I want to give you some context.  This is from downloading the ORCHESTRATION SAMPLES file from MOS


image


Note the one that is 0.03MB is the one that you want.


Lay this bad boy out on your AIS server.  rename the par.zip, or just unzip the par…  Note that you might have to yum install unzip


You need to make sure that you point this AIS configuration about to the right DIR, it as the following folders in it:

CrossReferences
Orchestrations
Rules
ServiceRequests
WhiteLists

Okay, so you have the right DIR.


Note that if like me you get the following error when you try and log into the orchestrator client;  (Authentication error)


http://e1webv3:9221/jderest/client 


You turn on all logging and get the following in the server logs for the AIS server:

09 Nov 2015 12:36:19,224[DEBUG][AIS]AISClientServlet session Exception
http://e1webv3:9221 com.oracle.e1.aisclient.JDERestServiceException: 401 Verifiy WLS Server Basic Authorization Header configuration in domain config.xml, enforce-valid-basic-auth-credentials must be false:
09 Nov 2015 12:41:18,581[DEBUG][AIS]AISClientServlet public
09 Nov 2015 12:41:18,582[DEBUG][AIS]AISClientServlet service method POST
09 Nov 2015 12:41:18,582[DEBUG][AIS]AISClientServlet doPost
09 Nov 2015 12:41:18,583[DEBUG][AIS]AISClientServlet params JDE-JPY920-*ALL-e1webv3:9221-Z1bp4u58flboTpjN-lD1DbZ3t2BH-UH2Li-UnQBYnIzxFhqr2A9P!-488571965
09 Nov 2015 12:41:18,584[DEBUG][AIS]AISClientServlet doPost aisServerhttp://e1webv3:9221
09 Nov 2015 12:41:18,584[DEBUG][AIS]AISClientServlet login path
09 Nov 2015 12:41:18,591[DEBUG][AIS]E1ResUtils getAISVersion buffer
09 Nov 2015 12:41:18,592[DEBUG][AIS]E1ResUtils getAISVersion in java.io.BufferedReader@6e293511
09 Nov 2015 12:41:18,593[DEBUG][AIS]E1ResUtils getAISVersion inputLine EnterpriseOne
09 Nov 2015 12:41:18,619[DEBUG][AIS]Successfully registered the runtime_config Runtime Metric for com.oracle.e1.jdemf.DefaultConfig@2a6547af Using null
09 Nov 2015 12:41:18,619[DEBUG][AIS]Successfully registered runtime_config Mbean com.oracle.e1.jdemf.DefaultConfig@2a6547af
09 Nov 2015 12:41:18,621[DEBUG][AIS]Required Capability List IN: null
You’ll find that this will make your eye’s roll  https://support.oracle.com/epmos/faces/DocContentDisplay?id=2040956.1

Note that the fix is to go to your config.xml for the domain that the AIS server is installed in:

/U01/Oracle/Middleware/user_projects/domains/E1_Apps/config

And edit the config.xml file – probably make a backup (or not if you are feeling like rebel)

  <name>E1_Apps</name>
<domain-version>12.1.3.0.0</domain-version>
<security-configuration>
<name>E1_Apps</name>
<enforce-valid-basic-auth-credentials>false</enforce-valid-basic-auth-credentials>
<realm>

See above, look for the realm entry and paste above that for your domain.  I did it in the wrong place initially and nothing worked.  Restart the AIS server instance from SM and you’ll be able to login.


image


Cool!  We are in:


image


Like I said a fairly simple interface for choosing an existing item from the list: (or dir)


image


Be able to enter the inputs


image


Add some values and hit go, you’ll see some cools things:

{
"inputs" : [ {
"name" : "SensorID",
"value" : "123"
}, {
"name" : "Date",
"value" : "101015"
}, {
"name" : "Time",
"value" : "01:35"
}, {
"name" : "VibrationReading",
"value" : "5435"
}, {
"name" : "TemperatureReading",
"value" : "5534"
}, {
"name" : "ShannonsTest",
"value" : "Hello World"
} ]
}

Nice, json input format, which we can test


And, even nicer, using chrome debug tools, you can get a cURL command

curl "http://e1webv3:9221/jderest/clientservice/orchestrator" -H "Origin: http://e1webv3:9221" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: en-US,en;q=0.8" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "Accept: */*" -H "Referer: http://e1webv3:9221/jderest/client/orchestrator.html" -H "Cookie: JSESSIONID=b5D14vor1wgZXx7MrUXPu4xnC_e_rxMQE0fyaAI32wA9U7To9wLj!1811286266; SMCONSOLE_SSID=jYj12SvLtf_HhobsFJGGXn2X-4ZdGG27K2O-3rI6tpxVkhkAb8-p!-1147834967" -H "Connection: keep-alive" --data "orchname=JDE_ORCH_Sample_AddConditionBasedAlert&generic=false&useJson=true&jsonString={"^
" ""inputs"" : [ {"^
" ""name"" : ""SensorID"","^
" ""value"" : ""123"""^
" }, {"^
" ""name"" : ""Date"","^
" ""value"" : ""101015"""^
" }, {"^
" ""name"" : ""Time"","^
" ""value"" : ""01:35"""^
" }, {"^
" ""name"" : ""VibrationReading"","^
" ""value"" : ""5435"""^
" }, {"^
" ""name"" : ""TemperatureReading"","^
" ""value"" : ""5534"""^
" }, {"^
" ""name"" : ""ShannonsTest"","^
" ""value"" : ""Hello World"""^
" } ]"^
"}&name_0=SensorID&value_0=123&name_1=Date&value_1=101015&name_2=Time&value_2=01:35&name_3=VibrationReading&value_3=5435&name_4=TemperatureReading&value_4=5534&name_5=ShannonsTest&value_5=Hello World" --compressed

 


Of course, this won’t help you – coz the cookie will be dead by the time I post this and this server in not on the internet, but you get the gist of what is being done.


What do you need to do to get this working?

<?xml version="1.0" encoding="UTF-8" ?>
<Orchestration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="JDE_Orchestration.xsd">
<inputTypes>
<inputTypes type="String">
<name>SensorID</name>
</inputTypes>
<inputTypes type="Date" dateFormat="Milliseconds">
<name>Date</name>
</inputTypes>
<inputTypes type="String">
<name>Time</name>
</inputTypes>
<inputTypes type="Numeric">
<name>VibrationReading</name>
</inputTypes>
<inputTypes type="Numeric">
<name>TemperatureReading</name>
</inputTypes>
</inputTypes>
<orchestrationSteps>
<orchestrationSteps type="CrossReference">
<name>JDE_XREF_Sample_SensorLocation</name>
</orchestrationSteps>
<orchestrationSteps type="CrossReference">
<name>JDE_XREF_Sample_AlertNotificationRecipients</name>
</orchestrationSteps>
<orchestrationSteps type="Rule">
<name>JDE_RULE_Sample_CBMAlarm_1</name>
<trueActions>
<orchestrationSteps type="ServiceRequest">
<name>JDE_SREQ_Sample_AddCBAlert_Alarm</name>
</orchestrationSteps>
</trueActions>
<falseActions>
<orchestrationSteps type="Rule">
<name>JDE_RULE_Sample_CBMAlarm_2</name>
<trueActions>
<orchestrationSteps type="ServiceRequest">
<name>JDE_SREQ_Sample_AddCBAlert_Alarm</name>
</orchestrationSteps>
</trueActions>
<falseActions>
<orchestrationSteps type="Rule">
<name>JDE_RULE_Sample_CBMAlarm_3</name>
<trueActions>
<orchestrationSteps type="ServiceRequest">
<name>JDE_SREQ_Sample_AddCBAlert_Alarm</name>
</orchestrationSteps>
</trueActions>
<falseActions>
<orchestrationSteps type="Rule">
<name>JDE_RULE_Sample_CBMWarning</name>
<trueActions>
<orchestrationSteps type="ServiceRequest">
<name>JDE_SREQ_Sample_AddCBAlert_Warning</name>
</orchestrationSteps>
</trueActions>
</orchestrationSteps>
</falseActions>
</orchestrationSteps>
</falseActions>
</orchestrationSteps>
</falseActions>
</orchestrationSteps>
</orchestrationSteps>
</Orchestration>

So we can see from the above document, how the various components are being called (cross reference etc)


P952000 will show you the maps that can be maintained in JDE for cross reference etc:


image


Note that I get the following error, because I need to load the cross reference data into my F952000 tables

{
"exception" : "java.lang.Exception",
"timeStamp" : "2015-11-11:20.59.05",
"message" : "Orchestration Aborted: Cross Reference Failure"
}

Saturday, 24 October 2015

Attending open world

I’m not too sure whether anyone out there (listening to this) is going to oracle open world, but I’m lucky enough to be attending.  Reach out to me if you’d like a demo of google analytics for JDE or perhaps a look at our enterprise mobility solutions.  We could also just talk about how cool 9.2 is until the wee hours of the morning…

I really look forward to see what is out there in the oracle space for the next year.  I’ll be sure to blog anything interesting that I learn.

Tuesday, 20 October 2015

getting OATS to work with OVR in E1–JDE load testing tips

This was not the easiest thing I’ve ever done, but interesting things never are.
I have been doing some load testing, but need to ensure that OVR reports are being load tested at the same time.  OVR, as you know runs on the xmlpserver / xmlpublisher technology from oracle.
Of course, I suspected that out of the box I might have a few issues getting this to work and I was not wrong.
I was getting a lot of errors like this:
http://e1ovr.myriad-it.com:9704/xmlpserver/io/zip/read-resource-cache 0.112 10-20 00:19:23 0.109  Warning Invalid HTTP response code: 500  Internal Server Error , for Url: http://e1ovr.myriad-it.com:9704/xmlpserver/io/zip/read-resource-cache   

image

image

So getting 500’s and 404’s when running, right – we need some fixes.

In general the server maintains cookies or passes header values back and forth to ensure that you have the ability to see it’s resources, xmlp is the same in this respect.  Passing the values that are recorded by OATS are never going to cut the mustard on a replay.  this is where you need to work out what variables that you need to ensure are unique for each session and then create some internal OATS variables for these.

For me this is generally a bit of trial and error, as really there is no way of determining exactly.

Here are some likely candidates for XMLP:
http://e1ovr.myriad-it.com:9704/xmlpserver/viewer.jsp?
_xpt=1&
_xdo=%2F%7Ebip%2Fruntime%2FMqDWksFPrgpvkky7wmj7qxKx95pXQkzn0vG1RJRQQgln79SKL%2F0640f55c252b4603baa1aa3dfd779e3a.xdo
_xt=Inventory+Valuation+by+Branch+Plant
_xl=en
_xf=analyze
_xtoken=B06BE2613C8F251D3044D54EB3A10C6A

Likely are _xdo and _xtoken, but what you’ll find is _xdo is unique for the report being called, so only xtoken needs to be replaced.

You’ll find this hidden in a jde screen, use a regular expression like this for extraction:
_xf=analyze&_xtoken=(.+?)'

or
http.solve("xtoken", "_xf=analyze&_xtoken=(.+?)'", "", false,
      Source.Html, 0, EncodeOptions.None)

Then you’ll also need to replace the unique number in the following string”":  cache:oracle.xdo.common.io.Cache5995658651262771787.tmp#  and pass this around to all commands that use it.

Note that this is the HTML returned by the command “http://jdebipubprod01.local:9704/xmlpserver/io/zip/allocate-resource-cache” search for allocate-resource-cache

image

Once both of the above are done, your load tests should start belting the OVR server just like they should.

Friday, 16 October 2015

weblogic cannot start E1 web instance with server manager

This is becoming a little frustrating.

Because weblogic redeploys the application after EVERY restart from the owl_deployment directories under jde_home – if you have any directories locked or explorer open on any of these directories accidently – the application cannot redeploy and will not start.

image

If you goto http://servername:7001/console and look at the application, you’ll see that it’s running!

image

You’ll see that it’s running in WLS, but JDE states it’s not.

Remove all of the locks on the runtime dirs, oracle\middleware\user_projects…

Then stop application from wls console

Then start from SM

Thursday, 15 October 2015

Schedule a basic oracle script

This is for me when I need to do this again in a week…

I keep forgetting

image

c:\windows\syswow64\wscript.exe //e:vbscript d:\myriad\scripts\CheckForCorruptVersionsInProd.vbs

The contents of the script:

The script is totally RAD, it does a query (nice), but also emails results and uses some basic password encryption for prying eyes.

'Username, password and URL settings
'Modify what is required to get this running, username, password (create read only innocuous users)
FromEmailAddress="jde@au.myriad.com"
Const strSmartHost = "smtpserver.com.au"
Company="myriad"
RecipientNames = ARRAY("smoir@au.myriad.com", "shannon.moir@myriad-it.com")
'
'The password below has been encrypted with a top secret encryption key
'If the JDE password changes, then you'll need to reencrypt the new password
'This can be done by calling EncryptPasswordToFile fCrypt("newPAsswordText","Something99"),"passwordFile"

EncryptedPassword="ThingsGoHere"

PasswordString="Password=" & fCrypt(EncryptedPassword, "Something99") & ";"

'EncryptPasswordToFile encrypted,"passwordFile"

Dim Oracon
set oraccon = wscript.createobject("ADODB.Connection")
Dim recset
set recset = wscript.createobject("ADODB.Recordset")
Dim cmd
set cmd = wscript.createobject("ADODB.Command")
Set Oracon = wscript.CreateObject("ADODB.Connection")

Oracon.ConnectionString = "Provider=OraOLEDB.Oracle;" & _
"Data Source=e1sys;" & _
"User ID=jde;" & _
PasswordString

Oracon.Open
Set cmd.ActiveConnection = Oracon
'cmd.CommandText = "Select count(*) from dvfindta.f0101"
cmd.CommandText = "SELECT vrpid, vrvers, vrjd, vrved FROM pd910.f983051 where vrvers not like 'XJDE%' and vrvers not like 'ZJDE%' and vrpodata is null and vrdstnm > ' '"
Set recset = cmd.Execute
i=0
'Note that often this is not supported by the DB, so... Need to use a variable
if recset.recordcount = -1 then
counter=500
else
counter=recset.recordcount
end if
emailBody=chr(10) & chr(13) & "*** This Script contains a list of versions that should not have NULL PO's (500 max) ***" & chr(10) & chr(13)
emailBody=emailBody & encrypted & chr(10) & chr(13)
emailBody=emailBody & cmd.CommandText & chr(10) & chr(13)
emailBody = emailBody & "vrpid, vrvers, vrjd, vrved" & chr(10) & chr(13)
while ((i < counter) and (recset.EOF <> true))
for each field in recset.fields
tuple=tuple & """" & field.value & ""","
next
i=i+1
recset.MoveNext
emailBody=emailBody & chr(10) & chr(13) & tuple
tuple=" "
wend

'wscript.echo emailBody
i=sendMail("WeeklySummary of NULL POs", emailBody,"")

set recset = nothing
set cmd = nothing
set oracon = nothing


'#####################################################################
'FUNCTION:sendMail
'#####################################################################
function sendMail(subjectText, emailBody, attachment)
on error resume next
Dim iMsg
Dim iConf
Dim Flds
Const cdoSendUsingPort = 2

for each name in RecipientNames
'Create the message object
Set iMsg = CreateObject("CDO.Message")
'Create the configuration object
Set iConf = iMsg.Configuration
'Set the fields of the configuration object to send using SMTP via port 25.
With iConf.Fields
.item("http://schemas.microsoft.com/cdo/configuration/sendusing") = cdoSendUsingPort
.item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSmartHost
.Update
End With

'Set the message to,from,subject,body properties.
if strlen(attachment) > 1 then
With iMsg
.AddAttachment attachment
.To = name
.From = FromEmailAddress
.Subject = subjectText & " " & now()
.TextBody = chr(1) & " " & emailBody
.Send
End With
else
With iMsg
.To = name
.From = FromEmailAddress
.Subject = subjectText & " " & now()
.TextBody = emailBody
.Send
End With
end if
set iMsg = Nothing
next

end function

Function fCrypt(sPlainText, sPassword)
'This function will encrypt or decrypt a string using the RSA's RC4 algorithm.
Dim aBox(255), aKey(255), sTemp, a, b, c, i, j, k, iCipherBy, sTempswap, iLength, sO
i = 0:j = 0:b = 0
iLength = Len(sPassword)
For a = 0 To 255
aKey(a) = Asc(Mid(sPassword, (a Mod iLength)+1, 1))
aBox(a) = a
Next
For a = 0 To 255
b = (b + aBox(a) + aKey(a)) Mod 256
sTempswap = aBox(a)
aBox(a) = aBox(b)
aBox(b) = sTempswap
Next
For c = 1 To Len(sPlainText)
i = (i + 1) Mod 256
j = (j + aBox(i)) Mod 256
sTemp = aBox(i)
aBox(i) = aBox(j)
aBox(j) = sTemp
k = aBox((aBox(i) + aBox(j)) Mod 256)
iCipherBy = Asc(Mid(sPlainText, c, 1)) Xor k
sO = sO & Chr(iCipherBy)
Next
fCrypt = sO
End Function

Function EncryptPasswordToFile(szPassword, filename)
Set wshShell = CreateObject( "WScript.Shell" )
tmpDirectory = wshShell.ExpandEnvironmentStrings( "%TMP%" )
set wshShell = Nothing
Const ForAppending = 8
logfile=tmpDirectory & "\" & filename & ".txt"
'Tempates

Set objFSO = CreateObject("Scripting.FileSystemObject")
set objTextFile = objFSO.OpenTextFile(logfile, ForAppending, True)

objTextFile.WriteLine(szPassword)
objTextFile.Close

end function

Thursday, 8 October 2015

Cheats way to copy a pathcode, quickly

Quick way to duplicate a pathcode:

Central objects copy, takes about 40 mins.  Honestly, forget import and export and security and indexes and constraints…  Just do this:

select 'TRUNCATE TABLE PP910.' || table_name || ';' from all_Tables where owner = 'PP910' and length(table_name) < 12 and table_name not in ('DATACOUNTS', 'F983051_BAK', 'F98950BK') ;

select 'INSERT INTO PP910.' || table_name || ' SELECT * FROM PD910.' || table_name || '@jde_e1sys ;' from all_Tables where owner = 'PP910' and length(table_name) < 12 and table_name not in ('DATACOUNTS', 'F983051_BAK', 'F98950BK') ;

update pp910.f983051 set vrenhv = 'PP910' ;

Then copy the PD910\include and PD910\source dirs on the dep server to PP910


Fix object librarian

create table jde.f9861srm as select * from ol910.f9861 where sipathcd = 'PD910' ;
delete from ol910.f9861 where sipathcd = 'PP910' ;
commit;
update jde.f9861srm set sipathcd = 'PP910' ;
insert into ol910.f9861 select * from jde.f9861srm ;
commit;

Full build and deploy.