現在時刻を偽装するJava Agent

作ってみたはいいが、実行するとJDK/JREの使用許諾に違反するようです。
現時点では著作権は放棄していませんしライセンスは未整理です。
javassist に依存しています。

作ってみたはいいが、実行するとJDK/JREの使用許諾に違反するようです。
現時点では著作権は放棄していませんしライセンスは未整理です。
javassist に依存しています。

  • タグ:
  • タグはありません
package org.ocharake.matobaa.utlib;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Calendar;
import java.util.Date;

import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;

public class NowDateMockAgent {
	/**
	 * An entry point for insert NowDateMockAgent functionality to
	 * java.util.Date and java.util.GregorianCalendar.
	 * 
	 * This method will be invoked before enter the main mathod with VM's
	 * runtime argument as follows: -javaagent:nowdateagent.jar
	 * 
	 * @param agentArgs
	 *            ignored. don't care.
	 * @param instrumentation
	 *            ignored. don't care.
	 */
	public static void premain(String agentArgs, Instrumentation instrumentation) {
		instrumentation.addTransformer(new DateTransformer());
	}

	private static final class DateTransformer implements ClassFileTransformer {

		static String expected = "Long.parseLong(System.getProperty(\""
				+ NowDateMockAgent.class.getCanonicalName() + "\"));";

		public byte[] transform(ClassLoader loader, String className,
				Class<?> void1, ProtectionDomain void2, byte[] classfileBuffer)
				throws IllegalClassFormatException {
			try {
				// insert "time=0" at end of
				// GregorianCalengar.<init>(TimeZone,Locale)
				if (className.equals("java/util/GregorianCalendar")) {
					ClassPool pool = ClassPool.getDefault();
					ByteArrayInputStream stream = new ByteArrayInputStream(
							classfileBuffer);
					CtClass targetType = pool.makeClass(stream);
					CtClass[] paramTypes = pool.get(new String[] {
							"java/util/TimeZone", "java/util/Locale" });
					CtBehavior constructor = targetType
							.getDeclaredConstructor(paramTypes);
					constructor.insertAfter("time = " + expected);
					return targetType.toBytecode();
				}
				// insert "fastTime=0" at end of java.util.Date.<init>()
				if (className.equals("java/util/Date")) {
					ClassPool pool = ClassPool.getDefault();
					ByteArrayInputStream stream = new ByteArrayInputStream(
							classfileBuffer);
					CtClass targetType = pool.makeClass(stream);
					targetType.getDeclaredConstructor(new CtClass[0])
							.insertAfter("fastTime = " + expected);
					return targetType.toBytecode();
				}
			} catch (Exception initCause) {
				IllegalClassFormatException e = new IllegalClassFormatException();
				e.initCause(initCause);
				throw e;
			}
			return null;
		}
	}

	static {
		System.setProperty(NowDateMockAgent.class.getCanonicalName(), "0");
	}

	/**
	 * Set the date value you expected.
	 * 
	 * @param dateExpected
	 *            expected date as long
	 */
	public static void setExpected(long dateExpected) {
		System.setProperty(NowDateMockAgent.class.getCanonicalName(),
				Long.toString(dateExpected));
	}

	/**
	 * Set the date value you expected
	 * 
	 * @param dateExpected
	 *            expected date as java.util.Date
	 */
	public static void setExpected(Date dateExpected) {
		setExpected(dateExpected.getTime());
	}

	/**
	 * Set the date value you expected
	 * 
	 * @param dateExpected
	 *            expected date as java.util.Calendar
	 */
	public static void setExpected(Calendar dateExpected) {
		setExpected(dateExpected.getTime().getTime());
	}
}