This is an automated email from the git hooks/post-receive script. New commit to branch feature/ligthTopiaIdFactory in repository topia. See http://git.nuiton.org/topia.git commit 5a83282246cb3154bbf53e53a741b8c5a5f18bb3 Author: Arnaud Thimel <thimel@codelutin.com> Date: Fri Sep 5 16:04:51 2014 +0200 refs #3495 Introduce a short TopiaIdFactory --- .../persistence/internal/TopiaIdFactoryTest.java | 64 +++++++++++ .../internal/DefaultTopiaIdFactory.java | 7 +- .../persistence/internal/LegacyTopiaIdFactory.java | 9 +- .../persistence/internal/ShortTopiaIdFactory.java | 128 +++++++++++++++++++++ 4 files changed, 200 insertions(+), 8 deletions(-) diff --git a/topia-it/src/test/java/org/nuiton/topia/persistence/internal/TopiaIdFactoryTest.java b/topia-it/src/test/java/org/nuiton/topia/persistence/internal/TopiaIdFactoryTest.java new file mode 100644 index 0000000..3fb1143 --- /dev/null +++ b/topia-it/src/test/java/org/nuiton/topia/persistence/internal/TopiaIdFactoryTest.java @@ -0,0 +1,64 @@ +package org.nuiton.topia.persistence.internal; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.topia.it.legacy.test.entities.Person; +import org.nuiton.topia.it.legacy.test.entities.PersonImpl; +import org.nuiton.topia.persistence.TopiaIdFactory; + +/** + * @author Arnaud Thimel (Code Lutin) + */ +public class TopiaIdFactoryTest { + + protected void testTopiaId(TopiaIdFactory topiaIdFactory, String topiaId) { + + Assert.assertTrue("Invalid topiaId: " + topiaId, topiaIdFactory.isTopiaId(topiaId)); + Assert.assertTrue("Invalid topiaId: " + topiaId, topiaId.contains(topiaIdFactory.getClassName(topiaId).getSimpleName() + topiaIdFactory.getSeparator() + topiaIdFactory.getRandomPart(topiaId))); + Assert.assertEquals("Invalid topiaId: " + topiaId, Person.class, topiaIdFactory.getClassName(topiaId)); + + } + protected void testTopiaIdFactory(TopiaIdFactory topiaIdFactory) { + String topiaId = topiaIdFactory.newTopiaId(Person.class, new PersonImpl()); + testTopiaId(topiaIdFactory, topiaId); + } + + @Test + public void testDefaultTopiaIdFactory() { + TopiaIdFactory topiaIdFactory = new DefaultTopiaIdFactory(); + testTopiaIdFactory(topiaIdFactory); + } + + @Test + public void testLegacyTopiaIdFactory() { + TopiaIdFactory topiaIdFactory = new LegacyTopiaIdFactory(); + testTopiaIdFactory(topiaIdFactory); + } + + @Test + public void testShortTopiaIdFactory() { + TopiaIdFactory topiaIdFactory = new ShortTopiaIdFactory(); + testTopiaIdFactory(topiaIdFactory); + } + + @Test + public void testShortTopiaIdFactoryForGivenTopiaId() { + TopiaIdFactory topiaIdFactory = new ShortTopiaIdFactory(); + testTopiaId(topiaIdFactory, "Person_4SHxCuN4R_yFZA1lZXaw_g"); + } + + @Test + public void testShortTopiaIdFactoryIsTopiaId() { + TopiaIdFactory topiaIdFactory = new ShortTopiaIdFactory(); + Assert.assertFalse(topiaIdFactory.isTopiaId("Person")); + Assert.assertFalse(topiaIdFactory.isTopiaId("Person_")); + Assert.assertTrue(topiaIdFactory.isTopiaId("Person_d")); + } + + @Test + public void testLegacyTopiaIdFactoryForGivenTopiaId() { + TopiaIdFactory topiaIdFactory = new LegacyTopiaIdFactory(); + testTopiaId(topiaIdFactory, "org.nuiton.topia.it.legacy.test.entities.Person#1409923331552#0.36362338680380535"); + } + +} diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/DefaultTopiaIdFactory.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/DefaultTopiaIdFactory.java index fd0495b..2f888d5 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/DefaultTopiaIdFactory.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/DefaultTopiaIdFactory.java @@ -45,11 +45,8 @@ public class DefaultTopiaIdFactory implements TopiaIdFactory { @Override public <E extends TopiaEntity> String newTopiaId(Class<E> entityClass, TopiaEntity topiaEntity) { - if (!entityClass.isInterface()) { - throw new IllegalArgumentException( - "Only interface is permit to create id: " + entityClass); - } - String result = entityClass.getName() + getSeparator() + UUID.randomUUID().toString(); + String randomPart = UUID.randomUUID().toString(); + String result = newTopiaId(entityClass, randomPart); return result; } diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/LegacyTopiaIdFactory.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/LegacyTopiaIdFactory.java index d46dc0b..e831398 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/LegacyTopiaIdFactory.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/LegacyTopiaIdFactory.java @@ -79,7 +79,7 @@ public class LegacyTopiaIdFactory implements TopiaIdFactory { @Override public String getRandomPart(String topiaId) { - return StringUtils.substringBefore(topiaId, getSeparator()); + return StringUtils.substringAfter(topiaId, getSeparator()); } @Override @@ -87,11 +87,14 @@ public class LegacyTopiaIdFactory implements TopiaIdFactory { boolean isTopiaId = false; if (str != null) { String[] split = str.split(getSeparator()); - if (split.length == 2) { + if (split.length >= 2) { String className = split[0]; try { Class.forName(className); - isTopiaId = StringUtils.isNoneBlank(split[1]); + isTopiaId = true; + for (int index=1; index<split.length; index++) { + isTopiaId &= StringUtils.isNoneBlank(split[index]); + } } catch (ClassNotFoundException eee) { // nothing to do, just return false if (log.isDebugEnabled()) { diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/ShortTopiaIdFactory.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/ShortTopiaIdFactory.java new file mode 100644 index 0000000..62981b4 --- /dev/null +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/ShortTopiaIdFactory.java @@ -0,0 +1,128 @@ +package org.nuiton.topia.persistence.internal; + +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaException; +import org.nuiton.topia.persistence.TopiaIdFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.io.BaseEncoding; + +/** + * Does the same than {@link DefaultTopiaIdFactory} but produces shorter topiaId. The class-name part uses only simple + * class names, and the random part is base64 encoded. + * <p/> + * Note: This TopiaIdFactory requires that you do not have several entities with the same simple class name. + * + * @author Arnaud Thimel (Code Lutin) + */ +public class ShortTopiaIdFactory implements TopiaIdFactory { + + private static final Log log = LogFactory.getLog(ShortTopiaIdFactory.class); + + protected static final Map<String, Class<? extends TopiaEntity>> ENTITY_CLASSES = Maps.newConcurrentMap(); + + @Override + public <E extends TopiaEntity> String newTopiaId(Class<E> entityClass, TopiaEntity topiaEntity) { + String uuid = UUID.randomUUID().toString(); + String escapedUuid = uuid.replace("-", "").toUpperCase(); + byte[] bytes = BaseEncoding.base16().decode(escapedUuid); + String randomPart = BaseEncoding.base64Url().encode(bytes); + // Base64 may produce tailing '=' as padding, remove it + randomPart = randomPart.replace("=", ""); + String result = newTopiaId(entityClass, randomPart); + return result; + } + + @Override + public <E extends TopiaEntity> String newTopiaId(Class<E> entityClass, String randomPart) { + if (!entityClass.isInterface()) { + throw new IllegalArgumentException( + "Only interface is permit to create id: " + entityClass); + } + String result = entityClass.getSimpleName() + getSeparator() + randomPart; + return result; + } + + @Override + public <E extends TopiaEntity> Class<E> getClassName(String topiaId) { + String simpleClassName = StringUtils.substringBefore(topiaId, getSeparator()); + try { + Class<E> entityClass = findClassName(simpleClassName); + return entityClass; + } catch (ClassNotFoundException cnfe) { + throw new TopiaException("Can't find class for topiaId = '" + topiaId + "'", cnfe); + } + } + + protected <E extends TopiaEntity> Class<E> findClassName(String simpleClassName) throws ClassNotFoundException { + Class<E> result; + if (ENTITY_CLASSES.containsKey(simpleClassName)) { + result = (Class<E>) ENTITY_CLASSES.get(simpleClassName); + } else { + Set<Class<?>> candidates = Sets.newHashSet(); + for (Package aPackage : Package.getPackages()) { + String fqn = aPackage.getName() + "." + simpleClassName; + try { + Class<?> aClass = Class.forName(fqn); + candidates.add(aClass); + } catch (Exception eee) { + // Nothing to do + } + } + Iterables.removeIf(candidates, new Predicate<Class<?>>() { + @Override + public boolean apply(Class<?> aClass) { + return !TopiaEntity.class.isAssignableFrom(aClass); + } + }); + if (candidates.size() == 1) { + result = (Class<E>) candidates.iterator().next(); + ENTITY_CLASSES.put(simpleClassName, result); + } else { + String message = String.format("Unable to find class with simple name=%s. " + + "Candidates are: %s", simpleClassName, candidates); + throw new ClassNotFoundException(message); + } + } + return result; + } + + @Override + public String getSeparator() { + return "_"; + } + + @Override + public String getRandomPart(String topiaId) { + return StringUtils.substringAfter(topiaId, getSeparator()); + } + + @Override + public boolean isTopiaId(String str) { + boolean isTopiaId = false; + if (str != null) { + String simpleClassName = StringUtils.substringBefore(str, getSeparator()); + try { + findClassName(simpleClassName); + isTopiaId = StringUtils.isNotBlank(StringUtils.substringAfter(str, getSeparator())); + } catch (ClassNotFoundException eee) { + // nothing to do, just return false + if (log.isDebugEnabled()) { + log.debug(eee); + } + } + } + return isTopiaId; + } + +} -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.