diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2013-01-04 17:33:40 +0100 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2013-01-04 17:33:40 +0100 |
commit | 8cce8890eca34fead35ad19a0db6d95dd047b3a6 (patch) | |
tree | 1843c791ab50c96c650ddd70a7ac8ec815dde267 | |
parent | 4a6c9c52d006ecb717bae7d9b502d9b661a08ccd (diff) | |
download | esper-testing-8cce8890eca34fead35ad19a0db6d95dd047b3a6.tar.gz esper-testing-8cce8890eca34fead35ad19a0db6d95dd047b3a6.tar.bz2 esper-testing-8cce8890eca34fead35ad19a0db6d95dd047b3a6.tar.xz esper-testing-8cce8890eca34fead35ad19a0db6d95dd047b3a6.zip |
o Trying out a custom UUID type for prettier formatting.
12 files changed, 362 insertions, 34 deletions
diff --git a/src/main/java/io/trygvis/esper/testing/Uuid.java b/src/main/java/io/trygvis/esper/testing/Uuid.java new file mode 100755 index 0000000..64fd6e5 --- /dev/null +++ b/src/main/java/io/trygvis/esper/testing/Uuid.java @@ -0,0 +1,182 @@ +package io.trygvis.esper.testing; + +import java.util.*; + +public class Uuid { + private transient final UUID uuid; + + public Uuid(UUID uuid) { + this.uuid = uuid; + } + + public static Uuid randomUuid() { + return new Uuid(UUID.randomUUID()); + } + + public String toUuidString() { + return uuid.toString(); + } + + public String toString() { + return toStringBase64(); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Uuid that = (Uuid) o; + + return uuid.equals(that.uuid); + } + + public int hashCode() { + return uuid.hashCode(); + } + + public String toStringBase64() { + char[] chars = new char[22]; + + int i = 0; + long most = uuid.getMostSignificantBits(); + int j; + + // The first 10 characters (60 bits) are easy + for (j = 64 - 6; j >= 0; j -= 6) { + long l = most >> j; + long y = 0x3f & l; + int x = (int) y; + char c = alphabet[x]; + chars[i++] = c; + } + + long least = uuid.getLeastSignificantBits(); + + // Use the four last digits from most and two from least + { + long y = (0xf & most) << 2; + long yy = 0xc000000000000000L & least; + + int z = (int) (yy >> 62); + + int x = (int) y + (0x3 & z); + char c = alphabet[x]; + chars[i++] = c; + } + + // Start from the 56th bit and generate 9 characters + for (j = 62 - 6; j >= 0; j -= 6) { + long l = least >> j; + long y = 0x3f & l; + int x = (int) y; + char c = alphabet[x]; + chars[i++] = c; + } + + // Use the last two bits for the last character + chars[i] = alphabet[(int)least & 0x3]; + + return new String(chars); + } + + public static Uuid fromString(String s) { + if (s == null) { + throw new NullPointerException(); + } + + if (s.length() == 36) { + return new Uuid(UUID.fromString(s)); + } + + if (s.length() == 22) { + long most = 0; + int i = 0; + int shift = 64; + for(; i < 10; i++) { + char c = s.charAt(i); + long b = alphabetR[c]; + + if(b == 0) { + throw new IllegalArgumentException(s); + } + + b--; + + shift -= 6; + + long l = b << shift; + + most |= l; + } + + long least; + + { + char c = s.charAt(i++); + long b = alphabetR[c]; + + if (b == 0) { + throw new IllegalArgumentException(s); + } + + b--; + + long l = b >> 2; + + most |= l; + + shift = 64 - 2; + + least = (b & 0x03) << shift; + } + + for(; i < 22; i++) { + char c = s.charAt(i); + long b = alphabetR[c]; + + if(b == 0) { + throw new IllegalArgumentException(s); + } + + b--; + + shift -= 6; + + long l = b << shift; + least |= l; + } + + return new Uuid(new UUID(most, least)); + } + + throw new IllegalArgumentException("Illegal: " + s); + } + + // http://en.wikipedia.org/wiki/Base64 + public final static char[] alphabet = new char[]{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'/* ,'+', '/'*/, '-', '_' + }; + + public final static byte[] alphabetR; + + static { + alphabetR = new byte[256]; + for (int i = 0; i < alphabet.length; i++) { + // plus one so it's possible to know if the lookup failed ('A' would normally be 0). + alphabetR[alphabet[i]] = (byte)(i + 1); + } + +// for (int i = 0; i < alphabetR.length; i++) { +// int v = alphabetR[i]; +// if (v == 0) { +// continue; +// } +// System.out.println(String.format("alphabetR[%3d / %c] = %d", i, (char) i, v)); +// } +// +// System.out.println("alphabetR = " + alphabetR['A']); + } +} diff --git a/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakablePoller.java b/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakablePoller.java index 3183304..7fb057a 100755 --- a/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakablePoller.java +++ b/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakablePoller.java @@ -52,7 +52,7 @@ public class UnbreakablePoller implements TablePoller.NewRowCallback<BuildDto> { UnbreakableBadgeProgress badge = UnbreakableBadgeProgress.initial(person); logger.info("New badge progress"); String state = badgeService.serialize(badge); - daos.personDao.insertBadgeProgress(person, UNBREAKABLE, state); + daos.personDao.insertBadgeProgress(new Uuid(person), UNBREAKABLE, state); continue; } @@ -82,7 +82,7 @@ public class UnbreakablePoller implements TablePoller.NewRowCallback<BuildDto> { String state = badgeService.serialize(badge); - daos.personDao.updateBadgeProgress(person, UNBREAKABLE, state); + daos.personDao.updateBadgeProgress(new Uuid(person), UNBREAKABLE, state); } } } diff --git a/src/main/java/io/trygvis/esper/testing/core/db/BuildDao.java b/src/main/java/io/trygvis/esper/testing/core/db/BuildDao.java index c7923d0..9fdf3f4 100755 --- a/src/main/java/io/trygvis/esper/testing/core/db/BuildDao.java +++ b/src/main/java/io/trygvis/esper/testing/core/db/BuildDao.java @@ -48,11 +48,11 @@ public class BuildDao { } } - public void insertBuildParticipant(UUID build, UUID person) throws SQLException { + public void insertBuildParticipant(UUID build, Uuid person) throws SQLException { try (PreparedStatement s = c.prepareStatement("INSERT INTO build_participant(build, person) VALUES(?, ?)")) { int i = 1; s.setString(i++, build.toString()); - s.setString(i, person.toString()); + s.setString(i, person.toUuidString()); s.executeUpdate(); } } diff --git a/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java b/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java index 96569dd..3288b56 100755 --- a/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java +++ b/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java @@ -1,5 +1,6 @@ package io.trygvis.esper.testing.core.db; +import io.trygvis.esper.testing.*; import io.trygvis.esper.testing.core.db.PersonBadgeDto.*; import io.trygvis.esper.testing.util.sql.*; import org.joda.time.*; @@ -20,7 +21,7 @@ public class PersonDao { public PersonDto apply(ResultSet rs) throws SQLException { int i = 1; return new PersonDto( - UUID.fromString(rs.getString(i++)), + Uuid.fromString(rs.getString(i++)), new DateTime(rs.getTimestamp(i++).getTime()), rs.getString(i++), rs.getString(i)); @@ -64,11 +65,11 @@ public class PersonDao { // Person // ----------------------------------------------------------------------- - public UUID insertPerson(String mail, String name) throws SQLException { + public Uuid insertPerson(String mail, String name) throws SQLException { try (PreparedStatement s = c.prepareStatement("INSERT INTO person(" + PERSON + ") VALUES(?, ?, ?, ?)")) { - UUID uuid = UUID.randomUUID(); + Uuid uuid = Uuid.randomUuid(); int i = 1; - s.setString(i++, uuid.toString()); + s.setString(i++, uuid.toUuidString()); s.setTimestamp(i++, new Timestamp(currentTimeMillis())); s.setString(i++, name); s.setString(i, mail); @@ -77,10 +78,10 @@ public class PersonDao { } } - public SqlOption<PersonDto> selectPerson(UUID uuid) throws SQLException { + public SqlOption<PersonDto> selectPerson(Uuid uuid) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person WHERE uuid=?")) { int i = 1; - s.setString(i, uuid.toString()); + s.setString(i, uuid.toUuidString()); return fromRs(s.executeQuery()).map(person); } } @@ -120,19 +121,19 @@ public class PersonDao { // Person Jenkins User // ----------------------------------------------------------------------- - public void insertPersonJenkinsUser(UUID person, UUID jenkinsUser) throws SQLException { + public void insertPersonJenkinsUser(Uuid person, UUID jenkinsUser) throws SQLException { try (PreparedStatement s = c.prepareStatement("INSERT INTO person_jenkins_user(person, jenkins_user) VALUES(?, ?)")) { int i = 1; - s.setString(i++, person.toString()); + s.setString(i++, person.toUuidString()); s.setString(i, jenkinsUser.toString()); s.executeUpdate(); } } - public boolean hasPersonJenkinsUser(UUID person, UUID jenkinsUser) throws SQLException { + public boolean hasPersonJenkinsUser(Uuid person, UUID jenkinsUser) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT 1 FROM person_jenkins_user WHERE person=? AND jenkins_user=?")) { int i = 1; - s.setString(i++, person.toString()); + s.setString(i++, person.toUuidString()); s.setString(i, jenkinsUser.toString()); ResultSet rs = s.executeQuery(); return rs.next(); @@ -168,10 +169,10 @@ public class PersonDao { } } - public List<PersonBadgeDto> selectBadges(UUID person) throws SQLException { + public List<PersonBadgeDto> selectBadges(Uuid person) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON_BADGE + " FROM person_badge WHERE person=? ORDER BY name, level DESC")) { int i = 1; - s.setString(i, person.toString()); + s.setString(i, person.toUuidString()); return toList(s, personBadge); } } @@ -199,32 +200,32 @@ public class PersonDao { } } - public List<PersonBadgeProgressDto> selectBadgeProgresses(UUID person) throws SQLException { + public List<PersonBadgeProgressDto> selectBadgeProgresses(Uuid person) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON_BADGE_PROGRESS + " FROM person_badge_progress WHERE person=? ORDER BY badge")) { int i = 1; - s.setString(i, person.toString()); + s.setString(i, person.toUuidString()); return toList(s, personBadgeProgress); } } - public void insertBadgeProgress(UUID person, BadgeType type, String state) throws SQLException { + public void insertBadgeProgress(Uuid person, BadgeType type, String state) throws SQLException { try (PreparedStatement s = c.prepareStatement("INSERT INTO person_badge_progress (" + PERSON_BADGE_PROGRESS + ") VALUES(?, ?, ?, ?, ?)")) { UUID uuid = UUID.randomUUID(); int i = 1; s.setString(i++, uuid.toString()); s.setTimestamp(i++, new Timestamp(currentTimeMillis())); - s.setString(i++, person.toString()); + s.setString(i++, person.toUuidString()); s.setString(i++, type.toString()); s.setString(i, state); s.executeUpdate(); } } - public void updateBadgeProgress(UUID person, BadgeType type, String state) throws SQLException { + public void updateBadgeProgress(Uuid person, BadgeType type, String state) throws SQLException { try (PreparedStatement s = c.prepareStatement("UPDATE person_badge_progress SET state=? WHERE person=? AND badge=?")) { int i = 1; s.setString(i++, state); - s.setString(i++, person.toString()); + s.setString(i++, person.toUuidString()); s.setString(i, type.toString()); s.executeUpdate(); } diff --git a/src/main/java/io/trygvis/esper/testing/core/db/PersonDto.java b/src/main/java/io/trygvis/esper/testing/core/db/PersonDto.java index 6dbea74..20780a3 100755 --- a/src/main/java/io/trygvis/esper/testing/core/db/PersonDto.java +++ b/src/main/java/io/trygvis/esper/testing/core/db/PersonDto.java @@ -3,14 +3,16 @@ package io.trygvis.esper.testing.core.db; import io.trygvis.esper.testing.*; import org.joda.time.*; -import java.util.*; - -public class PersonDto extends AbstractEntity { +public class PersonDto /*extends AbstractEntity*/ { + public final Uuid uuid; + public final DateTime createdDate; public final String name; public final String mail; - public PersonDto(UUID uuid, DateTime createdDate, String name, String mail) { - super(uuid, createdDate); + public PersonDto(Uuid uuid, DateTime createdDate, String name, String mail) { +// super(uuid, createdDate); + this.uuid = uuid; + this.createdDate = createdDate; this.name = name; this.mail = mail; } diff --git a/src/main/java/io/trygvis/esper/testing/core/jenkins/JenkinsBuildPoller.java b/src/main/java/io/trygvis/esper/testing/core/jenkins/JenkinsBuildPoller.java index 4689e4d..38152e0 100755 --- a/src/main/java/io/trygvis/esper/testing/core/jenkins/JenkinsBuildPoller.java +++ b/src/main/java/io/trygvis/esper/testing/core/jenkins/JenkinsBuildPoller.java @@ -110,7 +110,7 @@ public class JenkinsBuildPoller implements TablePoller.NewRowCallback<JenkinsBui knownPersons++; - UUID person = personO.get().uuid; + Uuid person = personO.get().uuid; logger.info("Created build participant, person={}", person); buildDao.insertBuildParticipant(uuidBuild, person); } diff --git a/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java b/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java index a02bb5c..8f66548 100755 --- a/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java +++ b/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java @@ -34,7 +34,7 @@ public class JerseyApplication extends Application { } public Set<Class<?>> getClasses() { - return new HashSet<>(Arrays.<Class<?>>asList(ResourceParamInjector.class)); + return new HashSet<>(Arrays.<Class<?>>asList(ResourceParamInjector.class, MyObjectMapper.class)); } public Set<Object> getSingletons() { @@ -97,6 +97,38 @@ public class JerseyApplication extends Application { } } }; + } else if (Uuid.class.equals(type)) { + + return new AbstractHttpContextInjectable() { + public Object getValue(HttpContext hc) { + + if (a.query().length() > 0) { + return parse(hc.getRequest().getQueryParameters().getFirst(a.query())); + } else { + MultivaluedMap<String, String> pathParameters = hc.getUriInfo().getPathParameters(); + + for (Map.Entry<String, List<String>> entry : pathParameters.entrySet()) { + if ("uuid".equals(entry.getKey())) { + return parse(entry.getValue().get(0)); + } + } + } + + throw new RuntimeException("@MagicParam used with Uuid argument with no {uuid} path variable."); + } + + private Uuid parse(String s) { + if(s == null) { + return null; + } + + try { + return Uuid.fromString(s); + } catch (IllegalArgumentException e) { + throw new WebApplicationException(400); + } + } + }; } return null; diff --git a/src/main/java/io/trygvis/esper/testing/web/MyObjectMapper.java b/src/main/java/io/trygvis/esper/testing/web/MyObjectMapper.java new file mode 100755 index 0000000..bfbd6eb --- /dev/null +++ b/src/main/java/io/trygvis/esper/testing/web/MyObjectMapper.java @@ -0,0 +1,37 @@ +package io.trygvis.esper.testing.web; + +import io.trygvis.esper.testing.*; +import org.codehaus.jackson.*; +import org.codehaus.jackson.map.*; +import org.codehaus.jackson.map.module.*; + +import java.io.*; +import javax.ws.rs.ext.*; + +public class MyObjectMapper implements ContextResolver<ObjectMapper> { + private ObjectMapper objectMapper; + + public MyObjectMapper() throws Exception { + objectMapper = new ObjectMapper(); + SimpleModule module = new SimpleModule("wat", Version.unknownVersion()); + module.addDeserializer(Uuid.class, new UuidDeserializer()); + module.addSerializer(Uuid.class, new UuidSerializer()); + objectMapper.registerModule(module); + } + + public ObjectMapper getContext(Class<?> type) { + return objectMapper; + } + + private static class UuidDeserializer extends JsonDeserializer<Uuid> { + public Uuid deserialize(JsonParser jp, DeserializationContext context) throws IOException { + return Uuid.fromString(jp.getText()); + } + } + + private static class UuidSerializer extends JsonSerializer<Uuid> { + public void serialize(Uuid value, JsonGenerator generator, SerializerProvider provider) throws IOException { + generator.writeString(value.toStringBase64()); + } + } +} diff --git a/src/main/java/io/trygvis/esper/testing/web/resource/CoreResource.java b/src/main/java/io/trygvis/esper/testing/web/resource/CoreResource.java index f006261..5849647 100755 --- a/src/main/java/io/trygvis/esper/testing/web/resource/CoreResource.java +++ b/src/main/java/io/trygvis/esper/testing/web/resource/CoreResource.java @@ -50,9 +50,9 @@ public class CoreResource extends AbstractResource { @GET @Path("/person/{uuid}") - public PersonJson getPerson(@PathParam("uuid") final String s) throws Exception { - final UUID uuid = JenkinsResource.parseUuid(s); - + public PersonJson getPerson(@PathParam("uuid") final Uuid uuid) throws Exception { + System.out.println("uuid.toStringBase64() = " + uuid.toStringBase64()); + System.out.println("uuid.toUuidString() = " + uuid.toUuidString()); return get(new DatabaseAccess.DaosCallback<Option<PersonJson>>() { public Option<PersonJson> run(Daos daos) throws SQLException { SqlOption<PersonDto> o = daos.personDao.selectPerson(uuid); diff --git a/src/main/java/io/trygvis/esper/testing/web/resource/PersonJson.java b/src/main/java/io/trygvis/esper/testing/web/resource/PersonJson.java index e8008e3..e26b120 100644..100755 --- a/src/main/java/io/trygvis/esper/testing/web/resource/PersonJson.java +++ b/src/main/java/io/trygvis/esper/testing/web/resource/PersonJson.java @@ -1,14 +1,16 @@ package io.trygvis.esper.testing.web.resource; +import io.trygvis.esper.testing.*; + import java.util.*; public class PersonJson { - public final UUID uuid; + public final Uuid uuid; public final String name; public final List<BadgeJson> badges; public final List<BadgeJson> badgesInProgress; - public PersonJson(UUID uuid, String name, List<BadgeJson> badges, List<BadgeJson> badgesInProgress) { + public PersonJson(Uuid uuid, String name, List<BadgeJson> badges, List<BadgeJson> badgesInProgress) { this.uuid = uuid; this.name = name; this.badges = badges; diff --git a/src/main/webapp/WEB-INF/urlrewrite.xml b/src/main/webapp/WEB-INF/urlrewrite.xml index 4d909ca..a649f8b 100644..100755 --- a/src/main/webapp/WEB-INF/urlrewrite.xml +++ b/src/main/webapp/WEB-INF/urlrewrite.xml @@ -21,6 +21,11 @@ <to type="forward">/person/person.jspx</to> </rule> + <rule match-type="regex"> + <from>^/person/([-_0-9A-Za-z]{22})$</from> + <set type="parameter" name="uuid">$1</set> + <to type="forward">/person/person.jspx</to> + </rule> <rule match-type="regex"> <from>^/build/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$</from> diff --git a/src/test/java/io/trygvis/esper/testing/UuidTest.java b/src/test/java/io/trygvis/esper/testing/UuidTest.java new file mode 100755 index 0000000..1efec73 --- /dev/null +++ b/src/test/java/io/trygvis/esper/testing/UuidTest.java @@ -0,0 +1,67 @@ +package io.trygvis.esper.testing; + +import org.apache.commons.lang.*; +import org.junit.*; + +import java.util.*; + +import static java.lang.String.format; +import static org.junit.Assert.*; + +public class UuidTest { + + @Test + public void testToString() { + String s = "fedcba98-7654-3210-fedc-ba9876543210"; + Uuid uuid = Uuid.fromString(s); + + String r = toBase64(0xfedcba9876543210L, 0xfedcba9876543210L); + + assertEquals(s, uuid.toUuidString()); +// assertEquals(uuid.toUuidString(), Uuid.fromString(uuid.toUuidString()).toUuidString()); +// assertEquals(uuid.toStringBase64(), Uuid.fromString(uuid.toStringBase64()).toStringBase64()); + + assertEquals(r, uuid.toStringBase64()); + } + + @Test + public void test2() { + Uuid uuid = Uuid.fromString("fedcba98-7654-3210-fedc-ba9876543210"); + + assertEquals(uuid, Uuid.fromString(uuid.toUuidString())); + + assertEquals(uuid.toUuidString(), Uuid.fromString(uuid.toStringBase64()).toUuidString()); + } + + @Test + public void random() { + Random random = new Random(0); + + for(int i = 0; i < 100; i++) { + long most = random.nextLong(); + long least = random.nextLong(); + System.out.println(format("i=%2d, most=%08x, least=%08x", i, most, least)); + + UUID s = new UUID(most, least); + Uuid uuid = Uuid.fromString(s.toString()); + + assertEquals(s.toString(), uuid.toUuidString()); + assertEquals(toBase64(most, least), uuid.toStringBase64()); + } + } + + private String toBase64(long most, long least) { + String x = StringUtils.leftPad(Long.toBinaryString(most), 64, '0') + StringUtils.leftPad(Long.toBinaryString(least), 64, '0'); + System.out.println(x); + + String r = ""; + for (int i = 0; i < 22; i++) { + int end = Math.min((i + 1) * 6, x.length()); + String y = x.substring(i * 6, end); + int number = Integer.parseInt(y, 2); + System.out.println(format("% 4d % 4d binary=%8s, dec=%2d %c", i, end, y, number, Uuid.alphabet[number])); + r += Uuid.alphabet[number]; + } + return r; + } +} |