0

This is for BOBJ 4.0 SP5 .net SDK.

Can anyone help me understand how to use infoStore.Commit? My code is pasted below. Based on my understanding this should work. But it doesn't. The IDE doesn't throw any errors, but when I run the code I get:

System.NullReferenceException: Object reference not set to an instance of an object. at BusinessObjects.Enterprise.Infostore.Internal.InfoStore.commitHelper(IInfoObjects objs, CommitFlags flag) at BusinessObjects.Enterprise.Infostore.Internal.InfoStore.Commit(IInfoObjects objs) at BOUpdate.Program.Main(String[] args) in C:\Users\username\Documents\Visual Studio 2017\Projects\UpdateInstances\UpdateInstances\Program.cs:line 55

Here is the code (the part I'm asking about is "infoStore.Commit(boInfoObjects);"):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BusinessObjects.Enterprise.Framework;
using BusinessObjects.Enterprise.Infostore;
using CrystalDecisions.Web;


namespace BOUpdate
{
    class Program
    {
        static void Main(string[] args)
        {
            string username = "username";
            string password = "password";
            string cmsname = "cmsname";
            string authType = "secEnterprise";

            string reportQuery = "Select * FROM CI_INFOOBJECTS where (SI_INSTANCE=1 or SI_RECURRING = 1) and SI_PARENTID = 4229118";

            IInfoStore infoStore;
            IInfoObjects boInfoObjects;
            ISessionMgr sm = CrystalEnterprise.GetSessionMgr();
            IEnterpriseSession es = sm.Logon(username, password, cmsname, authType);

            try
            {
                infoStore = (IInfoStore)es.GetService("", "InfoStore");

                int max_id = 0;
                int querysize = 0;
                int isCrystalReport = 0;
                String curKind = "";

                for (; ; )
                {
                    boInfoObjects = (IInfoObjects)infoStore.Query(reportQuery + " AND SI_ID > " + max_id + " ORDER BY SI_ID ASC");

                    int querySize = boInfoObjects.ResultSize;

                    for (int i = 0; i < querySize; i++)
                    {
                        IInfoObject boReport1 = (IInfoObject)boInfoObjects[0];

                        isCrystalReport = 1;
                        //Console.WriteLine(curKind);
                        if (boReport1.Properties.GetProperty("SI_KIND").Value.ToString() != "CrystalReports")
                        {
                            isCrystalReport = 0;
                            curKind = boReport1.Properties.GetProperty("SI_KIND").Value.ToString();
                            boReport1.Properties.SetProperty("SI_KIND", "CrystalReport");
                            infoStore.Commit(boInfoObjects);

                            boInfoObjects = (IInfoObjects)infoStore.Query(reportQuery + " AND SI_ID >= " + (boReport1.ID) + " ORDER BY SI_ID ASC");
                            boReport1 = (IInfoObject)boInfoObjects[0];
                            querysize = boInfoObjects.ResultSize;
                            i = 0;
                        }

                        Report tmpReport = (Report)boReport1;
                        Console.WriteLine(tmpReport.DataSources[0].ToString());
                        //ISDKList dbLogon = 
                    }
                }
            }
            catch (Exception e)
            {
                es.Logoff();
                Console.WriteLine(e);
            }


            //enterpriseSession.Logoff();            
        }
    }
}

Thank you for any insights you can provide!

Here is the original code (java) from SAP:

            <%@ page import = "com.crystaldecisions.sdk.exception.SDKException,
                               com.crystaldecisions.sdk.framework.*,
                               com.crystaldecisions.sdk.occa.infostore.*,
                               com.crystaldecisions.sdk.properties.*,
                               com.crystaldecisions.sdk.plugin.desktop.report.*,
                               com.crystaldecisions.sdk.plugin.desktop.common.*,
                               com.crystaldecisions.sdk.plugin.destination.diskunmanaged.*,
                               com.crystaldecisions.sdk.plugin.destination.smtp.*,
                               com.crystaldecisions.sdk.plugin.desktop.report.*,
                               java.io.*,
                               java.util.*"

            %><%

            // ------------------------------
            // How to use:
            //
            // Copy this jsp page into the folder C:\Program Files (x86)\SAP BusinessObjects\tomcat\webapps\AdminTools
            //
            // Copy the following jar files from the folder: C:\Program Files (x86)\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\java\lib 
            // to the folder 
            // C:\Program Files (x86)\SAP BusinessObjects\tomcat\webapps\AdminTools\WEB-INF\lib
            //
            // SL_plugins.jar
            // cereports.jar
            // CrystalReportsSDK.jar - This one isn't needed to run the sample - but copying the other two seems to break query builder unless you include this one.
            //
            //
            // Modify the User Credentials Section to appropriate logon credentials for your system
            // Modify the infostore query to return back the reports you want to modify.  I recommend testing the query in query builder first (http://myServer:8080/AdminTools)
            // In the WriteToLog function - change the logging path to whatever desired path you want the log file to be written to.  The default is in the AdminTools folder referenced above
            // Uncomment the functions for the properties you want to change.
            // Run this by opening a new browser and going to http://myServer:8080/AdminTools/modifyrecurringinstance.jsp
            // ------------------------------

            // User Credentials
            String username = "user";
            String password = "pass";
            String cmsname  = "localhost";
            String authType = "secEnterprise";

            // This is the query used to return back the report instances you want to modify.

            // All pending instances  (Both recurring and non-recurring)
            String reportQuery = "Select * FROM CI_INFOOBJECTS where (SI_INSTANCE=1 or SI_RECURRING = 1) and SI_SCHEDULEINFO.SI_PROGRESS = 1";

            // All pending recurring instances.  Note that it does not have SI_KIND='CrystalReport' in it.  This is because if you schedule a crystal report to PDF then SI_KIND will be 'PDF'
            //String reportQuery = "Select * FROM CI_INFOOBJECTS where SI_RECURRING =1 and SI_SCHEDULEINFO.SI_PROGRESS = 1";

            // All pending recurring instances owned by administrator (ID 12)
            //String reportQuery = "Select * FROM CI_INFOOBJECTS where SI_RECURRING =1 and SI_OWNERID=12 and SI_SCHEDULEINFO.SI_PROGRESS = 1";



            IEnterpriseSession enterpriseSession  = null;
            IInfoStore infoStore;
            IInfoObjects boInfoObjects; 

            enterpriseSession = CrystalEnterprise.getSessionMgr().logon(username, password, cmsname, authType);
            infoStore = (IInfoStore)enterpriseSession.getService("", "InfoStore");

            int max_id = 0;
            int querysize = 0;
            boolean isCrystalReport = false;
            String curKind = "";
            out.println("Starting </BR>");
            writeToLog("Starting Sample");

            for(;;) { 
                boInfoObjects = (IInfoObjects)infoStore.query(reportQuery + " AND SI_ID > " + max_id +  " ORDER BY SI_ID ASC");

                querysize = boInfoObjects.size();
                if( querysize == 0) 
                    break;


                for(int i =0; i< querysize; i++) {
                    IInfoObject boReport1 = (IInfoObject)boInfoObjects.get(i);

                    isCrystalReport = true;
                    out.println("Processing Report " + boReport1.getID() + " : " + boReport1.getTitle() + "</BR>");
                    writeToLog("Starting to Process Report " + boReport1.getID() + " : " + boReport1.getTitle());
                    // If the object is not of type crystal report (Scheduled to any format other than crystalreports) then we need to modify it.
                    if (!boReport1.getKind().equals("CrystalReport")) {

                        isCrystalReport = false;
                        curKind = boReport1.getKind();
                        boReport1.properties().setProperty("SI_KIND", "CrystalReport");
                        infoStore.commit(boInfoObjects); 

                        // At this point we need to requery for the same report - otherwise the rest of the code will not work.
                        // This also involves resetting the for loop
                        boInfoObjects = (IInfoObjects)infoStore.query(reportQuery + " AND SI_ID >= " + (boReport1.getID()) +  " ORDER BY SI_ID ASC");
                        boReport1 = (IInfoObject)boInfoObjects.get(0);
                        querysize = boInfoObjects.size();
                        i = 0;

                    }

                    // Now cast it to a crystal report object
                    IReport tmpReport = (IReport)boReport1;
                    try {

                        // Change the Report
                        // Uncomment the functions for the properties you want to change for the report.

                        // Update the database username and password.
                        //Note: This assumes that all the reports are using the default database logon info.  If they are using custom database logon 
                        // then they would need to use the method setCustomDatabaseName(“MyDatabaseName”); instead.
                        //They can tell if the report is using default or custom database logon info by looking at the method “isOriginalDataSource()”.
                        changeReportDBLogons(tmpReport, "mydbName");

                        // Change how many retries are allowed
                        //changeReportRetries(tmpReport, 5);

                        // Change the file IO username and password for unmanaged disk location
                        //changeReportUnmanagedDiskLogonCredentials(tmpReport, infoStore, "myOSUsername", "myOSPassword");

                        // Change the time the next instance will run at
                        //changeScheduleStartTime(tmpReport, new java.util.Date("7/13/25 4:15:00 PM"));

                        // Change the end time of the scheduled instance (The last time it will be allowed to run - defaults to 10 years in the future)
                        //changeScheduleEndTime(tmpReport, new java.util.Date("7/13/26 4:15:00 PM"));

                        // Change the from field for a schedule to SMTP instance
                        // changeScheduleFromFieldForScheduleSMTP(tmpReport, infoStore, "default@myserver.com");

                    } catch (Exception ex) {
                        writeToLog("Error modifying report: " + ex.toString());
                    } finally {
                        //  If we changed the SI_KIND - make sure we change it back to the original type
                        if (isCrystalReport == false) {
                            writeToLog("Changing report " + boReport1.getID() + " : " + boReport1.getTitle() + " back to type " + curKind.toString());
                            tmpReport.properties().setProperty("SI_KIND", curKind);
                        }
                    }

                    writeToLog("Finished Processing Report " + boReport1.getID() + " : " + boReport1.getTitle());

                    // Update the max id so the next infostore query doesn't include this report.
                    max_id = boReport1.getID();  
                }
                // Save the changes
                infoStore.commit(boInfoObjects); 
            }
            writeToLog("Finished Sample </BR>");

            out.println("Job Completed");
            %>
            <%!

            // Helper Methods
            public void writeToLog(String msg) {
                try {
                    // Set up Logging File
                    FileOutputStream FSout;
                    PrintStream pStream; // declare a print stream object
                    FSout = new FileOutputStream("C:\\Program Files (x86)\\SAP BusinessObjects\\tomcat\\webapps\\AdminTools\\TestOutput.txt", true);  // Append
                    pStream = new PrintStream(FSout); 
                    pStream.println(msg);
                    pStream.close();
                } catch (IOException e) {
                    //error writing to log
                }
            }

                // This function sets all database logons to the same username and password.  If you want to customize it for each logon, you will need to modify this function
                public void changeReportDBLogons(IReport myReport, String dbName) {
                              try {
                                           writeToLog("Changing Database Logon for report ID " + myReport.getID() + " : " + myReport.getTitle());
                                           ISDKList dbLogons = myReport.getReportLogons();
                                           for (int k=0; k<dbLogons.size(); k++) {
                                                         IReportLogon dbLogon = (IReportLogon)dbLogons.get(k);
                                                         dbLogon.setDatabaseName(dbName);
                                           }
                              } catch (Exception ex) {
                                           writeToLog("Error changing report database logons: " + ex.toString());
                              }
                }

                public void changeReportRetries(IReport myReport, int numRetries) {
                    try {
                        writeToLog("Changing retries for report ID " + myReport.getID() + " : " + myReport.getTitle());
                        myReport.getSchedulingInfo().setRetriesAllowed(numRetries);
                    } catch (Exception ex) {
                        writeToLog("Error changing report retries: " + ex.toString());
                    }
                }

                // This function assumes that the report has only been scheduled to one destination - in this case unmanaged disk
                public void changeReportUnmanagedDiskLogonCredentials(IReport myReport, IInfoStore boInfoStore, String osUsername, String osPassword) {
                    try {
                        writeToLog("Changing Unmanaged Username and Password for report ID " + myReport.getID() + " : " + myReport.getTitle());
                        ISchedulingInfo boSchedulingInfo = myReport.getSchedulingInfo();
                        IDestinations boDestinations = boSchedulingInfo.getDestinations();
                        IDestination boDestination = (IDestination)boDestinations.get(0);
                        IDestinationPlugin destinationPlugin = (IDestinationPlugin)boInfoStore.query("SELECT TOP 1 * FROM CI_SYSTEMOBJECTS WHERE SI_NAME='CrystalEnterprise.DiskUnmanaged'").get(0);
                        boDestination.copyToPlugin(destinationPlugin);
                        IDiskUnmanagedOptions diskUnmanagedOptions = (IDiskUnmanagedOptions) destinationPlugin.getScheduleOptions();
                        diskUnmanagedOptions.setUserName(osUsername);
                        diskUnmanagedOptions.setPassword(osPassword);
                        boDestination.setFromPlugin(destinationPlugin);
                    } catch (Exception ex) {
                        writeToLog("Error changing Unmanaged Disk Logon Credentials: " + ex.toString() );
                    }
                }

                public void changeScheduleStartTime(IReport myReport, java.util.Date newDate) {
                    try {
                        writeToLog("Changing schedule Start Time " + myReport.getID() + " : " + myReport.getTitle());
                        IProperties tmpProps = myReport.getSchedulingInfo().properties();
                        tmpProps.setProperty("SI_STARTTIME", newDate);
                    } catch (Exception ex) {
                        writeToLog("Error changing schedule Start Time: " + ex.toString());
                    }
                }

                public void changeScheduleEndTime(IReport myReport, java.util.Date newDate) {
                    try {
                        writeToLog("Changing schedule End Time " + myReport.getID() + " : " + myReport.getTitle());
                        IProperties tmpProps = myReport.getSchedulingInfo().properties();
                        tmpProps.setProperty("SI_ENDTIME", newDate);
                    } catch (Exception ex) {
                        writeToLog("Error changing schedule End Time: " + ex.toString());
                    }
                }
                // This function assumes that the report has only been scheduled to one destination - in this case SMTP
                public void changeScheduleFromFieldForScheduleSMTP(IReport myReport, IInfoStore boInfoStore, String newFrom) {
                    try {
                        writeToLog("Changing SMTP Schedule From value for report ID " + myReport.getID() + " : " + myReport.getTitle());
                        ISchedulingInfo boSchedulingInfo = myReport.getSchedulingInfo();
                        IDestinations boDestinations = boSchedulingInfo.getDestinations();
                        IDestination boDestination = (IDestination)boDestinations.get(0);
                        IDestinationPlugin destinationPlugin = (IDestinationPlugin)boInfoStore.query("SELECT TOP 1 * FROM CI_SYSTEMOBJECTS WHERE SI_NAME='CrystalEnterprise.Smtp'").get(0);
                        boDestination.copyToPlugin(destinationPlugin);
                        ISMTPOptions smtpOptions = (ISMTPOptions) destinationPlugin.getScheduleOptions();
                        smtpOptions.setSenderAddress(newFrom);
                        boDestination.setFromPlugin(destinationPlugin);
                    } catch (Exception ex) {
                        writeToLog("Error changing SMTP Schedule From value: " + ex.toString() );
                    }
                }

            %>
MrB
  • 101
  • 1
  • 9
  • I'm not sure if it's the cause of your error, but you can't change the type of infoobject simply by changing the SI_KIND property. For processed instances, the type will be defined by the actual file that was generated. For recurring instances, the type is set in the SI_PROCESSINFO property bag. – Joe Nov 02 '17 at 12:14
  • This is code I got from SAP. They gave it to me in Java. I'm trying to convert to C# bc their code doesn't exactly work and I like c# more... In their code example, they do the same as I am trying to do - unless I'm mistaken? Here is their code: if (!boReport1.getKind().equals("CrystalReport")) { isCrystalReport = false; curKind = boReport1.getKind(); boReport1.properties().setProperty("SI_KIND", "CrystalReport"); infoStore.commit(boInfoObjects); – MrB Nov 03 '17 at 18:57
  • There's nothing wrong with the `commit()` call itself, but something must getting screwy with the objects in the collection. Can you update your question with the text of the complete Java code from SAP? And I'm curious, what exactly is this supposed to do? I can't imagine why you'd be changing the si_kind property of instances. – Joe Nov 03 '17 at 20:02
  • What it is supposed to do: we moved our sql server and it has a new name. As short term fix I added entries in HOST file so the reports keep working. But this code is supposed to update the connections of the reports and scheduled instances in BOBJ to point to the new server name. The server name is hard coded in the connection string of all the reports. I will update my original post w/ the full code from SAP – MrB Nov 13 '17 at 19:41
  • Thanks, that helps me understand. On line 50, "CrystalReports" should be "CrystalReport", but that's not the cause of your error. I'm not certain it will help, but try changing `infoStore.Commit(boInfoObjects);` to `boReport1.save();` – Joe Nov 13 '17 at 19:56
  • Sadly this resulted in similar error. But it is cool to find out about Save(). Maybe there is a path to success hidden in there somewhere. I feel like I have all the right things gathered, I just can't figure out how to stick them together correctly. For what it's worth, the java code from SAP never worked either. So maybe the right parts are not here at all and I'm totally wasting my time down the wrong path. – MrB Nov 13 '17 at 22:02
  • The error was: System.NullReferenceException: Object reference not set to an instance of an object. at BusinessObjects.Enterprise.Infostore.Internal.InfoStore.commitHelper(IInfoObjects objs, CommitFlags flag) at BusinessObjects.Enterprise.Infostore.Internal.InfoStore.Commit(IInfoObjects objs) at BusinessObjects.Enterprise.Infostore.Internal.InfoObject.Save() at BOUpdate.Program.Main(String[] args) in C:\Users\XYZ\Documents\Visual Studio 2017\Projects\UpdateInstances\UpdateInstances\Program.cs:line 56 – MrB Nov 13 '17 at 22:03
  • Does it work if you don't modify the SI_KIND property? That looks really hack-ish, and I'm wondering if that's the issue. Did you get a similar error when you ran the Java version? – Joe Nov 14 '17 at 19:02
  • Java errors: lots of syntax errors, missing ";". A lot of "IReport cannot be resolved to a type". I think maybe they gave me trash code, I'm thinking maybe this SDK can't even do what they're saying it can. Business Objects can be a horrible mess of a management nightmare w/o any centralized data connections or if all your connections are embedded. Like in SSRS you could just do a find/replace in the RDLs w/ the new database name. Nothing so easy w/ BOBJ – MrB Nov 14 '17 at 22:42
  • i think for now HOST file is the fix. We will just need to never introduce a new server with the same name as the old db server we replaced. The alternative would be manually updating 300+ reports and 600+ instances to point to new server. Unless I can get SDK working for switching DB server name in the reports/instances – MrB Nov 14 '17 at 22:44
  • Hold on. The more I think about it, the less it makes sense to change the SI_KIND property. If it's a completed static (Excel/PDF) instance, then changing the property will NOT change the file type (and there's no point in changing the data source since it's already run). If it's a recurring static instance, then it would change the type to CR. I think you should just leave that part out and continue testing with the rest of the code. Re "no centralized data connections" - BO has Universes that do exactly what you say (you can change the data source in one place). – Joe Nov 15 '17 at 13:23
  • Also, regarding the Java code - you may have miscopied it; I did not get any errors for missing semicolons. And the error on IReport is resolved if you copy in the jar files mentioned in the comments at the top. I'm not certain that it will actually do what you want, but it does at least compile. – Joe Nov 15 '17 at 13:25

0 Answers0