com.ibm.ims.dli

Interface PCB



  • public interface PCB
    The program communication block (PCB) interface is used to generate a SSAList based on the PCB's view of an IMS database and issue DL/I calls to IMS to retrieve, insert, update, and delete database information. The PCB is essentially a cursor position in an IMS database. To obtain a PCB handle, a PSB must first be created to connect to the database. For a code example of how to create the PSB and obtain the PCB handle, see PSB.

    The PCB interface also returns the Application Interface Block (AIB) associated with the most recent DL/I call.

    See Also:
    AIB, PSB, SSAList
    • Field Summary

      Fields 
      Modifier and Type Field and Description
      static byte[] DBD_RESOURCE
      Constant indicating the requested catalog resource is a DBD resource
      static byte[] PSB_RESOURCE
      Constant indicating the requested catalog resource is a PSB resource
    • Method Summary

      Methods 
      Modifier and Type Method and Description
      int batchDelete(SSAList ssaList)
      Performs a batch delete operation in a single network call on multiple records matching a given SSAList criteria.
      PathSet batchRetrieve(SSAList ssaList)
      Returns a PathSet containing all records that satisfy a given SSAList criteria.
      PathSet batchRetrieve(SSAList ssaList, boolean isHoldCall)
      Returns a PathSet containing all records that satisfy a given SSAList criteria.
      int batchUpdate(Path path, SSAList ssaList)
      Performs a batch update operation in a single network call on multiple records matching a given SSAList criteria.
      void close()
      Closes this PCB and any resources associated with it.
      int create(Path path, SSAList ssaList)
      Performs a DL/I insert operation.
      short delete()
      Performs a DL/I Delete (DLET) operation to remove existing segments in the database.
      short delete(SSAList ssaList)
      Performs a DL/I Delete (DLET) operation to remove existing segments in the database.
      AIB getAIB()
      Returns the Application Interface Block associated with the most recent DL/I call
      byte[] getCatalogMetaDataAsXML(java.lang.String resourceName, byte[] resourceType)
      This method returns a byte array containing the requested catalog resource as an XML document.
      byte[] getCatalogMetaDataAsXML(java.lang.String resourceName, byte[] resourceType, java.lang.String timestamp)
      This method returns a byte array containing the requested catalog resource as an XML document.
      java.lang.String getIMSName()
      Returns the name of the PCB as defined by IMS
      java.lang.String getName()
      Returns the alias/external name of the PCB
      Path getNext(boolean isHoldCall)
      Issues a GN (Get Next) database call.
      boolean getNext(Path path, SSAList ssaList, boolean isHoldCall)
      Issues a GN (Get Next) database call.
      Path getNextWithinParent(boolean isHoldCall)
      Issues a GNP (Get Next Within Parent) database call.
      boolean getNextWithinParent(Path path, SSAList ssaList, boolean isHoldCall)
      Issue a GNP (Get Next Within Parent) database call.
      SSAList getSSAList(java.lang.String segment)
      This method returns an SSAList with a single unqualified SSA for the target segment.
      SSAList getSSAList(java.lang.String topLevelSegment, java.lang.String bottomLevelSegment)
      This method returns an SSAList that consists of unqualified SSAs from the top level segment down to the bottom level segment specified.
      boolean getUnique(Path path, SSAList ssaList, boolean isHoldCall)
      Issue a GU (Get Unique) database call.
      short insert(Path path, SSAList ssaList)
      Issues a DL/I ISRT (Insert) call.
      short replace(Path path)
      Issues a DL/I REPL (Replace) call.
      short replace(Path path, SSAList ssaList)
      Issues a DL/I REPL (Replace) call.
      void setFetchSize(int fetchSize)
      Gives the client a hint as to the number of rows that should be fetched from the database when more records are needed.
    • Method Detail

      • getIMSName

        java.lang.String getIMSName()
        Returns the name of the PCB as defined by IMS
        Returns:
        the name of the PCB
      • getName

        java.lang.String getName()
        Returns the alias/external name of the PCB
        Returns:
        the alias/external name of the PCB
      • getUnique

        boolean getUnique(Path path,
                        SSAList ssaList,
                        boolean isHoldCall)
                          throws DLIException
        Issue a GU (Get Unique) database call. If isHoldCall is true , a GHU (Get Hold Unique) database call is issued.

        The following code fragment illustrates how to use getUnique to retrieve patient records where the hospital name is "SANTA TERESA", the ward number is "44", and the number of doctors is greater than 2.

         SSAList ssaList = pcb.getSSAList("HOSPITAL","PATIENT");
         ssaList.addInitialQualification("WARD", "WARDNO, SSAList.EQUALS, "44");
         ssaList.appendQualification("WARD",SSAList.AND,"DOCCOUNT","SSAList.GREATER_THAN, "2");
         ssaList.addInitialQualification("HOSPITAL","HOSPNAME",SSAList.EQUALS,"SANTA TERESA");
         ssaList.markAllFieldsForRetrieval("PATIENT", true);
         Path path = ssaList.getPathForRetrieveReplace();
         pcb.getUnique(path, ssaList, true);
         
        Parameters:
        path - the Path to be used in the database call. It will contain the data returned from the call.
        ssaList - the SSAList to be used in the database call
        isHoldCall - a boolean indicating whether a hold call is required
        Returns:
        a boolean indicating whether data was returned
        Throws:
        DLIException - if an error occurs during processing
      • getNext

        Path getNext(boolean isHoldCall)
                     throws DLIException
        Issues a GN (Get Next) database call. If isHoldCall is true, a GHN (Get Hold Next) database call is issued.

        This method is used when the type of segment returned from the call is not known until the call is successful.

        Parameters:
        isHoldCall - a boolean indicating whether a hold call is required
        Returns:
        the Path containing the results of the database call, or null if no data was returned
        Throws:
        DLIException - if an error occurs during processing
      • getNext

        boolean getNext(Path path,
                      SSAList ssaList,
                      boolean isHoldCall)
                        throws DLIException
        Issues a GN (Get Next) database call. Use this method when you don't have an SSAList. The method returns a Path to whatever segment the cursor is currently position on. If isHoldCall is true, a GHN (Get Hold Next) database call is issued.
        Parameters:
        path - the Path to be used in the database call. It will contain the data returned from the call.
        ssaList - the SSAList to be used in the database call
        isHoldCall - a boolean indicating whether a hold call is required
        Returns:
        a boolean indicating whether data was returned
        Throws:
        DLIException - if an error occurs during processing
      • getNextWithinParent

        Path getNextWithinParent(boolean isHoldCall)
                                 throws DLIException
        Issues a GNP (Get Next Within Parent) database call. If isHoldCall is true, a GHNP (Get Hold Next Within Parent) database call will be issued.

        This method is used when the type of segment returned from the call is not known until the call is successful.

        Parameters:
        isHoldCall - a boolean indicating whether a hold call is required
        Returns:
        the Path containing the results of the database call, or null if no data was returned
        Throws:
        DLIException - if an error occurs during processing
      • getNextWithinParent

        boolean getNextWithinParent(Path path,
                                  SSAList ssaList,
                                  boolean isHoldCall)
                                    throws DLIException
        Issue a GNP (Get Next Within Parent) database call. Use this method when you don't have an SSAList. The method returns a Path to whatever segment the cursor is currently position on. If isHoldCall is true, a GHNP (Get Hold Next Within Parent) database call will be issued.
        Parameters:
        path - the Path to be used in the database call. It will contain the data returned from the call.
        ssaList - the SSAList to be used in the database call
        isHoldCall - a boolean indicating whether a hold call is required
        Returns:
        a boolean indicating whether data was returned
        Throws:
        DLIException - if an error occurs during processing
      • insert

        short insert(Path path,
                   SSAList ssaList)
                     throws DLIException
        Issues a DL/I ISRT (Insert) call. An exception is thrown if a key field is not set.

        The following code fragment illustrates how to use insert to add a new PATIENT and ILLNESS segment in the database where the hospital name is "SANTA TERESA" and the ward number is "WARDNO2".

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "ILLNESS");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "SANTA TERESA");
         ssaList.addInitialQualification("WARD", "WARDNO", SSAList.EQUALS, "WARDNO2");
         Path path = ssaList.getPathForInsert("HOSPITAL");
         path.setString("PATIENT", "PATNUM", "PATIENTNO7");
         path.setString("PATIENT", "PATNAME", "ROCKY BALBOA");
         path.setString("ILLNAME", "APPENDICITIS");
         pcb.insert(path, ssaList);
         
        Parameters:
        path - the Path to be used in the database call.
        ssaList - the SSAList to be used in the database call. The segment search arguments in this SSAList must be unqualified, otherwise an exception is thrown.
        Returns:
        the status code returned by IMS
        Throws:
        DLIException
      • replace

        short replace(Path path,
                    SSAList ssaList)
                      throws DLIException
        Issues a DL/I REPL (Replace) call. The application must obtain a SSAList and perform a Hold operation before issuing the replace call. The Hold operation can be a getUnique, getNext, or getNextWithinParent method call.

        The following code fragment shows how to use the replace method to update a patient's name to "JANET BOENINGER" in patient records where the hospital name is "ALEXANDRIA". In the example, the N command code is used to omit the HOSPITAL and WARD segments in the Path instance from being updated.

         SSAList ssaList = pcb.getSSAList("HOSPITAL","PATIENT");
         ssaList.addInitialQualification(1,"HOSPNAME",SSAList.EQUALS,"ALEXANDRIA");
        
         Path path = ssaList.getPathForRetrieveReplace();
         pcb.getUnique(path, ssaList, true);
         ssaList = pcb.getSSAList("HOSPITAL", "PATIENT");
         ssaList.addCommandCode("HOSPITAL", SSAList.CC_N); // exclude the HOSPITAL segment from updates
         ssaList.addCommandCode("WARD", SSAList.CC_N); // exclude the WARD segment from updates
         
         path.setString("HOSPITAL", "HOSPNAME", "SANTA CRUZ MED"); // update is not performed
         path.setString("WARD", "WARDNAME", "COSMETIC");           // update is not performed
         path.setString("PATIENT", "PATNAME", "JANET BOENINGER");  // update is performed
         pcb.replace(path, ssaList)
         
        Parameters:
        path - the Path to be used in the database call.
        ssaList - the SSAList to be used in the database call
        Returns:
        the status code returned by IMS
        Throws:
        DLIException - if an error occurs during processing
      • replace

        short replace(Path path)
                      throws DLIException
        Issues a DL/I REPL (Replace) call. The application must obtain a SSAList and perform a Hold operation before issuing the replace call. The Hold operation can be a getUnique, getNext, or getNextWithinParent method call.

        The following code fragment illustrates how to use replace to update a patient's name in patient records where the patient name is "ANDREA SMITH", the ward name is "SURGICAL", and the hospital name is "ALEXANDRIA".

         SSAList ssaList = pcb.getSSAList("HOSPITAL","PATIENT");
         ssaList.addInitialQualification("HOSPITAL","HOSPNAME",SSAList.EQUALS,"ALEXANDRIA");
         ssaList.addInitialQualification("WARD","WARDNAME",SSAList.EQUALS,"SURGICAL");
         ssaList.addInitialQualification("PATIENT","PATNAME",SSAList.EQUALS,"ANDREA SMITH");
         
         Path path = ssaList.getPathForRetrieveReplace();
         if (pcb.getUnique(path, ssaList, true)) {
            path.setString("PATNAME", "ANDREA TAYLOR");
            pcb.replace(path);
         }   
         while (pcb.getNext(path, ssaList, true) {
            path.setString("PATNAME", "ANDREA TAYLOR");
            pcb.replace(path);
         }
         
        Parameters:
        path - the Path to be used in the database call.
        Returns:
        the status code returned by IMS
        Throws:
        DLIException - if an error occurs during processing
      • delete

        short delete(SSAList ssaList)
                     throws DLIException
        Performs a DL/I Delete (DLET) operation to remove existing segments in the database. The application must obtain a SSAList and perform a Hold operation before issuing the delete call. The Hold operation can be a getUnique, getNext, or getNextWithinParent method call. The delete call must be provided with an unqualified SSAList as an argument. The delete call removes the first segment that is specified by the unqualified SSAList and its child segments if any. An exception is thrown if a qualified SSAList is provided as an argument.

        The following code fragment illustrates how to use the delete method to remove all ILLNESS segments and its dependent segments (TREATMNT, DOCTOR) where the patient name is "ANDREA SMITH", the ward name is "SURGICAL", the hospital name is "ALEXANDRIA", and the patient number is "PatientNo7".

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "ILLNESS");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "ALEXANDRIA");
         ssaList.addInitialQualification("WARD", "WARDNAME", SSAList.EQUALS, "SURGICAL");
         ssaList.addInitialQualification("PATIENT", "PATNAME", SSAList.EQUALS, "ANDREA SMITH");
         ssaList.markAllFieldsForRetrieval("PATIENT", true);
         Path path = ssaList.getPathForRetrieveReplace();
         SSAList illnessSSAList = pcb.getSSAList("ILLNESS");
         if (pcb.getUnique(path, ssaList, true)) {
                if (path.getString("PATIENT", "PATNUM").equals("PATIENTNO7")) {
                        pcb.delete(illnessSSAList);
                }
         }
         while (pcb.getNext(path, ssaList, true)) {
                if (path.getString("PATIENT", "PATNUM").equals("PATIENTNO7")) {
                        pcb.delete(illnessSSAList);
                }
         }
         
        Parameters:
        ssaList - the SSAList to be used in the database call
        Returns:
        the status code returned by IMS
        Throws:
        DLIException - if an error occurs during processing
      • delete

        short delete()
                     throws DLIException
        Performs a DL/I Delete (DLET) operation to remove existing segments in the database. The application must obtain a SSAList and perform a Hold operation before issuing the delete call. The Hold operation can be a getUnique, getNext, or getNextWithinParent method call. The delete call removes the first segment marked for retrieval and its child segments if any. If no segments are explicitly marked for retrieval, the delete call removes the lowest level segment specified by the SSAList and its child segments.

        The following code fragment illustrates how to use delete to selectively remove all PATIENT segments and its dependent segments (ILLNESS, TREATMNT, DOCTOR, BILLING) where the patient name is "ANDREA SMITH", the ward name is "SURGICAL", the hospital name is "ALEXANDRIA", and the patient number is "PatientNo7".

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "ILLNESS");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "ALEXANDRIA");
         ssaList.addInitialQualification("WARD", "WARDNAME", SSAList.EQUALS, "SURGICAL");
         ssaList.addInitialQualification("PATIENT", "PATNAME", SSAList.EQUALS, "ANDREA SMITH");
         ssaList.addCommandCode("PATIENT", SSAList.CC_D);
         Path path = ssaList.getPathForRetrieveReplace();
         if (pcb.getUnique(path, ssaList, true)) {
                if (path.getString("PATIENT", "PATNUM").equals("PATIENTNO7")) {
                        pcb.delete();
                }
         }
         while (pcb.getNext(path, ssaList, true)) {
                if (path.getString("PATIENT", "PATNUM").equals("PATIENTNO7")) {
                        pcb.delete();
                }
         }
         
        Returns:
        the status code returned by IMS
        Throws:
        DLIException - if an error occurs during processing
      • create

        int create(Path path,
                 SSAList ssaList)
                   throws DLIException
        Performs a DL/I insert operation. An exception is thrown if a key field is not set.

        The following code fragment illustrates how to use create to add a new PATIENT and ILLNESS segment in the database where the hospital name is "SANTA TERESA" and the ward number is "WARDNO2".

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "ILLNESS");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "SANTA TERESA");
         ssaList.addInitialQualification("WARD", "WARDNO", SSAList.EQUALS, "WARDNO2");
         Path path = ssaList.getPathForInsert("HOSPITAL");
         path.setString("PATIENT", "PATNUM", "PATIENTNO7");
         path.setString("PATIENT", "PATNAME", "ROCKY BALBOA");
         path.setString("ILLNAME", "APPENDICITIS");
         pcb.create(path, ssaList);
         
        Parameters:
        path - the Path to be used in the database call.
        ssaList - the SSAList to be used in the database call. The segment search arguments in this SSAList must be unqualified, otherwise an exception is thrown.
        Returns:
        the number of rows inserted. For now, this will always return 1.
        Throws:
        DLIException
      • batchRetrieve

        PathSet batchRetrieve(SSAList ssaList)
                              throws DLIException
        Returns a PathSet containing all records that satisfy a given SSAList criteria. In a batch retrieve operation, the host will do all of the GHU/GHN processing and will deliver results back to the client in a single batch network operation. Note that the fetch size determines how much data is sent back on each batch network operation.

        The following code fragment illustrates how to use batchRetrieve to retrieve all PATIENT segments in the Hospital database.

         SSAList ssaList = pcb.getSSAList("PATIENT");
         PathSet pathSet = pcb.batchRetrieve(ssaList);
         while (pathSet.hasNext()) {
                Path path = pathSet.next();
                String fieldValue = path.getString("PATIENT", "PATNAME");
         }
         
        Parameters:
        ssaList - the SSAList to be used in the database call
        Returns:
        the PathSet containing the results of the database call, or null if no data was returned
        Throws:
        DLIException - if an error occurs during processing
        See Also:
        PathSet
      • batchRetrieve

        PathSet batchRetrieve(SSAList ssaList,
                            boolean isHoldCall)
                              throws DLIException
        Returns a PathSet containing all records that satisfy a given SSAList criteria. In a batch retrieve operation, the host will do all of the GU/GN (or GHU/GHN) processing and will deliver results back to the client in a single batch network operation. Note that the fetch size determines how much data is sent back on each batch network operation.

        The following code fragment illustrates how to use batchRetrieve to retrieve all PATIENT segments in the Hospital database.

         SSAList ssaList = pcb.getSSAList("PATIENT");
         PathSet pathSet = pcb.batchRetrieve(ssaList, true);
         while (pathSet.hasNext()) {
                Path path = pathSet.next();
                String fieldValue = path.getString("PATIENT", "PATNAME");
         }
         
        Parameters:
        ssaList - the SSAList to be used in the database call
        isHoldCall - if true, GHU/GHN processing is used. if false, GU/GN processing is used.
        Returns:
        the PathSet containing the results of the database call, or null if no data was returned
        Throws:
        DLIException - if an error occurs during processing
        See Also:
        PathSet
      • batchUpdate

        int batchUpdate(Path path,
                      SSAList ssaList)
                        throws DLIException
        Performs a batch update operation in a single network call on multiple records matching a given SSAList criteria. In a batch update operation, the host will do a GU/GN loop and inside the loop perform the updates until there are no more segments to update and then return the number of records updated.

        The following code fragment illustrates how to use batchUpdate to modify a patient's name. The SSAList is set to update only records where the patient name is "ANDREA SMITH", the ward name is "SURGICAL", and the hospital name is "ALEXANDRIA". The SSAList.getPathForBatchUpdate method is called to obtain a Path contaning the PATIENT segment and its child segments. Finally, batchUpdate is called to change the value of the patient name field to "ANDREA TAYLOR".

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "PATIENT");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "ALEXANDRIA");
         ssaList.addInitialQualification("WARD", "WARDNAME", SSAList.EQUALS, "SURGICAL");
         ssaList.addInitialQualification("PATIENT", "PATNAME", SSAList.EQUALS, "ANDREA SMITH");
         Path path = ssaList.getPathForBatchUpdate("PATIENT");
         path.setString("PATNAME", "ANDREA TAYLOR");
         pcb.batchUpdate(path, ssaList);
         
        Parameters:
        path - the Path to be used in the database call.
        ssaList - the SSAList to be used in the database call
        Returns:
        the number of rows updated
        Throws:
        DLIException - if an error occurs during processing
        See Also:
        SSAList.getPathForBatchUpdate(String)
      • batchDelete

        int batchDelete(SSAList ssaList)
                        throws DLIException
        Performs a batch delete operation in a single network call on multiple records matching a given SSAList criteria. In a batch delete operation, the host will do a GU/GN loop and inside the loop delete each record until there are no more segments matching the SSAList and return the number of records deleted.

        The following code fragment illustrates how to use batchDelete to remove a patient's records. The SSAList is set to restrict the deletion operation to remove only records where the patient name is "ANDREA SMITH", the ward name is "SURGICAL", and the hospital name is "ALEXANDRIA". The records are deleted by calling batchDelete.

         SSAList ssaList = pcb.getSSAList("HOSPITAL", "PATIENT");
         ssaList.addInitialQualification("HOSPITAL", "HOSPNAME", SSAList.EQUALS, "ALEXANDRIA");
         ssaList.addInitialQualification("WARD", "WARDNAME", SSAList.EQUALS, "SURGICAL");
         ssaList.addInitialQualification("PATIENT", "PATNAME", SSAList.EQUALS, "ANDREA SMITH");
         pcb.batchDelete(ssaList);
         
        Parameters:
        ssaList - the SSAList to be used in the database call
        Returns:
        the number of rows deleted
        Throws:
        DLIException - if an error occurs during processing
      • getSSAList

        SSAList getSSAList(java.lang.String topLevelSegment,
                         java.lang.String bottomLevelSegment)
                           throws DLIException
        This method returns an SSAList that consists of unqualified SSAs from the top level segment down to the bottom level segment specified.
        Parameters:
        topLevelSegment - the top level segment to be included in the SSAList
        bottomLevelSegment - the bottom level segment to be included in the SSAList
        Returns:
        the SSAList
        Throws:
        DLIException - if an error occurs during processing
      • getSSAList

        SSAList getSSAList(java.lang.String segment)
                           throws DLIException
        This method returns an SSAList with a single unqualified SSA for the target segment.
        Parameters:
        segment - the name of the segment that the SSAList will represent
        Returns:
        the SSAList
        Throws:
        DLIException - if an error occurs during processing
      • setFetchSize

        void setFetchSize(int fetchSize)
        Gives the client a hint as to the number of rows that should be fetched from the database when more records are needed. The number of rows ( Path objects) specified affects only data returned using this PCB. If the value specified is zero or negative, the hint is ignored.
        Parameters:
        fetchSize - the number of rows to fetch
        See Also:
        batchRetrieve(SSAList)
      • getAIB

        AIB getAIB()
        Returns the Application Interface Block associated with the most recent DL/I call
        Returns:
        the AIB
      • close

        void close()
                   throws DLIException
        Closes this PCB and any resources associated with it.
        Throws:
        DLIException - if an error occurs during processing
      • getCatalogMetaDataAsXML

        byte[] getCatalogMetaDataAsXML(java.lang.String resourceName,
                                     byte[] resourceType)
                                       throws DLIException
        This method returns a byte array containing the requested catalog resource as an XML document.
        Parameters:
        resourceName - the name of the PSB or DBD resource in the catalog
        resourceType - the type of resource (PCB.PSB_RESOURCE or PCB.DBD_RESOURCE)
        Returns:
        the resource metadata in XML
        Throws:
        DLIException - if the resource was not found in the catalog or an error occurs during processing
        See Also:
        PSB_RESOURCE, DBD_RESOURCE
      • getCatalogMetaDataAsXML

        byte[] getCatalogMetaDataAsXML(java.lang.String resourceName,
                                     byte[] resourceType,
                                     java.lang.String timestamp)
                                       throws DLIException
        This method returns a byte array containing the requested catalog resource as an XML document.

        The following code fragment illustrates how to retrieve the timestamp (TSVERS) value from the IMS Catalog.

         PCB pcb = psb.getPCB("DFSCAT00");
         SSAList ssaList = pcb.getSSAList("HEADER", "DBD");
         Path path = ssaList.getPathForRetrieveReplace();
         pcb.getUnique(path, ssaList, false);
         String timestamp = path.getString("TSVERS");
         
        Parameters:
        resourceName - the name of the PSB or DBD resource in the catalog
        resourceType - the type of resource (PCB.PSB_RESOURCE or PCB.DBD_RESOURCE)
        timestamp - the TSVERS version for the resource following the pattern yyDDDHHmmssff
        Returns:
        the resource metadata in XML
        Throws:
        DLIException - if the resource was not found in the catalog or an error occurs during processing
        See Also:
        PSB_RESOURCE, DBD_RESOURCE

© Copyright IBM Corporation 2008, 2017.