Thursday 8 December 2016

PI JAVA Hanging

So in trying to investigate a PI issue, I discovered that the client was running pure Java stack. I've not spent loads of time there, but was sure I could pick it up once I was in the correct transactions : Going to

NWA/Configuration just left me with the spinny-circle-of-boringness... PI was hanging.

An OSS Note (I forget which) said that JAVA PI systems hanging can be fixed by making a setting in Configuration... WTF? I can't even reach that, because the system is hanging! Maybe I got the wrong note.

In the end, this was fixed by:

Installing the newer version of Java
https://java.com/en/download/

Adding the URL of the application to the exceptions list:
http://neo.jpl.nasa.gov/orbits/java_exception.html

Also, in the place where you can set the exceptions, ramping the security down to minimum.


And now I can do all my PI config!

I'm looking forward to the next time I run eclipse, and seeing what the problems with that are!

This is one of the usual complaints about Java, there's a whole bunch of incompatibilities that mean you can only really purpose Java for one thing at a time! That and that SAP/Eclipse/IE never seem to keep up with what Java is doing...


Thursday 10 November 2016

Can't see my Service in IWFND/MAINT_SERVICE

When trying to add my service, from my ED2(300) server, I can't see it in the Gateway IWFND/MAINT_SERVICE



It's definitely there in the backend, I've activated SEGW...

The way round this (for reasons unknown...) was to create a SEGW Project in the Gateway with the same name as the project in the backend. 
You don't need to populate it with the data entries, mappings to fms etc, just needs to be a faux shell.

Once that's done, go back into the IWFND/MAINT_SERVICE transaction, and try and add the Service again.

This time round, the Service was there, and the transaction even seems to have picked up that it needs to be looking at ED2(300). My guess as to why the latter should be the case is that this was a previously used service that was deleted then re-inserted.

Thanks a lot to Manu for this one... :D

Wednesday 2 November 2016

oData Cacheing

Hi guys,
 Caching eh? Supposed to make things a lot faster, prevent unnecessary trips to the server to get data the browser thinks it's got already.

Except it doesn't... 

Here was our scenario : We had a UI5 application that dragged data from SAP into the browser. The user could change this, and save the changes back to SAP. So far so good... 

except

when the user went out of the document, then back in again, they got the OLD version of the data. This took a bit of analysis to get to the bottom of.

Of course the first thing I tried was to put a breakpoint in the backend function, to see if that was even getting hit. It wasn't.

The next thing I tried was switching on debug mode (F12 in the browser - IE in my case) and using "Network"->"Monitor" to see what requests were going to the backend. Now, since my browser console is set to "Always refresh data from server" this then called SAP, and my breakpoint was hit...

The inconsistency here is really frustrating, as you can be debugging and see one set of results, tell your user that the problem is fixed, then have them see a different set of results.

So the issue here is that the oData results had been cached.

There were 2 ways round this... one "hackier" than the other...

1 : Spoof a filter option, that the backend then ignores...
This was a colleagues idea, and I liked it as it solved the problem without significant additional investigation. We included a dummy timestamped filter, which made the URL unique, and so the browser HAD to go to the backend because it couldn't find a cached result for that URL.

2: Switch off Caching : 
https://blogs.sap.com/2014/05/28/disabling-cache-for-crudfi-odata-scenarios-for-a-ui5-application-using-ie/

Really liked this guys style!

Thursday 25 August 2016

Naming your Models in UI5


Once again, I'm indebted to the ABAP community for their generosity of spirit and sharing. This post explains really succinctly how you can mix and mash up your models by naming them as you set them. 

http://scn.sap.com/thread/3948723

The biggest learning point for me was that the setModel method, which I'd thought indicated "Set the Model for the View" (i.e. you can only have one...)

this.getView().setModel(oSTModel,"TableModel")

Actually you can do this multiple times, setting several Models against the view. This is great, as we're now at the point where we need to draw data from several different places, and have them consolidated on the front end.

The named models can then be referred to by the XML view : 

