From: Erik Brakkee Date: Wed, 21 Jul 2010 18:48:03 +0000 (+0000) Subject: (no commit message) X-Git-Tag: wamblee-utils-0.7~232 X-Git-Url: http://wamblee.org/gitweb/?a=commitdiff_plain;h=0160b65d4c0f112ae839140980e80b4fa6f348d5;p=utils --- diff --git a/support/general/pom.xml b/support/general/pom.xml index f76dd170..da1ff2a5 100644 --- a/support/general/pom.xml +++ b/support/general/pom.xml @@ -14,9 +14,15 @@ /support/general http://wamblee.org + + javax.persistence + persistence-api + provided + javax javaee-api + provided oro diff --git a/support/general/src/main/java/org/wamblee/persistence/AbstractDetachable.java b/support/general/src/main/java/org/wamblee/persistence/AbstractDetachable.java new file mode 100644 index 00000000..1e7461bf --- /dev/null +++ b/support/general/src/main/java/org/wamblee/persistence/AbstractDetachable.java @@ -0,0 +1,115 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +/** + * Detachable implementation that takes care of the basic logic for detachable + * objects. All that needs to be done is to implement {@link #load()}. + * + * @param + * The type of the object to be attached/detached + * @param + * The type of the reference to store when the object is detached. + */ +public abstract class AbstractDetachable implements Detachable { + + private T object; + private Ref reference; + + /** + * Constructs the detachable. + * + * @param aObject + * Object. + * @throws IllegalArgumentException + * When the object passed in is null. + */ + protected AbstractDetachable(T aObject) { + if (aObject == null) { + throw new IllegalArgumentException("Object '" + aObject + + "' is null"); + } + object = aObject; + reference = null; + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.persistence.Detachable#detach() + */ + public void detach() { + if (object == null) { + return; // Nothing to do. + } + reference = getReference(object); + if (reference == null) { + throw new IllegalStateException("Object '" + object + + "' not persisted yet'"); + } + object = null; + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.persistence.Detachable#get() + */ + public T get() { + if (object == null) { + object = load(reference); + reference = null; + } + return object; + } + + /** + * For testing. + * + * @return current object. + */ + T getObject() { + return object; + } + + /** + * For testing. + * + * @return The reference. + */ + Ref getReference() { + return reference; + } + + /** + * Loads the object based on a reference. + * + * @param aReference + * Reference. + * @return Object (may be null ). + */ + protected abstract T load(Ref aReference); + + /** + * Obtains the reference for a given object. + * + * @param aObject + * Object. + * @return Reference. + */ + protected abstract Ref getReference(T aObject); + +} diff --git a/support/general/src/main/java/org/wamblee/persistence/Detachable.java b/support/general/src/main/java/org/wamblee/persistence/Detachable.java new file mode 100644 index 00000000..0d681d0c --- /dev/null +++ b/support/general/src/main/java/org/wamblee/persistence/Detachable.java @@ -0,0 +1,39 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +import java.io.Serializable; + +/** + * Represents a detachable object. It represent a reference to a persistent object. + * The object is detachable in that the memory footprint can be reduced by not keeping + * a reference to the complete java object, but only to its identify in persistent + * storage. This is typically the primary key in a relational database. + */ +public interface Detachable extends Serializable { + + /** + * Detaches the object. + */ + void detach(); + + /** + * Gets the object, attaching it if needed. + * @return + */ + T get(); + +} diff --git a/support/general/src/main/java/org/wamblee/persistence/InMemoryDetachable.java b/support/general/src/main/java/org/wamblee/persistence/InMemoryDetachable.java new file mode 100644 index 00000000..f8ba0c33 --- /dev/null +++ b/support/general/src/main/java/org/wamblee/persistence/InMemoryDetachable.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +/** + * Inmemory detachable that simply returns the object passed in. Typiocally used for testing. + * It does nothing at detach. + * + * @param + * Type of the detachable. + */ +public class InMemoryDetachable implements Detachable { + + private T object; + + /** + * Constructs the detachable. + * @param aObject + */ + public InMemoryDetachable(T aObject) { + object = aObject; + } + + /* + * (non-Javadoc) + * @see org.wamblee.persistence.Detachable#detach() + */ + public void detach() { + // No op. + } + + /* + * (non-Javadoc) + * @see org.wamblee.persistence.Detachable#get() + */ + public T get() { + return object; + } + +} diff --git a/support/general/src/main/java/org/wamblee/persistence/JpaDetachable.java b/support/general/src/main/java/org/wamblee/persistence/JpaDetachable.java new file mode 100644 index 00000000..ac0912f8 --- /dev/null +++ b/support/general/src/main/java/org/wamblee/persistence/JpaDetachable.java @@ -0,0 +1,57 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +import java.io.Serializable; + +import javax.persistence.EntityManager; + +/** + * Detachable JPA entity. + * + * @author Erik Brakkee + * + * @param Entity type. + */ +public class JpaDetachable extends AbstractDetachable { + + private EntityManager entityManager; + private Class entityType; + + /** + * Constructs the detachable. + * @param aEntity Entity. + */ + public JpaDetachable(EntityManager aEntityManager, T aEntity) { + super(aEntity); + entityManager = aEntityManager; + entityType = (Class)aEntity.getClass(); + } + + /* + * (non-Javadoc) + * @see org.wamblee.persistence.AbstractDetachable#getReference(java.lang.Object) + */ + protected Serializable getReference(T aObject) { + Persistent persistent = PersistentFactory.create(aObject); + return persistent.getPrimaryKey(); + } + + @Override + protected T load(Serializable aReference) { + return entityManager.find(entityType, aReference); + } +} diff --git a/support/general/src/main/java/org/wamblee/persistence/PersistentFactory.java b/support/general/src/main/java/org/wamblee/persistence/PersistentFactory.java index 6b24e3f0..2ad15265 100644 --- a/support/general/src/main/java/org/wamblee/persistence/PersistentFactory.java +++ b/support/general/src/main/java/org/wamblee/persistence/PersistentFactory.java @@ -132,15 +132,15 @@ public class PersistentFactory { List pkAccessors = AnnotationUtils.analyse(aClass, Id.class); List versionAccessors = AnnotationUtils.analyse(aClass, Version.class); - Accessor pk = null; - if ( pkAccessors.size() > 0 ) { + Accessor pk = null; + if (pkAccessors.size() > 0) { pk = pkAccessors.get(0); } - Accessor version = null; - if ( versionAccessors.size() > 0 ) { + Accessor version = null; + if (versionAccessors.size() > 0) { version = versionAccessors.get(0); } - if (pk != null|| version != null) { + if (pk != null || version != null) { return new EntityAccessor(pk, version); } return null; diff --git a/support/general/src/test/java/org/wamblee/persistence/AbstractDetachableTest.java b/support/general/src/test/java/org/wamblee/persistence/AbstractDetachableTest.java new file mode 100644 index 00000000..0a342e7b --- /dev/null +++ b/support/general/src/test/java/org/wamblee/persistence/AbstractDetachableTest.java @@ -0,0 +1,126 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +import static org.mockito.Mockito.*; + +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.TestCase.*; + +public class AbstractDetachableTest { + + public static class X { + + } + + public static interface DetachableMethods { + Integer getReference(X aObject); + + X load(Integer aReference); + } + + public class MyDetachable extends AbstractDetachable { + + public MyDetachable(X aObj) { + super(aObj); + } + + @Override + protected Integer getReference(X aObject) { + return methods.getReference(aObject); + } + + @Override + protected X load(Integer aReference) { + return methods.load(aReference); + } + + } + + private DetachableMethods methods; + private AbstractDetachable detachable; + private X x; + + @Before + public void setUp() { + methods = mock(DetachableMethods.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testNullPassedIn() { + detachable = new MyDetachable(null); + } + + @Test + public void testDetach() { + x = new X(); + Integer ref = 100; + when(methods.getReference(any(X.class))).thenReturn(ref); + detachable = new MyDetachable(x); + verifyNoMoreInteractions(methods); + detachable.detach(); + verify(methods).getReference(same(x)); + assertNull(detachable.getObject()); + assertEquals(ref, detachable.getReference()); + } + + @Test + public void testDetachTwice() { + reset(methods); + testDetach(); + detachable.detach(); + detachable.detach(); + verifyNoMoreInteractions(methods); + } + + @Test(expected = IllegalStateException.class) + public void testDetachWithNullReference() { + x = new X(); + Integer ref = 100; + when(methods.getReference(any(X.class))).thenReturn(null); + detachable = new MyDetachable(x); + verifyNoMoreInteractions(methods); + detachable.detach(); + } + + @Test + public void testReattach() { + testDetach(); + reset(methods); + + X x2 = new X(); // the new X loaded from persistent storage. + when(methods.load(detachable.getReference())).thenReturn(x2); + + X x3 = detachable.get(); + verify(methods).load(100); + assertSame(x2, x3); + + assertSame(x2, detachable.getObject()); + } + + @Test + public void testGetInvokedTwiceNoLoads() { + testReattach(); + reset(methods); + detachable.get(); + detachable.get(); + verifyNoMoreInteractions(methods); + } + + +} diff --git a/support/general/src/test/java/org/wamblee/persistence/InMemoryDetachableTest.java b/support/general/src/test/java/org/wamblee/persistence/InMemoryDetachableTest.java new file mode 100644 index 00000000..b7d0a01f --- /dev/null +++ b/support/general/src/test/java/org/wamblee/persistence/InMemoryDetachableTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +import static junit.framework.Assert.*; + +import org.junit.Test; + +public class InMemoryDetachableTest { + + public static class X { + + } + + @Test + public void testXxx() { + X x = new X(); + InMemoryDetachable detachable = new InMemoryDetachable(x); + assertSame(x, detachable.get()); + } +} diff --git a/support/general/src/test/java/org/wamblee/persistence/JpaDetachableTest.java b/support/general/src/test/java/org/wamblee/persistence/JpaDetachableTest.java new file mode 100644 index 00000000..0fee2dbe --- /dev/null +++ b/support/general/src/test/java/org/wamblee/persistence/JpaDetachableTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.persistence; + +import static org.mockito.Mockito.*; + +import javax.persistence.EntityManager; +import javax.persistence.Id; + +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.TestCase.*; + +public class JpaDetachableTest { + + public class X { + @Id + private int id; + + } + + private EntityManager em; + + @Before + public void setUp() { + em = mock(EntityManager.class); + } + + @Test + public void testDetachAttach() { + X x = new X(); + x.id = 100; + + JpaDetachable d = new JpaDetachable(em, x); + assertNull(d.getReference()); + d.detach(); + assertEquals(100, d.getReference()); + + X x2 = new X(); + x2.id = 100; + when(em.find(X.class, 100)).thenReturn(x2); + X x3 = d.get(); + assertSame(x2, x3); + verify(em).find(X.class, 100); + + } +}