3 Replies Latest reply on Sep 4, 2015 12:44 AM by Anil Nair

    Unable to pass a class(object) while passing as payload(Connection context)

    Anil Nair Newbie

      Hi All,

      I have a custom translator which accepts a class in different package . Payloadf class resides in the same package as class which extends.JDBCQueryExecution

      jboss with teiid starts fine without any errors but when i try to txecute query by passing payload from the client I get ClassNotFound execption for the payload class.

      Please note when I try to pass int or string directly instead of class it all works fine , assuming something to do with the serialization of custom class(though my custom class is serializable I still get ClassNotFound exception)

      Here is the code that I am using

      I have set added dependency in the module.xml file as mentioned in the documentation

      <?xml version="1.0" encoding="UTF-8"?>
      <module xmlns="urn:jboss:module:1.0" name="MyApp.teiid.translator">
        <resources>
        <resource-root
        path="MyApp-teiid-translator-5.jar" />
        <!-- This jar file that has the translator-->
        path="MyApp-teiid-translator-5.jar" />
        <!--This jar has the dependencies where the payload  and class which implements JDBCExecutionFactory)
      
        </resources>
      
      
        <dependencies>
        <module name="javax.api" />
        <module name="javax.resource.api" />
        <module name="org.jboss.teiid.common-core" />
        <module name="org.jboss.teiid.api" />
        <module name="org.jboss.teiid.translator.jdbc" />
        </dependencies>
      </module>
      

       

      Class which extends JDBCQueryExecution

      public class MultiEmployeeQueryExecutor extends
              org.teiid.translator.jdbc.JDBCQueryExecution {
          private Connection sqlconnection;
          private TeiidSqlServerPayload payload;
          private static final Logger LOGGER = LoggerFactory
                  .getLogger(MultiTenantQueryExecutor.class);
      
          public MultiEmployeeQueryExecutor(Command command, Connection connection,
                  ExecutionContext context, JDBCExecutionFactory env,
                  TeiidSqlServerPayload teiidsqlserverpayload) {
              super(command, connection, context, env);
              this.sqlconnection = connection;
              this.payload = teiidsqlserverpayload;
          }
      
          @Override
          public void close() {
              super.close();
              try {
                  afterExecution();
              } catch (SQLException e) {
                  LOGGER.error("Translator afterExecution error: {}", e);
              }
          }
      
      
          @Override
          public void execute() throws TranslatorException {
              try {
                  beforeExecution();
              } catch (SQLException e) {
                  LOGGER.error("Translator execute  error  {}", e);
                  throw new TranslatorException(e);
              }
              super.execute();
          }
      
      
          private void beforeExecution() throws SQLException {
              try (CallableStatement cstmt = sqlconnection
                      .prepareCall("{call spSetEmployeeInfo (?, ?)}")) {
                  cstmt.setInt(1, payload.getEmpId());
                  cstmt.setInt(2, payload.getDeptId());
                  cstmt.execute();
              }
          }
      
          private void afterExecution() throws SQLException {
              try (CallableStatement cstmt = sqlconnection
                      .prepareCall("{call spResetEmployeeInfo}")) {
                  cstmt.execute();
              }
          }
      }
      

      The  Payload class

      public class TeiidSqlServerPayload implements Serializable {
          private static final long serialVersionUID = 4736614740664143158L;
          private int empId;
          private int deptId;
          public int getEmpId() {
              return EmpId;
          }
          public void setEmpId(int empId) {
              this.empId = empId;
          }
          public int getDeptId() {
              return deptId;
          }
          public void setDeptId(int deptId) {
              this.deptId = deptId;
          }
      }
      

       

      The Translator class calling the class that extends JDBCQueryExecution

      @Translator(name = "MyApp-translator", description = "")
      public class MyAppExecutionFactory extends JDBCExecutionFactory {
      
      
          @Override
          public ResultSetExecution createResultSetExecution(QueryExpression command,
                  ExecutionContext executionContext, RuntimeMetadata metadata,
                  Connection conn) throws TranslatorException {
      
      
              TeiidSqlServerPayload payload = (TeiidSqlServerPayload) executionContext
                      .getCommandPayload();
              MultiEmployeeQueryExecutor exec = new MultiEmployeeQueryExecutor(command, conn,
                      executionContext, this, payload);
              return exec;
          }
      }
      

      Thanks

      Anil

        • 1. Re: Unable to pass a class(object) while passing as payload(Connection context)
          Ramesh Reddy Master

          Anil,

           

          Can attach stack trace?

           

          This will be due to un-marshelling of the object on the server side. Typically you could solve with setting the ThreadContextClassLoader for these kind of issues, but not in the case. The simplest workaround is to add your JAR with "TeiidSqlServerPayload" class to "modules/system/layers/dv/org/jboss/teiid/main/module.xml" file as one of entry and also place the JAR file in the same directory of module.xml.


          Otherwise, instead of sending a java object, you can send payload in the form of string or Map object, and construct the what you need in the translator. IMO, I prefer this route than previous one, both of them should work.


          HTH


          Ramesh..

          • 2. Re: Unable to pass a class(object) while passing as payload(Connection context)
            Steven Hawkins Master

            > The simplest workaround is to add your JAR with "TeiidSqlServerPayload" class to "modules/system/layers/dv/org/jboss/teiid/main/module.xml" file as one of entry and also place the JAR file in the same directory of module.xml.

             

            Just to clarify what he's saying is that the deserialization is effectively taking place just above the socket layer in the engine, which doesn't know about all of the classes available to the various translators.  The workaround isn't really recommended as the module.xml file is considered part of Teiid.  We'd have to add an option to associate more modules with the engine/transport for deserialization via the configuration.

             

            The other work around of sending a standard object, or sending the serialized bytes and deserializing in the custom translator will work fine as well.

            1 of 1 people found this helpful
            • 3. Re: Unable to pass a class(object) while passing as payload(Connection context)
              Anil Nair Newbie

              Thank you so much Ramesh and Steven

              I have tried the workaround you have mentioned and is working  as you have mentioned.

              Thanks

              Anil