package org.fakereplace;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.Set;

import javassist.bytecode.ClassFile;

import org.fakereplace.api.ClassChangeNotifier;
import org.fakereplace.api.IntegrationInfo;
import org.fakereplace.boot.Enviroment;
import org.fakereplace.classloading.ClassIdentifier;
import org.fakereplace.classloading.ClassLookupManager;
import org.fakereplace.replacement.AddedClass;
import org.fakereplace.replacement.ClassRedefiner;

/**
 * The agent entry point.
 * 
 * @author stuart
 * 
 */
public class Agent
{

   static Instrumentation inst;

   static Enviroment environment;

   public static void premain(java.lang.String s, java.lang.instrument.Instrumentation i)
   {
      Set<IntegrationInfo> integrationInfo = IntegrationLoader.getIntegrationInfo(ClassLoader.getSystemClassLoader());
      inst = i;
      environment = new Enviroment();
      inst.addTransformer(new Transformer(i, integrationInfo, environment));
   }

   static public void redefine(ClassDefinition[] classes, AddedClass[] addedData) throws UnmodifiableClassException, ClassNotFoundException
   {

      final ClassIdentifier[] addedClass = new ClassIdentifier[addedData.length];
      int count = 0;
      for (AddedClass i : addedData)
      {
         addedClass[count++] = i.getClassIdentifier();
      }
      final Class<?>[] changedClasses = new Class<?>[classes.length];
      count = 0;
      for (ClassDefinition i : classes)
      {
         changedClasses[count++] = i.getDefinitionClass();
      }

      ClassChangeNotifier.beforeChange(changedClasses, addedClass);

      ClassDefinition[] modifiedClasses = ClassRedefiner.rewriteLoadedClasses(classes);
      try
      {
         for (AddedClass c : addedData)
         {
            ClassLookupManager.addClassInfo(c.getClassName(), c.getLoader(), c.getData());
         }
         inst.redefineClasses(modifiedClasses);

         // we run the integration in a new thread
         // as it may cause new classes to be loaded
         // and they need to be transformed
         Thread t = new Thread(new Runnable()
         {

            public void run()
            {
               ClassChangeNotifier.notify(changedClasses, addedClass);
            }
         });
         t.start();
      }
      catch (Throwable e)
      {
         // dump the classes to /tmp so we can look at them
         for (ClassDefinition d : modifiedClasses)
         {
            try
            {
               DataInputStream ds = new DataInputStream(new ByteArrayInputStream(d.getDefinitionClassFile()));
               ClassFile file = new ClassFile(ds);
               Transformer.getManipulator().transformClass(file, d.getDefinitionClass().getClassLoader());
               String dumpDir = environment.getDumpDirectory();
               if (dumpDir == null)
               {
                  dumpDir = "/tmp";
               }
               FileOutputStream s = new FileOutputStream(dumpDir + '/' + d.getDefinitionClass().getName() + "1.class");
               DataOutputStream dos = new DataOutputStream(s);
               file.write(dos);
               s.write(d.getDefinitionClassFile());
               s.close();
            }
            catch (IOException a)
            {
               a.printStackTrace();
            }
         }
         throw (new RuntimeException(e));
      }
   }

   public static Instrumentation getInstrumentation()
   {
      return inst;
   }

}

@@ -2241,272 +2241,8 @@
 %0D%0A%0D%0A
-         // we run the integration in a new thread%0D%0A         // as it may cause new classes to be loaded%0D%0A         // and they need to be transformed%0D%0A         Thread t = new Thread(new Runnable()%0D%0A         %7B%0D%0A%0D%0A            public void run()%0D%0A            %7B%0D%0A      
     
@@ -2307,58 +2307,8 @@
 );%0D%0A
-            %7D%0D%0A         %7D);%0D%0A         t.start();%0D%0A
     

fix integrations