<core:ListItem text="{TableModel>Description}" additionalText="{TableModel>Key}" />




Tuesday 23 August 2016

view.byID

So I'd seen code examples all over the place referring to "view.byID"
When I coded them in, they never worked.

It's because the view variable needs to be declared.

Once that's been done, you can re-use the variable over and over.

Really simple, but if no-one's told you, it's not apparent!

How to loop around a JSON result...

Okay, I spent ages looking for how to do this. The tricky part I found was marrying up the data in the response from the server, and the labels that people were giving different parts of the request... Soooooo I'm going to add to the noise, and hopefully help a few people out.

First up - the address of my service that's providing the JSON data:

/sap/opu/odata/sap/ZPD_RR_SRV/RepairActivitySet

Although clearly, that's the oData, so with the JSON tag on the end:

/sap/opu/odata/sap/ZPD_RR_SRV/RepairActivitySet?$format=json

This returns a list of Repair Activities (viewed from Gateway):




Note that it has the structure d/results/{Rakey/Radesc}

This is what I wanted to loop around in my UI5 javascript application, in one of my ViewControllers.

Here's the complete code that reads the lot: 

var NRAModel = new sap.ui.model.json.JSONModel();
NRAModel.loadData("/sap/opu/odata/sap/ZPD_RR_SRV/RepairActivitySet", null, false); 
var NRAModelArray = NRAModel.getData();


var myResults = [];

myResults = NRAModelArray.d.results;
console.log(myResults.length);

for( i = 0; i < myResults.length; i++) {
     var obj = myResults[i];
      console.log(myResults[i]);
      console.log(myResults[i].Rakey );
      console.log(myResults[i].Radesc);

}


The thing to note here, is that myResults is declared as an Array, and is populated by passing the d.results content from the original NRAModel.getData

d.results, you'll notice, is the same path as that provided by my Service, in the first screenshot.

Using console.log as you go along really helps with understanding what each of the variables are doing.





Wednesday 17 August 2016

UI5 Deep Entities

Surprisingly, it's not possible to just pass a table of data (or an Array, if we're talking JavaScript) into an ABAP FM.
This was a little disappointing, given my oData experience so far went from 


  • messing around with the DPC_EXT methods (where you had to do a bit of work to read the contents of the message from the frontend) 
