From 8cce8890eca34fead35ad19a0db6d95dd047b3a6 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 4 Jan 2013 17:33:40 +0100 Subject: o Trying out a custom UUID type for prettier formatting. --- src/main/java/io/trygvis/esper/testing/Uuid.java | 182 +++++++++++++++++++++ .../testing/core/badge/UnbreakablePoller.java | 4 +- .../io/trygvis/esper/testing/core/db/BuildDao.java | 4 +- .../trygvis/esper/testing/core/db/PersonDao.java | 37 +++-- .../trygvis/esper/testing/core/db/PersonDto.java | 12 +- .../testing/core/jenkins/JenkinsBuildPoller.java | 2 +- .../esper/testing/web/JerseyApplication.java | 34 +++- .../trygvis/esper/testing/web/MyObjectMapper.java | 37 +++++ .../esper/testing/web/resource/CoreResource.java | 6 +- .../esper/testing/web/resource/PersonJson.java | 6 +- 10 files changed, 290 insertions(+), 34 deletions(-) create mode 100755 src/main/java/io/trygvis/esper/testing/Uuid.java create mode 100755 src/main/java/io/trygvis/esper/testing/web/MyObjectMapper.java mode change 100644 => 100755 src/main/java/io/trygvis/esper/testing/web/resource/PersonJson.java (limited to 'src/main/java') 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 { 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 { 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 selectPerson(UUID uuid) throws SQLException { + public SqlOption 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 selectBadges(UUID person) throws SQLException { + public List 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 selectBadgeProgresses(UUID person) throws SQLException { + public List 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> getClasses() { - return new HashSet<>(Arrays.>asList(ResourceParamInjector.class)); + return new HashSet<>(Arrays.>asList(ResourceParamInjector.class, MyObjectMapper.class)); } public Set 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 pathParameters = hc.getUriInfo().getPathParameters(); + + for (Map.Entry> 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 { + 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 { + public Uuid deserialize(JsonParser jp, DeserializationContext context) throws IOException { + return Uuid.fromString(jp.getText()); + } + } + + private static class UuidSerializer extends JsonSerializer { + 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>() { public Option run(Daos daos) throws SQLException { SqlOption 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 old mode 100644 new mode 100755 index e8008e3..e26b120 --- 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 badges; public final List badgesInProgress; - public PersonJson(UUID uuid, String name, List badges, List badgesInProgress) { + public PersonJson(Uuid uuid, String name, List badges, List badgesInProgress) { this.uuid = uuid; this.name = name; this.badges = badges; -- cgit v1.2.3