content: /*
   * Copyright (c) 2013 3 Round Stones Inc., Some Rights Reserved
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.callimachusproject.server;
  
  import java.util.concurrent.CountDownLatch;
  
  import org.apache.http.HttpResponse;
  import org.apache.http.HttpVersion;
  import org.apache.http.message.BasicHttpResponse;
  import org.callimachusproject.annotations.requires;
  import org.callimachusproject.server.base.MetadataServerTestCase;
  import org.callimachusproject.traits.CalliObject;
  import org.openrdf.annotations.Iri;
  import org.openrdf.annotations.Method;
  import org.openrdf.annotations.Path;
  import org.openrdf.annotations.Type;
  import org.openrdf.repository.object.ObjectConnection;
  
  import com.sun.jersey.api.client.ClientResponse;
  import com.sun.jersey.api.client.WebResource;
  
  public class ContentVersionTest extends MetadataServerTestCase {
  	private static CountDownLatch hasRead;
  	private static CountDownLatch willRespond;
  
  	@Iri("urn:test:MyEntity")
  	public interface MyEntity extends CalliObject {
  		@Iri("urn:test:label")
  		String getLabel();
  
  		@Iri("urn:test:label")
  		void setLabel(String label);
  
  		@Method("HEAD")
  		@Path("?no-store")
  		@requires("urn:test:grant")
  		HttpResponse headNoStore();
  
  		@Method("GET")
  		@Path("?no-store")
  		@requires("urn:test:grant")
  		@Type("text/plain")
  		String GetNoStoreLabel();
  
  		@Method("HEAD")
  		@Path("?validated")
  		@requires("urn:test:grant")
  		HttpResponse headValidated();
  
  		@Method("GET")
  		@Path("?validated")
  		@requires("urn:test:grant")
  		@Type("text/plain")
  		String GetValidatedLabel();
  	}
  
  	public static abstract class MyEntitySupport implements MyEntity {
  		public HttpResponse headNoStore() {
  			HttpResponse head = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
  			head.setHeader("Cache-Control", "no-store");
  			return head;
  		}
  		public String GetNoStoreLabel() {
  			String label = getLabel();
  			hasRead.countDown();
  			try {
  				willRespond.await();
  			} catch (InterruptedException e) {
  				// stop waiting
  			}
  			return label;
  		}
  		public HttpResponse headValidated() {
  			HttpResponse head = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
  			head.setHeader("Cache-Control", "must-revalidate");
  			return head;
  		}
  		public String GetValidatedLabel() {
  			String label = getLabel();
  			hasRead.countDown();
  			try {
  				willRespond.await();
  			} catch (InterruptedException e) {
  				// stop waiting
  			}
  			return label;
  		}
  	}
  
  	private WebResource entity;
  	private String uri;
  
  	public void setUp() throws Exception {
  		config.addConcept(MyEntity.class);
  		config.addBehaviour(MyEntitySupport.class);
  		super.setUp();
  		entity = client.path("/entity");
  		uri = entity.getURI().toASCIIString();
  		ObjectConnection con = repository.getConnection();
  		try {
  			MyEntity ref = con.addDesignation(con.getObject(uri),
  					MyEntity.class);
  			ref.setLabel("original");
  		} finally {
  			con.close();
  		}
  	}
  
  	public void testNoStoreContentVersionWhileChanging() throws Exception {
  		hasRead = new CountDownLatch(1);
  		willRespond = new CountDownLatch(1);
  		willRespond.countDown();
  		WebResource req = entity.queryParam("no-store", "");
  		ClientResponse resp = req.get(ClientResponse.class);
  		String version = resp.getHeaders().getFirst("Content-Version");
  		server.resetCache();
  		String body = resp.getEntity(String.class);
  		hasRead = new CountDownLatch(1);
  		willRespond = new CountDownLatch(1);
  		new Thread(new Runnable() {
  			public void run() {
  				try {
  					hasRead.await();
  				} catch (InterruptedException e) {
  					// stop waiting
  				}
  				try {
  					ObjectConnection con = repository.getConnection();
  					try {
  						MyEntity ref = con.getObject(MyEntity.class, uri);
  						ref.setLabel("modified");
  					} finally {
  						con.close();
  					}
  				} catch (Exception e) {
  					e.printStackTrace();
  				}
  				willRespond.countDown();
  			}
  		}).start();
  		resp = req.get(ClientResponse.class);
  		assertEquals(body, resp.getEntity(String.class));
  		assertEquals(version, resp.getHeaders().getFirst("Content-Version"));
  		resp = req.get(ClientResponse.class);
  		assertFalse(body.equals(resp.getEntity(String.class)));
  		assertFalse(version.equals(resp.getHeaders().getFirst("Content-Version")));
  	}
  
  	public void testValidatedContentVersionWhileChanging() throws Exception {
  		hasRead = new CountDownLatch(1);
  		willRespond = new CountDownLatch(1);
  		willRespond.countDown();
  		WebResource req = entity.queryParam("validated", "");
  		ClientResponse resp = req.get(ClientResponse.class);
  		String version = resp.getHeaders().getFirst("Content-Version");
  		server.resetCache();
  		String body = resp.getEntity(String.class);
  		hasRead = new CountDownLatch(1);
  		willRespond = new CountDownLatch(1);
  		new Thread(new Runnable() {
  			public void run() {
  				try {
  					hasRead.await();
  				} catch (InterruptedException e) {
  					// stop waiting
  				}
  				try {
  					ObjectConnection con = repository.getConnection();
  					try {
  						MyEntity ref = con.getObject(MyEntity.class, uri);
  						ref.setLabel("modified");
  					} finally {
  						con.close();
  					}
  				} catch (Exception e) {
  					e.printStackTrace();
  				}
  				willRespond.countDown();
  			}
  		}).start();
  		resp = req.get(ClientResponse.class);
  		assertEquals(body, resp.getEntity(String.class));
  		assertEquals(version, resp.getHeaders().getFirst("Content-Version"));
  		resp = req.get(ClientResponse.class);
  		String body2 = resp.getEntity(String.class);
  		String version2 = resp.getHeaders().getFirst("Content-Version");
  		assertFalse(body, body.equals(body2));
  		assertFalse(version, version.equals(version2));
  	}
  
  }
  