to
  • just cloning the FM interface out to an oData structure (where you didn't have to do any work...


I think you can guess which one I preferred... 

So when you need to populate lots of stuff into a function module (e.g. you're creating a Sales Order, and you need to pass header data and several lines of line Item data)

you need to use a "Deep Entity". This immediately makes me think that the entity is sitting around contemplating the meaning of life, questioning it's own existence, etc etc.

The setting up of a deep entity call is described in detail here:

http://scn.sap.com/community/gateway/blog/2014/04/27/step-by-step-development-guide-for-createdeepentity-operation

and the corresponding front-end call is described here: 

https://scn.sap.com/thread/3557655

I'm about to go through these; if there's anything notable about them, I'll blog in some additions below. Peace.





Monday 25 July 2016

UI5 SplitApp Container

Excellent jsbin here that explains how to have multiple views in a splitapp... 

http://jsbin.com/aku_switch_views/1/edit?html,output

The bit I'd been missing for a day or two was:

app.toDetail which includes the natty UI5 swishy animation for no extra development effort from myself! :D

Whilst we're here, we should probably shout out jsbin for their excellent crowd-sourced examples library, which also include an online editor (like the w3schools example). Super tool!

Monday 11 July 2016

Test data table randomiser

Okay, so I need to populate some interesting test data in a Z-table I'm supposed to be reading. I could be really boring and set up a bunch of sequential data, which all drops out of the table in a boring organised way. This is right out, it'll just look really contrived.

I could set up a number of itabs, each with lists of possible data, then randomly attack each of them, getting me an interesting set of data. I've done this in the past, and it looked fine, just took a while.

I could just populate the table whilly-nilly. This works fine, again, takes a while, and doesn't get the computer to do the work...

The method I've just employed, I'm happy with; populate a small table, whilly-nilly, then randomly attack that table to make the data you send to the database. This has the required combination of randomness, interestingness, and capacity to create lots of data all at the once. (I'm only doing 20 here, but could just as easily be 200!).

define getRand .


  CALL FUNCTION 'QF05_RANDOM_INTEGER'
  EXPORTING
    RAN_INT_MAX         5
    RAN_INT_MIN         1
  IMPORTING
    RAN_INT             l_rndInt.

READ TABLE t_zpd_rh2 INDEX l_rndINt into &1.

end-OF-DEFINITION.


REPORT ZPD_POP_RH2.

"Dataset to randomise out of...

datat_ZPD_RH2 type TABLE OF ZPD_RH2.


datal_ZPD_RH2 type ZPD_RH2,
      l_ZPD_RH2_feeder type ZPD_RH2,
      l_rndInt type QF00-RAN_INT.

*(operation/workcentre/plant/description)
l_zpd_rh2-property 1.
l_zpd_rh2-work_centre 'WC1'.
l_zpd_rh2-plant '1000'.
l_zpd_rh2-description 'Replace boiler'.
append l_zpd_rh2 to t_zpd_rh2.

l_zpd_rh2-property 2.
l_zpd_rh2-work_centre 'WC2'.
l_zpd_rh2-plant '2000'.
l_zpd_rh2-description 'Renovate Bathroom'.
append l_zpd_rh2 to t_zpd_rh2.

l_zpd_rh2-property 3.
l_zpd_rh2-work_centre 'WC3'.
l_zpd_rh2-plant '3000'.
l_zpd_rh2-description 'Replace kitchen sink'.
append l_zpd_rh2 to t_zpd_rh2.

l_zpd_rh2-property 4.
l_zpd_rh2-work_centre 'WC4'.
l_zpd_rh2-plant '4000'.
l_zpd_rh2-description 'Fix leaky tap'.
append l_zpd_rh2 to t_zpd_rh2.

l_zpd_rh2-property 5.
l_zpd_rh2-work_centre 'WC5'.
l_zpd_rh2-plant '5000'.
l_zpd_rh2-description 'Diagnose bad smell'.
append l_zpd_rh2 to t_zpd_rh2.

datal_operation type int4.


do 20 times.
  clear l_zpd_rh2.

  l_operation l_operation + 1.
  l_zpd_rh2-operation l_operation.

  getRand l_ZPD_RH2_feeder.
  l_zpd_rh2-work_centre l_ZPD_RH2_feeder-work_centre.

  getRand l_ZPD_RH2_feeder.
  l_zpd_rh2-plant l_ZPD_RH2_feeder-plant.

  getRand l_ZPD_RH2_feeder.
  l_zpd_rh2-description l_ZPD_RH2_feeder-description.

  getRand l_ZPD_RH2_feeder.
  l_zpd_rh2-property l_ZPD_RH2_feeder-property.


  append l_zpd_rh2 to t_zpd_rh2.

enddo.

MODIFY zpd_rh2 from TABLE t_zpd_rh2.

commit work and wait.

Friday 3 June 2016

PI Search Nuisance

PI Searching is case sensitive... thus 

yields different results to:

I need all the help I can get with PI, and this is just irritating!

Monday 18 April 2016

Memory ID tip..

Came across this neat trick today : 

So, normally, we use the "export to memory id" and "import from memory id" commands when we need to pick up data from one place and read it in another, without the hassle of passing it from place to place as the code gets processed.

In the above case, there were many shell layers between where the variable was set, and where it was read. However, Simon has done us all a favour, and assigned the variable to Class-attribute. The beauty of this is that it makes the SET really easy to find if you've got the READ, and vice versa... It's a neat simple trick, but it's a good way of organising your code!

Wednesday 6 January 2016

If Line Exists...

New to ABAP 740 (okay, that's well old, but new to me) this blog describes how to use the itab function "if line_exists"


Looks really useful!