Invariant Properties

  • rss
  • Home

Project Student: JPA Criteria Queries

Bear Giles | December 29, 2013

This is part of Project Student. Other posts are Webservice Client With Jersey, Webservice Server with Jersey, Business Layer, Persistence with Spring Data, Sharding Integration Test Data and Webservice Integration.

We’ve covered basic CRUD operations but that doesn’t take us very far. Spring Data makes it easy to include basic searches but it’s important to have other standard options. One of the most important is JPA criteria queries.

A good introduction to this material is Spring Data JPA tutorial – JPA Criteria Queries [http://www.petrikainulainen.net].

Design Decisions

JPA criteria – I’m using JPA criteria searches instead of querydsl. I’ll come back to querydsl later.

Limitations

Violation of Encapsulation – this design requires breaking the architectural goal of making each layer completely unaware of the implementation details of the other layers. This is a very small violation – only the JPA specifications – and we still have to deal with pagination. Put those together and I feel it’s premature optimization to worry about this too much at this time.

Webservices – the webservice client and server are not updated. Again we still have to deal with pagination and anything we do now will have to be changed anyway.

Refactoring Prior Work

I have three changes to prior work.

findCoursesByTestRun()

I had defined the method

  1. List findCoursesByTestRun(TestRun testRun);
List findCoursesByTestRun(TestRun testRun);

in the Course repository. That doesn’t have the intended effect. What I needed was

  1. List findCoursesByTestRun_Uuid(String uuid);
List findCoursesByTestRun_Uuid(String uuid);

with the appropriate changes to the calling code. Or you can just use the JPA criteria query discussed below.

FinderService and ManagerService

This comes from research on the Jumpstart site. The author splits the standard service interface into two pieces:

  • FinderService – read-only operations (searches)
  • ManagerService – read-write operations (create, update, delete)

This makes a lot of sense, e.g., it will be a lot easier to add behavior via AOP when we can operate at the class vs. method level. I’ve made the appropriate changes in the existing code.

FindBugs

I’ve fixed a number of issues identified by FindBugs.

Metadata

We begin by enabling access to metadata access to our persistent objects. This allows us to create queries that can be optimized by the JPA implementation.

  1. import javax.persistence.metamodel.SingularAttribute;
  2. import javax.persistence.metamodel.StaticMetamodel;
  3.  
  4. @StaticMetamodel(Course.class)
  5. public class Course_ {
  6.     public static volatile SingularAttribute<Course, TestRun> testRun;
  7. }
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@StaticMetamodel(Course.class)
public class Course_ {
    public static volatile SingularAttribute<Course, TestRun> testRun;
}

and

  1. @StaticMetamodel(TestRun.class)
  2. public class TestRun_ {
  3.     public static volatile SingularAttribute<TestRun, String> uuid;
  4. }
@StaticMetamodel(TestRun.class)
public class TestRun_ {
    public static volatile SingularAttribute<TestRun, String> uuid;
}

The name of the class is required due to convention over configuration.

For a discussion of this feature see Static metadata [jboss.org].

Specifications

We can now create the query specification using the metadata now available. This is a slightly more complex query since we need to drill into the structure. (This shouldn’t require an actual join since the testrun uuid is used as the foreign key.)

  1. public class CourseSpecifications {
  2.  
  3.     /**
  4.      * Creates a specification used to find courses with the specified testUuid.
  5.      *
  6.      * @param testRun
  7.      * @return
  8.      */
  9.     public static Specification<Course> testRunIs(final TestRun testRun) {
  10.  
  11.         return new Specification<Course>() {
  12.             @Override
  13.             public Predicate toPredicate(Root<Course> courseRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {
  14.                 Predicate p = null;
  15.                 if (testRun == null || testRun.getUuid() == null) {
  16.                     p = cb.isNull(courseRoot.<Course_> get("testRun"));
  17.                 } else {
  18.                     p = cb.equal(courseRoot.<Course_> get("testRun").<TestRun_> get("uuid"), testRun.getUuid());
  19.                 }
  20.                 return p;
  21.             }
  22.         };
  23.     }
  24. }
public class CourseSpecifications {

    /**
     * Creates a specification used to find courses with the specified testUuid.
     * 
     * @param testRun
     * @return
     */
    public static Specification<Course> testRunIs(final TestRun testRun) {

        return new Specification<Course>() {
            @Override
            public Predicate toPredicate(Root<Course> courseRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate p = null;
                if (testRun == null || testRun.getUuid() == null) {
                    p = cb.isNull(courseRoot.<Course_> get("testRun"));
                } else {
                    p = cb.equal(courseRoot.<Course_> get("testRun").<TestRun_> get("uuid"), testRun.getUuid());
                }
                return p;
            }
        };
    }
}

Some documentation suggests I could use get(Course_.testRun) instead of get(“testRun”) but eclipse was flagging it as a type violation on the get() method. Your mileage may vary.

Spring Data Repository

We must tell Spring Data that we’re using JPA Criteria queries. This is done by extending the JpaSpecificationExecutor interface.

  1. @Repository
  2. public interface CourseRepository extends JpaRepository<Course, Integer>,
  3.         JpaSpecificationExecutor<Course> {
  4.    
  5.     Course findCourseByUuid(String uuid);
  6.  
  7.     List findCoursesByTestRunUuid(String uuid);
  8. }
@Repository
public interface CourseRepository extends JpaRepository<Course, Integer>,
        JpaSpecificationExecutor<Course> {
    
    Course findCourseByUuid(String uuid);

    List findCoursesByTestRunUuid(String uuid);
}

FinderService Implementation

We can now use the JPA specification in our service implementations. As mentioned above using the JPA Criteria Specification violates encapsulation.

  1. import static com.invariantproperties.sandbox.student.specification.CourseSpecifications.testRunIs;
  2.  
  3. @Service
  4. public class CourseFinderServiceImpl implements CourseFinderService {
  5.     @Resource
  6.     private CourseRepository courseRepository;
  7.  
  8.     /**
  9.      * @see com.invariantproperties.sandbox.student.business.FinderService#
  10.      *      count()
  11.      */
  12.     @Transactional(readOnly = true)
  13.     @Override
  14.     public long count() {
  15.         return countByTestRun(null);
  16.     }
  17.  
  18.     /**
  19.      * @see com.invariantproperties.sandbox.student.business.FinderService#
  20.      *      countByTestRun(com.invariantproperties.sandbox.student.domain.TestRun)
  21.      */
  22.     @Transactional(readOnly = true)
  23.     @Override
  24.     public long countByTestRun(TestRun testRun) {
  25.         long count = 0;
  26.         try {
  27.             count = courseRepository.count(testRunIs(testRun));
  28.         } catch (DataAccessException e) {
  29.             if (!(e instanceof UnitTestException)) {
  30.                 log.info("internal error retrieving classroom count by " + testRun, e);
  31.             }
  32.             throw new PersistenceException("unable to count classrooms by " + testRun, e, 0);
  33.         }
  34.  
  35.         return count;
  36.     }
  37.  
  38.     /**
  39.      * @see com.invariantproperties.sandbox.student.business.CourseFinderService#
  40.      *      findAllCourses()
  41.      */
  42.     @Transactional(readOnly = true)
  43.     @Override
  44.     public List<Course> findAllCourses() {
  45.         return findCoursesByTestRun(null);
  46.     }
  47.  
  48.     /**
  49.      * @see com.invariantproperties.sandbox.student.business.CourseFinderService#
  50.      *      findCoursesByTestRun(java.lang.String)
  51.      */
  52.     @Transactional(readOnly = true)
  53.     @Override
  54.     public List<Course> findCoursesByTestRun(TestRun testRun) {
  55.         List<Course> courses = null;
  56.  
  57.         try {
  58.             courses = courseRepository.findAll(testRunIs(testRun));
  59.         } catch (DataAccessException e) {
  60.             if (!(e instanceof UnitTestException)) {
  61.                 log.info("error loading list of courses: " + e.getMessage(), e);
  62.             }
  63.             throw new PersistenceException("unable to get list of courses.", e);
  64.         }
  65.  
  66.         return courses;
  67.     }
  68.  
  69.     ....
  70. }
import static com.invariantproperties.sandbox.student.specification.CourseSpecifications.testRunIs;

@Service
public class CourseFinderServiceImpl implements CourseFinderService {
    @Resource
    private CourseRepository courseRepository;

    /**
     * @see com.invariantproperties.sandbox.student.business.FinderService#
     *      count()
     */
    @Transactional(readOnly = true)
    @Override
    public long count() {
        return countByTestRun(null);
    }

    /**
     * @see com.invariantproperties.sandbox.student.business.FinderService#
     *      countByTestRun(com.invariantproperties.sandbox.student.domain.TestRun)
     */
    @Transactional(readOnly = true)
    @Override
    public long countByTestRun(TestRun testRun) {
        long count = 0;
        try {
            count = courseRepository.count(testRunIs(testRun));
        } catch (DataAccessException e) {
            if (!(e instanceof UnitTestException)) {
                log.info("internal error retrieving classroom count by " + testRun, e);
            }
            throw new PersistenceException("unable to count classrooms by " + testRun, e, 0);
        }

        return count;
    }

    /**
     * @see com.invariantproperties.sandbox.student.business.CourseFinderService#
     *      findAllCourses()
     */
    @Transactional(readOnly = true)
    @Override
    public List<Course> findAllCourses() {
        return findCoursesByTestRun(null);
    }

    /**
     * @see com.invariantproperties.sandbox.student.business.CourseFinderService#
     *      findCoursesByTestRun(java.lang.String)
     */
    @Transactional(readOnly = true)
    @Override
    public List<Course> findCoursesByTestRun(TestRun testRun) {
        List<Course> courses = null;

        try {
            courses = courseRepository.findAll(testRunIs(testRun));
        } catch (DataAccessException e) {
            if (!(e instanceof UnitTestException)) {
                log.info("error loading list of courses: " + e.getMessage(), e);
            }
            throw new PersistenceException("unable to get list of courses.", e);
        }

        return courses;
    }

    ....
}

Unit Testing

Our unit tests require a small change to use a Specification.

  1. public class CourseFinderServiceImplTest {
  2.     private final Class<Specification<Course>> sClass = null;
  3.  
  4.     @Test
  5.     public void testCount() {
  6.         final long expected = 3;
  7.  
  8.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  9.         when(repository.count(any(sClass))).thenReturn(expected);
  10.  
  11.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  12.         final long actual = service.count();
  13.  
  14.         assertEquals(expected, actual);
  15.     }
  16.  
  17.     @Test
  18.     public void testCountByTestRun() {
  19.         final long expected = 3;
  20.         final TestRun testRun = new TestRun();
  21.  
  22.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  23.         when(repository.count(any(sClass))).thenReturn(expected);
  24.  
  25.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  26.         final long actual = service.countByTestRun(testRun);
  27.  
  28.         assertEquals(expected, actual);
  29.     }
  30.  
  31.     @Test(expected = PersistenceException.class)
  32.     public void testCountError() {
  33.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  34.         when(repository.count(any(sClass))).thenThrow(new UnitTestException());
  35.  
  36.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  37.         service.count();
  38.     }
  39.  
  40.     @Test
  41.     public void testFindAllCourses() {
  42.         final List<Course> expected = Collections.emptyList();
  43.  
  44.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  45.         when(repository.findAll(any(sClass))).thenReturn(expected);
  46.  
  47.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  48.         final List<Course> actual = service.findAllCourses();
  49.  
  50.         assertEquals(expected, actual);
  51.     }
  52.  
  53.     @Test(expected = PersistenceException.class)
  54.     public void testFindAllCoursesError() {
  55.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  56.         final Class<Specification<Course>> sClass = null;
  57.         when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());
  58.  
  59.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  60.         service.findAllCourses();
  61.     }
  62.  
  63.     @Test
  64.     public void testFindCourseByTestUuid() {
  65.         final TestRun testRun = new TestRun();
  66.         final Course course = new Course();
  67.         final List<Course> expected = Collections.singletonList(course);
  68.  
  69.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  70.         when(repository.findAll(any(sClass))).thenReturn(expected);
  71.  
  72.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  73.         final List actual = service.findCoursesByTestRun(testRun);
  74.  
  75.         assertEquals(expected, actual);
  76.     }
  77.  
  78.     @Test(expected = PersistenceException.class)
  79.     public void testFindCourseByTestUuidError() {
  80.         final TestRun testRun = new TestRun();
  81.  
  82.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  83.         when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());
  84.  
  85.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  86.         service.findCoursesByTestRun(testRun);
  87.     }
  88.  
  89.     @Test
  90.     public void testFindCoursesByTestUuid() {
  91.         final TestRun testRun = new TestRun();
  92.         final Course course = new Course();
  93.         final List<Course> expected = Collections.singletonList(course);
  94.  
  95.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  96.         when(repository.findAll(any(sClass))).thenReturn(expected);
  97.  
  98.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  99.         final List<Course> actual = service.findCoursesByTestRun(testRun);
  100.  
  101.         assertEquals(expected, actual);
  102.     }
  103.  
  104.     @Test(expected = PersistenceException.class)
  105.     public void testFindCoursesByTestUuidError() {
  106.         final TestRun testRun = new TestRun();
  107.  
  108.         final CourseRepository repository = Mockito.mock(CourseRepository.class);
  109.         when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());
  110.  
  111.         final CourseFinderService service = new CourseFinderServiceImpl(repository);
  112.         service.findCoursesByTestRun(testRun);
  113.     }
  114.  
  115.     ....
  116. }
