com.industrieit.ohr.OHRJavassister.java Source code

Java tutorial

Introduction

Here is the source code for com.industrieit.ohr.OHRJavassister.java

Source

/*
   Copyright 2013 Industrie IT Pty Ltd
    
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
    
   http://www.apache.org/licenses/LICENSE-2.0
    
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package com.industrieit.ohr;

import com.industrieit.ohr.array.LongInlineOHRArray;
import com.industrieit.ohr.array.OHRLongArray;
import com.industrieit.ohr.array.BooleanInlineOHRArray;
import com.industrieit.ohr.array.OHRBooleanArray;
import com.industrieit.ohr.array.ByteInlineOHRArray;
import com.industrieit.ohr.array.OHRByteArray;
import com.industrieit.ohr.array.DoubleInlineOHRArray;
import com.industrieit.ohr.array.OHRDoubleArray;
import com.industrieit.ohr.array.FloatInlineOHRArray;
import com.industrieit.ohr.array.OHRFloatArray;
import com.industrieit.ohr.array.IntInlineOHRArray;
import com.industrieit.ohr.array.IntInlineOHRArrayUnchecked;
import com.industrieit.ohr.array.OHRIntArray;
import com.industrieit.ohr.array.ShortInlineOHRArray;
import com.industrieit.ohr.array.OHRShortArray;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Externalizable;
import javassist.CtClass;
import javassist.CtMethod;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.StringTokenizer;
import javassist.CannotCompileException;

import static javassist.ClassPool.getDefault;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtNewMethod;
import javassist.NotFoundException;

import org.apache.commons.io.IOUtils;

import sun.misc.Unsafe;

public class OHRJavassister {

    private static Class[] cls = new Class[1000];
    private static int clcounter = 33;
    //private static int clincrement=133;
    private static IdentityHashMap<Class, Class> processed2 = new IdentityHashMap<Class, Class>();

    private static Class[] propertyOrdering = { OHRBase.class, OHRLongArray.class, OHRDoubleArray.class,
            Object.class, long.class, double.class, int.class, OHRIntArray.class, float.class, OHRFloatArray.class,
            short.class, OHRShortArray.class, String.class, CharSequence.class, byte.class, OHRByteArray.class,
            boolean.class, OHRBooleanArray.class };

    public static Class getClassForId(int id) {
        return cls[id];
    }

    private static Object incMutex = new Object();

    public static int incrementClsCounter() {
        synchronized (incMutex) {
            clcounter++;
            return clcounter;
        }

    }

    static int registerExternalOHR(Class cl) {
        int cnt = incrementClsCounter();
        cls[cnt] = cl;
        return cnt;
    }

    public static Class ohr(Class cll) {
        try {
            //System.out.println("++++++++++ "+cll.getName());
            /*if (cll.getName().startsWith("ohr."))
            {
            throw new RuntimeException(cll.getName());
            }*/
            if (processed2.containsKey(cll)) {
                return processed2.get(cll);
            }

            HashSet<Long> handleOffsets = new HashSet<Long>();

            String cnam = cll.getName();
            if (!cnam.startsWith("ohr.")) {
                cnam = "ohr." + cll.getName();
                //cnam=cnam.substring(4);
            }

            Class cl = Class.forName(cnam.substring(4));

            int clnumber = incrementClsCounter();

            List<Integer> owned = new ArrayList<Integer>();

            //remove the old implementation if its around from another process
            String fname = "target/classes/" + cnam.replace(".", "/") + ".class";
            System.out.println("deleted" + fname + " " + (new File(fname).delete()));

            if (!Modifier.isAbstract(cl.getModifiers())) {
                throw new RuntimeException("not an abstract class " + cl.getName());
            }

            System.out.println("processing ohr " + cnam);

            CtClass bc = getDefault().getCtClass(cl.getName());
            CtClass cc = getDefault().makeClass(cnam, bc);

            StringBuilder initBuilder = new StringBuilder();
            initBuilder.append("public void internalInit() {\n");

            StringBuilder constructBuilder = new StringBuilder();
            constructBuilder.append("{");

            String intname = OHRBase.class.getName();
            System.out.println("intername is " + intname);

            CtClass ci = getDefault().getCtClass(intname);
            CtClass extern = getDefault().getCtClass(Externalizable.class.getName());

            //cc.addInterface(ci);
            cc.setInterfaces(new CtClass[] { ci, extern });
            cc.setSuperclass(bc);

            //add base implmenetation methods and properties
            setBaseMixinsPre(cc, false);

            //first long for id and other stuff
            long offset = 8;

            BeanInfo bi = Introspector.getBeanInfo(cl);
            PropertyDescriptor[] pds = bi.getPropertyDescriptors();

            for (int co = 0; co < propertyOrdering.length; co++) {
                Class cprop = propertyOrdering[co];

                for (int i = 0; i < pds.length; i++) {
                    // Get property name
                    String propName = pds[i].getName();

                    if (propName.equals("class")) {
                        continue;
                    }

                    String typ = pds[i].getPropertyType().getName();
                    Class type = pds[i].getPropertyType();
                    //if (propName.startsWith("fath"))
                    //PL.pl("[[[[["+type+" "+propName+" "+cprop);
                    if (cprop == Object.class) {
                        //handle refs only
                        if (type.isPrimitive()) {
                            continue;
                        }
                        if (type == String.class) {
                            continue;
                        }
                        if (type == CharSequence.class) {
                            continue;
                        }
                        if (type == OHRLongArray.class) {
                            continue;
                        }
                        if (type == OHRIntArray.class) {
                            continue;
                        }
                        if (type == OHRShortArray.class) {
                            continue;
                        }
                        if (type == OHRByteArray.class) {
                            continue;
                        }
                        if (type == OHRBooleanArray.class) {
                            continue;
                        }
                        if (type == OHRDoubleArray.class) {
                            continue;
                        }
                        if (type == OHRFloatArray.class) {
                            continue;
                        }
                    } else if (cprop != type) {
                        //PL.pl("skipping "+type+" "+cprop);
                        continue;
                    }
                    //PL.pl("[[[[[    " + type + " - " + propName + " - " + cprop);
                    //System.out.println("--prop--" + propName);

                    String rname = pds[i].getReadMethod().getName();
                    String wname = null;
                    if (pds[i].getWriteMethod() != null) {
                        wname = pds[i].getWriteMethod().getName();
                    }

                    boolean reifread = isMethodReifAnnotated(pds[i].getReadMethod());
                    boolean reifwrite = isMethodReifAnnotated(pds[i].getWriteMethod());

                    String wcons = getConsistencyAsString(pds[i].getWriteMethod());
                    String rcons = getConsistencyAsString(pds[i].getReadMethod());

                    System.out.println("TYPE " + pds[i].getPropertyType().getName() + " "
                            + pds[i].getPropertyType().getInterfaces());

                    if (pds[i].getPropertyType() == String.class && isInlineString(pds[i])) {
                        //NOTE - only for inline strings - normal strings are handled as extrefs like any other object
                        System.out.println("ITS An inline string!!!!");

                        int length = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class).length();
                        boolean trim = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class)
                                .trimOverflow();
                        boolean ascii = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class).asciiOnly();

                        String wmeth = "public void " + wname + "(" + typ + " o) { ohwritestr" + wcons + "("
                                + offset + "l,o," + length + "," + trim + "," + ascii + "); }";
                        //add setter
                        CtMethod wmethod = CtNewMethod.make(wmeth, cc);

                        cc.addMethod(wmethod);

                        System.out.println(wmeth);
                        String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohreadstr" + rcons
                                + "(" + offset + "l," + ascii + "); }";
                        //add setter
                        CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                        //rmethod.getMethodInfo().addAttribute(attr);
                        cc.addMethod(rmethod);
                        System.out.println(rmeth);

                        int bytesperchar = ascii ? 1 : 2;

                        //pad to 16 bits
                        int ll = 4 + length * bytesperchar;
                        if (ll % 2 != 0) {
                            ll++;
                        }
                        offset += ll; //lebgth marker as well as unicode 16 encoded characters
                    } else if (pds[i].getPropertyType() == CharSequence.class && isInlineString(pds[i])) {
                        //NOTE - only for inline strings - normal strings are handled as extrefs like any other object
                        System.out.println("ITS An inline charsequence!!!!");

                        int length = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class).length();
                        boolean trim = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class)
                                .trimOverflow();
                        boolean ascii = pds[i].getWriteMethod().getAnnotation(InlineStringReify.class).asciiOnly();
                        String wmeth = "public void " + wname + "(" + typ + " o) { ohwritestr" + wcons + "("
                                + offset + "l,o," + length + "," + trim + "," + ascii + "); }";
                        //add setter
                        CtMethod wmethod = CtNewMethod.make(wmeth, cc);

                        cc.addMethod(wmethod);

                        System.out.println(wmeth);
                        String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohreadcs" + rcons
                                + "(" + offset + "l," + ascii + "); }";
                        //add setter
                        CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                        //rmethod.getMethodInfo().addAttribute(attr);
                        cc.addMethod(rmethod);
                        System.out.println(rmeth);

                        int bytesperchar = ascii ? 1 : 2;
                        //pad to 8 byte boundary!
                        int ll = (int) Math.ceil((4.0 + length * bytesperchar) / 8) * 8;
                        offset += ll; //lebgth marker as well as unicode 16 encoded characters
                    } else if ((pds[i].getPropertyType() == OHRLongArray.class
                            || pds[i].getPropertyType() == OHRIntArray.class
                            || pds[i].getPropertyType() == OHRShortArray.class
                            || pds[i].getPropertyType() == OHRByteArray.class
                            || pds[i].getPropertyType() == OHRFloatArray.class
                            || pds[i].getPropertyType() == OHRDoubleArray.class
                            || pds[i].getPropertyType() == OHRBooleanArray.class)
                            && pds[i].getReadMethod().isAnnotationPresent(InlineArrayReify.class)) {

                        int bitsperitem = 0;
                        String cldef = null;
                        Class at = pds[i].getPropertyType();
                        boolean unchecked = pds[i].getReadMethod().isAnnotationPresent(UncheckedBoundsXXX.class);
                        if (at == OHRLongArray.class) {
                            bitsperitem = 8 * 8;
                            cldef = LongInlineOHRArray.class.getName();
                        } else if (at == OHRIntArray.class) {
                            bitsperitem = 4 * 8;
                            //cldef=IntInlineOHRArrayCop.class.getName();
                            if (unchecked) {
                                cldef = IntInlineOHRArrayUnchecked.class.getName();
                            } else {
                                cldef = IntInlineOHRArray.class.getName();
                            }
                        }
                        if (at == OHRDoubleArray.class) {
                            bitsperitem = 8 * 8;
                            cldef = DoubleInlineOHRArray.class.getName();
                        }
                        if (at == OHRFloatArray.class) {
                            bitsperitem = 4 * 8;
                            cldef = FloatInlineOHRArray.class.getName();
                        }
                        if (at == OHRShortArray.class) {
                            bitsperitem = 2 * 8;
                            cldef = ShortInlineOHRArray.class.getName();
                        }
                        if (at == OHRByteArray.class) {
                            bitsperitem = 1 * 8;
                            cldef = ByteInlineOHRArray.class.getName();
                        }
                        if (at == OHRBooleanArray.class) {
                            bitsperitem = 1;
                            cldef = BooleanInlineOHRArray.class.getName();
                        }
                        //NOTE - only for inline strings - normal strings are handled as extrefs like any other object
                        System.out.println("ITS An inline array!!!!");

                        int length = pds[i].getReadMethod().getAnnotation(InlineArrayReify.class).length();

                        long bytealloc = OHRInlineArrayHandler.getGenericArrayAllocationSize(bitsperitem, length);

                        //PL.pl("byte allocation for logn array length "+length+" "+bytealloc);

                        CtClass ctc = getDefault().getCtClass(cldef);

                        String varname = "var" + i;
                        CtField cf = new CtField(ctc, varname, cc);
                        cf.setModifiers(Modifier.PRIVATE);
                        cc.addField(cf);

                        //add data to constructor
                        initBuilder.append(
                                "com.industrieit.ohr.OHRInlineArrayHandler.initialiseInlineGenericArray(this.basePtr+"
                                        + offset + "l," + length + "l," + bitsperitem + ");\n");
                        constructBuilder.append(varname + "=new " + cldef + "(this," + offset + "l);\n");

                        //+ "//this.basePtr"+offset+"l);");

                        //String wmeth = "public void " + wname + "(" + typ + " o) { throw new java.lang.RuntimeException(\"not supported\"); }";
                        //add setter
                        //CtMethod wmethod = CtNewMethod.make(wmeth, cc);

                        //cc.addMethod(wmethod);

                        //System.out.println(wmeth);
                        String rmeth = "public " + typ + " " + rname + "() { return " + varname + "; }";
                        //add setter
                        CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                        //rmethod.getMethodInfo().addAttribute(attr);
                        cc.addMethod(rmethod);
                        System.out.println("||||||||" + rmeth + "|||||||||");

                        offset += bytealloc;
                    } else if (pds[i].getPropertyType().isPrimitive()) {
                        //PL.pl("ITS A PRIMITIVE!");
                        int vv = 0;
                        if (cprop == long.class) {
                            vv = 8;
                        }
                        if (cprop == double.class) {
                            vv = 8;
                        }
                        if (cprop == int.class) {
                            vv = 4;
                        }
                        if (cprop == float.class) {
                            vv = 4;
                        }
                        if (cprop == short.class) {
                            vv = 2;
                        }
                        if (cprop == byte.class) {
                            vv = 1;
                        }

                        System.out.println(
                                "for " + pds[i].getName() + " typ is " + pds[i].getPropertyType().getName());

                        String wmeth = "public void " + wname + "(" + typ + " o) { ohwrite" + wcons + "(" + offset
                                + "l,o); }";
                        //add setter

                        //ConstPool constpool = cc.getClassFile().getConstPool();

                        if (reifwrite) {
                            CtMethod wmethod = CtNewMethod.make(wmeth, cc);
                            cc.addMethod(wmethod);
                            System.out.println("&&&&&&&" + wmeth);
                        }

                        String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohread" + typ
                                + rcons + "(" + offset + "l); }";
                        //add setter

                        //rmethod.getMethodInfo().addAttribute(attr);
                        if (reifread) {
                            CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                            cc.addMethod(rmethod);
                            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&" + rmeth + vv);
                        }

                        offset += vv;
                    } else {
                        System.out.println("ITS AN ASSUMED REIFY!!!");

                        if (pds[i].getWriteMethod().isAnnotationPresent(Owned.class)) {
                            owned.add(i);
                        }
                        //CtClass tc = getDefault().getCtClass(pds[i].getPropertyType().getName());
                        CtClass tc = getDefault().getCtClass(OHRBase.class.getName());
                        //String fnam="ohrt"+i;
                        //CtField f = new CtField(tc, fnam, cc);
                        //f.setModifiers(Modifier.PROTECTED);
                        //cc.addField(f);
                        //store by reify
                        //handleOffsets.add(offset);
                        String wmeth = "public void " + wname + "(" + typ + " o) { ohwritere" + wcons + "(" + offset
                                + "l,o); }";
                        //add setter
                        CtMethod wmethod = CtNewMethod.make(wmeth, cc);

                        if (reifwrite) {
                            cc.addMethod(wmethod);
                        }

                        System.out.println(wmeth);
                        //String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohreadre(" + offset + "l," + typ + ".class); }";
                        String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohreadre" + rcons
                                + "(" + offset + "l);  };";
                        //add setter
                        CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                        //rmethod.getMethodInfo().addAttribute(attr);
                        if (reifread) {
                            cc.addMethod(rmethod);
                        }
                        System.out.println(rmeth);
                        handleOffsets.add(offset);
                        offset += 8;
                    }

                    /* if (!isReif(type)) {
                        
                    PL.pl(""+pds[i].getName()+" is a non reified handle!!!!");
                    //store by handle
                    handleOffsets.add(offset);
                    String wmeth = "public void " + wname + "(" + typ + " o) { ohwritehand(" + offset + "l,o); }";
                    //add setter
                    CtMethod wmethod = CtNewMethod.make(wmeth, cc);
                        
                    if (reifwrite) {
                        cc.addMethod(wmethod);
                    }
                        
                    System.out.println(wmeth);
                    String rmeth = "public " + typ + " " + rname + "() { return (" + typ + ") ohreadhand(" + offset + "l); }";
                    //add setter
                        
                    CtMethod rmethod = CtNewMethod.make(rmeth, cc);
                    //rmethod.getMethodInfo().addAttribute(attr);
                    if (reifread) {
                        cc.addMethod(rmethod);
                    }
                    System.out.println(rmeth);
                    }*/
                }

                //PL.pl("offset is "+offset);

            }
            //offset+=8;
            //ok create the get handleoffsets method

            //print out total byts allocated
            //PL.pl("%%%%%%%%%% TOTAL BYTES = " + offset);

            StringBuilder sb = new StringBuilder();
            sb.append("public long[] handleOffsets() { ");
            sb.append("long a[] = new long[").append(handleOffsets.size()).append("];");
            int c = 0;
            for (long l : handleOffsets) {
                sb.append("a[").append(c).append("]=").append(l).append("l;");
                c++;
            }
            sb.append("return a; }");

            System.out.println(sb.toString());
            CtMethod om = CtNewMethod.make(sb.toString(), cc);
            cc.addMethod(om);

            String sizem = "public long gsize() { return " + (offset) + "l; }";
            //PL.pl(sizem);

            CtMethod sm = CtNewMethod.make(sizem, cc);
            cc.addMethod(sm);

            //add clsid
            CtMethod cmid = CtNewMethod.make("public int ohclassId() { return " + clnumber + "; }", cc);
            cc.addMethod(cmid);

            setBaseMixinsPost(cc, false, owned, pds, constructBuilder, initBuilder);

            cc.writeFile("target/classes");

            /*for (Method me : cc.toClass().getDeclaredMethods()) { //test print, ok
             //System.out.println(me.getName());
             }*/

            Class ppp = Class.forName(cnam);
            Field f = ppp.getDeclaredField("u");
            f.setAccessible(true);
            f.set(ppp.newInstance(), USafe.getUnsafe());
            //synchronized (mutex)
            //{
            processed2.put(cl, ppp);
            processed2.put(ppp, ppp);
            cls[clnumber] = ppp;
            return ppp;
            //}

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static Object mutex = new Object();
    private static HashMap<Class, Boolean> reifcache = new HashMap<Class, Boolean>();

    /*private static boolean isOHROverride(PropertyDescriptor pd)
    {
    boolean b=false;
    PL.pl("write method "+pd.getWriteMethod()+" rm "+pd.getReadMethod());
    if (pd.getWriteMethod()!=null)
    {
        PL.pl("is ohr override write method not false "+pd.getName());
        b= pd.getWriteMethod().isAnnotationPresent(OHR.class);
    }
    PL.pl("is ohr override "+pd.getName()+" "+b);
    return b;
    }*/

    private static boolean isAlreadyReifXXXXX(Class cl) {

        Boolean b = reifcache.get(cl);
        //PL.pl("jjjjjjjjjjjjj testing reif "+cl+" "+b);
        if (b != null) {
            return b.booleanValue();
        }

        reifcache.put(cl, Boolean.TRUE);
        return true;

        /*for (Class c : cl.getInterfaces()) {
        //System.out.println("class "+c.getName());
        if (c == OHReify.class) {
            //System.out.println("inside");
            reifcache.put(cl, Boolean.TRUE);
            return true;
        }
        }
            
        reifcache.put(cl, Boolean.FALSE);
        return false;*/
    }

    /*public long[] r() {
     long a[] = new long[3];
     a[1] = 2l;
     return a;
     }*/
    static Unsafe u;
    static {
        u = USafe.getUnsafe();
    }

    private static boolean isMethodReifAnnotated(Method m) {
        if (m == null) {
            return false;
        }
        return m.isAnnotationPresent(Reify.class);
    }

    private static boolean isInlineString(PropertyDescriptor pd) {
        return pd.getWriteMethod().isAnnotationPresent(InlineStringReify.class);
    }

    private static String getConsistencyAsString(Method meth) {
        return getConsistency(meth).name();
    }

    private static Consistency getConsistency(Method meth) {
        try {
            if (meth == null) {
                return Consistency.NORMAL;
            }
            Reify r = (Reify) meth.getAnnotation(Reify.class);
            return r.consistency();
        } catch (Exception e) {
            //never happens
            throw new RuntimeException(e);
        }
    }

    private static void setBaseMixinsPre(CtClass cc, boolean includeChecks)
            throws CannotCompileException, IOException, NotFoundException {
        //add fields

        //add basePtr
        //CtField cf = new CtField(CtClass.longType, "crapField", cc);
        //cf.setModifiers(Modifier.PRIVATE | Modifier.VOLATILE);
        //cc.addField(cf);

        //add basePtr
        CtField f = new CtField(CtClass.longType, "basePtr", cc);
        f.setModifiers(Modifier.PRIVATE | Modifier.VOLATILE);
        cc.addField(f);

        //add instmarker
        CtField fm = new CtField(CtClass.intType, "instmarker", cc);
        fm.setModifiers(Modifier.PRIVATE | Modifier.VOLATILE);
        cc.addField(fm);

        CtClass cu = getDefault().get("sun.misc.Unsafe");
        CtField f2 = new CtField(cu, "u", cc);
        f2.setModifiers(Modifier.STATIC | Modifier.PRIVATE);
        cc.addField(f2);

        //add check method
        String checkmeth = "public void doOHRCheck() { if (u.getInt(basePtr+4)!=instmarker) throw new com.industrieit.ohr.StaleHandleException(\"bad instmarker\"); }";
        //PL.pl(checkmeth);
        CtMethod cm = CtNewMethod.make(checkmeth, cc);
        cc.addMethod(cm);

        String str = IOUtils.toString(OHRJavassister.class.getResourceAsStream("/ohr/base/basemethodspre.txt"));

        String checkplace = "";
        if (includeChecks) {
            checkplace = "doOHRCheck();";
        }
        //place in prechecks if desired
        str = str.replace("<<READCHECK>>", checkplace);
        str = str.replace("<<WRITECHECK>>", checkplace);

        StringTokenizer st = new StringTokenizer(str, "~~~");

        while (st.hasMoreElements()) {
            String meth = st.nextToken();
            //PL.pl("adding method: " + meth);
            CtMethod wmethod = CtNewMethod.make(meth, cc);
            cc.addMethod(wmethod);
        }
    }

    private static void setBaseMixinsPost(CtClass cc, boolean includeChecks, List<Integer> owned,
            PropertyDescriptor[] pds, StringBuilder constructBuilder, StringBuilder initBuilder)
            throws CannotCompileException, IOException, NotFoundException {
        //empty constrcutor
        constructBuilder.append("}");
        System.out.println(constructBuilder.toString());
        CtConstructor ctc = new CtConstructor(new CtClass[0], cc);
        ctc.setBody(constructBuilder.toString());
        cc.addConstructor(ctc);

        initBuilder.append("\n}");
        System.out.println(initBuilder.toString());
        CtMethod initmeth = CtNewMethod.make(initBuilder.toString(), cc);
        cc.addMethod(initmeth);

        StringBuilder sb = new StringBuilder();
        sb.append("public void freeOwnedChildren() {");
        for (Integer i : owned) {
            String fnam = pds[i].getName();
            sb.append("com.industreiit.ohr.Reifier.freeOHR(" + pds[i].getReadMethod().getName() + "());");
        }
        sb.append("}");
        CtMethod owm = CtNewMethod.make(sb.toString(), cc);
        cc.addMethod(owm);

        String str = IOUtils.toString(OHRJavassister.class.getResourceAsStream("/ohr/base/basemethodspost.txt"));

        String checkplace = "";
        if (includeChecks) {
            checkplace = "doOHRCheck();";
        }

        str = str.replace("<<READCHECK>>", checkplace);
        str = str.replace("<<WRITECHECK>>", checkplace);

        StringTokenizer st = new StringTokenizer(str, "~~~");

        while (st.hasMoreElements()) {
            String meth = st.nextToken();
            //PL.pl("adding method: " + meth);
            CtMethod wmethod = CtNewMethod.make(meth, cc);
            cc.addMethod(wmethod);
        }

    }
}