You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by ie...@apache.org on 2009/01/08 10:07:31 UTC

svn commit: r732651 - in /incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi: ./ ActivityServiceDbTest.java AppDataServiceDbTest.java PersonServiceDbTest.java SpiDatabaseBootstrap.java SpiTestUtil.java

Author: ieb
Date: Thu Jan  8 01:07:30 2009
New Revision: 732651

URL: http://svn.apache.org/viewvc?rev=732651&view=rev
Log:
 	 SHINDIG-782
Patch from Chico Charlesworth
Fixes: Unit tests for samples implementation of PersonService, ActivityService and AppDataService
(modified patch to convert UTF8 chars to asci)
Thanks

Added:
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java   (with props)
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java   (with props)
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java   (with props)
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java   (with props)
    incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java   (with props)

Added: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java?rev=732651&view=auto
==============================================================================
--- incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java (added)
+++ incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java Thu Jan  8 01:07:30 2009
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shindig.social.opensocial.jpa.spi;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.social.opensocial.model.Activity;
+import org.apache.shindig.social.opensocial.model.EnumUtil;
+import org.apache.shindig.social.opensocial.spi.GroupId;
+import org.apache.shindig.social.opensocial.spi.RestfulCollection;
+import org.apache.shindig.social.opensocial.spi.UserId;
+import org.apache.shindig.social.opensocial.spi.UserId.Type;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ * Test the ActivityServiceDb implementation.
+ *
+ */
+public class ActivityServiceDbTest {
+  
+  // TODO ALL_FIELDS should be already in Activity as it is with Person
+  private final static Set<String> ACTIVITY_ALL_FIELDS = EnumUtil.getEnumStrings(Activity.Field.values());
+      
+  private final Activity testActivity = SpiTestUtil.buildTestActivity("1", "john.doe", "yellow", "what a color!");  
+
+  private ActivityServiceDb activityServiceDb;
+  
+  @Before
+  public void setup() throws Exception {
+    // Bootstrap hibernate and associated test db, and setup db with test data
+    SpiDatabaseBootstrap bootstrap = new SpiDatabaseBootstrap();
+    activityServiceDb = new ActivityServiceDb(bootstrap.getEntityManager());
+    bootstrap.init();    
+  }
+  
+  @Test
+  public void getJohnDoeActivityWithAppId1() throws Exception {
+    Future<Activity> result = this.activityServiceDb.getActivity(new UserId(Type.userId, "john.doe"), new GroupId(GroupId.Type.self, "@self"), null, ACTIVITY_ALL_FIELDS, "1", SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    Activity activity = result.get();
+    SpiTestUtil.assertActivityEquals(activity, testActivity);    
+  }
+  
+  @Test
+  public void getJohnDoeActivities() throws Exception {
+    Future<RestfulCollection<Activity>> result = this.activityServiceDb.getActivities(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), null, ACTIVITY_ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    RestfulCollection<Activity> activityCollection = result.get();
+    assertEquals(1, activityCollection.getTotalResults());
+    assertEquals(0, activityCollection.getStartIndex());
+    SpiTestUtil.assertActivityEquals(activityCollection.getEntry().get(0), testActivity);
+  }
+  
+  @Test
+  public void getJohnDoeFriendsActivities() throws Exception {
+    Future<RestfulCollection<Activity>> result = this.activityServiceDb.getActivities(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.friends, "@friends"), null, ACTIVITY_ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    RestfulCollection<Activity> activityCollection = result.get();
+    assertEquals(2, activityCollection.getTotalResults());
+    assertEquals(0, activityCollection.getStartIndex());
+  }
+  
+  @Test
+  public void createNewActivityForJohnDoe() throws Exception {
+    // Create new activity
+    final String title = "hi mom!";
+    final String body = "and dad.";
+    Activity activity = SpiTestUtil.buildTestActivity("2", "john.doe", title, body);    
+    this.activityServiceDb.createActivity(new UserId(Type.userId, "john.doe"), new GroupId(GroupId.Type.self, "@self"), "2", ACTIVITY_ALL_FIELDS, activity, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    
+    // Check activity was created as expected
+    Future<RestfulCollection<Activity>> result = this.activityServiceDb.getActivities(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), null, ACTIVITY_ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    RestfulCollection<Activity> activityCollection = result.get();
+    assertEquals(2, activityCollection.getTotalResults());
+    assertEquals(0, activityCollection.getStartIndex());
+    activity = activityCollection.getEntry().get(1);    
+    assertEquals(activity.getTitle(), title);
+    assertEquals(activity.getBody(), body);
+  }
+  
+}

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/ActivityServiceDbTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Added: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java?rev=732651&view=auto
==============================================================================
--- incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java (added)
+++ incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java Thu Jan  8 01:07:30 2009
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shindig.social.opensocial.jpa.spi;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.social.opensocial.spi.DataCollection;
+import org.apache.shindig.social.opensocial.spi.GroupId;
+import org.apache.shindig.social.opensocial.spi.UserId;
+import org.apache.shindig.social.opensocial.spi.UserId.Type;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ * Test the AppDataServiceDb implementation.
+ *
+ */
+public class AppDataServiceDbTest {
+  
+  private static final String DEFAULT_APPLICATION_ID = "app";
+
+    private AppDataServiceDb appDataServiceDb;
+  
+  @Before
+  public void setup() throws Exception {
+    // Bootstrap hibernate and associated test db, and setup db with test data
+    SpiDatabaseBootstrap bootstrap = new SpiDatabaseBootstrap();
+    appDataServiceDb = new AppDataServiceDb(bootstrap.getEntityManager());
+    bootstrap.init();
+  }
+  
+  @Test
+  public void getJohnDoeApplicationData() throws Exception {
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, null, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals("0", data.getEntry().get("john.doe").get("count"));
+  }
+  
+  @Test
+  public void getJohnDoeApplicationDataWithCountField() throws Exception {
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals("0", data.getEntry().get("john.doe").get("count"));
+  }
+  
+  @Test
+  public void getJohnDoeApplicationDataWithInvalidField() throws Exception {
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("peabody"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals(null, data.getEntry().get("john.doe").get("count"));
+  }
+  
+  @Test
+  public void getJohnDoeFriendsApplicationDataWithCountField() throws Exception {
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.friends, "@friends"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(3, data.getEntry().size());
+    assertEquals("7", data.getEntry().get("jane.doe").get("count"));
+    assertEquals("2", data.getEntry().get("george.doe").get("count"));    
+  }
+  
+  @Test
+  public void updateJohnDoeApplicationDataSettingCountTo5() throws Exception {
+    // Do update
+    Map<String, String> values = new ConcurrentHashMap<String, String>();
+    values.put("count", "5");
+    this.appDataServiceDb.updatePersonData(new UserId(Type.userId, "john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), values, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    
+    // Verify that update succeeded
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, null, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals("5", data.getEntry().get("john.doe").get("count"));
+  }
+  
+  @Test
+  public void deleteJohnDoeApplicationDataWithCountField() throws Exception {
+    // Do delete
+    this.appDataServiceDb.deletePersonData(new UserId(Type.userId, "john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    // Verify that delete succeeded
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals(null, data.getEntry().get("john.doe").get("count"));
+  }
+  
+  @Test
+  public void deleteJohnDoeApplicationDataWithInvalidField() throws Exception {
+    // Do delete with invalid field
+    this.appDataServiceDb.deletePersonData(new UserId(Type.userId, "john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("peabody"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    // Verify that delete did not occur
+    Future<DataCollection> results = this.appDataServiceDb.getPersonData(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.self, "@self"), DEFAULT_APPLICATION_ID, SpiTestUtil.asSet("count"), SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    DataCollection data = results.get();
+    assertEquals(1, data.getEntry().size());
+    assertEquals("0", data.getEntry().get("john.doe").get("count"));
+  }
+    
+}

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/AppDataServiceDbTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Added: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java?rev=732651&view=auto
==============================================================================
--- incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java (added)
+++ incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java Thu Jan  8 01:07:30 2009
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shindig.social.opensocial.jpa.spi;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.spi.CollectionOptions;
+import org.apache.shindig.social.opensocial.spi.GroupId;
+import org.apache.shindig.social.opensocial.spi.PersonService;
+import org.apache.shindig.social.opensocial.spi.RestfulCollection;
+import org.apache.shindig.social.opensocial.spi.UserId;
+import org.apache.shindig.social.opensocial.spi.UserId.Type;
+
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ * Test the PersonServiceDb implementation.
+ *
+ */
+public class PersonServiceDbTest {
+
+  private final Person canonical = SpiTestUtil.buildCanonicalPerson();
+  
+  private PersonServiceDb personServiceDb;  
+  
+  @Before
+  public void setup() throws Exception {
+    // Bootstrap hibernate and associated test db, and setup db with test data
+    SpiDatabaseBootstrap bootstrap = new SpiDatabaseBootstrap();
+    personServiceDb = new PersonServiceDb(bootstrap.getEntityManager());
+    bootstrap.init();    
+  }
+  
+  @Test
+  public void getCanonicalPerson() throws Exception {
+     Future<Person> person = this.personServiceDb.getPerson(new UserId(Type.userId, "canonical"), Person.Field.ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+     SpiTestUtil.assertPersonEquals(person.get(), canonical);
+  }
+  
+  @Test
+  public void getJohnDoeFriendsOrderedByName() throws Exception {
+    // Set collection options
+    CollectionOptions collectionOptions = new CollectionOptions();
+    collectionOptions.setSortBy("name");
+    collectionOptions.setSortOrder(PersonService.SortOrder.ascending);
+    collectionOptions.setMax(20);
+    
+    // Get all friends of john.doe
+    Future<RestfulCollection<Person>> result = this.personServiceDb.getPeople(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.friends, "@friends"), collectionOptions, Person.Field.ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    
+    RestfulCollection<Person> peopleCollection = result.get();
+    assertEquals(3, peopleCollection.getTotalResults());
+    assertEquals(0, peopleCollection.getStartIndex());    
+    List<Person> people = peopleCollection.getEntry();    
+    // The users should be in alphabetical order
+    SpiTestUtil.assertPersonEquals(people.get(0), "george.doe", "George Doe");
+    SpiTestUtil.assertPersonEquals(people.get(1), "jane.doe", "Jane Doe");     
+  }
+  
+  
+  @Test
+  public void getJohnDoeFriendsOrderedByNameWithPagination() throws Exception {    
+    // Set collection options
+    CollectionOptions collectionOptions = new CollectionOptions();
+    collectionOptions.setSortBy("name");
+    collectionOptions.setSortOrder(PersonService.SortOrder.ascending);
+    collectionOptions.setFirst(0);
+    collectionOptions.setMax(1);
+    
+    // Get first friend of john.doe
+    Future<RestfulCollection<Person>> result = this.personServiceDb.getPeople(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.friends, "@friends"), collectionOptions, Person.Field.ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);    
+    RestfulCollection<Person> peopleCollection = result.get();
+    assertEquals(1, peopleCollection.getTotalResults());
+    assertEquals(0, peopleCollection.getStartIndex());    
+    List<Person> people = peopleCollection.getEntry();    
+    SpiTestUtil.assertPersonEquals(people.get(0), "george.doe", "George Doe");
+    
+    // Get second friend of john.doe
+    collectionOptions.setFirst(1);
+    result = this.personServiceDb.getPeople(SpiTestUtil.buildUserIds("john.doe"), new GroupId(GroupId.Type.friends, "@friends"), collectionOptions, Person.Field.ALL_FIELDS, SpiTestUtil.DEFAULT_TEST_SECURITY_TOKEN);
+    peopleCollection = result.get();
+    assertEquals(1, peopleCollection.getTotalResults());
+    assertEquals(1, peopleCollection.getStartIndex());    
+    people = peopleCollection.getEntry();    
+    SpiTestUtil.assertPersonEquals(people.get(0), "jane.doe", "Jane Doe");    
+  }
+  
+  
+}

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/PersonServiceDbTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Added: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java?rev=732651&view=auto
==============================================================================
--- incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java (added)
+++ incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java Thu Jan  8 01:07:30 2009
@@ -0,0 +1,661 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shindig.social.opensocial.jpa.spi;
+
+import org.apache.shindig.social.opensocial.jpa.ActivityDb;
+import org.apache.shindig.social.opensocial.jpa.AddressDb;
+import org.apache.shindig.social.opensocial.jpa.ApplicationDataMapDb;
+import org.apache.shindig.social.opensocial.jpa.ApplicationDb;
+import org.apache.shindig.social.opensocial.jpa.BodyTypeDb;
+import org.apache.shindig.social.opensocial.jpa.EmailDb;
+import org.apache.shindig.social.opensocial.jpa.EnumDb;
+import org.apache.shindig.social.opensocial.jpa.FriendDb;
+import org.apache.shindig.social.opensocial.jpa.MediaItemDb;
+import org.apache.shindig.social.opensocial.jpa.NameDb;
+import org.apache.shindig.social.opensocial.jpa.OrganizationAddressDb;
+import org.apache.shindig.social.opensocial.jpa.PersonAddressDb;
+import org.apache.shindig.social.opensocial.jpa.PersonDb;
+import org.apache.shindig.social.opensocial.jpa.PersonOrganizationDb;
+import org.apache.shindig.social.opensocial.jpa.PhoneDb;
+import org.apache.shindig.social.opensocial.jpa.PhotoDb;
+import org.apache.shindig.social.opensocial.jpa.UrlDb;
+import org.apache.shindig.social.opensocial.model.Address;
+import org.apache.shindig.social.opensocial.model.Enum;
+import org.apache.shindig.social.opensocial.model.ListField;
+import org.apache.shindig.social.opensocial.model.MediaItem;
+import org.apache.shindig.social.opensocial.model.Organization;
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.model.Url;
+import org.apache.shindig.social.opensocial.model.Enum.Drinker;
+import org.apache.shindig.social.opensocial.model.Enum.LookingFor;
+import org.apache.shindig.social.opensocial.model.Enum.NetworkPresence;
+import org.apache.shindig.social.opensocial.model.Enum.Smoker;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+/**
+ * 
+ * Bootstrap class to setup a test database with some dummy data,
+ * which is used by unit tests in spi package.
+ *
+ */
+public class SpiDatabaseBootstrap {
+
+  private final static SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
+  private static final String DEFAULT_UNIT_NAME = "hibernate";
+  
+  private EntityManager entityManager;
+  
+  public SpiDatabaseBootstrap() {
+    this(DEFAULT_UNIT_NAME);
+  }
+  
+  public SpiDatabaseBootstrap(String unitName) {
+    EntityManagerFactory emFactory = Persistence.createEntityManagerFactory(unitName, new HashMap<String, String>());
+    this.entityManager = emFactory.createEntityManager();
+  }
+  
+  public EntityManager getEntityManager() {
+    return entityManager;
+  }
+
+  /*
+   * Init database bootstrap
+   */
+  public void init() throws Exception {
+    this.bootstrapDatabase();    
+  }
+  
+  /*
+   * Bootstrap database with some dummy test data
+   */
+  protected void bootstrapDatabase() throws Exception {
+    // Start transaction
+    entityManager.getTransaction().begin();
+  
+    // Build person with dummy data
+    Person canonical = buildCanonicalPerson();    
+    Person johnDoe = buildPerson("john.doe", "Johnny", Person.Gender.male, true, "Doe", "John", "John Doe");
+    Person janeDoe = buildPerson("jane.doe", "Janey", Person.Gender.female, true, "Doe", "Jane", "Jane Doe"); 
+    Person georgeDoe = buildPerson("george.doe", "Georgey", Person.Gender.male, true, "Doe", "George", "George Doe");
+    Person mario = buildPerson("mario.rossi", "Mario", Person.Gender.male, true, "Rossi", "Mario", "Mario Rossi"); 
+    Person maija = buildPerson("maija.m", "Maija", Person.Gender.female, true, "Meik\u00e4l\u00e4inen", "Maija", "Maija Meik\u00e4l\u00e4inen");
+    
+    // Persist each person
+    entityManager.persist(canonical);
+    entityManager.persist(johnDoe);
+    entityManager.persist(janeDoe);    
+    entityManager.persist(georgeDoe);
+    entityManager.persist(mario);
+    entityManager.persist(maija);
+    
+    // Build and persist friend relationships
+    entityManager.persist(buildFriend(canonical, johnDoe));
+    entityManager.persist(buildFriend(canonical, janeDoe));
+    entityManager.persist(buildFriend(canonical, georgeDoe));
+    entityManager.persist(buildFriend(canonical, maija));
+    entityManager.persist(buildFriend(johnDoe, janeDoe));
+    entityManager.persist(buildFriend(johnDoe, georgeDoe));
+    entityManager.persist(buildFriend(johnDoe, maija));
+    entityManager.persist(buildFriend(janeDoe, johnDoe));
+    entityManager.persist(buildFriend(georgeDoe, johnDoe));
+    
+    // Build and persist activity test data    
+    entityManager.persist(buildCanonicalActivity("canonical", "1"));
+    entityManager.persist(buildCanonicalActivity("canonical", "2"));
+    
+    ActivityDb activity1 = buildActivityTemplate("john.doe", "1");    
+    activity1.setTitle("yellow");
+    activity1.setBody("what a color!");
+    entityManager.persist(activity1);
+    
+    ActivityDb activity2 = buildActivityTemplate("jane.doe", "1");    
+    activity2.setBody("and she thinks you look like him");
+    List<MediaItem> mediaItems = new ArrayList<MediaItem>();
+    MediaItemDb mediaItem1 = new MediaItemDb();
+    mediaItem1.setMimeType("image/jpeg");
+    mediaItem1.setType(MediaItem.Type.IMAGE);
+    mediaItem1.setUrl("http://animals.nationalgeographic.com/staticfiles/NGS/Shared/StaticFiles/animals/images/primary/black-spider-monkey.jpg");
+    MediaItemDb mediaItem2 = new MediaItemDb();
+    mediaItem2.setMimeType("image/jpeg");
+    mediaItem2.setType(MediaItem.Type.IMAGE);
+    mediaItem2.setUrl("http://image.guardian.co.uk/sys-images/Guardian/Pix/gallery/2002/01/03/monkey300.jpg");
+    mediaItems.add(mediaItem1);
+    mediaItems.add(mediaItem2);
+    activity2.setMediaItems(mediaItems);
+    activity2.setStreamTitle("jane's photos");
+    activity2.setTitle("Jane just posted a photo of a monkey");
+    entityManager.persist(activity2);
+    
+    ActivityDb activity3 = buildActivityTemplate("jane.doe", "2");    
+    activity3.setBody("or is it you?");
+    List<MediaItem> mediaItems2 = new ArrayList<MediaItem>();
+    MediaItemDb mediaItem3 = new MediaItemDb();
+    mediaItem3.setMimeType("image/jpeg");
+    mediaItem3.setType(MediaItem.Type.IMAGE);
+    mediaItem3.setUrl("http://www.funnyphotos.net.au/images/fancy-dress-dog-yoda-from-star-wars1.jpg");
+    mediaItems2.add(mediaItem3);
+    activity3.setMediaItems(mediaItems2);
+    activity3.setStreamTitle("jane's photos");
+    activity3.setTitle("Jane says George likes yoda!");
+    entityManager.persist(activity3);
+    
+    // Build and persist application data test data
+    ApplicationDb testApplication = new ApplicationDb();
+    testApplication.setId("app");
+    entityManager.persist(testApplication);
+    
+    ApplicationDataMapDb applicationDataMap1 = buildApplicationDataTemplate(testApplication, "canonical", "2");
+    applicationDataMap1.getValues().put("size", "100");
+    entityManager.persist(applicationDataMap1);
+    
+    ApplicationDataMapDb applicationDataMap2 = buildApplicationDataTemplate(testApplication, "john.doe", "0");
+    entityManager.persist(applicationDataMap2);
+    
+    ApplicationDataMapDb applicationDataMap3 = buildApplicationDataTemplate(testApplication, "george.doe", "2");
+    entityManager.persist(applicationDataMap3);
+    
+    ApplicationDataMapDb applicationDataMap4 = buildApplicationDataTemplate(testApplication, "jane.doe", "7");
+    entityManager.persist(applicationDataMap4);
+    
+    ApplicationDataMapDb applicationDataMap5 = buildApplicationDataTemplate(testApplication, "maija.m", null);
+    entityManager.persist(applicationDataMap5);
+   
+    // Commit transaction
+    entityManager.getTransaction().commit();
+  }
+  
+  //
+  // Build methods that create dummy test data 
+  //
+  
+  private ApplicationDataMapDb buildApplicationDataTemplate(ApplicationDb application, String personId, String count) {
+    ApplicationDataMapDb applicationDataMap = new ApplicationDataMapDb();
+    applicationDataMap.setApplication(application);
+    applicationDataMap.setPersonId(personId);    
+    Map<String, String> values = new ConcurrentHashMap<String, String>();
+    if (null != count) {
+      values.put("count", count);
+    }
+    applicationDataMap.setValues(values);
+    return applicationDataMap;
+  }
+  
+  private ActivityDb buildCanonicalActivity(String userId, String id) {
+    ActivityDb activity = buildActivityTemplate(userId, id);
+    
+    // Common attributes
+    activity.setPriority(0.7F);
+    activity.setStreamFaviconUrl("http://upload.wikimedia.org/wikipedia/commons/0/02/Nuvola_apps_edu_languages.gif");
+    activity.setStreamSourceUrl("http://www.example.org/canonical/streamsource");
+    activity.setStreamTitle("All my activities");
+    activity.setStreamUrl("http://www.example.org/canonical/activities");
+        
+    // Set othe attributes depending on given id
+    if ("1".equals(id)) {          
+      activity.setBody("Went rafting");
+      activity.setBodyId("1");
+      activity.setExternalId("http://www.example.org/123456");
+      List<MediaItem> mediaItems = new ArrayList<MediaItem>();
+      MediaItemDb mediaItem1 = new MediaItemDb();
+      mediaItem1.setMimeType("image/*");
+      mediaItem1.setType(MediaItem.Type.IMAGE);
+      mediaItem1.setUrl("http://upload.wikimedia.org/wikipedia/commons/thumb/7/77/Rafting_em_Brotas.jpg/800px-Rafting_em_Brotas.jpg");
+      MediaItemDb mediaItem2 = new MediaItemDb();
+      mediaItem2.setMimeType("audio/mpeg");
+      mediaItem2.setType(MediaItem.Type.AUDIO);
+      mediaItem2.setUrl("http://www.archive.org/download/testmp3testfile/mpthreetest.mp3");
+      mediaItems.add(mediaItem1);
+      mediaItems.add(mediaItem2);
+      activity.setMediaItems(mediaItems);
+      activity.setPostedTime(1111111111L);
+      Map<String, String> templateParams = new ConcurrentHashMap<String, String>();
+      templateParams.put("small", "true");
+      templateParams.put("otherContent", "and got wet");
+      activity.setTemplateParams(templateParams);
+      activity.setTitle("My trip");
+      activity.setTitleId("1");
+      activity.setUpdated(new Date());
+      activity.setUrl("http://www.example.org/canonical/activities/1");
+      
+    } else if ("2".equals(id)) {      
+      activity.setBody("Went skiing");
+      activity.setBodyId("2");
+      activity.setExternalId("http://www.example.org/123457");
+      List<MediaItem> mediaItems = new ArrayList<MediaItem>();
+      activity.setMediaItems(mediaItems);
+      activity.setPostedTime(1111111112L);
+      Map<String, String> templateParams = new ConcurrentHashMap<String, String>();
+      templateParams.put("small", "true");
+      templateParams.put("otherContent", "and went fast");
+      activity.setTemplateParams(templateParams);
+      activity.setTitle("My next trip");
+      activity.setTitleId("2");
+      activity.setUpdated(new Date());
+      activity.setUrl("http://www.example.org/canonical/activities/2");
+    }
+    return activity;
+  }
+
+  private ActivityDb buildActivityTemplate(String userId, String id) {
+    ActivityDb activity = new ActivityDb();
+    activity.setUserId(userId);
+    activity.setAppId(id);    
+    activity.setBody("");
+    activity.setBodyId("");
+    activity.setExternalId("");
+    activity.setId(id);
+    List<MediaItem> mediaItems = new ArrayList<MediaItem>();
+    MediaItemDb mediaItem = new MediaItemDb();
+    mediaItem.setMimeType("");
+    mediaItem.setType(MediaItem.Type.VIDEO);
+    mediaItem.setUrl("");
+    mediaItems.add(mediaItem);
+    activity.setMediaItems(mediaItems);
+    activity.setPostedTime(new Date().getTime());
+    activity.setPriority(0F);
+    activity.setStreamFaviconUrl("");
+    activity.setStreamSourceUrl("");
+    activity.setStreamTitle("");
+    activity.setStreamUrl("");
+    Map<String, String> templateParams = new ConcurrentHashMap<String, String>();
+    activity.setTemplateParams(templateParams);
+    activity.setTitle("");
+    activity.setTitleId("");
+    activity.setUpdated(new Date());
+    activity.setUrl("");
+    return activity;
+  }
+  
+  private FriendDb buildFriend(Person person, Person friend) {
+    FriendDb friendDb = new FriendDb();
+    friendDb.setPerson(person);
+    friendDb.setFriend(friend);
+    return friendDb;
+  }
+
+  private Person buildPerson(String id, String displayName, Person.Gender gender, boolean hasApp,
+      String familyName, String givenName, String unstructured) throws Exception {
+    Person person = buildPersonTemplate(id);
+    person.setDisplayName(displayName);
+    person.setGender(gender);
+    person.setHasApp(hasApp);
+    
+    NameDb name = new NameDb();
+    name.setFamilyName(familyName);
+    name.setGivenName(givenName);
+    name.setUnstructured(unstructured);
+    person.setName(name);
+    
+    return person;
+  }
+  
+  private Person buildCanonicalPerson() throws Exception {
+    Person person = buildPersonTemplate("canonical");
+    person.setAboutMe("I have an example of every piece of data");    
+    person.setActivities(asList("Coding Shindig"));    
+    List<Address> addresses = new ArrayList<Address>();
+    PersonAddressDb address = new PersonAddressDb();
+    address.setCountry("US");
+    address.setLatitude(28.3043F);
+    address.setLongitude(143.0859F);
+    address.setLocality("who knows");
+    address.setPostalCode("12345");
+    address.setRegion("Apache, CA");
+    address.setStreetAddress("1 OpenStandards Way");
+    address.setType("home");
+    address.setFormatted("PoBox 3565, 1 OpenStandards Way, Apache, CA");
+    // address.setPerson(person);
+    addresses.add(address);
+    person.setAddresses(addresses);    
+    person.setAge(33);
+    
+    BodyTypeDb bodyType = new BodyTypeDb();
+    bodyType.setBuild("svelte");
+    bodyType.setEyeColor("blue");
+    bodyType.setHairColor("black");
+    bodyType.setHeight(1.84F);
+    bodyType.setWeight(74F);
+    person.setBodyType(bodyType);
+    
+    person.setBooks(asList("The Cathedral & the Bazaar","Catch 22"));
+    person.setCars(asList("beetle","prius"));
+    person.setChildren("3");
+    
+    AddressDb currentLocation = new AddressDb();
+    currentLocation.setLatitude(48.858193F);
+    currentLocation.setLongitude(2.29419F);
+    person.setCurrentLocation(currentLocation);
+        
+    person.setBirthday(buildDate("1975-01-01"));
+    person.setDisplayName("Shin Digg");
+    person.setDrinker(new EnumDb<Drinker>(Drinker.SOCIALLY));
+    
+    List<ListField> emails = new ArrayList<ListField>();
+    EmailDb email = new EmailDb();
+    email.setValue("shindig-dev@incubator.apache.org");
+    email.setType("work");
+    emails.add(email);
+    person.setEmails(emails);
+   
+    person.setEthnicity("developer");    
+    person.setFashion("t-shirts");    
+    person.setFood(asList("sushi","burgers"));    
+    person.setGender(Person.Gender.male);
+    person.setHappiestWhen("coding");    
+    person.setHasApp(true);    
+    person.setHeroes(asList("Doug Crockford", "Charles Babbage"));    
+    person.setHumor("none to speak of");    
+    person.setInterests(asList("PHP","Java"));    
+    person.setJobInterests("will work for beer");
+    
+    List<Organization> organizations = new ArrayList<Organization>();
+    
+    PersonOrganizationDb organization1 = new PersonOrganizationDb();
+    OrganizationAddressDb orgAddress1 = new OrganizationAddressDb();
+    orgAddress1.setFormatted("1 Shindig Drive");
+    organization1.setAddress(orgAddress1);
+    organization1.setDescription("lots of coding");
+    organization1.setEndDate(buildDate("2010-10-10"));
+    organization1.setField("Software Engineering");
+    organization1.setName("Apache.com");
+    organization1.setSalary("$1000000000");
+    organization1.setStartDate(buildDate("1995-01-01"));
+    organization1.setSubField("Development");
+    organization1.setTitle("Grand PooBah");
+    organization1.setWebpage("http://incubator.apache.org/projects/shindig.html");
+    organization1.setType("job");
+    
+    PersonOrganizationDb organization2 = new PersonOrganizationDb();
+    OrganizationAddressDb orgAddress2 = new OrganizationAddressDb();
+    orgAddress2.setFormatted("1 Skid Row");
+    organization2.setAddress(orgAddress2);
+    organization2.setDescription("");
+    organization2.setEndDate(buildDate("1995-01-01"));
+    organization2.setField("College");
+    organization2.setName("School of hard Knocks");
+    organization2.setSalary("$100");
+    organization2.setStartDate(buildDate("1991-01-01"));
+    organization2.setSubField("Lab Tech");
+    organization2.setTitle("Gopher");
+    organization2.setWebpage("");
+    organization2.setType("job");
+    
+    organizations.add(organization1);
+    organizations.add(organization2);
+    person.setOrganizations(organizations);
+    
+    person.setLanguagesSpoken(asList("English","Dutch","Esperanto"));
+    person.setUpdated(new Date());
+    person.setLivingArrangement("in a house");
+        
+    List<Enum<LookingFor>> lookingForList = new ArrayList<Enum<LookingFor>>();
+    EnumDb<LookingFor> lookingFor1 = new EnumDb<LookingFor>(LookingFor.RANDOM);
+    EnumDb<LookingFor> lookingFor2 = new EnumDb<LookingFor>(LookingFor.NETWORKING);
+    lookingForList.add(lookingFor1);
+    lookingForList.add(lookingFor2);
+    person.setLookingFor(lookingForList);
+    
+    person.setMovies(asList("Iron Man", "Nosferatu"));
+    person.setMusic(asList("Chieftains","Beck"));
+    
+    NameDb name = new NameDb();
+    name.setAdditionalName("H");
+    name.setFamilyName("Digg");
+    name.setGivenName("Shin");
+    name.setHonorificPrefix("Sir");
+    name.setHonorificSuffix("Social Butterfly");
+    name.setUnstructured("Sir Shin H. Digg Social Butterfly");
+    person.setName(name);
+    
+    person.setNetworkPresence(new EnumDb<NetworkPresence>(NetworkPresence.ONLINE));
+    
+    person.setNickname("diggy");
+    person.setPets("dog,cat");
+    
+    List<ListField> phoneNumbers = new ArrayList<ListField>();
+    PhoneDb phone1 = new PhoneDb();
+    phone1.setValue("111-111-111");
+    phone1.setType("work");
+    PhoneDb phone2 = new PhoneDb();
+    phone2.setValue("999-999-999");
+    phone2.setType("mobile");
+    phoneNumbers.add(phone1);
+    phoneNumbers.add(phone2);
+    person.setPhoneNumbers(phoneNumbers);
+    
+    person.setPoliticalViews("open leaning");    
+    person.setProfileSong(buildUrl("http://www.example.org/songs/OnlyTheLonely.mp3", "Feelin' blue", "road"));
+    person.setProfileUrl("http://www.example.org/?id=1");
+    person.setProfileVideo(buildUrl("http://www.example.org/videos/Thriller.flv", "Thriller", "video"));
+   
+    person.setQuotes(asList("I am therfore I code", "Doh!"));
+    person.setRelationshipStatus("married to my job");
+    person.setReligion("druidic");
+    person.setRomance("twice a year");
+    person.setScaredOf("COBOL");
+    person.setSexualOrientation("north");
+    person.setSmoker(new EnumDb<Smoker>(Smoker.NO));    
+    person.setSports(asList("frisbee","rugby"));
+    person.setStatus("happy");
+    person.setTags(asList("C#","JSON","template"));
+    person.setUtcOffset(-8L);
+    person.setTurnOffs(asList("lack of unit tests","cabbage"));
+    person.setTurnOns(asList("well document code"));
+    person.setTvShows(asList("House","Battlestar Galactica"));
+    
+    List<Url> urls = new ArrayList<Url>();
+    urls.add(buildUrl("http://www.example.org/?id=1", "my profile", "Profile"));
+    urls.add(buildUrl("http://www.example.org/pic/?id=1", "my awesome picture", "Thumbnail"));
+    person.setUrls(urls);
+    
+    List<ListField> photos = new ArrayList<ListField>();
+    PhotoDb photo = new PhotoDb();
+    photo.setValue("http://www.example.org/pic/?id=1");
+    photo.setType("thumbnail");
+    photos.add(photo);
+    person.setPhotos(photos);
+    
+    return person;
+  }
+  
+  private Person buildPersonTemplate(String personId) {
+    PersonDb person = new PersonDb();
+    person.setId(personId);
+    person.setAboutMe("");
+    
+    person.setActivities(asList(""));
+    
+    List<Address> addresses = new ArrayList<Address>();
+    PersonAddressDb address = new PersonAddressDb();
+    address.setCountry("");
+    address.setLatitude(0F);
+    address.setLongitude(0F);
+    address.setLocality("");
+    address.setPostalCode("");
+    address.setRegion("");
+    address.setStreetAddress("");
+    address.setType("");
+    address.setFormatted("");
+    // TODO This causes problems when converting back to json.
+    // address.setPerson(person);
+    addresses.add(address);
+    person.setAddresses(addresses);
+    
+    person.setAge(0);
+    
+    BodyTypeDb bodyType = new BodyTypeDb();
+    bodyType.setBuild("");
+    bodyType.setEyeColor("");
+    bodyType.setHairColor("");
+    bodyType.setHeight(0F);
+    bodyType.setWeight(0F);
+    person.setBodyType(bodyType);
+    
+    person.setBooks(asList(""));
+    person.setCars(asList(""));
+    person.setChildren("");
+    
+    AddressDb currentLocation = new AddressDb();
+    currentLocation.setLatitude(0F);
+    currentLocation.setLongitude(0F);
+    person.setCurrentLocation(currentLocation);
+    
+    person.setBirthday(new Date());
+    person.setDisplayName("");
+    person.setDrinker(new EnumDb<Drinker>(Drinker.SOCIALLY));
+    
+    List<ListField> emails = new ArrayList<ListField>();
+    EmailDb email = new EmailDb();
+    email.setValue("");
+    email.setType("");
+    emails.add(email);
+    person.setEmails(emails);
+    
+    person.setEthnicity("");    
+    person.setFashion("");    
+    person.setFood(asList(""));    
+    person.setGender(Person.Gender.male);
+    person.setHappiestWhen("");    
+    person.setHasApp(true);    
+    person.setHeroes(asList(""));    
+    person.setHumor("");    
+    person.setInterests(asList(""));    
+    person.setJobInterests("");
+    
+    List<Organization> organizations = new ArrayList<Organization>();
+    
+    PersonOrganizationDb organization1 = new PersonOrganizationDb();
+    OrganizationAddressDb orgAddress1 = new OrganizationAddressDb();
+    orgAddress1.setFormatted("");
+    organization1.setAddress(orgAddress1);
+    organization1.setDescription("");
+    organization1.setEndDate(new Date());
+    organization1.setField("");
+    organization1.setName("");
+    organization1.setSalary("");
+    organization1.setStartDate(new Date());
+    organization1.setSubField("");
+    organization1.setTitle("");
+    organization1.setWebpage("");
+    organization1.setType("");    
+    
+    organizations.add(organization1);
+    person.setOrganizations(organizations);
+    
+    person.setLanguagesSpoken(asList(""));
+    person.setUpdated(new Date());
+    person.setLivingArrangement("");
+        
+    List<Enum<LookingFor>> lookingForList = new ArrayList<Enum<LookingFor>>();
+    EnumDb<LookingFor> lookingFor1 = new EnumDb<LookingFor>(LookingFor.RANDOM);
+    EnumDb<LookingFor> lookingFor2 = new EnumDb<LookingFor>(LookingFor.NETWORKING);
+    lookingForList.add(lookingFor1);
+    lookingForList.add(lookingFor2);
+    person.setLookingFor(lookingForList);
+    
+    person.setMovies(asList(""));
+    person.setMusic(asList(""));
+    
+    NameDb name = new NameDb();
+    name.setAdditionalName("");
+    name.setFamilyName("");
+    name.setGivenName("");
+    name.setHonorificPrefix("");
+    name.setHonorificSuffix("");
+    name.setUnstructured("");
+    person.setName(name);
+    
+    person.setNetworkPresence(new EnumDb<NetworkPresence>(NetworkPresence.ONLINE));
+    person.setNickname("");
+    person.setPets("");
+    
+    List<ListField> phoneNumbers = new ArrayList<ListField>();
+    PhoneDb phone1 = new PhoneDb();
+    phone1.setValue("");
+    phone1.setType("");
+    PhoneDb phone2 = new PhoneDb();
+    phone2.setValue("");
+    phone2.setType("");
+    phoneNumbers.add(phone1);
+    phoneNumbers.add(phone2);
+    person.setPhoneNumbers(phoneNumbers);
+    
+    person.setPoliticalViews("");    
+    person.setProfileSong(buildUrl("", "Link Text", "URL"));
+    person.setProfileUrl("");
+    person.setProfileVideo(buildUrl("", "Link Text", "URL"));
+    person.setQuotes(asList(""));
+    person.setRelationshipStatus("");
+    person.setReligion("");
+    person.setRomance("");
+    person.setScaredOf("");
+    person.setSexualOrientation("");
+    person.setSmoker(new EnumDb<Smoker>(Smoker.NO));    
+    person.setSports(asList(""));
+    person.setStatus("");
+    person.setTags(asList(""));
+    person.setUtcOffset(-8L);
+    person.setTurnOffs(asList(""));
+    person.setTurnOns(asList(""));
+    person.setTvShows(asList(""));
+    
+    List<Url> urls = new ArrayList<Url>();
+    urls.add(buildUrl("", "", "Profile"));
+    urls.add(buildUrl("", "", "Thumbnail"));
+    person.setUrls(urls);
+    
+    List<ListField> photos = new ArrayList<ListField>();
+    PhotoDb photo = new PhotoDb();
+    photo.setValue("");
+    photo.setType("thumbnail");
+    photos.add(photo);
+    person.setPhotos(photos);
+    
+    return person;
+  }
+  
+  private Date buildDate(String dateAsString) throws Exception {    
+    return DATE_FORMATTER.parse(dateAsString);
+  }
+  
+  private List<String> asList(String... items) {
+    return Arrays.asList(items);
+  }
+  
+  private Url buildUrl(String targetUrl, String linkTest, String type) {
+    Url url = new UrlDb();
+    url.setValue(targetUrl);
+    url.setLinkText(linkTest);
+    url.setType(type);
+    return url;
+  }
+  
+}

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiDatabaseBootstrap.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Added: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java?rev=732651&view=auto
==============================================================================
--- incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java (added)
+++ incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java Thu Jan  8 01:07:30 2009
@@ -0,0 +1,388 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shindig.social.opensocial.jpa.spi;
+
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.social.core.model.ActivityImpl;
+import org.apache.shindig.social.core.model.AddressImpl;
+import org.apache.shindig.social.core.model.BodyTypeImpl;
+import org.apache.shindig.social.core.model.EnumImpl;
+import org.apache.shindig.social.core.model.ListFieldImpl;
+import org.apache.shindig.social.core.model.NameImpl;
+import org.apache.shindig.social.core.model.OrganizationImpl;
+import org.apache.shindig.social.core.model.PersonImpl;
+import org.apache.shindig.social.core.model.UrlImpl;
+import org.apache.shindig.social.opensocial.model.Activity;
+import org.apache.shindig.social.opensocial.model.Address;
+import org.apache.shindig.social.opensocial.model.BodyType;
+import org.apache.shindig.social.opensocial.model.Enum;
+import org.apache.shindig.social.opensocial.model.ListField;
+import org.apache.shindig.social.opensocial.model.Name;
+import org.apache.shindig.social.opensocial.model.Organization;
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.model.Url;
+import org.apache.shindig.social.opensocial.spi.UserId;
+import org.apache.shindig.social.opensocial.spi.UserId.Type;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.common.collect.Lists;
+
+/**
+ * 
+ * Convenient build and assert methods used by spi unit tests
+ *
+ */
+public class SpiTestUtil {
+  
+  public final static SecurityToken DEFAULT_TEST_SECURITY_TOKEN = (SecurityToken) new FakeGadgetToken();
+  public final static SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
+  
+  /*
+   * Build canonical test person instance
+   */
+  public static Person buildCanonicalPerson() {    
+    NameImpl name = new NameImpl("Sir Shin H. Digg Social Butterfly");
+    name.setAdditionalName("H");
+    name.setFamilyName("Digg");
+    name.setGivenName("Shin");
+    name.setHonorificPrefix("Sir");
+    name.setHonorificSuffix("Social Butterfly");
+    
+    Person canonical = new PersonImpl("canonical", "Shin Digg", name);
+
+    canonical.setAboutMe("I have an example of every piece of data");
+    canonical.setActivities(Lists.newArrayList("Coding Shindig"));
+
+    Address address = new AddressImpl("PoBox 3565, 1 OpenStandards Way, Apache, CA");
+    address.setCountry("US");
+    address.setLatitude(28.3043F);
+    address.setLongitude(143.0859F);
+    address.setLocality("who knows");
+    address.setPostalCode("12345");
+    address.setRegion("Apache, CA");
+    address.setStreetAddress("1 OpenStandards Way");
+    address.setType("home");
+    address.setFormatted("PoBox 3565, 1 OpenStandards Way, Apache, CA");
+    canonical.setAddresses(Lists.newArrayList(address));
+
+    canonical.setAge(33);
+    BodyTypeImpl bodyType = new BodyTypeImpl();
+    bodyType.setBuild("svelte");
+    bodyType.setEyeColor("blue");
+    bodyType.setHairColor("black");
+    bodyType.setHeight(1.84F);
+    bodyType.setWeight(74F);
+    canonical.setBodyType(bodyType);
+
+    canonical.setBooks(Lists.newArrayList("The Cathedral & the Bazaar", "Catch 22"));
+    canonical.setCars(Lists.newArrayList("beetle", "prius"));
+    canonical.setChildren("3");
+    AddressImpl location = new AddressImpl();
+    location.setLatitude(48.858193F);
+    location.setLongitude(2.29419F);
+    canonical.setCurrentLocation(location);
+
+    canonical.setBirthday(buildDate("1975-01-01"));
+    canonical.setDrinker(new EnumImpl<Enum.Drinker>(Enum.Drinker.SOCIALLY));
+    ListField email = new ListFieldImpl("work", "shindig-dev@incubator.apache.org");
+    canonical.setEmails(Lists.newArrayList(email));
+
+    canonical.setEthnicity("developer");
+    canonical.setFashion("t-shirts");
+    canonical.setFood(Lists.newArrayList("sushi", "burgers"));
+    canonical.setGender(Person.Gender.male);
+    canonical.setHappiestWhen("coding");
+    canonical.setHasApp(true);
+    canonical.setHeroes(Lists.newArrayList("Doug Crockford", "Charles Babbage"));
+    canonical.setHumor("none to speak of");
+    canonical.setInterests(Lists.newArrayList("PHP", "Java"));
+    canonical.setJobInterests("will work for beer");
+
+    Organization job1 = new OrganizationImpl();
+    job1.setAddress(new AddressImpl("1 Shindig Drive"));
+    job1.setDescription("lots of coding");
+    job1.setEndDate(buildDate("2010-10-10"));
+    job1.setField("Software Engineering");
+    job1.setName("Apache.com");
+    job1.setSalary("$1000000000");
+    job1.setStartDate(buildDate("1995-01-01"));
+    job1.setSubField("Development");
+    job1.setTitle("Grand PooBah");
+    job1.setWebpage("http://incubator.apache.org/projects/shindig.html");
+    job1.setType("job");
+
+    Organization job2 = new OrganizationImpl();
+    job2.setAddress(new AddressImpl("1 Skid Row"));
+    job2.setDescription("");
+    job2.setEndDate(buildDate("1995-01-01"));
+    job2.setField("College");
+    job2.setName("School of hard Knocks");
+    job2.setSalary("$100");
+    job2.setStartDate(buildDate("1991-01-01"));
+    job2.setSubField("Lab Tech");
+    job2.setTitle("Gopher");
+    job2.setWebpage("");
+    job2.setType("job");
+
+    canonical.setOrganizations(Lists.newArrayList(job1, job2));
+
+    canonical.setUpdated(new Date());
+    canonical.setLanguagesSpoken(Lists.newArrayList("English", "Dutch", "Esperanto"));
+    canonical.setLivingArrangement("in a house");
+    Enum<Enum.LookingFor> lookingForRandom =
+        new EnumImpl<Enum.LookingFor>(Enum.LookingFor.RANDOM, "Random");
+    Enum<Enum.LookingFor> lookingForNetworking =
+        new EnumImpl<Enum.LookingFor>(Enum.LookingFor.NETWORKING, "Networking");
+    canonical.setLookingFor(Lists.newArrayList(lookingForRandom, lookingForNetworking));
+    canonical.setMovies(Lists.newArrayList("Iron Man", "Nosferatu"));
+    canonical.setMusic(Lists.newArrayList("Chieftains", "Beck"));
+    canonical.setNetworkPresence(new EnumImpl<Enum.NetworkPresence>(Enum.NetworkPresence.ONLINE));
+    canonical.setNickname("diggy");
+    canonical.setPets("dog,cat");
+    canonical.setPhoneNumbers(Lists.<ListField> newArrayList(new ListFieldImpl("work",
+        "111-111-111"), new ListFieldImpl("mobile", "999-999-999")));
+
+    canonical.setPoliticalViews("open leaning");
+    canonical.setProfileSong(new UrlImpl("http://www.example.org/songs/OnlyTheLonely.mp3",
+        "Feelin' blue", "road"));
+    canonical.setProfileVideo(new UrlImpl("http://www.example.org/videos/Thriller.flv",
+        "Thriller", "video"));
+
+    canonical.setQuotes(Lists.newArrayList("I am therfore I code", "Doh!"));
+    canonical.setRelationshipStatus("married to my job");
+    canonical.setReligion("druidic");
+    canonical.setRomance("twice a year");
+    canonical.setScaredOf("COBOL");
+    canonical.setSexualOrientation("north");
+    canonical.setSmoker(new EnumImpl<Enum.Smoker>(Enum.Smoker.NO));
+    canonical.setSports(Lists.newArrayList("frisbee", "rugby"));
+    canonical.setStatus("happy");
+    canonical.setTags(Lists.newArrayList("C#", "JSON", "template"));
+    canonical.setThumbnailUrl("http://www.example.org/pic/?id=1");
+    canonical.setUtcOffset(-8L);
+    canonical.setTurnOffs(Lists.newArrayList("lack of unit tests", "cabbage"));
+    canonical.setTurnOns(Lists.newArrayList("well document code"));
+    canonical.setTvShows(Lists.newArrayList("House", "Battlestar Galactica"));
+
+    canonical.setUrls(Lists.<Url>newArrayList(
+        new UrlImpl("http://www.example.org/?id=1", "my profile", "Profile"),
+        new UrlImpl("http://www.example.org/pic/?id=1", "my awesome picture", "Thumbnail")));
+    
+    return canonical;
+  }
+  
+  /*
+   * Build userId set
+   */
+  public static Set<UserId> buildUserIds(String... userIds) {
+    // Set user id list
+    Set<UserId> userIdSet = new HashSet<UserId>();
+    for (String userId: userIds) {
+      userIdSet.add(new UserId(Type.userId, userId));
+    }
+    return userIdSet;
+  }
+  
+  /*
+   * Asserts actual person instance has the expected person id and (unstructured) name.
+   * 
+   */
+  public static void assertPersonEquals(Person actual, String expectedId, String expectedName) {
+    assertEquals(actual.getId(), expectedId);
+    assertTrue(actual.getName() != null);
+    assertEquals(actual.getName().getUnstructured(), expectedName);
+  }
+
+  /*
+   * Asserts actual person instance equals expected person instance
+   * 
+   * Verified each individual variable so to know which variable is causing it to fail.
+   * Note that person.updated isn't verified as we can't expect this to be equal.
+   * 
+   */
+  public static void assertPersonEquals(Person actual, Person expected) {
+    
+    assertEquals(actual.getAboutMe(), expected.getAboutMe());
+    assertEquals(actual.getActivities(), expected.getActivities());    
+    assertCollectionSizeEquals(actual.getAddresses(), expected.getAddresses());
+    for (int i = 0; i < actual.getAddresses().size(); i++) {
+      assertAddressEquals(actual.getAddresses().get(i), expected.getAddresses().get(i));
+    }    
+    assertEquals(actual.getAge(), expected.getAge());    
+    assertBodyTypeEquals(actual.getBodyType(), expected.getBodyType());
+    assertEquals(actual.getBooks(), expected.getBooks());
+    assertEquals(actual.getCars(), expected.getCars());
+    assertEquals(actual.getChildren(), expected.getChildren());    
+    assertAddressEquals(actual.getCurrentLocation(), expected.getCurrentLocation());    
+    assertEquals(actual.getDisplayName(), expected.getDisplayName());
+    assertEquals(actual.getBirthday(), expected.getBirthday());    
+    assertCollectionSizeEquals(actual.getEmails(), expected.getEmails());
+    for (int i = 0; i < actual.getEmails().size(); i++) {
+      assertListFieldEquals(actual.getEmails().get(i), expected.getEmails().get(i));
+    }    
+    assertEquals(actual.getEthnicity(), expected.getEthnicity());
+    assertEquals(actual.getFashion(), expected.getFashion());
+    assertEquals(actual.getFood(), expected.getFood());
+    assertEquals(actual.getGender(), expected.getGender());
+    assertEquals(actual.getHappiestWhen(), expected.getHappiestWhen());
+    assertEquals(actual.getHasApp(), expected.getHasApp());
+    assertEquals(actual.getHeroes(), expected.getHeroes());
+    assertEquals(actual.getHumor(), expected.getHumor());
+    assertEquals(actual.getId(), expected.getId());
+    assertEquals(actual.getInterests(), expected.getInterests());
+    assertEquals(actual.getJobInterests(), expected.getJobInterests());    
+    assertCollectionSizeEquals(actual.getOrganizations(), expected.getOrganizations());
+    for (int i = 0; i < actual.getOrganizations().size(); i++) {
+      assertOrganizationEquals(actual.getOrganizations().get(i), expected.getOrganizations().get(i));
+    }    
+    assertEquals(actual.getLanguagesSpoken(), expected.getLanguagesSpoken());
+    assertEquals(actual.getLivingArrangement(), expected.getLivingArrangement());    
+    assertCollectionSizeEquals(actual.getLookingFor(), expected.getLookingFor());
+    for (int i = 0; i < actual.getLookingFor().size(); i++) {
+      assertEquals(actual.getLookingFor().get(i).getValue(), expected.getLookingFor().get(i).getValue());
+    }    
+    assertEquals(actual.getMovies(), expected.getMovies());
+    assertEquals(actual.getMusic(), expected.getMusic());    
+    assertNameEquals(actual.getName(), expected.getName());
+    assertEquals(actual.getNetworkPresence().getValue(), expected.getNetworkPresence().getValue());
+    assertEquals(actual.getNickname(), expected.getNickname());
+    assertEquals(actual.getPets(), expected.getPets());    
+    assertCollectionSizeEquals(actual.getPhoneNumbers(), expected.getPhoneNumbers());
+    for (int i = 0; i < actual.getPhoneNumbers().size(); i++) {
+      assertListFieldEquals(actual.getPhoneNumbers().get(i), expected.getPhoneNumbers().get(i));
+    }    
+    assertEquals(actual.getPoliticalViews(), expected.getPoliticalViews());    
+    assertUrlEquals(actual.getProfileSong(), expected.getProfileSong());    
+    assertEquals(actual.getProfileUrl(), expected.getProfileUrl());
+    assertUrlEquals(actual.getProfileVideo(), expected.getProfileVideo());
+    assertEquals(actual.getQuotes(), expected.getQuotes());
+    assertEquals(actual.getRelationshipStatus(), expected.getRelationshipStatus());
+    assertEquals(actual.getReligion(), expected.getReligion());
+    assertEquals(actual.getRomance(), expected.getRomance());
+    assertEquals(actual.getScaredOf(), expected.getScaredOf());
+    assertEquals(actual.getSexualOrientation(), expected.getSexualOrientation());
+    assertEquals(actual.getSmoker().getValue(), expected.getSmoker().getValue());
+    assertEquals(actual.getSports(), expected.getSports());
+    assertEquals(actual.getStatus(), expected.getStatus());
+    assertEquals(actual.getTags(), expected.getTags());
+    assertEquals(actual.getThumbnailUrl(), expected.getThumbnailUrl());
+    assertEquals(actual.getUtcOffset(), expected.getUtcOffset());
+    assertEquals(actual.getTurnOffs(), expected.getTurnOffs());
+    assertEquals(actual.getTurnOns(), expected.getTurnOns());
+    assertEquals(actual.getTvShows(), expected.getTvShows());    
+  }
+  
+  private static void assertUrlEquals(Url actual, Url expected) {
+    assertEquals(actual.getLinkText(), expected.getLinkText());
+    assertEquals(actual.getPrimary(), expected.getPrimary());
+    assertEquals(actual.getType(), expected.getType());
+    assertEquals(actual.getValue(), expected.getValue());    
+  }
+
+  private static void assertNameEquals(Name actual, Name expected) {
+    assertEquals(actual.getAdditionalName(), expected.getAdditionalName());
+    assertEquals(actual.getFamilyName(), expected.getFamilyName());
+    assertEquals(actual.getGivenName(), expected.getGivenName());
+    assertEquals(actual.getHonorificPrefix(), expected.getHonorificPrefix());
+    assertEquals(actual.getHonorificSuffix(), expected.getHonorificSuffix());
+    assertEquals(actual.getUnstructured(), expected.getUnstructured());    
+  }
+
+  private static void assertOrganizationEquals(Organization actual, Organization expected) {
+    assertAddressEquals(actual.getAddress(), expected.getAddress());
+    assertEquals(actual.getDescription(), expected.getDescription());
+    assertEquals(actual.getEndDate(), expected.getEndDate());
+    assertEquals(actual.getField(), expected.getField());
+    assertEquals(actual.getName(), expected.getName());
+    assertEquals(actual.getPrimary(), expected.getPrimary());
+    assertEquals(actual.getSalary(), expected.getSalary());
+    assertEquals(actual.getStartDate(), expected.getStartDate());
+    assertEquals(actual.getSubField(), expected.getSubField());
+    assertEquals(actual.getTitle(), expected.getTitle());
+    assertEquals(actual.getType(), expected.getType());
+    assertEquals(actual.getWebpage(), expected.getWebpage());    
+  }
+
+  private static void assertCollectionSizeEquals(Collection<?> actual, Collection<?> expected) {
+    assertTrue(actual != null && expected != null);
+    assertEquals(actual.size(), expected.size());
+  }
+  
+  private static void assertAddressEquals(Address actual, Address expected) {    
+    assertEquals(actual.getCountry(), expected.getCountry());
+    assertEquals(actual.getLatitude(), expected.getLatitude());
+    assertEquals(actual.getLocality(), expected.getLocality());
+    assertEquals(actual.getLongitude(), expected.getLongitude());
+    assertEquals(actual.getPostalCode(), expected.getPostalCode());
+    assertEquals(actual.getRegion(), expected.getRegion());
+    assertEquals(actual.getStreetAddress(), expected.getStreetAddress());
+    assertEquals(actual.getType(), expected.getType());
+    assertEquals(actual.getFormatted(), expected.getFormatted());    
+  }
+
+  private static void assertBodyTypeEquals(BodyType actual, BodyType expected) {
+    assertEquals(actual.getBuild(), expected.getBuild());
+    assertEquals(actual.getEyeColor(), expected.getEyeColor());
+    assertEquals(actual.getHairColor(), expected.getHairColor());
+    assertEquals(actual.getHeight(), expected.getHeight());
+    assertEquals(actual.getWeight(), expected.getWeight());
+  }
+  
+  private static void assertListFieldEquals(ListField actual, ListField expected) {
+    assertEquals(actual.getPrimary(), expected.getPrimary());
+    assertEquals(actual.getType(), expected.getType());
+    assertEquals(actual.getValue(), expected.getValue());
+  }
+  
+  public static void assertActivityEquals(Activity actual, Activity expected) {
+    assertEquals(actual.getId(), expected.getId());
+    assertEquals(actual.getUserId(), expected.getUserId());
+    assertEquals(actual.getTitle(), expected.getTitle());
+    assertEquals(actual.getBody(), expected.getBody());
+  }
+  
+  public static Activity buildTestActivity(String id, String userId, String title, String body) {
+    Activity activity = new ActivityImpl(id, userId); 
+    activity.setTitle(title);
+    activity.setBody(body);
+    return activity;
+  }
+  
+  public static Date buildDate(String dateAsString) {    
+    try {
+      return DATE_FORMATTER.parse(dateAsString);
+    } catch (Exception e) {
+      throw new RuntimeException("Failed to parse date - " + dateAsString, e);
+    }
+  }
+  
+  public static Set<String> asSet(String... items) {
+    return new HashSet<String>(Arrays.asList(items));
+  }
+  
+}

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/shindig/trunk/java/samples/src/test/java/org/apache/shindig/social/opensocial/jpa/spi/SpiTestUtil.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id