Archive for November, 2007

Community Activism

Wednesday, November 28th, 2007

The SDN leadership have done a great thing, they have linked their “points” incentive program to a good world cause, School Feeding.  From Chief Evangelist Mark Finnern’s blog Food for Points:

The whole community collected around 2.5 million points last year.

If we reach the same amount of points next year, we will have 100K Euro. (If we don’t, we will walk in shame.)

If we reach 3.0 million points, SAP will donate 150K Euro.

Now if we even reach 3.5 million points, the amount will rise to the maximum of 200K Euro.

From the World Food Programme’s web site:

It costs just 10 US cents a day to give a child a cup of porridge at school. An additional nine US cents a day provides a child with a nutritional package, including basic health and sanitation support.

1 Pt * ( # of Euros / # of Points ) *  ( 1 USD / .67 EUR ) * ( child / .1 USD ) = Conversion

Roughly translated back to points that means for every point you earn on SDN you will feed between .6 and .85 children for one day.  With the average blog post getting around 50 points, one blog can feed 30-40 children that day.

“One person can make a difference and every person should try.” John Fitzgerald Kennedy

SAP Web Services in Flex Builder

Wednesday, November 14th, 2007

SAP web services are really complex, tables inside rows inside tables inside structures.  I’ve been fielding an increasing number of questions about using these in the forum so, instead of answering everyone separately here are a few examples from simple to complex.

Let’s start off with one of the simpler examples just to get the hang of it.  Use SAPLink and install this function group and generate a web service from the one function in it.  Now, lets write some Flex code to call this.

Import Statements

A few people have asked me to add the import statements to this.  For reference if you go to the object that has the error, move your cursor to the end of the word hold control and press space the import will be added for you automatically, welcome to the wonderful world of a good IDE.  But the following in a <mx:Script> block between the <mx:Application> tags.

import mx.rpc.AbstractOperation; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.soap.LoadEvent; import mx.rpc.soap.WebService;

Simplest Example

Step 1 - Get your WSDL

1 private function callWebService():void{ 2 fooService = new WebService(); 3 fooService.wsdl = "http://localhost/sap/bc/srt/rfc/sap/Z_TEST_CHANGING_PARAM?sap-client=300&wsdl=1.1"; 4 fooService.addEventListener(LoadEvent.LOAD, loadListener); 5 fooService.addEventListener(ResultEvent.RESULT, resultTrigger); 6 fooService.addEventListener(FaultEvent.FAULT,fault); 7 fooService.loadWSDL(); 8 }

Line by Line:

  1. Declare a function that will start the whole process
  2. Create a WebService object, this should be global or at least visible to the other methods ( you’ll need it later )
  3. Point the WS to the location of the WSDL
  4. Add an EventListener for when the Loading of the WSDL is complete
  5. Add an EventListener for the results coming back from the call
  6. Add an EventListener for any errors that occur
  7. Tell the WS to load the WSDL

Step 2 - Set Some Parameters

1 private function loadListener(event:LoadEvent):void{ 2 var op:AbstractOperation = fooService.getOperation("Z_DOUBLE_ROWS"); 3 var input:Object = new Object(); 4 input.TEST = new Array(); 5 input.TEST.push("foo"); 6 input.TEST.push("bar"); 7 op.arguments = input; 8 op.send(); 9 }

Line by Line:

  1. Declare a function who handles the event you subscribed to in the Step 1 line 4.
  2. Get the Operation from the WSDL file.  This is one of those “standard” ways of doing things.  If you look at your WSDL file you will see that it could have more then one operation in it, this gets the particular operation you want to call.
  3. Create a dynamic object that will hold the inbound parameters to your WS.  In this case the parameter TEST is a table of strings.
  4. Here we create what Flex builder thinks is how to hold  a table, an Array.
  5. Then we push each “row” of the table into the array again, in this case it’s just one string at a time.
  6. See Line 5
  7. We then map the input object to the arguments of the WS.
  8. Send our request including all the input data to the server

Step 3 - Look at the Output

1 private function resultTrigger(event:ResultEvent):void{ 2 var item:String; 3 for each(item in event.result){ 4 trace(item); 5 } 6 }

Line by Line

  1. Define a function to handle the event from section 1 line 5
  2. Declare on object to hold each result
  3. Loop at each item in the result list, which happen to be strings.
  4. Print them out to the debug console

I will talk about more advanced parsing of the result set later on.

Inbound Table Parameter

First, get your WSDL, in this case I will be using the FM BAPI_FLIGHT_GETLIST from the SFLIGHTS example we are all so fond of.  You should run this FM a few times to make sure you have data on the ABAP side, I will be passing in a date range to this FM so, you might want to find two dates that return some data for you. ( I named my WebService “Z_GET_FLIGHT_LIST” )

Step 1 - Get Your WSDL

This is the same exact thing you did before, just with a different WSDL.

Step 2 - Set some Parameters

There is a strange behavior with ABAP WebServices where if you have a table that is both Input and Output you must pass it as part request to get it filled.  You’ll see in a second:

1 private function loadListener(event:LoadEvent):void{ 2 var op:AbstractOperation = fooService.getOperation("BAPI_FLIGHT_GETLIST"); 3 var input:Object = new Object(); 4 input.FLIGHT_LIST = new Array(); 5 input.RETURN = new Array(); 6 op.arguments = input; 7 op.send(); 8 }

Line by Line

  1. Define a function that handles the event
  2. Get the right operation
  3. Dynamic input object
  4. You have to pass blank parameters to the WS so that the Web Application Server will fill them
  5. See line 4
  6. Same as last time
  7. Same here

Set Table Parameters

1 var dateRangeRow:Object = new Object(); 2 input.DATE_RANGE = new Array(); 3 dateRangeRow.SIGN = "I"; 4 dateRangeRow.OPTION = "EQ"; 5 dateRangeRow.LOW = "2002-12-20"; 6 dateRangeRow.HIGH = ""; 7 input.DATE_RANGE.push(dateRangeRow);

Line by Line ( add this between lines 5 and 6 from the prior example )

  1. Create a new dynamic object that holds a Row of the DATE_RANGE table
  2. Create an array called DATE_RANGE which will map to the DATE_RANGE input parameter
  3. Set each field dynamically
  4. More fields
  5. More fields
  6. More fields ( don’t need to pass this one because it’s blank )
  7. Push this row into the array

Step 3 - Look at the Output

1 private function resultTrigger(event:ResultEvent):void{ 2 var row:Object; 3 for each (row in event.result.FLIGHT_LIST){ 4 trace(row.AIRLINE + " " + row.CITYFROM); 5 } 6 }

Line by Line

  1. Function, again.
  2. Use a place holder dynamic object
  3. Loop at the table called FLIGHT_LIST ( looks like ABAP doesn’t it? )
  4. Print to the console the fields you want ( looks like ABAP doesn’t it? )

Disclaimer: There are a number of ways to call WebServices in Flex, I believe this is the most complete and “standard” way to call them, if not someone please point me to Adobe docs that show the most correct way.

Life Hub "Spec"

Monday, November 5th, 2007

I want a Life Hub.  Don’t worry I still want a phone/PDA, iPod, camera and computer.  I’m one of those people that believes a device that does “everything” doesn’t do any of them particularly well.  I want something that I can carry around that plugs me into my or your devices and shares my data with them.

When I sit in my car, I want my Life Hub to connect up to my music interface device which connects to my car so the controls are mapped to the steering wheel and the music comes out the speakers.

When I go to the office, I want my Life Hub to connect to my work phone and register my cell number so my work phone will ring with calls placed to my cell phone.

When I take a picture with my camera, I want it saved on my Life Hub.  I want to be able to browse those pictures on my smart phone and email them to my friends.  Kind of like Dave’s social camera.  If I so chose my Life Hub can broadcast to others the picture I just took, without or without the tagging my camera added.

Why do I need 97 different syncing programs to get my Outlook Calendar, Google Calendar, and iCal Calendar to line up!  Aren’t these just visualizations of the same data set?  If I had my calendar on my Life Hub, I could just access it from there.  Who cares where I’m sitting, at my home machine, work machine or at the Library.

So, what is a Life Hub, basically a high capacity solid state memory drive ( Intel is looking to get up to 160GB in the next few years ) with a very high bandwidth wireless connection.  It has a UI that lets you “allow” devices to connect for a period of time and access certain types of data on your Life Hub, read and/or write.  The idea is that this thing should eventually be small enough to fit on a key chain, think thumb drive on crack — in reality it could be your key chain!  Ever seen someone unlock and start their Prius without taking a key out?

If it had strong encryption you could store your X-Rays and patient files on the drive.  What if you could allow your doctor to review a certain set of them for a period then when they are done zap the records back to you?  Why should Microsoft control your health records, or even Google for that matter?  Today Adobe PDFs can be locked so they are only viewed for a period of time.

Is all this possible today?  Some of it — some of it is also hard, standardizing the wireless protocol for instance.  Currently, there is no wireless standard that rivals Firewire for throughput sending a RAW image from today’s DSLR cameras, BlueTooth just won’t do.

I have no idea how to solve these problems or “the chicken and the egg problem” of this only being useful if there are devices out there that can connect to it.  I do know that I want one.