Coverage Report - org.apache.tapestry.enhance.ClassFabImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassFabImpl
0%
0/93
0%
0/20
2.438
ClassFabImpl$AddedConstructor
0%
0/27
0%
0/10
2.438
 
 1  
 // Copyright 2007 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 // http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 package org.apache.tapestry.enhance;
 15  
 
 16  
 import java.lang.reflect.Modifier;
 17  
 import java.util.ArrayList;
 18  
 import java.util.HashMap;
 19  
 import java.util.Iterator;
 20  
 import java.util.List;
 21  
 import java.util.Map;
 22  
 
 23  
 import javassist.CannotCompileException;
 24  
 import javassist.CtClass;
 25  
 import javassist.CtConstructor;
 26  
 import javassist.CtField;
 27  
 import javassist.CtMethod;
 28  
 import javassist.NotFoundException;
 29  
 
 30  
 import org.apache.hivemind.ApplicationRuntimeException;
 31  
 import org.apache.hivemind.service.ClassFab;
 32  
 import org.apache.hivemind.service.MethodFab;
 33  
 import org.apache.hivemind.service.MethodSignature;
 34  
 
 35  
 /**
 36  
  * Implementation replacement for hivemind {@link ClassFab} utiltity to get around some javassist
 37  
  * incompatibilties found with the latest 3.4 version of javassist.
 38  
  * 
 39  
  * @author jkuhnert
 40  
  */
 41  
 public class ClassFabImpl extends AbstractFab implements ClassFab
 42  
 {
 43  
     /**
 44  
      * Stores information about a constructor; used by toString().
 45  
      * 
 46  
      * @since 1.1
 47  
      */
 48  
 
 49  
     private class AddedConstructor
 50  
     {
 51  
         private Class[] _parameterTypes;
 52  
 
 53  
         private Class[] _exceptionTypes;
 54  
 
 55  
         private String _body;
 56  
 
 57  
         AddedConstructor(Class[] parameterTypes, Class[] exceptionTypes, String body)
 58  0
         {
 59  0
             _parameterTypes = parameterTypes;
 60  0
             _exceptionTypes = exceptionTypes;
 61  0
             _body = body;
 62  0
         }
 63  
 
 64  
         public String toString()
 65  
         {
 66  0
             StringBuffer buffer = new StringBuffer();
 67  
 
 68  0
             buffer.append("public ");
 69  0
             buffer.append(getCtClass().getName());
 70  
 
 71  0
             buffer.append("(");
 72  
 
 73  0
             int count = size(_parameterTypes);
 74  0
             for(int i = 0; i < count; i++) {
 75  0
                 if (i > 0) buffer.append(", ");
 76  
 
 77  0
                 buffer.append(_parameterTypes[i].getName());
 78  
 
 79  0
                 buffer.append(" $");
 80  0
                 buffer.append(i + 1);
 81  
             }
 82  
 
 83  0
             buffer.append(")");
 84  
 
 85  0
             count = size(_exceptionTypes);
 86  0
             for(int i = 0; i < count; i++) {
 87  0
                 if (i == 0)
 88  0
                     buffer.append("\n  throws ");
 89  0
                 else buffer.append(", ");
 90  
 
 91  0
                 buffer.append(_exceptionTypes[i].getName());
 92  
             }
 93  
 
 94  0
             buffer.append("\n");
 95  0
             buffer.append(_body);
 96  
 
 97  0
             buffer.append("\n");
 98  
 
 99  0
             return buffer.toString();
 100  
         }
 101  
 
 102  
         private int size(Object[] array)
 103  
         {
 104  0
             return array == null ? 0 : array.length;
 105  
         }
 106  
     }
 107  
 
 108  
     /**
 109  
      * Map of {@link MethodFab}keyed on {@link MethodSignature}.
 110  
      */
 111  0
     private Map _methods = new HashMap();
 112  
 
 113  
     /**
 114  
      * List of {@link AddedConstructor}.
 115  
      * 
 116  
      * @since 1.1
 117  
      */
 118  
 
 119  0
     private List _constructors = new ArrayList();
 120  
 
 121  
     public ClassFabImpl(CtClassSource source, CtClass ctClass)
 122  
     {
 123  0
         super(source, ctClass);
 124  0
     }
 125  
 
 126  
     /**
 127  
      * Returns a representation of the fabricated class, including inheritance, fields,
 128  
      * constructors, methods and method bodies.
 129  
      * 
 130  
      * @since 1.1
 131  
      */
 132  
     public String toString()
 133  
     {
 134  0
         StringBuffer buffer = new StringBuffer("ClassFab[\n");
 135  
 
 136  
         try {
 137  0
             buildClassAndInheritance(buffer);
 138  
 
 139  0
             buildFields(buffer);
 140  
 
 141  0
             buildConstructors(buffer);
 142  
 
 143  0
             buildMethods(buffer);
 144  
 
 145  0
         } catch (Exception ex) {
 146  0
             buffer.append(" *** ");
 147  0
             buffer.append(ex);
 148  0
         }
 149  
 
 150  0
         buffer.append("\n]");
 151  
 
 152  0
         return buffer.toString();
 153  
     }
 154  
 
 155  
     /** @since 1.1 */
 156  
     private void buildMethods(StringBuffer buffer)
 157  
     {
 158  0
         Iterator i = _methods.values().iterator();
 159  0
         while(i.hasNext()) {
 160  
 
 161  0
             MethodFab mf = (MethodFab) i.next();
 162  
 
 163  0
             buffer.append("\n");
 164  0
             buffer.append(mf);
 165  0
             buffer.append("\n");
 166  0
         }
 167  0
     }
 168  
 
 169  
     /** @since 1.1 */
 170  
     private void buildConstructors(StringBuffer buffer)
 171  
     {
 172  0
         Iterator i = _constructors.iterator();
 173  
 
 174  0
         while(i.hasNext()) {
 175  0
             buffer.append("\n");
 176  0
             buffer.append(i.next());
 177  
         }
 178  0
     }
 179  
 
 180  
     /** @since 1.1 */
 181  
     private void buildFields(StringBuffer buffer)
 182  
         throws NotFoundException
 183  
     {
 184  0
         CtField[] fields = getCtClass().getDeclaredFields();
 185  
 
 186  0
         for(int i = 0; i < fields.length; i++) {
 187  0
             buffer.append("\n");
 188  0
             buffer.append(modifiers(fields[i].getModifiers()));
 189  0
             buffer.append(" ");
 190  0
             buffer.append(fields[i].getType().getName());
 191  0
             buffer.append(" ");
 192  0
             buffer.append(fields[i].getName());
 193  0
             buffer.append(";\n");
 194  
         }
 195  0
     }
 196  
 
 197  
     /** @since 1.1 */
 198  
     private void buildClassAndInheritance(StringBuffer buffer)
 199  
         throws NotFoundException
 200  
     {
 201  0
         buffer.append(modifiers(getCtClass().getModifiers()));
 202  0
         buffer.append(" class ");
 203  0
         buffer.append(getCtClass().getName());
 204  0
         buffer.append(" extends ");
 205  0
         buffer.append(getCtClass().getSuperclass().getName());
 206  0
         buffer.append("\n");
 207  
 
 208  0
         CtClass[] interfaces = getCtClass().getInterfaces();
 209  
 
 210  0
         if (interfaces.length > 0) {
 211  0
             buffer.append("  implements ");
 212  
 
 213  0
             for(int i = 0; i < interfaces.length; i++) {
 214  0
                 if (i > 0) buffer.append(", ");
 215  
 
 216  0
                 buffer.append(interfaces[i].getName());
 217  
             }
 218  
 
 219  0
             buffer.append("\n");
 220  
         }
 221  0
     }
 222  
 
 223  
     private String modifiers(int modifiers)
 224  
     {
 225  0
         return Modifier.toString(modifiers);
 226  
     }
 227  
 
 228  
     /**
 229  
      * Returns the name of the class fabricated by this instance.
 230  
      */
 231  
     String getName()
 232  
     {
 233  0
         return getCtClass().getName();
 234  
     }
 235  
 
 236  
     public void addField(String name, Class type)
 237  
     {
 238  0
         CtClass ctType = convertClass(type);
 239  
 
 240  
         try {
 241  0
             CtField field = new CtField(ctType, name, getCtClass());
 242  0
             field.setModifiers(Modifier.PRIVATE);
 243  
 
 244  0
             getCtClass().addField(field);
 245  0
         } catch (CannotCompileException ex) {
 246  0
             throw new ApplicationRuntimeException(EnhanceMessages.unableToAddField(name, getCtClass(), ex), ex);
 247  0
         }
 248  0
     }
 249  
 
 250  
     public boolean containsMethod(MethodSignature ms)
 251  
     {
 252  0
         return _methods.get(ms) != null;
 253  
     }
 254  
 
 255  
     public MethodFab addMethod(int modifiers, MethodSignature ms, String body)
 256  
     {
 257  0
         if (_methods.get(ms) != null)
 258  0
             throw new ApplicationRuntimeException(EnhanceMessages.duplicateMethodInClass(ms, this));
 259  
         
 260  0
         if (body.indexOf("isWrapperFor") > 0 || body.indexOf("unwrap") > 0)
 261  0
             return new MethodFabImpl(null, ms, null, "{ throw new UnsupportedOperationException(\"Method not implemented\"); }");
 262  
         
 263  0
         CtClass ctReturnType = convertClass(ms.getReturnType());
 264  
 
 265  0
         CtClass[] ctParameters = convertClasses(ms.getParameterTypes());
 266  0
         CtClass[] ctExceptions = convertClasses(ms.getExceptionTypes());
 267  
         
 268  0
         CtMethod method = new CtMethod(ctReturnType, ms.getName(), ctParameters, getCtClass());
 269  
         
 270  
         try {
 271  0
             method.setModifiers(modifiers);
 272  0
             method.setBody(body);
 273  0
             method.setExceptionTypes(ctExceptions);
 274  
             
 275  0
             getCtClass().addMethod(method);
 276  0
         } catch (Exception ex) {
 277  
             
 278  0
             throw new ApplicationRuntimeException(EnhanceMessages.unableToAddMethod(ms, getCtClass(), ex), ex);
 279  0
         }
 280  
 
 281  
         // Return a MethodFab so the caller can add catches.
 282  
 
 283  0
         MethodFab result = new MethodFabImpl(getSource(), ms, method, body);
 284  
 
 285  0
         _methods.put(ms, result);
 286  
 
 287  0
         return result;
 288  
     }
 289  
     
 290  
     public MethodFab getMethodFab(MethodSignature ms)
 291  
     {
 292  0
         return (MethodFab) _methods.get(ms);
 293  
     }
 294  
 
 295  
     public void addConstructor(Class[] parameterTypes, Class[] exceptions, String body)
 296  
     {
 297  0
         CtClass[] ctParameters = convertClasses(parameterTypes);
 298  0
         CtClass[] ctExceptions = convertClasses(exceptions);
 299  
 
 300  
         try {
 301  0
             CtConstructor constructor = new CtConstructor(ctParameters, getCtClass());
 302  0
             constructor.setExceptionTypes(ctExceptions);
 303  0
             constructor.setBody(body);
 304  
 
 305  0
             getCtClass().addConstructor(constructor);
 306  
 
 307  0
             _constructors.add(new AddedConstructor(parameterTypes, exceptions, body));
 308  0
         } catch (Exception ex) {
 309  0
             throw new ApplicationRuntimeException(EnhanceMessages.unableToAddConstructor(getCtClass(), ex), ex);
 310  0
         }
 311  0
     }
 312  
 }