File Source: CallbackObject.java

         /* 
    P/P   *  Method: com.dmdirc.parser.irc.callbacks.CallbackObject__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.parser.irc.callbacks;
    24  
    25  import com.dmdirc.parser.irc.IRCParser;
    26  import com.dmdirc.parser.irc.ParserError;
    27  import com.dmdirc.parser.irc.callbacks.interfaces.ICallbackInterface;
    28  
    29  import java.lang.annotation.Annotation;
    30  import java.lang.reflect.Constructor;
    31  import java.lang.reflect.InvocationTargetException;
    32  import java.lang.reflect.Method;
    33  import java.util.ArrayList;
    34  import java.util.HashMap;
    35  import java.util.List;
    36  import java.util.Map;
    37  
    38  /**
    39   * CallbackObject.
    40   * Superclass for all callback types.
    41   *
    42   * @author            Shane Mc Cormack
    43   */
    44  public class CallbackObject {
    45  
    46      /** The type of callback that this object is operating with. */
    47      protected final Class<? extends ICallbackInterface> type;
    48  
    49  	/** Arraylist for storing callback information related to the callback. */
    50  	protected final List<ICallbackInterface> callbackInfo = new ArrayList<ICallbackInterface>();
    51  	
    52  	/** Reference to the IRCParser that owns this callback. */
    53  	protected IRCParser myParser;
    54  	/** Reference to the CallbackManager in charge of this callback. */
    55  	protected CallbackManager myManager;
    56  	
    57  	/**
    58  	 * Create a new instance of the Callback Object.
    59  	 *
    60  	 * @param parser IRCParser That owns this callback
    61  	 * @param manager CallbackManager that is in charge of this callback
    62       * @param type The type of callback to use
    63       * @since 0.6.3m1
    64  	 */
    65  	protected CallbackObject(final IRCParser parser, final CallbackManager manager,
                     /* 
    P/P               *  Method: void com.dmdirc.parser.irc.callbacks.CallbackObject(IRCParser, CallbackManager, Class)
                      * 
                      *  Postconditions:
                      *    this.callbackInfo == &amp;new ArrayList(CallbackObject#1)
                      *    this.myManager == manager
                      *    init'ed(this.myManager)
                      *    this.myParser == parser
                      *    init'ed(this.myParser)
                      *    this.type == type
                      *    init'ed(this.type)
                      *    new ArrayList(CallbackObject#1) num objects == 1
                      */
    66              final Class<? extends ICallbackInterface> type) {
    67  		this.myParser = parser;
    68  		this.myManager = manager;
    69          this.type = type;
    70  	}
    71  	
    72  	/**
    73  	 * Add a callback pointer to the appropriate ArrayList.
    74  	 *
    75  	 * @param eMethod OBject to callback to.
    76  	 */
    77  	protected final void addCallback(final ICallbackInterface eMethod) {
        		 /* 
    P/P 		  *  Method: void addCallback(ICallbackInterface)
        		  * 
        		  *  Preconditions:
        		  *    this.callbackInfo != null
        		  * 
        		  *  Test Vectors:
        		  *    java.util.List:contains(...)@78: {1}, {0}
        		  */
    78  		if (!callbackInfo.contains(eMethod)) {
    79              callbackInfo.add(eMethod);
    80          }
    81  	}
    82  	
    83  	/**
    84  	 * Delete a callback pointer from the appropriate ArrayList.
    85  	 *
    86  	 * @param eMethod Object that was being called back to.
    87  	 */
    88  	protected final void delCallback(final ICallbackInterface eMethod) {
                 /* 
    P/P           *  Method: void delCallback(ICallbackInterface)
                  * 
                  *  Preconditions:
                  *    this.callbackInfo != null
                  */
    89          callbackInfo.remove(eMethod);
    90  	}
    91  	
    92  	/**
    93  	 * Call the OnErrorInfo callback.
    94  	 *
    95  	 * @param errorInfo ParserError object to pass as error.
    96  	 * @return true if error call succeeded, false otherwise
    97  	 */
    98  	protected final boolean callErrorInfo(final ParserError errorInfo) {
        		 /* 
    P/P 		  *  Method: bool callErrorInfo(ParserError)
        		  * 
        		  *  Preconditions:
        		  *    this.myManager != null
        		  *    this.myManager.callbackHash != null
        		  * 
        		  *  Presumptions:
        		  *    getCallbackType(...)@99 init'ed
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  */
    99  		return myManager.getCallbackType("OnErrorInfo").call(errorInfo);
   100  	}
   101  	
   102  	/**
   103  	 * Add a new callback.
   104  	 *
   105  	 * @param eMethod Object to callback to.
   106  	 */
        	 /* 
    P/P 	  *  Method: void add(ICallbackInterface)
        	  * 
        	  *  Preconditions:
        	  *    this.callbackInfo != null
        	  */
   107  	public void add(final ICallbackInterface eMethod) { addCallback(eMethod); }
   108  	
   109  	/**
   110  	 * Remove a callback.
   111  	 *
   112  	 * @param eMethod Object to remove callback to.
   113  	 */
        	 /* 
    P/P 	  *  Method: void del(ICallbackInterface)
        	  * 
        	  *  Preconditions:
        	  *    this.callbackInfo != null
        	  */
   114  	public void del(final ICallbackInterface eMethod) { delCallback(eMethod); }
   115  	
   116  	/**
   117  	 * Get the name for this callback.
   118  	 *
   119  	 * @return Name of callback
   120  	 */
   121  	public String getName() {
        		 /* 
    P/P 		  *  Method: String getName()
        		  * 
        		  *  Preconditions:
        		  *    this.type != null
        		  * 
        		  *  Presumptions:
        		  *    java.lang.Class:getSimpleName(...)@122 != null
        		  * 
        		  *  Postconditions:
        		  *    java.lang.StringBuilder:toString(...)._tainted == 0
        		  *    return_value == &amp;java.lang.StringBuilder:toString(...)
        		  */
   122  		return "On" + type.getSimpleName().substring(1); // Trim the 'I'
   123  	}
   124  	
   125  	/**
   126  	 * Get the name for this callback in lowercase.
   127  	 *
   128  	 * @return Name of callback, in lowercase
   129  	 */
        	 /* 
    P/P 	  *  Method: String getLowerName()
        	  * 
        	  *  Preconditions:
        	  *    this.type != null
        	  * 
        	  *  Postconditions:
        	  *    return_value != null
        	  */
   130  	public final String getLowerName() { return this.getName().toLowerCase(); }
   131  
   132      /**
   133       * Actually calls this callback. The specified arguments must match those
   134       * specified in the callback's interface, or an error will be raised.
   135       *
   136       * @param args The arguments to pass to the callback implementation
   137       * @return True if a method was called, false otherwise
   138       */
   139      public boolean call(final Object ... args) {
        		 /* 
    P/P 		  *  Method: bool call(Object[])
        		  * 
        		  *  Preconditions:
        		  *    args != null
        		  *    this.myParser != null
        		  *    init'ed(this.myParser.createFake)
        		  *    (soft) init'ed(args[...])
        		  *    (soft) this.myManager != null
        		  *    (soft) this.myManager.callbackHash != null
        		  *    (soft) init'ed(this.myParser.lastLine)
        		  *    (soft) this.type != null
        		  * 
        		  *  Presumptions:
        		  *    java.lang.Class:getMethods(...).length@152 >= 1
        		  *    java.lang.Class:getMethods(...)@152 != null
        		  *    java.lang.Class:getMethods(...)[0]@152 != null
        		  *    java.util.ArrayList:iterator(...)@150 != null
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  * 
        		  *  Test Vectors:
        		  *    this.myParser.createFake: {0}, {1}
        		  *    java.util.Iterator:hasNext(...)@150: {0}, {1}
        		  */
   140  		boolean bResult = false;
   141  
   142          final Object[] newArgs = new Object[args.length + 1];
   143          System.arraycopy(args, 0, newArgs, 1, args.length);
   144          newArgs[0] = myParser;
   145  
   146          if (myParser.getCreateFake()) {
   147              createFakeArgs(newArgs);
   148          }
   149  
   150  		for (ICallbackInterface iface : new ArrayList<ICallbackInterface>(callbackInfo)) {
   151  			try {
   152                  type.getMethods()[0].invoke(iface, newArgs);
   153  			} catch (Exception e) {
   154  				final ParserError ei = new ParserError(ParserError.ERROR_ERROR,
   155                          "Exception in callback ("+e.getMessage()+")", myParser.getLastLine());
   156  				ei.setException(e);
   157  				callErrorInfo(ei);
   158  			}
   159  			bResult = true;
   160  		}
   161  		return bResult;
   162      }
   163  
   164      /**
   165       * Replaces all null entries in the specified array with fake values,
   166       * if the corresponding parameter of this callback's type is marked with
   167       * the {@link FakableArgument} annotation. The fake classes are constructed
   168       * by using parameters designated {@link FakableSource}.
   169       *
   170       * @param args The arguments to be faked
   171       */
   172      protected void createFakeArgs(final Object[] args) {
                 /* 
    P/P           *  Method: void createFakeArgs(Object[])
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) args != null
                  *    (soft) args.length >= 1
                  *    (soft) init'ed(args[...])
                  * 
                  *  Presumptions:
                  *    arr$.length@175 <= args.length
                  *    arr$.length@175 <= 232-1
                  *    arr$.length@175 in {1..232-1}
                  *    arr$.length@175 >= 1
                  *    arr$[i$]@175 != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    init'ed(args[...])
                  * 
                  *  Test Vectors:
                  *    java.lang.Object:equals(...)@177: {0}, {1}
                  */
   173          int i = 0;
   174  
   175          for (Annotation[] anns : type.getMethods()[0].getParameterAnnotations()) {
   176              for (Annotation ann : anns) {
   177                  if (ann.annotationType().equals(FakableArgument.class)
   178                          && args[i] == null) {
   179                      args[i] = getFakeArg(args, type.getMethods()[0].getParameterTypes()[i]);
   180                  }
   181              }
   182  
   183              i++;
   184          }
   185      }
   186  
   187      /**
   188       * Tries to create fake argument of the specified target class, by using
   189       * {@link FakableSource} denoted parameters from the specified arg array.
   190       *
   191       * If an argument is missing, the method attempts to create a fake instance
   192       * by recursing into this method again. Note that this could cause an
   193       * infinite recursion in cases of cyclic dependencies. If recursion fails,
   194       * the constructor is skipped.
   195       *
   196       * If the created object has a <code>setFake(boolean)</code> method, it
   197       * is automatically invoked with an argument of <code>true</code>.
   198       *
   199       * @param args The arguments array to use for sources
   200       * @param target The class that should be constructed
   201       * @return An instance of the target class, or null on failure
   202       */
   203      protected Object getFakeArg(final Object[] args, final Class<?> target) {
                 /* 
    P/P           *  Method: Object getFakeArg(Object[], Class)
                  * 
                  *  Preconditions:
                  *    target != null
                  *    this.type != null
                  *    (soft) args != null
                  *    (soft) args.length >= 1
                  *    (soft) init'ed(args[...])
                  * 
                  *  Presumptions:
                  *    arr$.length@207 in {1..232-1}
                  *    arr$.length@207 <= 232-1
                  *    arr$.length@207 <= args.length
                  *    arr$.length@207 - arr$.length@207 in {0..232-1}
                  *    arr$.length@217 <= 232-1
                  *    ...
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.lang.Object:equals(...)@209: {0}, {1}
                  *    java.lang.Object:equals(...)@241: {0}, {1}
                  *    java.lang.String:equals(...)@241: {0}, {1}
                  *    java.lang.reflect.Method:getParameterTypes(...).length@241: {0, 2..+Inf}, {1}
                  *    java.util.Map:containsKey(...)@225: {0}, {1}
                  */
   204          final Map<Class, Object> sources = new HashMap<Class, Object>();
   205          int i = 0;
   206  
   207          for (Annotation[] anns : type.getMethods()[0].getParameterAnnotations()) {
   208              for (Annotation ann : anns) {
   209                  if (ann.annotationType().equals(FakableSource.class)) {
   210                      sources.put(type.getMethods()[0].getParameterTypes()[i], args[i]);
   211                  }
   212              }
   213  
   214              i++;
   215          }
   216  
   217          for (Constructor<?> ctor : target.getConstructors()) {
   218              Object[] params = new Object[ctor.getParameterTypes().length];
   219  
   220              i = 0;
   221              Object param;
   222              boolean failed = false;
   223  
   224              for (Class<?> needed : ctor.getParameterTypes()) {
   225                  if (sources.containsKey(needed)) {
   226                      params[i] = sources.get(needed);
   227                  } else if ((param = getFakeArg(args, needed)) != null) {
   228                      params[i] = param;
   229                  } else {
   230                      failed = true;
   231                  }
   232  
   233                  i++;
   234              }
   235  
   236              if (!failed) {
   237                  try {
   238                      final Object instance = ctor.newInstance(params);
   239  
   240                      for (Method method : target.getMethods()) {
   241                          if (method.getName().equals("setFake")
   242                                  && method.getParameterTypes().length == 1
   243                                  && method.getParameterTypes()[0].equals(Boolean.TYPE)) {
   244  
   245                              method.invoke(instance, true);
   246                          }
   247                      }
   248  
   249                      return instance;
   250                  } catch (InstantiationException ex) {
   251                      // Do nothing
   252                  } catch (IllegalAccessException ex) {
   253                      // Do nothing
   254                  } catch (IllegalArgumentException ex) {
   255                      // Do nothing
   256                  } catch (InvocationTargetException ex) {
   257                      // Do nothing
   258                  }
   259              }
   260          }
   261  
   262          return null;
   263      }
   264  
   265  }








SofCheck Inspector Build Version : 2.17854
CallbackObject.java 2009-Jun-25 01:54:24
CallbackObject.class 2009-Sep-02 17:04:12