[topia] branch feature/ligthTopiaIdFactory created (now 5a83282)
This is an automated email from the git hooks/post-receive script. New change to branch feature/ligthTopiaIdFactory in repository topia. See http://git.nuiton.org/topia.git at 5a83282 refs #3495 Introduce a short TopiaIdFactory This branch includes the following new commits: new 5a83282 refs #3495 Introduce a short TopiaIdFactory The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 5a83282246cb3154bbf53e53a741b8c5a5f18bb3 Author: Arnaud Thimel <thimel@codelutin.com> Date: Fri Sep 5 16:04:51 2014 +0200 refs #3495 Introduce a short TopiaIdFactory -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
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>.
participants (1)
-
nuiton.org scm