package org.fakereplace;

import java.beans.Introspector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.data.ClassDataStore;
import org.fakereplace.replacement.AddedClass;
import org.fakereplace.replacement.ClassRedefiner;
import org.fakereplace.replacement.ReplacementResult;

/**
 * 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), true);
   }

   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();
         ClassDataStore.markClassReplaced(i.getClass());
      }
      // notify the integration classes that stuff is about to change
      ClassChangeNotifier.beforeChange(changedClasses, addedClass);
      // re-write the classes so their field
      ReplacementResult result = ClassRedefiner.rewriteLoadedClasses(classes);
      try
      {
         for (AddedClass c : addedData)
         {
            ClassLookupManager.addClassInfo(c.getClassName(), c.getLoader(), c.getData());
         }
         inst.redefineClasses(result.getClasses());
         if (!result.getClassesToRetransform().isEmpty())
         {
            inst.retransformClasses(result.getClassesToRetransform().toArray(new Class[result.getClassesToRetransform().size()]));
         }
         Introspector.flushCaches();

         ClassChangeNotifier.notify(changedClasses, addedClass);
      }
      catch (Throwable e)
      {
         try
         {
            // dump the classes to /tmp so we can look at them
            for (ClassDefinition d : classes)
            {
               try
               {
                  ByteArrayInputStream bin = new ByteArrayInputStream(d.getDefinitionClassFile());
                  DataInputStream dis = new DataInputStream(bin);
                  ClassFile file = new ClassFile(dis);

                  Transformer.getManipulator().transformClass(file, d.getDefinitionClass().getClassLoader(), environment);
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
                  DataOutputStream dos = new DataOutputStream(bos);
                  file.write(dos);
                  dos.close();

                  String dumpDir = environment.getDumpDirectory();
                  if (dumpDir == null)
                  {
                     dumpDir = "/tmp";
                  }
                  FileOutputStream s = new FileOutputStream(dumpDir + '/' + d.getDefinitionClass().getName() + "1.class");
                  dos = new DataOutputStream(s);
                  file.write(dos);
                  dos.flush();
                  dos.close();
                  // s.write(d.getDefinitionClassFile());
                  s.close();
               }
               catch (IOException a)
               {
                  a.printStackTrace();
               }
            }
         }
         catch (Exception ex)
         {
            ex.printStackTrace();
         }
         throw (new RuntimeException(e));
      }
   }

   public static Instrumentation getInstrumentation()
   {
      return inst;
   }

}

@@ -25,422 +25,8 @@
 %0D%0A%0D%0A
-import java.beans.Introspector;%0D%0Aimport java.io.ByteArrayInputStream;%0D%0Aimport java.io.ByteArrayOutputStream;%0D%0Aimport java.io.DataInputStream;%0D%0Aimport java.io.DataOutputStream;%0D%0Aimport java.io.FileOutputStream;%0D%0Aimport java.io.IOException;%0D%0Aimport java.lang.instrument.ClassDefinition;%0D%0Aimport java.lang.instrument.Instrumentation;%0D%0Aimport java.lang.instrument.UnmodifiableClassException;%0D%0Aimport java.util.Set;%0D%0A%0D%0A
 impo
@@ -55,26 +55,24 @@
 ClassFile;%0D%0A
-%0D%0A
 import org.f
@@ -507,16 +507,430 @@
 ult;%0D%0A%0D%0A
+import java.beans.Introspector;%0D%0Aimport java.io.ByteArrayInputStream;%0D%0Aimport java.io.ByteArrayOutputStream;%0D%0Aimport java.io.DataInputStream;%0D%0Aimport java.io.DataOutputStream;%0D%0Aimport java.io.FileOutputStream;%0D%0Aimport java.io.IOException;%0D%0Aimport java.lang.instrument.ClassDefinition;%0D%0Aimport java.lang.instrument.Instrumentation;%0D%0Aimport java.lang.instrument.UnmodifiableClassException;%0D%0Aimport java.util.Set;%0D%0A%0D%0A
 /**%0D%0A * 
@@ -951,25 +951,24 @@
 y point.%0D%0A *
- 
 %0D%0A * @author
@@ -978,17 +978,16 @@
 uart%0D%0A *
- 
 %0D%0A */%0D%0Ap
@@ -1439,16 +1439,374 @@
 true);%0D%0A
+%0D%0A%0D%0A      //Add jboss AS7 CL support%0D%0A      String modules = System.getProperty(%22jboss.modules.system.pkgs%22);%0D%0A       if(modules == null %7C%7C modules.isEmpty()) %7B%0D%0A           System.setProperty(%22jboss.modules.system.pkgs%22,%22org.fakereplace%22);%0D%0A       %7D else %7B%0D%0A           System.setProperty(%22jboss.modules.system.pkgs%22,modules + %22,org.fakereplace%22);%0D%0A       %7D%0D%0A
    %7D%0D%0A%0D%0A

Add AS7 integration hack