title: Setting JT400 to connect to IBM i (AS400) using port 23
body: <p>I'm trying to connect to IBM midrange (AS400) machine from my java program and then reset a user's password. Using Jt400.jar, I manage to do so. But the problem is, I need to set the port to specificly use port 23. I want it to follow tn5250 on how it connect to AS400. From the IBM website <a href="http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzahh/com/ibm/as400/access/AS400.html" rel="nofollow">here</a>, I knew I can do so by using <code>as400.connectToPort(23)</code>.</p>
  
  <p>What confuses me, when I add that method, I got a <code>java.lang.RuntimeException: java.lang.NegativeArraySizeException</code>. I did try to search what's causing this exception which lead me to <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/NegativeArraySizeException.html" rel="nofollow">here</a> and more explanation <a href="http://craftingjava.blogspot.com/2012/07/handling-javalangnegativearraysizeexcep.html" rel="nofollow">here</a>. This is my code:</p>
  
  <pre><code>public void executeSetPassword(final String userName, final GuardedString password)  {
  
      if ((userName != null) &amp;&amp; (password != null)) {
          final String host = configuration.getHost();
          final String remoteUser = configuration.getRemoteUser();
          GuardedString passwd = configuration.getPassword();
          boolean isSuccessful;
  
          final AS400 as400 = new AS400();
  
          try {
              as400.setSystemName(host);
              as400.setUserId(remoteUser);
  
              passwd.access(new Accessor(){
                  @Override
                  public void access(char[] clearChars) {
                      try {
                          as400.setPassword(new String(clearChars));
                      }catch (Exception e) {
                          e.printStackTrace();
                      }
                  }});
  
              as400.setGuiAvailable(false);
              as400.connectToPort(23);
  
              final CommandCall cc = new CommandCall(as400);
              final StringBuilder command = new StringBuilder();
              password.access(new Accessor(){
                      @Override
                      public void access(char[] clearChars) {
                              command.append("CHGUSRPRF USRPRF(" + userName + ") PASSWORD(" + new String(clearChars) + ")");
                      }});
              try {
                  isSuccessful = cc.run(command.toString());
  
  
                  logger.info("command status is = " + isSuccessful);
                  // getMessageList returns an array of AS400Message objects
                  for(AS400Message msg : cc.getMessageList()){
                      logger.info(
                              "  msg: " + msg.getID() + ": " + msg.getText());
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          } catch (Exception e){
              throw new RuntimeException(e);
          }
      }
  }
  </code></pre>
  
  <p>This is the log file:</p>
  
  <pre><code>Thread Id: 1    Time: 2015-06-29 14:27:05.592   Class: com.mastersam.connectors.AS400.AS400ConnectorTests   Method: updateTest(AS400ConnectorTests.java:150)    Level: INFO Message: Running Update Test
  Thread Id: 1    Time: 2015-06-29 14:27:05.705   Class: org.identityconnectors.framework.api.operations.UpdateApiOp  Method: update  Level: OK   Message: Enter: update(ObjectClass: __ACCOUNT__, Attribute: {Name=__UID__, Value=[fikrie1]}, [Attribute: {Name=__PASSWORD__, Value=[org.identityconnectors.common.security.GuardedString@408a7bb8]}], OperationOptions: {})
  Thread Id: 1    Time: 2015-06-29 14:27:07.749   Class: org.identityconnectors.framework.api.operations.UpdateApiOp  Method: update  Level: OK   Message: Exception: 
  java.lang.RuntimeException: java.lang.NegativeArraySizeException
  at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:261)
  at com.mastersam.connectors.AS400.AS400Connector.update(AS400Connector.java:199)
  at org.identityconnectors.framework.impl.api.local.operations.UpdateImpl.update(UpdateImpl.java:88)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.local.operations.ConnectorAPIOperationRunnerProxy.invoke(ConnectorAPIOperationRunnerProxy.java:97)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.local.operations.ThreadClassLoaderManagerProxy.invoke(ThreadClassLoaderManagerProxy.java:96)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.DelegatingTimeoutProxy.invoke(DelegatingTimeoutProxy.java:98)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.LoggingProxy.invoke(LoggingProxy.java:76)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at org.identityconnectors.framework.impl.api.AbstractConnectorFacade.update(AbstractConnectorFacade.java:176)
  at com.mastersam.connectors.AS400.AS400ConnectorTests.updateTest(AS400ConnectorTests.java:156)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
  at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
  at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
  at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
  at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
  at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
  at org.testng.TestRunner.privateRun(TestRunner.java:767)
  at org.testng.TestRunner.run(TestRunner.java:617)
  at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
  at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
  at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
  at org.testng.SuiteRunner.run(SuiteRunner.java:240)
  at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
  at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
  at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
  at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
  at org.testng.TestNG.run(TestNG.java:1057)
  at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
  at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
  at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
  Caused by: java.lang.NegativeArraySizeException
  at com.ibm.as400.access.AS400XChgRandSeedReplyDS.read(AS400XChgRandSeedReplyDS.java:58)
  at com.ibm.as400.access.AS400ImplRemote.getConnection(AS400ImplRemote.java:823)
  at com.ibm.as400.access.AS400ImplRemote.connectToPort(AS400ImplRemote.java:408)
  at com.ibm.as400.access.AS400.connectToPort(AS400.java:1152)
  at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:239)
  ... 52 more
  FAILED: updateTest
  java.lang.RuntimeException: java.lang.NegativeArraySizeException
  at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:261)
  at com.mastersam.connectors.AS400.AS400Connector.update(AS400Connector.java:199)
  at org.identityconnectors.framework.impl.api.local.operations.UpdateImpl.update(UpdateImpl.java:88)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.local.operations.ConnectorAPIOperationRunnerProxy.invoke(ConnectorAPIOperationRunnerProxy.java:97)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.local.operations.ThreadClassLoaderManagerProxy.invoke(ThreadClassLoaderManagerProxy.java:96)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.DelegatingTimeoutProxy.invoke(DelegatingTimeoutProxy.java:98)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.identityconnectors.framework.impl.api.LoggingProxy.invoke(LoggingProxy.java:76)
  at com.sun.proxy.$Proxy10.update(Unknown Source)
  at org.identityconnectors.framework.impl.api.AbstractConnectorFacade.update(AbstractConnectorFacade.java:176)
  at com.mastersam.connectors.AS400.AS400ConnectorTests.updateTest(AS400ConnectorTests.java:156)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
  at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
  at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
  at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
  at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
  at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
  at org.testng.TestRunner.privateRun(TestRunner.java:767)
  at org.testng.TestRunner.run(TestRunner.java:617)
  at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
  at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
  at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
  at org.testng.SuiteRunner.run(SuiteRunner.java:240)
  at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
  at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
  at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
  at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
  at org.testng.TestNG.run(TestNG.java:1057)
  at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
  at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
  at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
  Caused by: java.lang.NegativeArraySizeException
  at com.ibm.as400.access.AS400XChgRandSeedReplyDS.read(AS400XChgRandSeedReplyDS.java:58)
  at com.ibm.as400.access.AS400ImplRemote.getConnection(AS400ImplRemote.java:823)
  at com.ibm.as400.access.AS400ImplRemote.connectToPort(AS400ImplRemote.java:408)
  at com.ibm.as400.access.AS400.connectToPort(AS400.java:1152)
  at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:239)
  ... 52 more
  </code></pre>
  
  <p>So, why does adding one method from jt400 causes a NegativeArraySizeException? </p>
  
  <p>While looking for alternative, I found more info on the JT400 method <a href="http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzahh/com/ibm/as400/access/AS400.html" rel="nofollow">here</a>, then tried to use <code>as400.connectService()</code>. From <a href="http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzahh/constant-values.html%23com.ibm.as400.access.AS400.DATABASE?lang=en" rel="nofollow">here</a>, I assume the service that I should be using is <code>COMMAND</code> and <code>SIGNON</code>. This is part of my code after trying this method:</p>
  
  <pre><code>final AS400 as400 = new AS400();                
          try {
  
              as400.setSystemName(host);
              as400.setUserId(remoteUser);
              passwd.access(new Accessor(){
                  @Override
                  public void access(char[] clearChars) {
                      try {
                          as400.setPassword(new String(clearChars));
                      }catch (Exception e) {
                          e.printStackTrace();
                      }
                  }});
              as400.setGuiAvailable(false);
  
              as400.connectService(7);      //I added this
              as400.setServicePort(7, 23);  //I added this
              as400.setServicePort(6, 23);  //I added this
              logger.info("port is = " + as400.getServicePort(7));
              final CommandCall cc = new CommandCall(as400);
              final StringBuilder command = new StringBuilder();
              password.access(new Accessor(){
                      @Override
                      public void access(char[] clearChars) {
                              command.append("CHGUSRPRF USRPRF(" + userName + ") PASSWORD(" + new String(clearChars) + ")");
                      }});
              try {
  
                  isSuccessful = cc.run(command.toString());
                  as400.setServicePort(2, 23); //I added this
                  logger.info("port is = " + as400.getServicePort(2));
  }
  </code></pre>
  
  <p>According to the log, the port is 23. But when I double check using Wireshark apps, the port that it use to connect to AS400 is not 23. Please guide me if I'm doing a mistake anywhere.</p>
  
  <p>Other thing that I have tried,</p>
  
  <ol>
  <li><p>Swap line between <code>as400.connectService()</code> and <code>as400.setServicePort()</code></p>
  
  <ul>
  <li>Causes the same error as the previous one : java.lang.NegativeArraySizeException</li>
  </ul></li>
  <li><p>Check either port 23 is available to use or not. Use tn5250 to connect to AS400. The connection is ok.</p></li>
  <li><p>Set as400.connectToPort() to use other port.</p>
  
  <ul>
  <li>Causes the same error like using port 23.</li>
  </ul></li>
  </ol>