Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
ted_ueda
Employee
Employee
0 Kudos
>

+I work for SAP Business Objects in Technical Customer Assurance.  My speciality is the Software Development Kits (SDKs) that we provide with our Business Intelligence products - BusinessObjects Enterprise, Web Intelligence, Desktop Intelligence, Crystal Reports and Crystal Xcelsius.  +

+In my blog, I discuss subjects that I personally find interesting - little known or not-well-documented corners of the SDK, new functionality or new SDKs, or interesting issues that I've come across in a SAP Incident or SAP Developer Network forums.  +

+You're more than welcome to suggest any topic (SAP Business Objects SDK related, of course...) that you'd like me to discuss - I have a dozen or so items on my blog to-do list, but I'm always on the hunt for anything interesting with our SDKs.+   

+*** Update: revised Flex sample to use the new suppress_response_codes feature (thanks, Bo!) to work with Internet Explorer! ***+ If you're interested in {code:html}+Polestar in the cloud+{code} and the recently announced {code:html}+Polestar in the cloud+ API $20K IDEAtion Challenge{code}, then this blog entry may be of interest to you.   I'm going to present here a few sample codes for that API, so you'll quickly get up to speed and have a head start on the competition! Each of the sample codes follow the same workflow: retrieve data, upload the dataset to OnDemand, then view it in +Polestar in the cloud+.  What differs is the programming language used and the data source.  The four samples are:   * C# with data retrieved from Query as a Web Service (http://labs.businessobjects.com/querywizard/default.asp)0.1. [Xcelsius | https://www.sdn.sap.com/irj/boc/xcelsius] SDK - Adobe Flex component. 0.2. Java with RSS Feed (http://en.wikipedia.org/wiki/RSS_(file_format)) data.
h5. +Polestar in the cloud+ API Ty Miller, a Techical Director here, sent me email about a month ago asking whether I was interested in checking out a cool new Web Services API for the [BusinessObjects Labs | http://labs.businessobjects.com] project called {code:html}+Polestar in the cloud+{code}. I figured whatever Ty's involved in is high on the hot-and-interesting scale - he's sent a few pretty interesting Customer Support cases my way in the past - but at the time I was busy helping customers and working with {code:html}Crystal Reports for Eclipse 2.0{code} and Universe Data Access Driver Development Kit SDK (Web Intelligence XI 3.x - Reporting off the BusinessObjects Enterprise CMS Via Data Access DDK), so I had to flag his email for later action. [Rob Horne | /people/robert.horne/blog], who's also into pretty interesting stuff, recently [blogged | Get a peek at the hottest product at SAP BusinessObjects] about +Polestar in the cloud.+  Reading his blog certainly encouraged me to check it out  (although I have to say I'm far from a Steve Nash fan), and what I found was pretty impressive.  Polestar makes the relationship between you and your data highly personal - I've gotten tremendous insight, and seen relationships I've not thought of, merely by uploading data and working with it in Polestar.  Having Polestar as part of the "Cloud" computing on Whohar - the [http://create.ondemand.com/ | http://create.ondemand.com/] portal - makes it that much more compelling.  Now you can upload and store your data on Whohar, and analyze it using different dashboards as well as Polestar.  Programmatic dataset management is accomplished via the Whohar RESTful (http://en.wikipedia.org/wiki/Representational_State_Transfer) Web Services API - you can upload, download, update and delete datasets via simple HTTP calls.  You can then invoke a URL to view a dataset in Polestar. The beauty of the API is in its simplicity - you're able to code against it using most programming languages out there, and have a very elegant means to integrate your app with +Polestar in the cloud+. Rob kindly sent me a preview of the Whohar API docs - it's now available publicly {code:html}here{code} - and I've been playing with the API since.    I've cleaned up some of my sample codes and present it here for your enjoyment.  I do hope it helps you in quickly working out the API workflow required to integrate your stuff with +Polestar in the cloud+. h5. Python Script with Inline DataSet Here's a short Python (http://www.python.org/) script that I used to get a 'feel' for the API -

bq. *Python script uploading data to +Polestar in the clo+ud* #!/usr/bin/env python 1. 2. whohar_polestar.py # 1. Upload data to Whohar and view in Polestar in the cloud #=============================================================================== import base64 import os import urllib2, cookielib import webbrowser 1. 2. URL to Whohar Dataset API and Logon Credentials # url = 'https://create.ondemand.com/v1/datasets' username='' 1. 2. Dataset to upload to Whohar # data = '''''' # 1. Log on and send data to Whohar # datasetURL = None 1. Define HTTP Basic Authentication header string base64string = base64.encodestring('%s:%s' % (username, password))[:-1] authheader = "Basic %s" % base64string 1. Define HTTP Cookie container - used to retrieve Session ID cookieJar = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookieJar)) 1. Construct HTTP request with authentication header req = urllib2.Request(url) req.add_header("Authorization", authheader) 1. Send dataset to Whohar. HTTP Response to successful upload is HTTP Code 201. 2. Python throws an exception on 201, so we trap and retrieve content Location. try: handle = opener.open(req, data) except IOError, e: if e.code != 201: raise datasetURL = e.read() datasetURL = datasetURL[datasetURL.index("http"):-1] 1. Parse URL for the dataset ID id = datasetURL[datasetURL.rfind('/') + 1 :] 1. Retrieve Session ID from HTTP Cookie session=None for cookie in cookieJar: if cookie.name == '_whohar_session' : session = cookie.value # 1. Open Polestar OnDemand with dataset ID and session ID 2. polestar_url='https://create.ondemand.com/polestar/show_exploration/' + id + '?whohar_session_id=' + session 1. Open a web browser with the Polestar OnDemand URL #webbrowser.open_new(polestar_url) 1. I use Cygwin, for which webbrowser isn't defined, so I 2. open the browser manually: os.system('"/cygdrive/c/Program Files/Internet Explorer/iexplore.exe" ' + '"' + polestar_url + '"') that shows the basics of uploading a dataSet and viewing it in Polestar: the {code:html}required XML dataset format{code}, setting up the HTTP Basic Authentication, retrieving the dataSet ID and session ID, and redirecting to +Polestar in the cloud+. Edit the top of the file to insert your create.ondemand.com logon credentials, and modify the bottom to use either the webbrowser lib or explicit launching of a web browser, and run it using the Python interpreter. You'll note how simple the API is - the advantage of using a RESTful Web Services design. h5. C# With Data Retrieved from Query as a Web Service A bit more useful example, using C# - I wrote it on Visual Studio 2008 - that consumes data from Query as a Web Service (QaaWS), upload them to Whohar and view in +Polestar in the cloud+.  Here's a screenshot of what you get, showing both the QaaWS client with the query, and the Polestar view of the data:     The query is based on the eFashion sample Universe, and Polestar is displaying the breakdown of sales revenue, quanitity of merchandise sold, and margin for stores by State.  Texas is looking pretty good (more on Texas later)... Here's the code: bq. *C# 2008 to upload QaaWS-generated data to Polestar OnDemand* using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.ServiceModel.Description; using System.Text; using System.Web; namespace QaaWS2Polestar { /* Call and retrieve data from QaaWS and send to Polestar OnDemand via Whohar (https://create.ondemand.com) 1. 1. Sample Usage: 1. 1. QaaWS2Polestar.exe http://tueda-bexi3.crystald.net:8080/dswsbobje/qaawsservices/?WSDL&cuid=Af6QUpRFAexMhAuYi2onVtQ Administrator "" MyWhoharUsername MyWhoharPassword * */ class Program { static void Main(string[] args) { if (args.Length "); } string qaaws_url = args[0]; string qaaws_username = args[1]; string qaaws_password = args[2]; string polestar_username = args[3]; string polestar_password = args[4]; /* 1. QaaWS invocation variables. */ object rows; int fetchedrows; Type rowType; PropertyInfo[] rowProperties; /* 1. Polestar OnDemand Web Services variables. */ string whohar_url = "https://create.ondemand.com/v1/datasets"; HttpWebResponse httpWebResponse; string polestar_data_param; string document_id; string session_id; string polestar_display_url = "https://create.ondemand.com/polestar/show_exploration/"; /* 1. Call QaaWS and retrieve data as Array and determine the properties of the element type. */ rows = retrieveQaaWSData(qaaws_url, qaaws_username, qaaws_password); fetchedrows = ((Array)rows).GetLength(0); rowType = rows.GetType().GetElementType(); rowProperties = rowType.GetProperties(); /* 1. Construct data XML from data retrieved from QaaWS */ polestar_data_param = " "; /* 1. For each column, specify name, type, aggregation and qualification 1. from type. */ polestar_data_param += " "; /* 1. Copy data from QaaWS into data XML */ polestar_data_param += " "; /* 1. Send data to Polestar, then retrieve document ID and Session ID */ httpWebResponse = getHttpPOSTResponse(whohar_url, polestar_data_param, polestar_username, polestar_password); session_id = httpWebResponse.Cookies["_whohar_session"].Value; document_id = httpWebResponse.Headers["Location"]; document_id = document_id.Substring(document_id.LastIndexOf('/') + 1); System.Diagnostics.Process.Start("iexplore.exe", polestar_display_url + document_id + "?whohar_session_id=" + session_id); } /* 1. Send HTTP POST Request to URL and return the response. */ static HttpWebResponse getHttpPOSTResponse(string url, string data, string username, string password) { HttpWebRequest webRequest; CookieContainer cookieContainer; byte[] dataBytes; //Disable Expect: 100-continue header //System.Net.ServicePointManager.Expect100Continue = false; /* 1. Define cookie container to persist HTTP Cookies across request redirection. */ cookieContainer = new CookieContainer(); /* 1. Encode HTTP POST body content and POST to the url. */ dataBytes = Encoding.UTF8.GetBytes(data); webRequest = (HttpWebRequest)HttpWebRequest.Create(url); webRequest.CookieContainer = cookieContainer; webRequest.Method = "POST"; webRequest.ContentType = "text/xml"; webRequest.ContentLength = dataBytes.Length; if (username != null) { /* 1. HTTP Basic Authentication */ webRequest.Credentials = new NetworkCredential(username, password); } webRequest.GetRequestStream().Write(dataBytes, 0, dataBytes.Length); webRequest.GetRequestStream().Close(); try { return (HttpWebResponse) webRequest.GetResponse(); } catch (WebException webException) { WebResponse webResponse; webResponse = webException.Response; StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()); String body = streamReader.ReadToEnd(); streamReader.Close(); throw webException; } } /* 1. Call the Query As A Web Service defined by the WSDL found at the specified URL with the 1. specified logon credentials, and return an array of dotNetBeans (instances of class with 1. properties). */ static object retrieveQaaWSData(string qaaws_url, string qaaws_username, string qaaws_password) { /* 1. Variables used to specify QaaWS as a Service Reference */ MetadataExchangeClient metadataExchangeClient; MetadataSet metadataSet; WsdlImporter wsdlImporter; ServiceEndpoint serviceEndpoint; System.ServiceModel.Channels.Binding binding; /* 1. Variables used to compile the Service Reference generated code from QaaWS */ ServiceContractGenerator generator; CodeCompileUnit codeCompileUnit; CompilerParameters compilerParameters; CodeDomProvider codeDomProvider; CompilerResults compilerResults; /* 1. Variables representing the generated QaaWS objects */ Assembly qaawsAssembly; Type qaawsType; Type qaawsHeaderType; Type qaawsParamType; object qaawsHeader; object qaawsParam; object qaaws; /* 1. Retrieve the QaaWS WSDL and generate code as a Service Reference. Note that we could 1. have used the simpler Web Reference, but Service Reference is programmatically nicer, 1. since we can use Reflection introspect the QaaWS parameters and infer meaning from the 1. property names. */ metadataExchangeClient = new MetadataExchangeClient(new Uri(qaaws_url), MetadataExchangeClientMode.HttpGet); metadataExchangeClient.ResolveMetadataReferences = true; metadataSet = metadataExchangeClient.GetMetadata(); wsdlImporter = new WsdlImporter(metadataSet); // Import the endpoint and binding info that's needed when instantiating the QaaWS client object. serviceEndpoint = wsdlImporter.ImportAllEndpoints()[0]; binding = wsdlImporter.ImportAllBindings()[0]; generator = new ServiceContractGenerator(); foreach (ContractDescription contract in wsdlImporter.ImportAllContracts()) { generator.GenerateServiceContractType(contract); } /* 1. Compile the QaaWS code. */ codeCompileUnit = generator.TargetCompileUnit; // System.ServiceModel.dll isn't found by default, so manually find and update reference. for (int i = codeCompileUnit.ReferencedAssemblies.Count - 1; i >= 0; i--) { string assemblyName = codeCompileUnit.ReferencedAssemblies[i]; switch (assemblyName) { case "System.ServiceModel.dll": codeCompileUnit.ReferencedAssemblies[i] = typeof(ServiceContractGenerator).Assembly.Location; break; default: break; } } compilerParameters = new CompilerParameters(); compilerParameters.GenerateExecutable = false; compilerParameters.GenerateInMemory = true; codeDomProvider = CodeDomProvider.CreateProvider("CSharp"); compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, new CodeCompileUnit[] {codeCompileUnit}); if (compilerResults.Errors.Count > 0) { string errorMessage = "Error Compiling .NET Proxy Code Generated from the WSDL"; foreach (CompilerError error in compilerResults.Errors) { errorMessage += error.ErrorText + "
"; } throw new Exception(errorMessage); } /* 1. Load the generated assembly and create the QaaWS client, QaaWS header object, and QaaWS 1. parameter objects. */ qaawsAssembly = compilerResults.CompiledAssembly; qaawsType = qaawsAssembly.GetType("QueryAsAServiceSoapClient", false); qaawsHeaderType = qaawsAssembly.GetType("QaaWSHeader", false); qaawsParamType = qaawsAssembly.GetType("runQueryAsAService", false); if (qaawsType == null || qaawsHeaderType == null || qaawsParamType == null) { throw new Exception("QaaWS Web Service not found."); } // Note: since we don't have a app.config file with the generated QaaWS binding and endpoint // info, we pass it into the constructor. qaaws = qaawsAssembly.CreateInstance(qaawsType.Name, false, BindingFlags.Default, null, new object[] { binding, serviceEndpoint.Address }, null, null); qaawsHeader = qaawsAssembly.CreateInstance(qaawsHeaderType.Name); qaawsParam = qaawsAssembly.CreateInstance(qaawsParamType.Name); // Set the QaaWS logon credentials. If the QaaWS has prompts, you would Reflect for // the prompt property and set them here. qaawsParamType.GetProperty("login").SetValue(qaawsParam, qaaws_username, null); qaawsParamType.GetProperty("password").SetValue(qaawsParam, qaaws_password, null); return qaawsType.GetMethod("runQueryAsAService").Invoke(qaaws, new object[] { qaawsHeader, qaawsParam, null, null, null, null, null, null, null, null, }); } } }I created this sample using Adobe Flex Builder 3 (
http://www.adobe.com/products/flex/) and the {code:html}SAP Dashboard Design (Xcelsius Engage) 2008 Component SDK SP3{code}.  Implementation uses MXML (http://www.adobe.com/devnet/flex/articles/paradigm.html) that subclasses a mx:Button component that, when clicked, reads a bound 2D Array, constructs the Whohar dataSet XML, uploads the data and displays it in +Polestar in the cloud+.    import flash.net.navigateToURL;   import mx.controls.Alert;;   import mx.managers.PopUpManager;   import mx.rpc.events.FaultEvent;   import mx.rpc.events.ResultEvent;   import mx.utils.StringUtil;      /*    1. Polestar OnDemand logon variables.  Pass the suppress_response_codes parameter to    1. prohibit return of non-HTTP 200 codes (other than 5xx errors), since Flex on IE    1. throws exceptions on HTTP 201 Created.    */   private var _psURL:String = "https://create.ondemand.com/v1/datasets?suppress_response_codes=true";   private var _psUser:String = "";   private var _psPassword:String = "";         /*    1. Property dataArray holds the 2D Array to be sent to Polestar.    */   private var _dataArray:Array = null;      [Inspectable(type="Array")]   public function get dataArray():Array {    return _dataArray;   }      public function set dataArray(value:Array):void {    _dataArray = value;    invalidateProperties();   }      /*    1. Begin process of sending data to Polestar OnDemand.    1. First query user for OnDemand Logon credentials.    */   private function sendToPolestarOnDemand(event:Event):void {    var logonDialog:PolestarOnDemandLogon = PopUpManager.createPopUp(            this.parentApplication as DisplayObject, PolestarOnDemandLogon, true) as PolestarOnDemandLogon;    logonDialog.username = _psUser;    logonDialog.password = _psPassword;    logonDialog.addEventListener("logonDialogOK", retrieveLogonCredentials);    PopUpManager.centerPopUp(logonDialog);   }      /*    1. Retrieve the OnDemand logon credentials entered by user, and go to next step -     1. sending data to OnDemand.    */   private function retrieveLogonCredentials(event:Event) : void {    var logonDialog:PolestarOnDemandLogon = event.target as PolestarOnDemandLogon;    _psUser = logonDialog.username;    _psPassword = logonDialog.password;       try {     sendDataToPolestarOnDemand(_psURL, _psUser, _psPassword);    } catch(err:Error) {     Alert.show(err.message + "
" + err.getStackTrace());    }   }            /*             1. Create the dataset XML then stream to OnDemand.             */   private function sendDataToPolestarOnDemand(url:String, username:String, password:String):void {       var data:String;       var row:Array;       var i:int, j:int;           /*     1. Set HTTP Basic Authentication header.       1. Flex3 has Base64Encoder, but Flex2 does not.  Since Xcelsius currently supports Flex2 only,      1. we use an open source Base64 library by Jason Nussbaum (
http://blog.jasonnussbaum.com/?p=108).     */           dataService.headers = {Authorization: "Base " + Base64.Encode(username + ":" + password)};              /*         1. Construct the dataSet preface info.        */       data = " ";          /*        1. Define the dataSet.        */       data += "
";              if(_dataArray.length <= 0) {        throw new Error("Error: No data");       }              /*        1. Specify column type depending on type of data.  We assume column is a measure if        1. it's a numeric type, and dimension otherwise.  Aggregation is set to 'sum' if         1. numeric, and 'none' otherwise.        */       data += "
";        /*     1. Add the data in <r><v>ColValue1</v><v>ColValue2</v></r> format.     */       data += "";           /*        1. Send data to OnDemand        */       dataService.url = url;    dataService.send(new XML(data));   }      /*    1. Retrieve the dataset ID from the Polestar OnDemand data request    1. response, then hand off to method that opens a web browser to Polestar OnDemand.    */   private function retrieveDocumentInfo(event:ResultEvent):void {    try {     var datasetId:String = null;     var sessionId:String = null;          var body:String = event.result.toString();        datasetId = body.substring(body.lastIndexOf("/")+ 1, body.length - 1);          if(datasetId == null || StringUtil.trim(datasetId).length == 0) {      throw new Error("Data Error: missing dataset ID.");     }          // Open web browser with Polestar OnDemand showing document.     openBrowserWithPolestarOnDemand(datasetId);         } catch(err:Error) {     Alert.show("retrieveDocumentInfo: " + err.message + "
"             + err.getStackTrace());    }   }      /*    1. Open web browser to view Polestar OnDemand with specified dataset Id.    1. Expectation here is that previous requests would have set the HTTP Cookie    1. with the OnDemand logon session ID, so that no re-logon will be required for    1. the redirection.    */   private function openBrowserWithPolestarOnDemand(datasetId:String):void {     var url:String = "
https://create.ondemand.com/polestar/show_exploration/" + datasetId;     var urlRequest:URLRequest = new URLRequest(url);     navigateToURL(urlRequest);   }      /*    1. Make the world safe for tags to live in peace and harmony.    */   private function entify(s:String):String {    return s == null ? null             : s.replace(/&/, "&")               .replace(/</, "<")               .replace(/>/, ">");   }      /*    1. Error in sending data.    */   private function dataError(event:FaultEvent):void {    Alert.show("Data Error: " + event.message);   }      bq. *PolestarOnDemandLogon.xml - Logon dialog box for PolestarOnDemand.xml*bq. *PolestarOnDemandPropertySheet.mxml - Xcelsius Property Sheet for PolestarOnDemand.xml*    import xcelsius.binding.BindingDirection;   import xcelsius.binding.tableMaps.input.InputBindings;   import xcelsius.binding.tableMaps.output.OutputBindings;   import xcelsius.propertySheets.interfaces.PropertySheetFunctionNamesSDK;   import xcelsius.propertySheets.impl.PropertySheetExternalProxy;      // Proxy for this Property Sheet and its Xcelsius custom component.   protected var proxy:PropertySheetExternalProxy = new PropertySheetExternalProxy();       // Holds name of property currently being (re)binded.   protected var propertyToBind:String;   // Holds ID of property currently being (re)binded.   protected var currentBindingID:String;         protected function init():void {    // Register callback for bind completion.    proxy.addCallback(PropertySheetFunctionNamesSDK.RESPONSE_BINDING_ID, continueBind);        // Notify Xcelsius that proxy initialization is complete.    proxy.callContainer(PropertySheetFunctionNamesSDK.INIT_COMPLETE_FUNCTION);       // Fill the controls with the current values of the component.    initValues();   }      /*    1. Initialize property values being displayed in Property Sheet     */   protected function initValues():void   {      // Retrieve properties to initialized      var propertyValues:Array = proxy.getProperties(["dataArray"]);        /*     1. For each property, set the relevant UI component field values.     */    for (var i:int=0, m:int = (propertyValues == null ? 0: propertyValues.length) ; i < m; i++) {     var propertyObject:Object = propertyValues[i];          var propertyName:String = propertyObject.name;          var propertyValue:* = propertyObject.value;     // Process the property by name, either show the value or show the cell address if      // bound to the Excel spreadsheet.     var bindingText:String;         switch (propertyName) {      case "dataArray":       bindingText = getPropertyBindDisplayName(propertyName);       if (bindingText != null){        valueEditor.enabled = false;   // When bound the user cannot edit the value.        valueEditor.text = bindingText;// Show the address we are bound to.         } else {                valueEditor.text = propertyValue;       }       break;      default:       break;     }         }    /*     1. Initialize any property styles here.     */   }      /*    1. Return display string for the currently bound value of the specified property.    */     protected function getPropertyBindDisplayName(propertyName:String):String   {    /*     1. Return the first binding if there is any, otherwise return null.     */    var propertyBindings:Array = proxy.getBindings( (propertyName));    if((propertyBindings == null) || (propertyBindings.length == 0)             || (propertyBindings[0] == null) || (propertyBindings[0].length == 0)) {        return null;    }    var bindingID:String = propertyBindings[0][0];    return proxy.getBindingDisplayName(bindingID);   }             /*    1. Handle User request to bind a property to Excel cells.    */   protected function initiateBind(propertyName:String):void {    // If there is an existing binding for this property show that in the Excel binding    // selection window.    // Store the currentBindingID (null if there is no current binding), we need this when we    // "completeBind".    currentBindingID = null;    var propertyBindings:Array = proxy.getBindings( (propertyName));    if ((propertyBindings != null) && (propertyBindings.length > 0)) {     currentBindingID = propertyBindings[0];  // Use the 1st binding address for the property.    }    // Store the name of the property that we are binding, we need this when we "continueBinding".        propertyToBind = propertyName;    // Let the user choose where to bind to in the Excel spreadsheet.    proxy.requestUserSelection(currentBindingID);   }            /*    1. Complete User request to bind property to Excel cells.    */   protected function continueBind(bindingID:String):void {    // Define common variables here.    var propertyName:String = propertyToBind;    var propertyValues:Array;    var propertyObject:Object;    var bindingAddresses:Array;              // Clear any existing bindings - so we can re-bind.    if (currentBindingID != null) {     proxy.unbind(currentBindingID);     currentBindingID = null;    }    // Process the property binding.    switch (propertyName) {      case "dataArray":      // User explicitly cleared binding, do not create another.      if ((bindingID == null) || (bindingID == "")) {       valueEditor.enabled = true;  // Re-enable manual entry.       // Fill the control back with current value instead of range address.       propertyValues = proxy.getProperties( (propertyName));       propertyObject = propertyValues[0];       valueEditor.text = String(propertyObject.value);       // Make sure we set the property on the component as well.       proxy.setProperty(propertyName, propertyObject.value);       return;      }      // Disable the option to manually enter a value once the component is bound.      valueEditor.enabled = false;      // Display the range address.      valueEditor.text = proxy.getBindingDisplayName(bindingID);            // Excel spreadsheet binding:-      //      // BindingDirection.BOTH    - Update the custom component "value" property when the spreadsheet changes      //                            and also update the spreadsheet when the custom component "value" changes.      // InputBindings.ARRAY  - Write to multiple cells in the spreadsheet.      // OutputBindings.ARRAY - Read a multiple cells in the spreadsheet.      //      proxy.bind("dataArray", null, bindingID, BindingDirection.BOTH, InputBindings.ARRAY2D, OutputBindings.ARRAY2D);      break;     default:         break;    }   }      bq. *PolestarOnDemandApp.mxml - embedding PolestarOnDemand.mxml component*I didn't Style the component for Xcelsius - if you want to specify fonts and colors for the component in Xcelsius, you'd need to specify styling in the code.  I recommend looking at the {code:html}ComboBox sample{code} for an example on how to property style a Xcelsius SDK component.h5. Java With RSS Feed Data Last example - retrieve data from Yahoo! HotJobs (http://hotjobs.yahoo.com/) RSS Feed, upload and view in PoleStar OnDemand.  I always wanted to be a spaceman, so I enter 'astronaut' for the HotJobs keyword, and this is the +Polestar in the cloud+ result:  
10 Comments