public class CourseFinderServiceImplTest {
    private final Class<Specification<Course>> sClass = null;

    @Test
    public void testCount() {
        final long expected = 3;

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.count(any(sClass))).thenReturn(expected);

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        final long actual = service.count();

        assertEquals(expected, actual);
    }

    @Test
    public void testCountByTestRun() {
        final long expected = 3;
        final TestRun testRun = new TestRun();

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.count(any(sClass))).thenReturn(expected);

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        final long actual = service.countByTestRun(testRun);

        assertEquals(expected, actual);
    }

    @Test(expected = PersistenceException.class)
    public void testCountError() {
        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.count(any(sClass))).thenThrow(new UnitTestException());

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        service.count();
    }

    @Test
    public void testFindAllCourses() {
        final List<Course> expected = Collections.emptyList();

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.findAll(any(sClass))).thenReturn(expected);

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        final List<Course> actual = service.findAllCourses();

        assertEquals(expected, actual);
    }

    @Test(expected = PersistenceException.class)
    public void testFindAllCoursesError() {
        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        final Class<Specification<Course>> sClass = null;
        when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        service.findAllCourses();
    }
 
    @Test
    public void testFindCourseByTestUuid() {
        final TestRun testRun = new TestRun();
        final Course course = new Course();
        final List<Course> expected = Collections.singletonList(course);

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.findAll(any(sClass))).thenReturn(expected);

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        final List actual = service.findCoursesByTestRun(testRun);

        assertEquals(expected, actual);
    }

    @Test(expected = PersistenceException.class)
    public void testFindCourseByTestUuidError() {
        final TestRun testRun = new TestRun();

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        service.findCoursesByTestRun(testRun);
    }

    @Test
    public void testFindCoursesByTestUuid() {
        final TestRun testRun = new TestRun();
        final Course course = new Course();
        final List<Course> expected = Collections.singletonList(course);

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.findAll(any(sClass))).thenReturn(expected);

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        final List<Course> actual = service.findCoursesByTestRun(testRun);

        assertEquals(expected, actual);
    }

    @Test(expected = PersistenceException.class)
    public void testFindCoursesByTestUuidError() {
        final TestRun testRun = new TestRun();

        final CourseRepository repository = Mockito.mock(CourseRepository.class);
        when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());

        final CourseFinderService service = new CourseFinderServiceImpl(repository);
        service.findCoursesByTestRun(testRun);
    }

    ....
}

