Other Notes

  • As documented in the main Helix Server documentation, Helix Server form triggers can cause additional output on form commands such as “change” or “client”, even when the trigger succeeds. This trigger output is available through the P4Java command callback feature, but note that there is currently no way to differentiate trigger output from normal command output, and that such trigger output will also be prepended or appended to normal string output on commands such as IOptionsServer.newLabel.
  • P4Java’s command callback feature, documented in class com.perforce.p4java.server.callback.ICommandCallback, is a useful way to get blow-by-blow command status messages and trigger output messages from the server in a way that can mimic the p4 command line client’s output. Usage is straightforward, but note the potential for deadlocks and blocking if you are not careful with callback method implementation.
  • P4Java’s progress callback feature gives users a somewhat impressionistic measure of command progress for longer-running commands. Progress callbacks are documented in the Javadoc for class com.perforce.p4java.server.callback.IProgressCallback. Once again, if you use this feature, ensure that your callback implementations do not cause deadlocks or blocking.
  • We strongly recommend setting the progName and progVersion properties (either globally or for each IOptionsServer instance) whenever you use P4Java. Set these values to something meaningful that reflects the application or tool in which P4Java is embedded; this can help Helix Server administrators and application debugging.

    For example, the following code sets progName and progVersion via the JVM invocation property flags:

    $ java -Dcom.perforce.p4java.programName=p4test
        -Dcom.perforce.p4java.programVersion=2.01A ...

    Alternatively, you can also use the server factory getServer method’s properties parameter:

Properties props = new Properties(System.getProperties());
props.setProperty(PropertyDefs.PROG_NAME_KEY, "ant-test");
props.setProperty(PropertyDefs.PROG_VERSION_KEY, "Alpha 0.9d");

    ...

server = IOptionServerFactory.getServer(serverUriString, props);
  • If your application receives a ConnectionException from an IOptionsServer or IClient method while communicating with a Helix Server, the only truly safe action is to close the connection and start over with a new connection, rather than continue using the connection.

    A ConnectionException event typically represents a serious network error (such as the Helix Server unexpectedly closing a connection or a bad checksum in a network packet), and there’s no guarantee that after receiving such an event the connection is even usable, let alone reliable.

  • There is currently no diff method on IFileSpec interfaces to compare versions of the same Helix Server-managed file, but this functionality may be easily implemented with a combination of IOptionsServer.getFileContents to retrieve the contents of specific versions to temporary files, and the use of the operating system’s diff application on these temporary files as shown below:

    InputStream fspecStream1 = server.getFileContents(
      FileSpecBuilder.makeFileSpecList(
        new String[] {spec1}), false, true);
    InputStream fspecStream2 = server.getFileContents(
      FileSpecBuilder.makeFileSpecList(
        new String[] {spec2}), false, true);
    
    File file1 = null;
    File file2 = null;
    
    try {
      file1 = File.createTempFile("p4jdiff", ".tmp");
      file2 = File.createTempFile("p4jdiff", ".tmp");
      FileOutputStream outStream1 = new FileOutputStream(file1);
      FileOutputStream outStream2 = new FileOutputStream(file2);
      byte[] bytes = new byte[1024];
      int bytesRead = 0;
      while bytesRead = fspecStream1.read(bytes > 0) {
        outStream1.write(bytes, 0, bytesRead);
      }
      fspecStream1.close();
      outStream1.close();
      while bytesRead = fspecStream2.read(bytes > 0) {
        outStream2.write(bytes, 0, bytesRead);
      }
      fspecStream2.close();
      outStream2.close();
      Process diffProc = Runtime.getRuntime().exec(new String[] {
        "/usr/bin/diff",file1.getPath(),file2.getPath()});
      diffProc.waitFor();
      if (diffProc != null) {
        InputStream iStream = diffProc.getInputStream();
        byte[] inBytes = new byte[1024];
        int inBytesRead = 0;
        while inBytesRead = iStream.read(inBytes > 0) {
          System.out.write(inBytes, 0, inBytesRead);
        }
      }
    } catch (Exception exc) {
      error("diff error: " + exc.getLocalizedMessage());
      return;
    } finally {
      if (file1 != null) file1.delete();
      if (file2 != null) file2.delete();
    }