package com.perforce.client.api; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; /** * Java adapter to native Error class. * Accumulates and reports layered errors. * * <p> The basic idea of Error is that the top level caller should * have one on its stack and hand it by reference down to all lower * layers. If any operation fails, it can add its description of the * error to the structure. After each operation that can potentially * fail, the caller should use {@link #test} to check for errors. The * top level should do the check and then report if necessary. * * <p> Alternately, the {@link #checkException} method can be used to * check Error and raise a Java exception if necessary. * * <p> Each error code is composed of 5 parts. * <pre> * sev - ErrorSeverity (4 bits) * arg - # of arguments, error specific (4 bits) * gen - generic error (8 bits) * sub - subsystem id (6 bits) * cod - code within subsystem, error specific (10 bits) * </pre> */ public class P4Error { /** * nothing yet * @see #severity * @see "error.h" */ public static final int SEVERITY_EMPTY = 0; /** * something good happened * @see #severity * @see "error.h" */ public static final int SEVERITY_INFO = 1; /** * something not good happened * @see #severity * @see "error.h" */ public static final int SEVERITY_WARN = 2; /** * user did somthing wrong * @see #severity * @see "error.h" */ public static final int SEVERITY_FAILED = 3; /** * system broken -- nothing can continue * @see #severity * @see "error.h" */ public static final int SEVERITY_FATAL = 4; /** * misc * @see #generic * @see "errornum.h" */ public static final int GENERIC_NONE = 0; // The fault of the user /** * request not consistent with dox * @see #generic * @see "errornum.h" */ public static final int GENERIC_USAGE = 0x01; /** * using unknown entity * @see #generic * @see "errornum.h" */ public static final int GENERIC_UNKNOWN = 0x02; /** * using entity in wrong context * @see #generic * @see "errornum.h" */ public static final int GENERIC_CONTEXT = 0x03; /** * trying to do something you can't * @see #generic * @see "errornum.h" */ public static final int GENERIC_ILLEGAL = 0x04; /** * something must be corrected first * @see #generic * @see "errornum.h" */ public static final int GENERIC_NOTYET = 0x05; /** * protections prevented operation * @see #generic * @see "errornum.h" */ public static final int GENERIC_PROTECT = 0x06; // No fault at all /** * action returned empty results * @see #generic * @see "errornum.h" */ public static final int GENERIC_EMPTY = 0x11; // not the fault of the user /** * inexplicable program fault * @see #generic * @see "errornum.h" */ public static final int GENERIC_FAULT = 0x21; /** * client side program errors * @see #generic * @see "errornum.h" */ public static final int GENERIC_CLIENT = 0x22; /** * server administrative action required * @see #generic * @see "errornum.h" */ public static final int GENERIC_ADMIN = 0x23; /** * client configuration inadequate * @see #generic * @see "errornum.h" */ public static final int GENERIC_CONFIG = 0x24; /** * client or server too old to interact * @see #generic * @see "errornum.h" */ public static final int GENERIC_UPGRADE = 0x25; /** * communications error * @see #generic * @see "errornum.h" */ public static final int GENERIC_COMM = 0x26; /** * OS error * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_OS = 0; /** * Misc support * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_SUPP = 1; /** * librarian * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_LBR = 2; /** * messaging * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_RPC = 3; /** * database * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_DB = 4; /** * database support * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_DBSUPP = 5; /** * data manager * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_DM = 6; /** * top level of server * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_SERVER = 7; /** * top level of client * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_CLIENT = 8; /** * pseudo subsystem for information messages * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_INFO = 9; /** * pseudo subsystem for help messages * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_HELP = 10; /** * pseudo subsystem for spec/comment messages * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_SPEC = 11; /** * P4FTP server * @see #subsystem * @see "errornum.h" */ public static final int SUBSYSTEM_FTPD = 12; /** * Extracts code within subsystem, error specific. * @param code a 32-bit <code>int</code> error code * @return 10 bits */ public static final int subCode(final int code) { return (code >> 0) & 0x3ff; } /** * Extracts the subsystem id, defined in errornum.h. * @param code a 32-bit <code>int</code> error code * @return 6 bits */ public static final int subsystem(final int code) { return (code >> 10) & 0x3f; } /** * Extracts the generic error id, defined in errornum.h. * @param code a 32-bit <code>int</code> error code * @return 8 bits */ public static final int generic(final int code) { return (code >> 16) & 0xff; } /** * Extracts number of arguments, error specific. * @param code a 32-bit <code>int</code> error code * @return 4 bits */ public static final int argCount(final int code) { return (code >> 24) & 0x0f; } /** * Extracts error severity. * @param code a 32-bit <code>int</code> error code * @return 4 bits */ public static final int severity(final int code) { return (code >> 28) & 0x0f; } /** * Extracts subsystem + subcode. * @param code a 32-bit <code>int</code> error code * @return 16 bits */ public static final int uniqueCode(final int code) { return code & 0xffff; } /** the native peer instance of the error */ long instance = 0; long id() { return nId(this.instance); } int code() { return nCode(this.instance); } String fmt() { return nFmt(this.instance); } /** * Test to see if there was an error made. * * @return if there is an error or not. * **/ public boolean test() { return nTest(this.instance); } P4Error() { this.instance = nNewInstance(); javaCreatedTheInstance = true; } /** * Make a new P4Error that will just bind to an already * existing native Error. * * @param instance a native peer to bind this to. * @return the java interface. * **/ static P4Error makeJavaPeer(long instance) { return new P4Error(instance); } /** * Take a P4ClientException, and make sure that the * error on the native side is set. * * <p> You would call this when you've caught a P4ClientException * and want to convey that to the native side. * * @param err the exception that we use to see what to set. * **/ void convertException(P4ClientException err) { int id = err.getErrorCode(); if (id != 0) nSetErrorId(this.instance, id); else nSetMessage(this.instance, err.toString()); } /** * Checks if there was an exception on the native side. * If so, throws the corresponding P4ClientException. * * <p> You would use this if you wanted to convert from P4's Error * handling system to a more java-like exception mechanism. * * @exception P4ClientException containing the error code from Error, * but only if one needs to be thrown. * **/ public void checkException() throws P4ClientException { // Check to see if there was an error. if (!test()) return; // There was, so get the native one and, as best we // can, throw the corresponding exception. final long id = id(); final int code = code(); final String fmt = fmt(); if (ids2Cons.size() == 0) initIds2Cons(); Constructor c = (Constructor) ids2Cons.get(new Long(id)); if (c == null) throw new P4ClientException(code, fmt); try { throw (P4ClientException) c.newInstance(new Object[] {new Integer(code), fmt}); } catch (InstantiationException e) { P4ClientException p4e = new P4ClientException(code, fmt); p4e.initCause(e); throw p4e; } catch (IllegalAccessException e) { P4ClientException p4e = new P4ClientException(code, fmt); p4e.initCause(e); throw p4e; } catch (IllegalArgumentException e) { P4ClientException p4e = new P4ClientException(code, fmt); p4e.initCause(e); throw p4e; } catch (InvocationTargetException e) { P4ClientException p4e = new P4ClientException(code, fmt); p4e.initCause(e.getCause()); throw p4e; } } /** * If this instance was create to pass to the native side, then a * native pointer was allocated and we need to clean that up, * otherwise, this was created as a face to an Error that was * created outside of Java and we do not want to clean that up. */ protected void finalize() throws Throwable { if (javaCreatedTheInstance) nDeleteInstance(this.instance); super.finalize(); } /** to track if we created this or the native side did */ private boolean javaCreatedTheInstance; // // methods to create and dispose of native Error pointers. // private static native long nNewInstance(); private static native void nDeleteInstance(long instance); private static Map<Long, Constructor> ids2Cons = new HashMap<Long, Constructor>(); private static void initIds2Cons() { long[] ids = nGetErrorIdPtrs(); String[] names = nGetErrorIdNames(); assert(ids.length == names.length); for (int i = 0; i < ids.length; i++) { try { addCons(ids[i], Class.forName("P4" + names[i] + "Exception")); } catch (ClassNotFoundException e) { // just skip it } } } private static void addCons(long id, Class c) { Class[] sig = new Class[] {Integer.TYPE, String.class}; try { ids2Cons.put(new Long(id), c.getConstructor(sig)); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } /** * Make a P4Error to use as a "face" to an actual, pre-existing * native Error instance. * * @param instance the pre-existing native instance. * **/ private P4Error(long instance) { this.instance = instance; javaCreatedTheInstance = false; } private static native String[] nGetErrorIdNames(); private static native String[] nGetErrorIdFmts(); private static native long[] nGetErrorIdPtrs(); private static native void nSetErrorId(long errInstance, long errorrIDInstance); private static native void nSetErrorCode(long errInstance, int id); private static native void nSetMessage(long errInstance, String message); private static native boolean nTest(long instance); private static native String nFmt(long instance); private static native long nId(long instance); private static native int nCode(long instance); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#9 | 4181 | Paul Krause |
Rename //guest/paul_krause/perforce/api/java/wcvm/com/... //guest/paul_krause/perforce/api/java/wcvm/javax/... To //guest/paul_krause/perforce/api/java/wcvm/src-15/... |
||
#8 | 4177 | Paul Krause | parameterize container types - requires tiger or pizza | ||
#7 | 4173 | Paul Krause | add serialVersionUID | ||
#6 | 4129 | Paul Krause | use msgclient.h in place of old errclient.h | ||
#5 | 4107 | Paul Krause | fix JNI sigs for ErrorId | ||
#4 | 4103 | Paul Krause | ditch clienterror.h | ||
#3 | 4100 | Paul Krause | fix type problems | ||
#2 | 4097 | Paul Krause | remove support for unimplemented abort() function | ||
#1 | 4073 | Paul Krause | branch com.perforce.api package from michael_bishop | ||
//guest/michael_bishop/P4APIForJava/java/com/perforce/client/api/P4Error.java | |||||
#1 | 430 | Michael Bishop |
Initial checkin. Seems to work. Not very much testing. Not very much documentation. Some more commenting needs to take place. But, it's there to experiment with. |