I could eliminate a lot of duplicate code by using a @Begin method but decided against it to support parallel testing.

Integration Testing

We finally come to our integration tests. We know we did something right because the only is one line to test additional functionality – counting the number of courses in the database.

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = { BusinessApplicationContext.class, TestBusinessApplicationContext.class,
  3.         TestPersistenceJpaConfig.class })
  4. @Transactional
  5. @TransactionConfiguration(defaultRollback = true)
  6. public class CourseServiceIntegrationTest {
  7.  
  8.     @Resource
  9.     private CourseFinderService fdao;
  10.  
  11.     @Resource
  12.     private CourseManagerService mdao;
  13.  
  14.     @Resource
  15.     private TestRunService testService;
  16.  
  17.     @Test
  18.     public void testCourseLifecycle() throws Exception {
  19.         final TestRun testRun = testService.createTestRun();
  20.  
  21.         final String name = "Calculus 101 : " + testRun.getUuid();
  22.  
  23.         final Course expected = new Course();
  24.         expected.setName(name);
  25.  
  26.         assertNull(expected.getId());
  27.  
  28.         // create course
  29.         Course actual = mdao.createCourseForTesting(name, testRun);
  30.         expected.setId(actual.getId());
  31.         expected.setUuid(actual.getUuid());
  32.         expected.setCreationDate(actual.getCreationDate());
  33.  
  34.         assertThat(expected, equalTo(actual));
  35.         assertNotNull(actual.getUuid());
  36.         assertNotNull(actual.getCreationDate());
  37.  
  38.         // get course by id
  39.         actual = fdao.findCourseById(expected.getId());
  40.         assertThat(expected, equalTo(actual));
  41.  
  42.         // get course by uuid
  43.         actual = fdao.findCourseByUuid(expected.getUuid());
  44.         assertThat(expected, equalTo(actual));
  45.  
  46.         // get all courses
  47.         final List<Course> courses = fdao.findCoursesByTestRun(testRun);
  48.         assertTrue(courses.contains(actual));
  49.  
  50.         // count courses
  51.         final long count = fdao.countByTestRun(testRun);
  52.         assertTrue(count > 0);
  53.  
  54.         // update course
  55.         expected.setName("Calculus 102 : " + testRun.getUuid());
  56.         actual = mdao.updateCourse(actual, expected.getName());
  57.         assertThat(expected, equalTo(actual));
  58.  
  59.         // delete Course
  60.         mdao.deleteCourse(expected.getUuid(), 0);
  61.         try {
  62.             fdao.findCourseByUuid(expected.getUuid());
  63.             fail("exception expected");
  64.         } catch (ObjectNotFoundException e) {
  65.             // expected
  66.         }
  67.  
  68.         testService.deleteTestRun(testRun.getUuid());
  69.     }
  70. }
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { BusinessApplicationContext.class, TestBusinessApplicationContext.class,
        TestPersistenceJpaConfig.class })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class CourseServiceIntegrationTest {

    @Resource
    private CourseFinderService fdao;

    @Resource
    private CourseManagerService mdao;

    @Resource
    private TestRunService testService;

    @Test
    public void testCourseLifecycle() throws Exception {
        final TestRun testRun = testService.createTestRun();

        final String name = "Calculus 101 : " + testRun.getUuid();

        final Course expected = new Course();
        expected.setName(name);

        assertNull(expected.getId());

        // create course
        Course actual = mdao.createCourseForTesting(name, testRun);
        expected.setId(actual.getId());
        expected.setUuid(actual.getUuid());
        expected.setCreationDate(actual.getCreationDate());

        assertThat(expected, equalTo(actual));
        assertNotNull(actual.getUuid());
        assertNotNull(actual.getCreationDate());

        // get course by id
        actual = fdao.findCourseById(expected.getId());
        assertThat(expected, equalTo(actual));

        // get course by uuid
        actual = fdao.findCourseByUuid(expected.getUuid());
        assertThat(expected, equalTo(actual));

        // get all courses
        final List<Course> courses = fdao.findCoursesByTestRun(testRun);
        assertTrue(courses.contains(actual));

        // count courses
        final long count = fdao.countByTestRun(testRun);
        assertTrue(count > 0);

        // update course
        expected.setName("Calculus 102 : " + testRun.getUuid());
        actual = mdao.updateCourse(actual, expected.getName());
        assertThat(expected, equalTo(actual));

        // delete Course
        mdao.deleteCourse(expected.getUuid(), 0);
        try {
            fdao.findCourseByUuid(expected.getUuid());
            fail("exception expected");
        } catch (ObjectNotFoundException e) {
            // expected
        }

        testService.deleteTestRun(testRun.getUuid());
    }
}

