import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Collections;

public class ASyncIteration {
	
	/**
	 * Tets a property mentioned in (see {@link Collections#synchronizedCollection(Collection)}),
	 * which says that one should only iterate over a synchronized collection from within
	 * a synchronized block.
	 */
	
	public static void main(String[] args) {
		
		final Collection c = new ArrayList();
		Collection sc = Collections.synchronizedCollection(c);

		synchronized (sc) {
			//this is ok
			Iterator iter = sc.iterator();
			System.err.println("ok");
		}
		
		//this not
		Iterator iter = sc.iterator();		
	}

	static aspect SyncCheck{
		
		/*
		 * Those tracechecks check that one does not directly access a Map or Collection
		 * that has been put into Collections.synchronized*(..).
		 */		
		
		pointcut createSync(): call(* Collections.synchr*(..));
		
		//most common supertype of Map anc Collection is Object unfortunately
		tracematch(Object sync) {
			
			sym sync after returning(sync): createSync();
			
			sym asyncIteration before: call(* Collection+.iterator()) && target(sync) && if(!Thread.holdsLock(sync));			

			sync asyncIteration {
				if(System.getProperty("TMTEST_ACTIVE").toLowerCase().equals("true")) {
					throw new IllegalStateException("Collection "+System.identityHashCode(sync)+
					" is synchronized. You may only iterate from within a synchronized block.");
				}
			}
			
		}

	}
			
}
