package com.shin1ogawa;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.jdo.listener.InstanceLifecycleEvent;
import javax.jdo.listener.StoreLifecycleListener;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.junit.Test;

import com.shin1ogawa.entity.OtherA;
import com.shin1ogawa.entity.OtherB;

public class PersistHookTest extends AbstractRelasionShipTest {
	PersistenceManager pm = super.getPersistenceManager();

	@Test
	public void lifecycle() {
		// pm.addInstanceLifecycleListener(new StoreHookListener(),
		// StoreHookAdapter.class);
		StoreHookListener listener = new StoreHookListener();
		pm.addInstanceLifecycleListener(listener, Object.class);

		OtherB entity = new OtherB();
		Transaction transaction = pm.currentTransaction();
		transaction.begin();
		try {
			Logger.getLogger(PersistHookTest.class.getName()).info(
					"before commit."
							+ ToStringBuilder.reflectionToString(entity));
			entity.save(pm, 1);
			assertThat(listener.preStoreCount, is(1));
			assertThat(listener.postStoreCount, is(1));
			Logger.getLogger(PersistHookTest.class.getName()).info(
					"after commit."
							+ ToStringBuilder.reflectionToString(entity));
			transaction.commit();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
		}
		// pm.addInstanceLifecycleListener()の第2引数を実装していないので、
		// StoreHookListenerが実行されない。が、
		// pm.addInstanceLifecycleListener(new StoreHookListener(),
		// Object.class);
		// とすればいつでもどんなEntityに対してもStoreHookListenerが実行されてくれる。
		OtherA parent1 = new OtherA();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.makePersistent(parent1);
			assertThat(listener.preStoreCount, is(2));
			assertThat(listener.postStoreCount, is(2));
			tx.commit();
		} finally {
			if (tx.isActive()) {
				tx.rollback();
			}
		}
	}

	public static interface StoreHookAdapter {
		public void preStore();

		public void postStore();
	}

	public static final class StoreHookListener implements
			StoreLifecycleListener {

		int postStoreCount = 0;
		int preStoreCount = 0;

		public void postStore(InstanceLifecycleEvent event) {
			Logger.getLogger(StoreHookListener.class.getName()).info(
					"*************postStore() "
							+ event.getPersistentInstance().getClass());
			postStoreCount++;
			if (event.getPersistentInstance() instanceof StoreHookAdapter) {
				((StoreHookAdapter) event.getPersistentInstance()).postStore();
			}
		}

		public void preStore(InstanceLifecycleEvent event) {
			Logger.getLogger(StoreHookListener.class.getName()).info(
					"*************preStore() "
							+ event.getPersistentInstance().getClass());
			preStoreCount++;
			if (event.getPersistentInstance() instanceof StoreHookAdapter) {
				((StoreHookAdapter) event.getPersistentInstance()).preStore();
			}
		}
	}
}