Source Code

The source code is at https://github.com/beargiles/project-student [github] and http://beargiles.github.io/project-student/ [github pages].

Categories
java
Comments rss
Comments rss
Trackback
Trackback

« How Many Lines Of Code Do You Write Every Day? Project Student: Maintenance Webapp (read-only) »

Leave a Reply

Click here to cancel reply.

You must be logged in to post a comment.

Archives

  • May 2020 (1)
  • March 2019 (1)
  • August 2018 (1)
  • May 2018 (1)
  • February 2018 (1)
  • November 2017 (4)
  • January 2017 (3)
  • June 2016 (1)
  • May 2016 (1)
  • April 2016 (2)
  • March 2016 (1)
  • February 2016 (3)
  • January 2016 (6)
  • December 2015 (2)
  • November 2015 (3)
  • October 2015 (2)
  • August 2015 (4)
  • July 2015 (2)
  • June 2015 (2)
  • January 2015 (1)
  • December 2014 (6)
  • October 2014 (1)
  • September 2014 (2)
  • August 2014 (1)
  • July 2014 (1)
  • June 2014 (2)
  • May 2014 (2)
  • April 2014 (1)
  • March 2014 (1)
  • February 2014 (3)
  • January 2014 (6)
  • December 2013 (13)
  • November 2013 (6)
  • October 2013 (3)
  • September 2013 (2)
  • August 2013 (5)
  • June 2013 (1)
  • May 2013 (2)
  • March 2013 (1)
  • November 2012 (1)
  • October 2012 (3)
  • September 2012 (2)
  • May 2012 (6)
  • January 2012 (2)
  • December 2011 (12)
  • July 2011 (1)
  • June 2011 (2)
  • May 2011 (5)
  • April 2011 (6)
  • March 2011 (4)
  • February 2011 (3)
  • October 2010 (6)
  • September 2010 (8)

Recent Posts

  • 8-bit Breadboard Computer: Good Encapsulation!
  • Where are all the posts?
  • Better Ad Blocking Through Pi-Hole and Local Caching
  • The difference between APIs and SPIs
  • Hadoop: User Impersonation with Kerberos Authentication

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Pages

  • About Me
  • Notebook: Common XML Tasks
  • Notebook: Database/Webapp Security
  • Notebook: Development Tips

Syndication

Java Code Geeks

Know Your Rights

Support Bloggers' Rights
Demand Your dotRIGHTS

Security

  • Dark Reading
  • Krebs On Security Krebs On Security
  • Naked Security Naked Security
  • Schneier on Security Schneier on Security
  • TaoSecurity TaoSecurity

Politics

  • ACLU ACLU
  • EFF EFF

News

  • Ars technica Ars technica
  • Kevin Drum at Mother Jones Kevin Drum at Mother Jones
  • Raw Story Raw Story
  • Tech Dirt Tech Dirt
  • Vice Vice

Spam Blocked

53,793 spam blocked by Akismet
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox