package com.github.xbn.experimental; import com.github.xbn.lang.ObjectOrCrashIfNull; import com.github.xbn.lang.CrashIfObject; import com.github.xbn.lang.Copyable; import com.github.xbn.experimental.BadInterfaceBehaviorException; import com.github.xbn.experimental.xcontext.EXContextable; import com.github.xbn.experimental.xcontext.ElementExceptionContext; import com.github.xbn.experimental.xcontext.ExceptionContext; import com.github.xbn.experimental.xcontext.ObjectExceptionContext; import com.github.xbn.experimental.xcontext.XContextable; /** <p>For wrapping all interface function-calls in a try-block, to protect against untrustworthy implementations and diagnose other interface-related issues. All {@code InterfaceWrapper}-s must implement the interface itself (the interface being wrapped), so it can be arbitrarily used as a replacement for an actual instance.</p> **/ public abstract class InterfaceWrapper implements XContextable, Copyable { private ExceptionContext xc = null; private Object oii = null; /** <p>Create a new {@code InterfaceWrapper}.</p> <p>This calls<ol> <li>{@link #setXContext(ExceptionContext) setXContext}{@code (x_c)}</li> <li>{@link #setGetIInstance(Object, String) setGetIInstance}{@code (o_iinstance, null)}</li> </ol></p> */ public InterfaceWrapper(Object o_iinstance, ExceptionContext x_c) { setXContext(x_c); setGetIInstance(o_iinstance, null); } /** <p>Create a new {@code InterfaceWrapper} as a duplicate of another.</p> <p>This calls<ol> <li><code>{@link #setGetIInstance(Object, String) setGetIInstance}(to_copy.{@link #getIInstance() getIInstance}(), null)</code></li> <li><code>{@link #setXContext(ExceptionContext) setXContext}((ExceptionContext)to_copy.{@link #getXContext() getXContext}().{@link com.github.xbn.experimental.xcontext.ExceptionContext#getObjectCopy() getObjectCopy}())</code></li> </ol></p> * @param to_copy May not be {@code null}. * @see #getObjectCopy() */ public InterfaceWrapper(InterfaceWrapper to_copy) { try { setGetIInstance(to_copy.getIInstance(), null); } catch(RuntimeException rx) { throw CrashIfObject.nullOrReturnCause(to_copy, "to_copy", null, rx); } setXContext(ObjectOrCrashIfNull.<ExceptionContext>getCopy(getXContext(), ExceptionContext.class, "getXContext()")); } /** <p>Set the interface instance, then immediately return it. To set the instance to {@code null}, use {@link #removeIInstance() removeIInstance}{@code ()}. Attempting to use this function results in an ambiguous reference compile error.</p> * @param o_iinstance Get with {@link #getIInstance() getIInstance}{@code ()}. At initialization of this {@code InterfaceWrapper}, this may be {@code null} (before any functions are called against it). Otherwise, it should never be {@code null}. * @return {@code o_iinstance} <i>This makes it easier to maintain a redundant reference to the object, via <br/>     {@code o = iw.setGetIInstance(...);} <br/>This extra reference minimizes the need for calling this function, when the instance simply needs to be passed or tested for {@code null}.</i> * @see #setXContext(ExceptionContext) setXContext(xc) * @see #setIInstanceSubIWs(Object, String, InterfaceWrapper...) setIInstanceSubIWs(s,o,iw...) */ public Object setGetIInstance(Object o_iinstance, String nonNull_objName) { if(nonNull_objName != null) { try { getOXContext().setObjectName(nonNull_objName); } catch(ClassCastException ccx) { throw new ClassCastException("nonNull_objName (\"" + nonNull_objName + "\") is non-null, but getXContext() is not an ObjectExceptionContext. getXContext()=[" + getXContext() + "]"); } } oii = o_iinstance; return o_iinstance; } /** <p>Set the interface-instance to {@code null}.</p> * <p>Equal to <br/>     {@link #setGetIInstance(Object, String) setGetIInstance(null, null)}</p> */ public void removeIInstance() { setGetIInstance(null, null); } /** <p>Set the interface instance into multiple {@code InterfaceWrapper}-s. This is useful when an {@code InterfaceWrapper} has multiple sub-{@code InterfaceWrapper}-s.</p> <p>For each, this calls <br/>     {@link #setGetIInstance(Object, String) setGetIInstance(o_iinstance, nonNull_objName)}</p> */ public void setIInstanceSubIWs(Object o_iinstance, String nonNull_objName, InterfaceWrapper... ddd_iw) { if(ddd_iw.length == 0) { throw new IllegalArgumentException("ddd_iw.length is zero."); } for(InterfaceWrapper iw : ddd_iw) { iw.setGetIInstance(o_iinstance, nonNull_objName); } } /** <p>Set the context for potential errors.</p> * @param x_c May not be {@code null}. Get with {@link #getXContext() getXContext}{@code ()}. * @see #setGetIInstance(Object, String) setGetIInstance(o,s) */ public void setXContext(ExceptionContext x_c) { if(x_c == null) { throw new NullPointerException("x_c"); } xc = x_c; } /** <p>Shortcut for {@code getXContext().setExtraInfo(o)}.</p> */ public void setExtraInfo(Object o_iinstance, XContextable... ddd_xcblOthers) { ExceptionContext xc = getXContext(); xc.setExtraInfo(o_iinstance); for(XContextable xcl : ddd_xcblOthers) { xcl.getXContext().setExtraInfo(o_iinstance); } } /** <p>Reset the context's index to zero.</p> * <p>Equal to <br/>     {@link #setIndex(int, EXContextable...) setIndex}{@code (0)}</p> */ public void setIndexTo0(EXContextable... ddd_xcblOthers) { setIndex(0); } /** <p>Shortcut for {@code getXContext().setIndex(i)}.</p> * @see #setIndexTo0(EXContextable...) setIndexTo0}(exc...) */ public void setIndex(int index, EXContextable... ddd_xcblOthers) { ElementExceptionContext exc = getEXContext(); exc.setIndex(index); for(EXContextable excl : ddd_xcblOthers) { excl.getEXContext().setIndex(index); } } /** <p>Get the interface instance.</p> * @return {@code o_iinstance}, as provided to {@link #setGetIInstance(Object, String) setGetIInstance(o,s)} */ public Object getIInstance() { return oii; } /** <p>Get the exception context.</p> * @return {@code x_c}, as provided to {@link #setXContext(ExceptionContext) setXContext(xc)}. */ public ExceptionContext getXContext() { return xc; } /** <p>Get the object exception context.</p> * @return {@code x_c}, as provided to {@link #setXContext(ExceptionContext) setXContext(xc)}. * @exception ClassCastException If {@link #getXContext() getXContext}{@code ()} is not an {@code ObjectExceptionContext} */ public ObjectExceptionContext getOXContext() { try { return (ObjectExceptionContext)getXContext(); } catch(ClassCastException ccx) { throw new ClassCastException("getXContext() is not an ObjectExceptionContext. getXContext().getClass()=" + getXContext().getClass()); } } /** <p>Get the object exception context.</p> * @return {@code x_c}, as provided to {@link #setXContext(ExceptionContext) setXContext(xc)}. * @exception ClassCastException If {@link #getXContext() getXContext}{@code ()} is not an {@code ElementExceptionContext} */ public ElementExceptionContext getEXContext() { try { return (ElementExceptionContext)getXContext(); } catch(ClassCastException ccx) { throw new ClassCastException("getXContext() is not an ElementExceptionContext. getXContext().getClass()=" + getXContext().getClass()); } } public String toString() { return super.toString() + ": getIInstance()=[" + getIInstance() + "], getXContext()=[" + getXContext() + "]"; } /** * @return {@code true} If {@code o_iinstance} is non-{@code null}, aYYY {@code InterfaceWrapper}, and {@link #areFieldsEqual(InterfaceWrapper) areFieldsEqual}{@code ((InterfaceWrapper)to_compareTo)} is {@code true}. */ @Override public boolean equals(Object to_compareTo) { //See internal comments for com.github.xbn.lang.SimpleXbnObject.equals(o) if(to_compareTo == null) { throw new NullPointerException("to_compareTo"); } if(this == to_compareTo) { return true; } if(!(to_compareTo instanceof InterfaceWrapper)) { return false; } InterfaceWrapper xo = (InterfaceWrapper)to_compareTo; return areFieldsEqual(xo); } /** <p>Are all internal values in the provided {@code InterfaceWrapper} the same as in <i>{@code this}</i>?. <i>This ignores the interface-instances (they may be different or {@code null}).</i></p> * @return {@link #getXContext() getXContext}{@code ().equals(wrapper.getXContext())} */ public boolean areFieldsEqual(InterfaceWrapper wrapper) { return getXContext().equals(wrapper.getXContext()); } //Non static wrappers for required interface functions...START /** <p>Wrapper for {@code <i>[Object]</i>.getClass()}.</p> YYY * @return {@code InterfaceWrapper.{@link #iiGetClass(Object, ExceptionContext) iiGetClass}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())} */ public final Class iiGetClass() { return InterfaceWrapper.iiGetClass(getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.hashCode()}.</p> YYY * @return {@code InterfaceWrapper.{@link #iiHashCode(Object, ExceptionContext) iiHashCode}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())} */ public final int iiHashCode() { return InterfaceWrapper.iiHashCode(getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.equals(o)}.</p> YYY * @return {@code InterfaceWrapper.{@link #iiEquals(Object, Object, ExceptionContext) iiEquals}(to_compareTo, {@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())} */ public final boolean iiEquals(Object to_compareTo) { return InterfaceWrapper.iiEquals(to_compareTo, getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.toString()}.</p> YYY * @return {@code InterfaceWrapper.{@link #iiToString(Object, ExceptionContext) iiToString}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())} */ public final String iiToString() { return InterfaceWrapper.iiToString(getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.notify()}.</p> YYY * <p>Equal to <br/>     {@code InterfaceWrapper.{@link #iiNotify(Object, ExceptionContext) iiNotify}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())}</p> */ public final void iiNotify() { InterfaceWrapper.iiNotify(getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.notifyAll()}.</p> YYY * <p>Equal to <br/>     {@code InterfaceWrapper.{@link #iiNotifyAll(Object, ExceptionContext) iiNotifyAll}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())}</p> */ public final void iiNotifyAll() { InterfaceWrapper.iiNotifyAll(getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.wait(l)}.</p> YYY * <p>Equal to <br/>     {@code InterfaceWrapper.{@link #iiWait(long, Object, ExceptionContext) iiWait}(timeout_mills, {@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())}</p> */ public final void iiWait(long timeout_mills) throws InterruptedException { InterfaceWrapper.iiWait(timeout_mills, getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.wait(l,i)}.</p> YYY * <p>Equal to <br/>     {@code InterfaceWrapper.{@link #iiWait(long, int, Object, ExceptionContext) iiWait}(timeout_mills, nanos, {@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())}</p> */ public final void iiWait(long timeout_mills, int nanos) throws InterruptedException { InterfaceWrapper.iiWait(timeout_mills, nanos, getIInstance(), getXContext()); } /** <p>Wrapper for {@code <i>[Object]</i>.wait()}.</p> YYY * <p>Equal to <br/>     {@code InterfaceWrapper.{@link #iiWait(Object, ExceptionContext) iiWait}({@link #getIInstance() getIInstance}(), <i>[{@link com.github.xbn.testdev.InterfaceWrapper super}]</i>.{@link com.github.xbn.testdev.InterfaceWrapper#getXContext() getXContext}())}</p> */ public final void iiWait() throws InterruptedException { InterfaceWrapper.iiWait(getIInstance(), getXContext()); } //Non static wrappers for required interface functions...END //Static wrappers for required interface functions...START /** <p>Wrapper for {@code <i>[Object]</i>.getClass()}.</p> YYY * @return <code>o_iinstance.{@link Object#getClass() getClass}()</code> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code getClass()} fails for any unexpected reason. */ public static final Class iiGetClass(Object o_iinstance, ExceptionContext x_c) { try { return o_iinstance.getClass(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException("Error context: " + x_c, rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.hashCode()}.</p> YYY * @return <code>o_iinstance.{@link Object#hashCode() hashCode}()</code> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code hashCode()} fails for any unexpected reason. */ public static final int iiHashCode(Object o_iinstance, ExceptionContext x_c) { try { return o_iinstance.hashCode(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.equals(o)}.</p> YYY * @return <code>o_iinstance.{@link Object#equals(Object) equals}(to_compareTo)</code> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code equals()} fails for any unexpected reason. */ public static final boolean iiEquals(Object to_compareTo, Object o_iinstance, ExceptionContext x_c) { try { return o_iinstance.equals(to_compareTo); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.iiToString()}.</p> YYY * @return <code>o_iinstance.{@link Object#toString() toString}()</code> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code toString()} fails for any unexpected reason. */ public static final String iiToString(Object o_iinstance, ExceptionContext x_c) { try { return o_iinstance.toString(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.notify()}.</p> YYY * <p>Equal to <br/>     <code>o_iinstance.{@link Object#notify() notify}()</code></p> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code notify()} fails for any unexpected reason. */ public static final void iiNotify(Object o_iinstance, ExceptionContext x_c) { try { o_iinstance.notify(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.notifyAll()}.</p> YYY * <p>Equal to <br/>     <code>o_iinstance.{@link Object#notifyAll() notifyAll}()</code></p> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code notifyAll()} fails for any unexpected reason. */ public static final void iiNotifyAll(Object o_iinstance, ExceptionContext x_c) { try { o_iinstance.notifyAll(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.wait(l)}.</p> YYY * <p>Equal to <br/>     <code>o_iinstance.{@link Object#wait(long) wait}(timeout_mills)</code></p> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code wait()} fails for any unexpected reason. */ public static final void iiWait(long timeout_mills, Object o_iinstance, ExceptionContext x_c) throws InterruptedException { try { o_iinstance.wait(timeout_mills); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.wait(l,i)}.</p> YYY * <p>Equal to <br/>     <code>o_iinstance.{@link Object#wait(long, int) wait}(timeout_mills, nanos)</code></p> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code wait()} fails for any unexpected reason. */ public static final void iiWait(long timeout_mills, int nanos, Object o_iinstance, ExceptionContext x_c) throws InterruptedException { try { o_iinstance.wait(timeout_mills, nanos); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } /** <p>Wrapper for {@code <i>[Object]</i>.wait()}.</p> YYY * <p>Equal to <br/>     <code>o_iinstance.{@link Object#wait() wait}()</code></p> * @param o_iinstance May not be {@code null}. * @param x_c May not be {@code null}. * @exception NullPointerException When {@code o_iinstance} is {@code null} * @exception BadInterfaceBehaviorException When {@code o_iinstance} is non-{@code null} and the call to {@code wait()} fails for any unexpected reason. */ public static final void iiWait(Object o_iinstance, ExceptionContext x_c) throws InterruptedException { try { o_iinstance.wait(); } catch(RuntimeException rx) { CrashIfObject.nnull(o_iinstance, "o_iinstance", x_c); throw new BadInterfaceBehaviorException(x_c.toString(), rx); } } //Static wrappers for required interface functions...END }