0

I use RESTful Web Service API (BOBJ 4.1) to retrieve the information about the reports in the repository.

When I try to derive the list of data providers, it works file for most of the reports. However, for some of the reports I get back the message

(404) not found

I appreciate that it's a valid response for reports which don't have any data providers, but I'm sure that the reports I get the 404 message for definitely have one or more data providers. I also don't expect it to be related to the permissions, because I don't get the "access denied" message and I can open the "problematic" reports using the Rich Client.

I use the following link:

http://{servername}:{port}/biprws/raylight/v1/documents/{reportID}/dataproviders

Has anyone experienced this kind of a problem before? Am I missing something?

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
IgorShch
  • 149
  • 1
  • 4
  • 21
  • 1
    Can you try to retrieve the information using the QueryBuilder and see if that returns any meaningful information regarding the data providers for these documents? – DocZerø Jan 29 '15 at 11:54
  • @Kristof Yes, I can get the information about the "problematic" reports from the query builder. Most of them are returned as bound to a specific universe, which if I think identified from the data providers in the report – IgorShch Jan 29 '15 at 12:18
  • 1
    I was thinking of unbound reports causing this issue, but that doesn't seem to be the issue. Perhaps you could look if there's anything that these problematic reports have in common, but from the looks of it, you've hit a bug with the REST SDK. I would suggest opening an incident with SAP Support. – DocZerø Jan 29 '15 at 12:24
  • 1
    is there anything in the body of the 404 response? Sometimes (but not always) there is a more descriptive error message. – Joe Jan 29 '15 at 13:28
  • @Joe 404 is not really a response, but rather an exception, so it does not have a proper description – IgorShch Feb 02 '15 at 13:54
  • The REST API will sometimes return descriptive error messages in the body of the response, even with HTTP error codes like 404. It may be empty, but worth a look. – Joe Feb 02 '15 at 17:48
  • 1
    Try looking at the log file for the WACS server (extension `.glf`) to see if there's any information there that could help you determine the cause of the error. If necessary, change the log level in the WACS server's properties (in the CMC). – DocZerø Apr 07 '15 at 08:53

2 Answers2

1

I was having the same problem with some of the BO REST services (some of which went away after we rebooted our server).

You don't say which technology you're using to call the web services, but here's how you'd get the error information in a C# application.

In my C# app, below are the functions I use to call a GET & POST Business Objects 4.x REST service, and if something goes wrong, it attempts to read in the error message, so we get more than just "404 not found" or "503 Server error"...

To use these functions, you must've logged into BO and got a Login token.

protected string CallGETWebService(string URL, string token)
{
    HttpWebRequest GETRequest = null;
    try
    {
        GETRequest = (HttpWebRequest)WebRequest.Create(URL);
        GETRequest.Method = "GET";
        GETRequest.Accept = "application/xml";
        GETRequest.Timeout = 3 * 60 * 1000;         //  Wait for upto 3 minutes
        GETRequest.KeepAlive = false;
        GETRequest.Headers.Add("X-SAP-LogonToken", token);

        HttpWebResponse GETResponse = (HttpWebResponse)GETRequest.GetResponse();
        Stream GETResponseStream = GETResponse.GetResponseStream();
        StreamReader reader = new StreamReader(GETResponseStream);

        string response = reader.ReadToEnd();
        return response;
    }
    catch (WebException ex)
    {
        //  If the web service throws an exception, attempt to see if it give us any clues about what went wrong.
        string exception = GetExceptionMessage(URL, ex);
        throw new Exception(exception);
    }
}

protected string CallPOSTWebService(string URL, string token, string XMLdata)
{
    try
    {
        // Call a "POST" web service, passing it some XML, and expecting some XML back as a Response.
        byte[] formData = UTF8Encoding.UTF8.GetBytes(XMLdata);

        HttpWebRequest POSTRequest = (HttpWebRequest)WebRequest.Create(URL);
        POSTRequest.Method = "POST";
        POSTRequest.ContentType = "application/xml";
        POSTRequest.Accept = "application/xml";
        POSTRequest.Timeout = 3 * 60 * 1000;         //  Wait for upto 3 minutes
        POSTRequest.KeepAlive = false;
        POSTRequest.ContentLength = formData.Length;
        POSTRequest.Headers.Add("X-SAP-LogonToken", token);

        Stream POSTstream = POSTRequest.GetRequestStream();
        POSTstream.Write(formData, 0, formData.Length);

        HttpWebResponse POSTResponse = (HttpWebResponse)POSTRequest.GetResponse();
        StreamReader reader = new StreamReader(POSTResponse.GetResponseStream(), Encoding.UTF8);

        string response = reader.ReadToEnd();
        return response;
    }
    catch (WebException ex)
    {
        //  If the web service throws an exception, attempt to see if it give us any clues about what went wrong.
        string exception = GetExceptionMessage(URL, ex);
        throw new Exception(exception);
    }
}

protected string GetExceptionMessage(string URL, WebException ex)
{
    //  If one of the BO web service threw an exception, attempt to see if it give us any clues about what went wrong.
    string exception = "An exception occurred whilst calling: " + URL + ", " + ex.Message;
    try
    {
        if (ex.Response == null)
            return exception;
        if (ex.Response.ContentLength == 0)
            return exception;

        using (Stream sr = ex.Response.GetResponseStream())
        {
            //  The web service will return a string containing XML, which we need to parse, to obtain the actual error message.
            StreamReader reader = new StreamReader(sr);
            string XMLResponse = reader.ReadToEnd();

            XElement XML = XElement.Parse(XMLResponse);
            XElement XMLException = XML.Elements().Where(e => e.Name.LocalName == "message").FirstOrDefault();
            if (XMLException != null)
                exception = XMLException.Value;   //  eg "Info object with ID 132673 not found.  (RWS 000012)"
        }
    }
    catch 
    {
        //  If the web service returned some other kind of response, don't let it crash our Exception handler !
    }
    return exception;
}

The important thing here is that if BO's REST services fail, the GetResponse() will throw a WebException, and we then use my GetExceptionMessage() function to check the error response (which the BO Rest Services return in XML format) and try to extract the error message from it.

Using this functionality, our C# code can throw an exception with some useful information in it:

Info object with ID 132673 not found.  (RWS 000012)

..rather than just throwing a vague exception like this (which, by the way, is what all of SAP's own C# examples will do, as none include any error-handling)...

(404) Page not found
(503) Service unavailable

I've also had cases where the BO REST Services will actually throw a "(503) Service Unavailable" exception... which was completely misleading ! Again, this code will help to give us the real error message.

If BO's REST services are successful, they'll return a string containing some XML data. Let's look at some sample code showing how we'd use my functions to call the REST service to get details about a particular Webi Report.

We'll call the REST services, then convert the XML response string into an XElement, so we can obtain the Report's name from the XML.

string token = /*  Your login-token */
string URL = string.Format("http://MyServer:6405/biprws/infostore/{0}", ReportID);
string WebiReportResponse = CallGETWebService(URL, token);

//  Parse the web service's XML response, and obtain the name of our Webi Report  
XElement ReportDetails = XElement.Parse(WebiReportResponse);
XElement title = ReportDetails.Elements().Where(e => e.Name.LocalName == "title").FirstOrDefault();
string ReportName = (title == null) ? "Unknown" : title.Value;

I thoroughly loathe the SAP documentation (and lack of it).

Life would've been MUCH easier if SAP themselves had provided some sample .Net code like this...

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
  • 1
    Thanks a lot for such a detailed reply, @Mike. I will try your code and come back. – IgorShch Apr 12 '16 at 09:42
  • @IgorShch: You're very welcome. I've wasted *a lot* of time with this BO REST services stuff as SAP simply haven't published (m)any decent examples out there. Certainly none that do any error checking. Yesterday, for example, I found when you schedule a Webi Report, the XML elements which you POST to the REST service *must* be in a specifiic order, otherwise it fails. Finding that information is a nightmare though. I will probably do a thorough CodeProject article about how to do all of this stuff, once I've calmed down !!! – Mike Gledhill Apr 12 '16 at 11:06
0

I've regularly had this problem in a Java routine that trawls through all WebI reports in the system to find their data-providers. At the start of the routine it works OK but as time progresses it gets slower and throws up more and more of this kind of error. I'm fairly convinced that the program itself does nothing untoward to slow down the system and it calls other BO RESTful services with no problem.

In the end I went back to getting the information using the Java SDK and it works fine. It's also much faster than Restful, even when it's working normally. Using BO 4.1 SP7