From 0a502dc25a6d944f8a609ba1fa12ae18c4ab4464 Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Mon, 18 Jun 2018 23:26:28 +0200 Subject: [PATCH 1/7] Introducing short-lived synonyms --- create_release.sh | 3 +++ .../anonimatron/anonymizer/SynonymCache.java | 11 +++++++++++ .../anonimatron/synonyms/DateSynonym.java | 6 ++++++ .../anonimatron/synonyms/HashedFromSynonym.java | 6 ++++++ .../anonimatron/synonyms/NullSynonym.java | 8 ++++++-- .../anonimatron/synonyms/StringSynonym.java | 6 ++++++ .../rolfje/anonimatron/synonyms/Synonym.java | 17 +++++++++++++++++ .../anonymizer/SynonymCacheTest.java | 10 ++++++++++ 8 files changed, 65 insertions(+), 2 deletions(-) diff --git a/create_release.sh b/create_release.sh index 1608e24..419f966 100755 --- a/create_release.sh +++ b/create_release.sh @@ -34,6 +34,9 @@ git commit -m "Update version to $2" git push --follow-tags +# Sign the zip file +gpg -ab --default-key D6584B937338F123 target/anonimatron*.zip + echo "The file to upload for this release is:" echo ls -l target/anonimatron*.zip diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java b/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java index 99c1718..6639e6d 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java @@ -67,7 +67,18 @@ public void toFile(File synonymXMLfile) throws XMLException, IOException, Mappin .writeToFile(allSynonyms, synonymXMLfile.getAbsolutePath()); } + /** + * Stores the given {@link Synonym} in the synonym cache, except when the + * given synonym is short-lived. Short-lived synonyms are not stored or + * re-used. + * + * @param synonym + */ public void put(Synonym synonym) { + if (synonym.isShortLived()) { + return; + } + Map map = synonymCache.get(synonym.getType()); if (map == null) { map = new HashMap(); diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java index b098026..f4de60d 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java @@ -11,6 +11,7 @@ public class DateSynonym implements Synonym { private String type; private Date from; private Date to; + private boolean shortlived = false; public String getType() { return type; @@ -36,6 +37,11 @@ public void setFrom(Object from) { this.from = (Date) from; } + @Override + public boolean isShortLived() { + return shortlived; + } + @Override public boolean equals(Object obj) { return this.hashCode() == obj.hashCode(); diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java index 8e803c4..95957fa 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java @@ -7,6 +7,7 @@ public class HashedFromSynonym implements Synonym { private String from; private Object to; private String type; + private boolean shortLived = false; public HashedFromSynonym() { } @@ -32,6 +33,11 @@ public Object getTo() { return to; } + @Override + public boolean isShortLived() { + return shortLived; + } + public void setFrom(String from) { this.from = from; } diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/NullSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/NullSynonym.java index 2bb4ad0..1d4e238 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/NullSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/NullSynonym.java @@ -2,13 +2,12 @@ /** - * Represents a synonym for a null value of any type. + * Represents a transient synonym for a null value of any type. * */ public class NullSynonym implements Synonym { private String type; - public NullSynonym(String type) { this.type=type; } @@ -25,6 +24,11 @@ public Object getTo() { return null; } + @Override + public boolean isShortLived() { + return true; + } + @Override public boolean equals(Object obj) { return this.hashCode() == obj.hashCode(); diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java index 136f19c..07cb82a 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java @@ -9,6 +9,7 @@ public class StringSynonym implements Synonym { private String type; private String from; private String to; + private boolean shortlived = false; public StringSynonym() { } @@ -43,6 +44,11 @@ public void setFrom(Object from) { this.from = (String) from; } + @Override + public boolean isShortLived() { + return shortlived; + } + @Override public boolean equals(Object obj) { return this.hashCode() == obj.hashCode(); diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java index eb20ebe..285128b 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java @@ -10,6 +10,23 @@ */ public interface Synonym { + /** + * Indicates if this Synonym is short-lived or transient, meaning that + * it should not be stored in the synonyms file. Transient Synonyms + * are not stored, need to be calculated each run time. + * + * Transient synonyms are: + * + *
    + *
  1. Not stored in memory.
  2. + *
  3. Not stored in the synonym file.
  4. + *
+ * + * @return true if the synonym should be thrown away + * after use (not stored in the synonym file). + */ + boolean isShortLived(); + /** * @return The semantic data type of this Synonym, usually something * descriptive as "NAME" or "STREET". diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java index f3a615e..19a7375 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java @@ -1,11 +1,21 @@ package com.rolfje.anonimatron.anonymizer; +import com.rolfje.anonimatron.synonyms.NullSynonym; import com.rolfje.anonimatron.synonyms.StringSynonym; import com.rolfje.anonimatron.synonyms.Synonym; import junit.framework.TestCase; public class SynonymCacheTest extends TestCase { + public void testNoStorageOfShortLivedSynonyms() { + SynonymCache synonymCache = new SynonymCache(); + + NullSynonym n = new NullSynonym("null"); + synonymCache.put(n); + + assertNull(synonymCache.get(n.getType(), n.getFrom())); + } + public void testNoHashing() throws Exception { SynonymCache synonymCache = new SynonymCache(); From 66b336c5b90ecb519ccab2f6d0ed082a4f086a76 Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Thu, 21 Jun 2018 20:09:16 +0200 Subject: [PATCH 2/7] Optional short-lived configuration for columns. --- .../anonimatron/configuration/Column.java | 97 +++++++++++-------- .../ColumnShortLivedFieldHandler.java | 48 +++++++++ .../configuration/Configuration.java | 11 +++ .../configuration/castor-config-mapping.xml | 3 + .../anonymizer/CountryCodeAnonymizerTest.java | 1 + .../configuration/ConfigurationTest.java | 10 +- 6 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandler.java diff --git a/src/main/java/com/rolfje/anonimatron/configuration/Column.java b/src/main/java/com/rolfje/anonimatron/configuration/Column.java index b846555..54f4bcc 100644 --- a/src/main/java/com/rolfje/anonimatron/configuration/Column.java +++ b/src/main/java/com/rolfje/anonimatron/configuration/Column.java @@ -1,43 +1,62 @@ package com.rolfje.anonimatron.configuration; public class Column { - private String name; - private String type; - private int size = -1; - - public Column() { - - } - - public Column(String name, String type) { - this.name = name; - this.type = type; - } - - public Column(String name, String type, int size) { - this(name,type); - this.size = size; - } - - - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - public String getType() { - return type; - } - public void setType(String type) { - this.type = type; - } - - public int getSize() { - return size; - } - public void setSize(int size) { - this.size = size; - } + private String name; + private String type; + private int size = -1; + private boolean shortlived; + + public Column() { + + } + + public Column(String name, String type) { + this.name = name; + this.type = type; + } + + public Column(String name, String type, int size) { + this(name, type); + this.size = size; + } + + public Column(String name, String type, int size, boolean shortlived) { + this(name, type); + this.size = size; + this.shortlived = shortlived; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public boolean isShortLived() { + return shortlived; + } + + public void setShortlived(boolean shortlived) { + this.shortlived = shortlived; + } + } diff --git a/src/main/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandler.java b/src/main/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandler.java new file mode 100644 index 0000000..6128efa --- /dev/null +++ b/src/main/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandler.java @@ -0,0 +1,48 @@ +package com.rolfje.anonimatron.configuration; + +import org.exolab.castor.mapping.FieldHandler; +import org.exolab.castor.mapping.ValidityException; + +/** + * Field handler which makes sure that if {@link Column#isShortLived()} returns false, + * this handler returns null so that Castor will not put it in the configuration file. + */ +public class ColumnShortLivedFieldHandler implements FieldHandler { + + @Override + public Boolean getValue(Object o) throws IllegalStateException { + if (o instanceof Column) { + return ((Column) o).isShortLived() + ? Boolean.TRUE + : null; + } + return null; + } + + @Override + public void setValue(Object o, Boolean b) throws IllegalStateException, IllegalArgumentException { + + boolean shortlived = (b != null && b.booleanValue()); + + if (o instanceof Column) { + ((Column) o).setShortlived(shortlived); + } else { + throw new UnsupportedOperationException("Can not set shortlived boolean on object of type " + o.getClass()); + } + } + + @Override + public void resetValue(Object o) throws IllegalStateException, IllegalArgumentException { + setValue(o, false); + } + + @Override + public void checkValidity(Object o) throws ValidityException, IllegalStateException { + // not much to check on a boolean + } + + @Override + public Boolean newInstance(Object o) throws IllegalStateException { + return null; + } +} diff --git a/src/main/java/com/rolfje/anonimatron/configuration/Configuration.java b/src/main/java/com/rolfje/anonimatron/configuration/Configuration.java index 4fb008f..bd48d80 100644 --- a/src/main/java/com/rolfje/anonimatron/configuration/Configuration.java +++ b/src/main/java/com/rolfje/anonimatron/configuration/Configuration.java @@ -1,8 +1,10 @@ package com.rolfje.anonimatron.configuration; import com.rolfje.anonimatron.anonymizer.AnonymizerService; +import com.rolfje.anonimatron.anonymizer.StringAnonymizer; import com.rolfje.anonimatron.file.CsvFileReader; import com.rolfje.anonimatron.file.CsvFileWriter; +import com.rolfje.anonimatron.synonyms.StringSynonym; import org.apache.log4j.Logger; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.mapping.MappingException; @@ -259,6 +261,15 @@ private static List getColumns() throws Exception { c.setType(type); columns.add(c); } + + // Add a demo configuration for a shortlived (non-stored) column. + Column c = new Column(); + c.setName("A_SHORTLIVED_COLUMN"); + c.setType(new StringAnonymizer().getType()); + c.setShortlived(true); + columns.add(c); + + return columns; } diff --git a/src/main/java/com/rolfje/anonimatron/configuration/castor-config-mapping.xml b/src/main/java/com/rolfje/anonimatron/configuration/castor-config-mapping.xml index 25cc369..b1df576 100644 --- a/src/main/java/com/rolfje/anonimatron/configuration/castor-config-mapping.xml +++ b/src/main/java/com/rolfje/anonimatron/configuration/castor-config-mapping.xml @@ -97,6 +97,9 @@ + + + diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java index 5ac6415..6c6b399 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java @@ -18,6 +18,7 @@ private void testInternal(int size, String from) { assertEquals(from, nld.getFrom()); assertFalse(from.equals(nld.getTo())); assertEquals(size, ((String) nld.getTo()).length()); + assertFalse(nld.isShortLived()); } } \ No newline at end of file diff --git a/src/test/java/com/rolfje/anonimatron/configuration/ConfigurationTest.java b/src/test/java/com/rolfje/anonimatron/configuration/ConfigurationTest.java index 9ae3269..52df1ae 100644 --- a/src/test/java/com/rolfje/anonimatron/configuration/ConfigurationTest.java +++ b/src/test/java/com/rolfje/anonimatron/configuration/ConfigurationTest.java @@ -21,7 +21,10 @@ public void testPrintMappedConfig() throws Exception { String demoxml = Configuration.getDemoConfiguration(); assertNotNull(demoxml); assertTrue(demoxml.length()>10); - + + // For convenience and visual checking. + System.out.println(demoxml); + // See if all anonymizer types are represented in the demo xml AnonymizerService as = new AnonymizerService(); Set customtypes = as.getCustomAnonymizerTypes(); @@ -34,11 +37,12 @@ public void testPrintMappedConfig() throws Exception { assertTrue("Demo xml does not contain "+type,demoxml.indexOf(type.toUpperCase().replace('.','_'))>0); } + assertTrue(demoxml.indexOf("A_SHORTLIVED_COLUMN") > 0); + assertTrue(demoxml.indexOf("shortlived") > 0); + // See if we have File records in the configuration. assertTrue(demoxml.contains(" Date: Thu, 21 Jun 2018 21:04:35 +0200 Subject: [PATCH 3/7] Passing on shortlived column configuration onto generated synonyms. --- .../anonymizer/AnonymizerService.java | 24 +++-- .../file/FileAnonymizerService.java | 6 +- .../rolfje/anonimatron/jdbc/ColumnWorker.java | 5 +- .../jdbc/JdbcAnonymizerService.java | 22 +++-- .../anonimatron/jdbc/TableSynonyms.java | 24 ----- .../anonymizer/AnonymizerServiceTest.java | 97 ++++++++++--------- .../ColumnShortLivedFieldHandlerTest.java | 75 ++++++++++++++ 7 files changed, 156 insertions(+), 97 deletions(-) delete mode 100644 src/main/java/com/rolfje/anonimatron/jdbc/TableSynonyms.java create mode 100644 src/test/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandlerTest.java diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java index 19951ff..a01c0e1 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java @@ -1,5 +1,6 @@ package com.rolfje.anonimatron.anonymizer; +import com.rolfje.anonimatron.configuration.Column; import com.rolfje.anonimatron.synonyms.NullSynonym; import com.rolfje.anonimatron.synonyms.Synonym; import org.apache.log4j.Logger; @@ -78,24 +79,33 @@ public Set getDefaultAnonymizerTypes() { return Collections.unmodifiableSet(defaultTypeMapping.keySet()); } - public Synonym anonymize(String type, Object from, int size) { + public Synonym anonymize(Column c, Object from) { if (from == null) { - return new NullSynonym(type); + return new NullSynonym(c.getType()); } // Hash from here. String hashedFrom = new Hasher("secretsalt").base64Hash(from); // Find for regular type - Synonym synonym = synonymCache.get(type, from); + Synonym synonym = getSynonym(c, from); + if (synonym == null) { - // Fallback for default type - synonym = synonymCache.get(defaultTypeMapping.get(type), from); + synonym = getAnonymizer(c.getType()).anonymize(from, c.getSize()); + synonymCache.put(synonym); } + return synonym; + } + private Synonym getSynonym(Column c, Object from) { + if (c.isShortLived()){ + return null; + } + + Synonym synonym = synonymCache.get(c.getType(), from); if (synonym == null) { - synonym = getAnonymizer(type).anonymize(from, size); - synonymCache.put(synonym); + // Fallback for default type + synonym = synonymCache.get(defaultTypeMapping.get(c.getType()), from); } return synonym; } diff --git a/src/main/java/com/rolfje/anonimatron/file/FileAnonymizerService.java b/src/main/java/com/rolfje/anonimatron/file/FileAnonymizerService.java index 2052559..327eb37 100644 --- a/src/main/java/com/rolfje/anonimatron/file/FileAnonymizerService.java +++ b/src/main/java/com/rolfje/anonimatron/file/FileAnonymizerService.java @@ -196,12 +196,8 @@ Record anonymize(Record record, Map columns) { Object value = record.getValues()[i]; if (columns.containsKey(name)) { - Column column = columns.get(name); - String type = column.getType(); - int size = column.getSize(); - - Synonym synonym = anonymizerService.anonymize(type, value, size); + Synonym synonym = anonymizerService.anonymize(column, value); values[i] = synonym.getTo(); } else { values[i] = value; diff --git a/src/main/java/com/rolfje/anonimatron/jdbc/ColumnWorker.java b/src/main/java/com/rolfje/anonimatron/jdbc/ColumnWorker.java index 75fac59..4b3be38 100644 --- a/src/main/java/com/rolfje/anonimatron/jdbc/ColumnWorker.java +++ b/src/main/java/com/rolfje/anonimatron/jdbc/ColumnWorker.java @@ -20,9 +20,7 @@ public interface ColumnWorker { * @param results the resultset in which this worker runs. Can be used to * update the column value when anonymizing. * @param column The column which was fetched from the configuration. - * @param columnType Overrides the column type from the configuration. * @param databaseColumnValue The current value for this column. - * @param columnDisplaySize The displaysize according to the database for * this column. * @return true if the columnworker is ready to process the * next value after this one, or false if the column @@ -32,7 +30,6 @@ public interface ColumnWorker { * @throws SQLException On database access or SQL errors. */ boolean processColumn(ResultSet results, Column column, - String columnType, Object databaseColumnValue, - int columnDisplaySize) throws SQLException; + Object databaseColumnValue) throws SQLException; } diff --git a/src/main/java/com/rolfje/anonimatron/jdbc/JdbcAnonymizerService.java b/src/main/java/com/rolfje/anonimatron/jdbc/JdbcAnonymizerService.java index c230546..2d0a5ab 100644 --- a/src/main/java/com/rolfje/anonimatron/jdbc/JdbcAnonymizerService.java +++ b/src/main/java/com/rolfje/anonimatron/jdbc/JdbcAnonymizerService.java @@ -122,9 +122,9 @@ private void setConnection() throws SQLException { private void preScanTable(Table table) throws SQLException { ColumnWorker worker = new ColumnWorker() { @Override - public boolean processColumn(ResultSet results, Column column, String columnType, - Object databaseColumnValue, int columnDisplaySize) throws SQLException { - return anonymizerService.prepare(columnType, + public boolean processColumn(ResultSet results, Column column, + Object databaseColumnValue) throws SQLException { + return anonymizerService.prepare(column.getType(), databaseColumnValue); } }; @@ -135,11 +135,10 @@ public boolean processColumn(ResultSet results, Column column, String columnType private void anonymizeTableInPlace(Table table) throws SQLException { ColumnWorker worker = new ColumnWorker() { @Override - public boolean processColumn(ResultSet results, Column column, String columnType, - Object databaseColumnValue, int columnDisplaySize) throws SQLException { - Synonym synonym = anonymizerService.anonymize(columnType, - databaseColumnValue, - columnDisplaySize); + public boolean processColumn(ResultSet results, Column column, + Object databaseColumnValue) throws SQLException { + Synonym synonym = anonymizerService.anonymize(column, + databaseColumnValue); if (results.getConcurrency() == ResultSet.CONCUR_UPDATABLE) { // Update the contents of this row with the given Synonym @@ -199,15 +198,18 @@ private void processTableColumns(Table table, final ColumnWorker columnWorker, i String columnType = column.getType(); if (columnType == null) { columnType = resultsMetaData.getColumnClassName(results.findColumn(column.getName())); + column.setType(columnType); } NDC.push("Type '" + columnType + "'"); - Object databaseColumnValue = results.getObject(column.getName()); int columnDisplaySize = resultsMetaData.getColumnDisplaySize(results.findColumn(column.getName())); + column.setSize(columnDisplaySize); + + Object databaseColumnValue = results.getObject(column.getName()); /* If any call returns true, process the next record. */ - processNextRecord = columnWorker.processColumn(results, column, columnType, databaseColumnValue, columnDisplaySize) + processNextRecord = columnWorker.processColumn(results, column, databaseColumnValue) || processNextRecord; NDC.pop(); // type diff --git a/src/main/java/com/rolfje/anonimatron/jdbc/TableSynonyms.java b/src/main/java/com/rolfje/anonimatron/jdbc/TableSynonyms.java deleted file mode 100644 index 0c114a6..0000000 --- a/src/main/java/com/rolfje/anonimatron/jdbc/TableSynonyms.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.rolfje.anonimatron.jdbc; - -import java.util.ArrayList; -import java.util.List; - -import com.rolfje.anonimatron.configuration.Table; -import com.rolfje.anonimatron.synonyms.Synonym; - -public class TableSynonyms extends Table { - List> synonymrows = new ArrayList>(); - - public TableSynonyms(Table t) { - this.setName(t.getName()); - this.setColumns(t.getColumns()); - } - - public void addSynonyms(List synonymrow){ - synonymrows.add(synonymrow); - } - - public List> getSynonymrows() { - return synonymrows; - } -} diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/AnonymizerServiceTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/AnonymizerServiceTest.java index d65cf6e..af81464 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/AnonymizerServiceTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/AnonymizerServiceTest.java @@ -1,5 +1,6 @@ package com.rolfje.anonimatron.anonymizer; +import com.rolfje.anonimatron.configuration.Column; import com.rolfje.anonimatron.synonyms.Synonym; import junit.framework.TestCase; @@ -8,69 +9,71 @@ import java.util.List; public class AnonymizerServiceTest extends TestCase { - AnonymizerService anonService; + AnonymizerService anonService; - protected void setUp() throws Exception { - anonService = new AnonymizerService(); - } + protected void setUp() throws Exception { + anonService = new AnonymizerService(); + } - public void testStringAnonymizer() throws Exception { - List fromList = new ArrayList(); - fromList.add("String 1"); - fromList.add("String 2"); - fromList.add("String 3"); + public void testStringAnonymizer() throws Exception { + List fromList = new ArrayList(); + fromList.add("String 1"); + fromList.add("String 2"); + fromList.add("String 3"); - String type = new StringAnonymizer().getType(); + String type = new StringAnonymizer().getType(); - testAnonymizer(fromList, type, type); - } + testAnonymizer(fromList, type, type); + } - public void testUUIDAnonymizer() throws Exception { - List fromList = new ArrayList(); - fromList.add("String 1"); - fromList.add("String 2"); - fromList.add("String 3"); + public void testUUIDAnonymizer() throws Exception { + List fromList = new ArrayList(); + fromList.add("String 1"); + fromList.add("String 2"); + fromList.add("String 3"); - String type = new UUIDAnonymizer().getType(); + String type = new UUIDAnonymizer().getType(); - testAnonymizer(fromList, type, type); - } + testAnonymizer(fromList, type, type); + } - public void testDateAnonymizer() { + public void testDateAnonymizer() { - assertEquals(new Date(0), new Date(0)); + assertEquals(new Date(0), new Date(0)); - List fromList = new ArrayList(); - fromList.add(new Date(0)); - fromList.add(new Date(86400000L)); - fromList.add(new Date(172800000L)); + List fromList = new ArrayList(); + fromList.add(new Date(0)); + fromList.add(new Date(86400000L)); + fromList.add(new Date(172800000L)); - String type = Date.class.getName(); + String type = Date.class.getName(); - testAnonymizer(fromList, type, "DATE"); - } + testAnonymizer(fromList, type, "DATE"); + } - private void testAnonymizer(List fromList, String lookupType, String synonymType) { - List toList = new ArrayList(); + private void testAnonymizer(List fromList, String lookupType, String synonymType) { + List toList = new ArrayList(); - // First pass - for (Object from : fromList) { - Synonym s = anonService.anonymize(lookupType, from, 100); + Column column = new Column("Testcolumn", lookupType, 100); - assertEquals(from, s.getFrom()); - assertEquals(synonymType, s.getType()); - assertNotNull(s.getTo()); + // First pass + for (Object from : fromList) { + Synonym s = anonService.anonymize(column, from); - toList.add(s.getTo()); - } + assertEquals(from, s.getFrom()); + assertEquals(synonymType, s.getType()); + assertNotNull(s.getTo()); - // Second pass (consistency check) - for (int i = 0; i < fromList.size(); i++) { - Synonym s = anonService.anonymize(lookupType, fromList.get(i), 100); - assertEquals(toList.get(i), s.getTo()); - } + toList.add(s.getTo()); + } - // Test passing in null - assertNull(anonService.anonymize(lookupType, null, 100).getTo()); - } + // Second pass (consistency check) + for (int i = 0; i < fromList.size(); i++) { + Synonym s = anonService.anonymize(column, fromList.get(i)); + assertEquals(toList.get(i), s.getTo()); + } + + // Test passing in null + assertNull(anonService.anonymize(column, null).getTo()); + } } diff --git a/src/test/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandlerTest.java b/src/test/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandlerTest.java new file mode 100644 index 0000000..0aec70f --- /dev/null +++ b/src/test/java/com/rolfje/anonimatron/configuration/ColumnShortLivedFieldHandlerTest.java @@ -0,0 +1,75 @@ +package com.rolfje.anonimatron.configuration; + +import org.exolab.castor.mapping.ValidityException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ColumnShortLivedFieldHandlerTest { + + private ColumnShortLivedFieldHandler handler; + + @Before + public void setUp() throws Exception { + handler = new ColumnShortLivedFieldHandler(); + } + + @Test + public void getValue() { + assertTrue(handler.getValue(shortLivedColumn())); + assertNull(handler.getValue(column())); + assertNull(handler.getValue(new Object())); + } + + @Test + public void setValue() { + Column column = column(); + handler.setValue(column, true); + assertTrue(column.isShortLived()); + + handler.setValue(column, false); + assertFalse(column.isShortLived()); + + try { + handler.setValue(new Object(), true); + fail("Can not set boolean on non-column object."); + } catch (UnsupportedOperationException e) { + // ok + } + } + + @Test + public void resetValue() { + Column column = shortLivedColumn(); + handler.resetValue(column); + assertFalse(column.isShortLived()); + } + + @Test + public void checkValidity() throws ValidityException { + boolean[] all = new boolean[]{true, false}; + for (boolean b : all) { + // Should not do anything + Column column = column(); + column.setShortlived(b); + handler.checkValidity(column); + assertEquals(b, column.isShortLived()); + } + } + + @Test + public void newInstance() { + assertNull(handler.newInstance(new Object())); + } + + private Column shortLivedColumn() { + Column column = new Column(); + column.setShortlived(true); + return column; + } + + private Column column() { + return new Column(); + } +} \ No newline at end of file From 0fef9209375da331d38439993cfb8893ee2e3ad8 Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Thu, 21 Jun 2018 22:04:22 +0200 Subject: [PATCH 4/7] Test to prove that the file anonymizer does not respect the "shortlived" property. --- .../anonymizer/AnonymizerService.java | 4 +- .../anonymizer/CharacterStringAnonymizer.java | 2 - .../anonimatron/anonymizer/SynonymCache.java | 204 +++++++++--------- .../file/FileAnonymizerServiceTest.java | 23 +- 4 files changed, 125 insertions(+), 108 deletions(-) diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java index a01c0e1..5514ed9 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java @@ -84,14 +84,12 @@ public Synonym anonymize(Column c, Object from) { return new NullSynonym(c.getType()); } - // Hash from here. - String hashedFrom = new Hasher("secretsalt").base64Hash(from); - // Find for regular type Synonym synonym = getSynonym(c, from); if (synonym == null) { synonym = getAnonymizer(c.getType()).anonymize(from, c.getSize()); + synonymCache.put(synonym); } return synonym; diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java index 11e9627..48be02f 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java @@ -17,8 +17,6 @@ protected String getDefaultCharacterString() { return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } - - @Override public String getType() { return "RANDOMCHARACTERS"; diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java b/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java index 6639e6d..00e4090 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java @@ -12,104 +12,110 @@ public class SynonymCache { - private Map> synonymCache = new HashMap<>(); - private Hasher hasher; - - public SynonymCache() { - } - - /** - * Reads the synonyms from the specified file and (re-)initializes the - * {@link #synonymCache} with it. - * - * @param synonymXMLfile the xml file containing the synonyms, as written by - * {@link #toFile(File)} - * - * @throws MappingException When synonyms can not be read from file. - * @throws IOException When synonyms can not be read from file. - * @throws XMLException When synonyms can not be read from file. - * - * @return Synonyms as the were stored on last run. - */ - public static SynonymCache fromFile(File synonymXMLfile) throws MappingException, IOException, XMLException { - - SynonymCache synonymCache = new SynonymCache(); - List synonymsFromFile = SynonymMapper - .readFromFile(synonymXMLfile.getAbsolutePath()); - - for (Synonym synonym : synonymsFromFile) { - synonymCache.put(synonym); - } - - return synonymCache; - } - - /** - * Writes all known {@link Synonym}s in the cache out to the specified file - * in XML format. - * - * @param synonymXMLfile an empty writeable xml file to write the synonyms - * to. - * @throws XMLException When there is a problem writing the synonyms to file. - * @throws IOException When there is a problem writing the synonyms to file. + private Map> synonymCache = new HashMap<>(); + private Hasher hasher; + private long size = 0; + + public SynonymCache() { + } + + /** + * Reads the synonyms from the specified file and (re-)initializes the + * {@link #synonymCache} with it. + * + * @param synonymXMLfile the xml file containing the synonyms, as written by + * {@link #toFile(File)} + * @return Synonyms as the were stored on last run. + * @throws MappingException When synonyms can not be read from file. + * @throws IOException When synonyms can not be read from file. + * @throws XMLException When synonyms can not be read from file. + */ + public static SynonymCache fromFile(File synonymXMLfile) throws MappingException, IOException, XMLException { + + SynonymCache synonymCache = new SynonymCache(); + List synonymsFromFile = SynonymMapper + .readFromFile(synonymXMLfile.getAbsolutePath()); + + for (Synonym synonym : synonymsFromFile) { + synonymCache.put(synonym); + } + + return synonymCache; + } + + /** + * Writes all known {@link Synonym}s in the cache out to the specified file + * in XML format. + * + * @param synonymXMLfile an empty writeable xml file to write the synonyms + * to. + * @throws XMLException When there is a problem writing the synonyms to file. + * @throws IOException When there is a problem writing the synonyms to file. * @throws MappingException When there is a problem writing the synonyms to file. - */ - public void toFile(File synonymXMLfile) throws XMLException, IOException, MappingException { - List allSynonyms = new ArrayList(); - - // Flatten the type -> From -> Synonym map. - Collection> allObjectMaps = synonymCache.values(); - for (Map typeMap : allObjectMaps) { - allSynonyms.addAll(typeMap.values()); - } - - SynonymMapper - .writeToFile(allSynonyms, synonymXMLfile.getAbsolutePath()); - } - - /** - * Stores the given {@link Synonym} in the synonym cache, except when the - * given synonym is short-lived. Short-lived synonyms are not stored or - * re-used. - * - * @param synonym - */ - public void put(Synonym synonym) { - if (synonym.isShortLived()) { - return; - } - - Map map = synonymCache.get(synonym.getType()); - if (map == null) { - map = new HashMap(); - synonymCache.put(synonym.getType(), map); - } - - if (hasher != null) { - // Hash sensitive data before storing - Synonym hashed = new HashedFromSynonym(hasher, synonym); - map.put(hashed.getFrom(), hashed); - } else { - // Store as-is - map.put(synonym.getFrom(), synonym); - } - - } - - public Synonym get(String type, Object from) { - Map typemap = synonymCache.get(type); - if (typemap == null) { - return null; - } - - if (hasher != null) { - return typemap.get(hasher.base64Hash(from)); - } else { - return typemap.get(from); - } - } - - public void setHasher(Hasher hasher) { - this.hasher = hasher; - } + */ + public void toFile(File synonymXMLfile) throws XMLException, IOException, MappingException { + List allSynonyms = new ArrayList(); + + // Flatten the type -> From -> Synonym map. + Collection> allObjectMaps = synonymCache.values(); + for (Map typeMap : allObjectMaps) { + allSynonyms.addAll(typeMap.values()); + } + + SynonymMapper + .writeToFile(allSynonyms, synonymXMLfile.getAbsolutePath()); + } + + /** + * Stores the given {@link Synonym} in the synonym cache, except when the + * given synonym is short-lived. Short-lived synonyms are not stored or + * re-used. + * + * @param synonym + */ + public void put(Synonym synonym) { + if (synonym.isShortLived()) { + return; + } + + Map map = synonymCache.get(synonym.getType()); + if (map == null) { + map = new HashMap(); + synonymCache.put(synonym.getType(), map); + } + + if (hasher != null) { + // Hash sensitive data before storing + Synonym hashed = new HashedFromSynonym(hasher, synonym); + if (map.put(hashed.getFrom(), hashed) == null) { + size++; + } + } else { + // Store as-is + if (map.put(synonym.getFrom(), synonym) == null) { + size++; + } + } + } + + public Synonym get(String type, Object from) { + Map typemap = synonymCache.get(type); + if (typemap == null) { + return null; + } + + if (hasher != null) { + return typemap.get(hasher.base64Hash(from)); + } else { + return typemap.get(from); + } + } + + public void setHasher(Hasher hasher) { + this.hasher = hasher; + } + + public long size() { + return size; + } } diff --git a/src/test/java/com/rolfje/anonimatron/file/FileAnonymizerServiceTest.java b/src/test/java/com/rolfje/anonimatron/file/FileAnonymizerServiceTest.java index 65f3e56..079a01f 100644 --- a/src/test/java/com/rolfje/anonimatron/file/FileAnonymizerServiceTest.java +++ b/src/test/java/com/rolfje/anonimatron/file/FileAnonymizerServiceTest.java @@ -19,12 +19,13 @@ public class FileAnonymizerServiceTest extends TestCase { private FileAnonymizerService fileAnonymizerService; + private AnonymizerService anonymizerService; public void setUp() throws Exception { super.setUp(); Configuration config = new Configuration(); - AnonymizerService anonymizerService = new AnonymizerService(); + anonymizerService = new AnonymizerService(); anonymizerService.registerAnonymizers(config.getAnonymizerClasses()); fileAnonymizerService = new FileAnonymizerService(config, anonymizerService); } @@ -39,6 +40,8 @@ public void testAnonymize() throws Exception { assertEquals(record.getNames()[0], anonymize.getNames()[0]); assertFalse(record.getValues()[0].equals(anonymize.getValues()[0])); + + assertEquals(1, anonymizerService.getSynonymCache().size()); } public void testNoExceptionOnEmptyConfig() throws Exception { @@ -54,6 +57,8 @@ public void testPassThroughAnonymization() throws Exception { assertEquals(record.getNames()[0], anonymize.getNames()[0]); assertEquals(record.getValues()[0], anonymize.getValues()[0]); + + assertEquals(0, anonymizerService.getSynonymCache().size()); } public void testAnonymizeRecords() throws Exception { @@ -124,14 +129,16 @@ public void write(Record record) { assertNotNull(target.getNames()[j]); } } + + assertEquals(2, anonymizerService.getSynonymCache().size()); } public void testIntegrationTest() throws Exception { // Create testfile File tempInput = File.createTempFile("tempInput", ".csv"); PrintWriter printWriter = new PrintWriter(tempInput); - printWriter.write("test1,notouch,test2,test3\n"); - printWriter.write("test3,notouch,test2,test1\n"); + printWriter.write("test1,notouch,test2,test3,transient\n"); + printWriter.write("test3,notouch,test2,test1,transient\n"); printWriter.close(); String tempOutput = tempInput.getAbsoluteFile() + ".out.csv"; @@ -139,7 +146,8 @@ public void testIntegrationTest() throws Exception { List columns = Arrays.asList( new Column("1", "STRING", 50), new Column("3", "STRING", 50), - new Column("4", "STRING", 50)); + new Column("4", "STRING", 50), + new Column("5", "STRING", 50, true)); DataFile dataFile = new DataFile(); dataFile.setInFile(tempInput.getAbsolutePath()); @@ -169,7 +177,14 @@ public void testIntegrationTest() throws Exception { assertEquals(outputRecord1.getValues()[2], outputRecord2.getValues()[2]); assertEquals(outputRecord1.getValues()[3], outputRecord2.getValues()[0]); + // The fifth column is transient, so anonymization will not be consistent, + // as the value is not stored in the cache. + assertFalse(outputRecord1.getValues()[4].equals(outputRecord2.getValues()[4])); + assertFalse("transient".equals(outputRecord2.getValues()[4])); + assertEquals("notouch", outputRecord1.getValues()[1]); assertEquals("notouch", outputRecord2.getValues()[1]); + + assertEquals(3, anonymizerService.getSynonymCache().size()); } } \ No newline at end of file From 1f67ba6ff6ad4d353e855c7fe2dc4dcd7fe3925e Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Thu, 21 Jun 2018 23:03:56 +0200 Subject: [PATCH 5/7] passing "shortlived" setting from column to anonymizer to synonym so that it can be set per column (not per data type) --- .../anonymizer/AbstractNameGenerator.java | 18 +- .../anonimatron/anonymizer/Anonymizer.java | 44 +-- .../anonymizer/AnonymizerService.java | 9 +- .../anonymizer/CharacterStringAnonymizer.java | 15 +- .../CharacterStringPrefetchAnonymizer.java | 4 +- .../anonymizer/CountryCodeAnonymizer.java | 7 +- .../anonymizer/DateAnonymizer.java | 3 +- .../anonymizer/DigitStringAnonymizer.java | 12 +- .../anonymizer/DutchBSNAnononymizer.java | 91 +++--- .../DutchBankAccountAnononymizer.java | 268 +++++++++--------- .../anonymizer/DutchZipCodeAnonymizer.java | 8 +- .../anonymizer/EmailAddressAnonymizer.java | 21 +- .../anonymizer/IbanAnonymizer.java | 14 +- .../anonymizer/StringAnonymizer.java | 53 ++-- .../anonymizer/UUIDAnonymizer.java | 68 ++--- .../anonimatron/synonyms/DateSynonym.java | 4 + .../anonimatron/synonyms/StringSynonym.java | 18 +- ...CharacterStringPrefetchAnonymizerTest.java | 65 +++-- .../anonymizer/CountryCodeAnonymizerTest.java | 28 +- .../anonymizer/DutchBSNAnononymizerTest.java | 8 +- .../DutchZipCodeAnonymizerTest.java | 52 ++-- .../anonymizer/IbanAnonymizerTest.java | 2 +- .../anonymizer/RomanNameGeneratorTest.java | 6 +- .../anonymizer/SynonymCacheTest.java | 4 +- .../anonymizer/ToLowerAnonymizer.java | 24 +- .../synonyms/SynonymMapperTest.java | 113 ++++---- .../anonimatron/synonyms/SynonymTest.java | 36 +-- 27 files changed, 512 insertions(+), 483 deletions(-) diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/AbstractNameGenerator.java b/src/main/java/com/rolfje/anonimatron/anonymizer/AbstractNameGenerator.java index 8719551..2ac13c9 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/AbstractNameGenerator.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/AbstractNameGenerator.java @@ -407,17 +407,13 @@ && hatesPreviousVocals(sur.get(c)) || last == 2 } @Override - public Synonym anonymize(Object from, int size) { - - StringSynonym synonym = new StringSynonym(); - synonym.setFrom(from); - - if (from != null){ - synonym.setTo(getName(size)); - } - - synonym.setType(getType()); - return synonym; + public Synonym anonymize(Object from, int size, boolean shortlived) { + return new StringSynonym( + getType(), + (String) from, + from == null ? null : getName(size), + shortlived + ); } private String getName(int size) { diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/Anonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/Anonymizer.java index 36585c6..d90306c 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/Anonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/Anonymizer.java @@ -6,37 +6,37 @@ /** * Provides functionality for consitently anonymizing a piece of data. - * + *

* Implementations of this interface must make sure that anonymization is done * in a reproducable manner. That is, if A transforms into B, it has to * consistently do so on each and every call. - * + *

* By doing this, anonimatron can guarantee that data is transformed * consistently accross all tables of the database, and referential constraints * can be re-enforced after anonymization. */ public interface Anonymizer { - /** - * - * @return The ID or name of this anonymizer, as used in the XML - * configuration file. This is generally something along the lines - * of "LASTNAME" or "UNEVENNUMBER". Please see the output of the - * -configexample command line option when running Anonimatron. - */ - String getType(); + /** + * @return The ID or name of this anonymizer, as used in the XML + * configuration file. This is generally something along the lines + * of "LASTNAME" or "UNEVENNUMBER". Please see the output of the + * -configexample command line option when running Anonimatron. + */ + String getType(); - /** - * Anonymizes the given data into a non-tracable, non-reversible synonym, - * and does it consistently, so that A always translates to B. - * - * @param from - * the data to be anonymized, usually passed in as a - * {@link String}, {@link Integer}, {@link Date} or other classes - * which can be stored in a single JDBC database column. - * @param size the optional maximum size of the generated value - * @return a {@link Synonym} - */ - Synonym anonymize(Object from, int size); + /** + * Anonymizes the given data into a non-tracable, non-reversible synonym, + * and does it consistently, so that A always translates to B. + * + * @param from the data to be anonymized, usually passed in as a + * {@link String}, {@link Integer}, {@link Date} or other classes + * which can be stored in a single JDBC database column. + * @param size the optional maximum size of the generated value + * @param shortlived indicates that the generated synonym must have the + * {@link Synonym#isShortLived()} boolean set + * @return a {@link Synonym} + */ + Synonym anonymize(Object from, int size, boolean shortlived); } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java index 5514ed9..d2c5928 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/AnonymizerService.java @@ -79,16 +79,17 @@ public Set getDefaultAnonymizerTypes() { return Collections.unmodifiableSet(defaultTypeMapping.keySet()); } - public Synonym anonymize(Column c, Object from) { + public Synonym anonymize(Column column, Object from) { if (from == null) { - return new NullSynonym(c.getType()); + return new NullSynonym(column.getType()); } // Find for regular type - Synonym synonym = getSynonym(c, from); + Synonym synonym = getSynonym(column, from); if (synonym == null) { - synonym = getAnonymizer(c.getType()).anonymize(from, c.getSize()); + Anonymizer anonymizer = getAnonymizer(column.getType()); + synonym = anonymizer.anonymize(from, column.getSize(), column.isShortLived()); synonymCache.put(synonym); } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java index 48be02f..410e773 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringAnonymizer.java @@ -23,10 +23,11 @@ public String getType() { } @Override - public Synonym anonymize(Object from, int size) { - int length = from.toString().length(); + public Synonym anonymize(Object from, int size, boolean shortlived) { + String fromString = from.toString(); Random r = new Random(); + int length = fromString.length(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.append(CHARS.charAt(r.nextInt(CHARS.length()))); @@ -34,10 +35,12 @@ public Synonym anonymize(Object from, int size) { String to = sb.toString(); - StringSynonym stringSynonym = new StringSynonym(); - stringSynonym.setFrom(from); - stringSynonym.setType(getType()); - stringSynonym.setTo(to); + StringSynonym stringSynonym = new StringSynonym( + getType(), + fromString, + to, + shortlived + ); return stringSynonym; } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizer.java index 36cef0c..31a0570 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizer.java @@ -32,12 +32,12 @@ public void prefetch(Object sourceData) { } @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { if (CHARS.length() < 1) { LOG.warn("No characters were collected during prefetch. Using the default set '" + getDefaultCharacterString() + "'."); CHARS = getDefaultCharacterString(); } - return super.anonymize(from, size); + return super.anonymize(from, size, shortlived); } @Override diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizer.java index 656677e..bd5e8c5 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizer.java @@ -23,7 +23,7 @@ public String getType() { } @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { if (size < 2) { throw new UnsupportedOperationException("Can not produce country codes of one character."); @@ -50,10 +50,9 @@ else if (size == 2) { return new StringSynonym( getType(), from.toString(), - country + country, + shortlived ); - - } public static String padRight(String s, int n) { diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/DateAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/DateAnonymizer.java index 7d9c9c6..1e2a88f 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/DateAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/DateAnonymizer.java @@ -14,9 +14,10 @@ class DateAnonymizer implements Anonymizer { private Set generatedDates = new HashSet(); @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { DateSynonym s = new DateSynonym(); s.setType(TYPE); + s.setShortlived(shortlived); if (from == null) { s.setFrom(null); diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/DigitStringAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/DigitStringAnonymizer.java index 1049d62..d430b97 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/DigitStringAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/DigitStringAnonymizer.java @@ -11,16 +11,18 @@ public String getType() { } @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { int length = from.toString().length(); int[] digits = getRandomDigits(length); String to = digitsAsNumber(digits); - StringSynonym stringSynonym = new StringSynonym(); - stringSynonym.setFrom(from); - stringSynonym.setType(getType()); - stringSynonym.setTo(to); + StringSynonym stringSynonym = new StringSynonym( + getType(), + (String) from, + to, + shortlived + ); return stringSynonym; } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizer.java index 9239672..4dae58c 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizer.java @@ -13,47 +13,52 @@ * See http://nl.wikipedia.org/wiki/Rekeningnummer */ public class DutchBSNAnononymizer extends AbstractElevenProofAnonymizer { - private static int LENGTH = 9; - - @Override - public String getType() { - return "BURGERSERVICENUMMER"; - } - - @Override - public Synonym anonymize(Object from, int size) { - if (size < LENGTH) { - throw new UnsupportedOperationException( - "Can not generate a BSN that fits in a " - + size - + " character string. Must be " + LENGTH + " characters or more."); - } - - StringSynonym s = new StringSynonym(); - s.setType(getType()); - s.setFrom(from); - - do { - // Never generate identical number - s.setTo(generateBSN(LENGTH)); - } while (s.getFrom().equals(s.getTo())); - - return s; - } - - String generateBSN(int numberOfDigits) { - // Generate random BSN number - int[] bsnnumber; - - do { - bsnnumber = generate11ProofNumber(numberOfDigits); - - // SOFI numbers can not start with 3 zeroes, left digit digit van - // not be >3 - } while ((bsnnumber[0] > 3) && (0 != (bsnnumber[0] + bsnnumber[1] + bsnnumber[2]))); - - // Return the BSN - String result = digitsAsNumber(bsnnumber); - return result; - } + private static int LENGTH = 9; + + @Override + public String getType() { + return "BURGERSERVICENUMMER"; + } + + @Override + public Synonym anonymize(Object from, int size, boolean shortlived) { + if (size < LENGTH) { + throw new UnsupportedOperationException( + "Can not generate a BSN that fits in a " + + size + + " character string. Must be " + LENGTH + " characters or more."); + } + + String fromString = (String) from; + String toString = fromString; + + do { + // Never generate identical number + toString = generateBSN(LENGTH); + } while (fromString.equals(toString)); + + + return new StringSynonym( + getType(), + fromString, + toString, + shortlived + ); + } + + String generateBSN(int numberOfDigits) { + // Generate random BSN number + int[] bsnnumber; + + do { + bsnnumber = generate11ProofNumber(numberOfDigits); + + // SOFI numbers can not start with 3 zeroes, left digit digit van + // not be >3 + } while ((bsnnumber[0] > 3) && (0 != (bsnnumber[0] + bsnnumber[1] + bsnnumber[2]))); + + // Return the BSN + String result = digitsAsNumber(bsnnumber); + return result; + } } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBankAccountAnononymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBankAccountAnononymizer.java index db03b0e..d7c057f 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBankAccountAnononymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchBankAccountAnononymizer.java @@ -1,11 +1,10 @@ package com.rolfje.anonimatron.anonymizer; -import java.security.SecureRandom; - -import org.apache.log4j.Logger; - import com.rolfje.anonimatron.synonyms.StringSynonym; import com.rolfje.anonimatron.synonyms.Synonym; +import org.apache.log4j.Logger; + +import java.security.SecureRandom; /** * Generates valid Dutch Bank Account number with the same length as the given @@ -18,217 +17,220 @@ * See http://nl.wikipedia.org/wiki/Elfproef */ public class DutchBankAccountAnononymizer extends AbstractElevenProofAnonymizer implements BankAccountAnonymizer { - private static Logger LOG = Logger.getLogger(DutchBankAccountAnononymizer.class); + private static Logger LOG = Logger.getLogger(DutchBankAccountAnononymizer.class); - private static int LENGTH = 9; + private static int LENGTH = 9; - private final SecureRandom random = new SecureRandom(); + private final SecureRandom random = new SecureRandom(); - @Override - public String getType() { - return "DUTCHBANKACCOUNT"; - } + @Override + public String getType() { + return "DUTCHBANKACCOUNT"; + } - @Override - public Synonym anonymize(Object from, int size) { - if (size < LENGTH) { - throw new UnsupportedOperationException( - "Can not generate a Dutch Bank Account number that fits in a " + size + " character string. Must be " + LENGTH - + " characters or more."); - } + @Override + public Synonym anonymize(Object from, int size, boolean shortlived) { + if (size < LENGTH) { + throw new UnsupportedOperationException( + "Can not generate a Dutch Bank Account number that fits in a " + size + " character string. Must be " + LENGTH + + " characters or more."); + } - int originalLength = ((String) from).length(); - if (originalLength > LENGTH) { - LOG.warn("Original bank account number had more than " + LENGTH - + " digits. The resulting anonymous bank account number with the same length will not be a valid account number."); + String fromString = (String) from; - } + int originalLength = (fromString).length(); + if (originalLength > LENGTH) { + LOG.warn("Original bank account number had more than " + LENGTH + + " digits. The resulting anonymous bank account number with the same length will not be a valid account number."); - StringSynonym s = new StringSynonym(); - s.setType(getType()); - s.setFrom(from); + } - do { - // Never generate identical number - s.setTo(generateBankAccount(originalLength)); - } while (s.getFrom().equals(s.getTo())); + String toString = fromString; + do { + toString = generateBankAccount(originalLength); + } while (fromString.equals(toString)); - return s; - } + return new StringSynonym( + getType(), + fromString, + toString, + shortlived + ); + } - @Override - public String generateBankAccount(int numberOfDigits) { - if (numberOfDigits == LENGTH) { - // Generate 11-proof bank account number - int[] elevenProof = generate11ProofNumber(numberOfDigits); - return digitsAsNumber(elevenProof); - } else { - // Generate non-11 proof bank account number - int[] randomnumber = getRandomDigits(numberOfDigits); - return digitsAsNumber(randomnumber); - } - } + @Override + public String generateBankAccount(int numberOfDigits) { + if (numberOfDigits == LENGTH) { + // Generate 11-proof bank account number + int[] elevenProof = generate11ProofNumber(numberOfDigits); + return digitsAsNumber(elevenProof); + } else { + // Generate non-11 proof bank account number + int[] randomnumber = getRandomDigits(numberOfDigits); + return digitsAsNumber(randomnumber); + } + } - @Override - public String generateBankCode() { - DutchBankCode bankCode = DutchBankCode.values()[random.nextInt(DutchBankCode.values().length)]; + @Override + public String generateBankCode() { + DutchBankCode bankCode = DutchBankCode.values()[random.nextInt(DutchBankCode.values().length)]; - return bankCode.bankCode; - } + return bankCode.bankCode; + } - /** - * Enumeration of the Dutch bank codes, used to generate valid IBAN for Dutch bank accounts. - * - * @see https://www.betaalvereniging.nl/aandachtsgebieden/giraal-betalingsverkeer/bic-sepa-transacties/ - */ - private enum DutchBankCode { + /** + * Enumeration of the Dutch bank codes, used to generate valid IBAN for Dutch bank accounts. + * + * @see https://www.betaalvereniging.nl/aandachtsgebieden/giraal-betalingsverkeer/bic-sepa-transacties/ + */ + private enum DutchBankCode { - ABNA("ABNANL2A", "ABNA", "ABN AMRO"), + ABNA("ABNANL2A", "ABNA", "ABN AMRO"), - FTSB("ABNANL2A", "FTSB", "ABN AMRO (ex FORTIS)"), + FTSB("ABNANL2A", "FTSB", "ABN AMRO (ex FORTIS)"), - ADYB("ADYBNL2A", "ADYB", "ADYEN"), + ADYB("ADYBNL2A", "ADYB", "ADYEN"), - AEGO("AEGONL2U", "AEGO", "AEGON BANK"), + AEGO("AEGONL2U", "AEGO", "AEGON BANK"), - ANAA("ANAANL21", "ANAA", "BRAND NEW DAY (ex ALLIANZ)"), + ANAA("ANAANL21", "ANAA", "BRAND NEW DAY (ex ALLIANZ)"), - ANDL("ANDLNL2A", "ANDL", "ANADOLUBANK"), + ANDL("ANDLNL2A", "ANDL", "ANADOLUBANK"), - ARBN("ARBNNL22", "ARBN", "ACHMEA BANK"), + ARBN("ARBNNL22", "ARBN", "ACHMEA BANK"), - ARSN("ARSNNL21", "ARSN", "ARGENTA SPAARBANK"), + ARSN("ARSNNL21", "ARSN", "ARGENTA SPAARBANK"), - ASNB("ASNBNL21", "ASNB", "ASN BANK"), + ASNB("ASNBNL21", "ASNB", "ASN BANK"), - ATBA("ATBANL2A", "ATBA", "AMSTERDAM TRADE BANK"), + ATBA("ATBANL2A", "ATBA", "AMSTERDAM TRADE BANK"), - BCDM("BCDMNL22", "BCDM", "BANQUE CHAABI DU MAROC"), + BCDM("BCDMNL22", "BCDM", "BANQUE CHAABI DU MAROC"), - BCIT("BCITNL2A", "BCIT", "INTESA SANPAOLO"), + BCIT("BCITNL2A", "BCIT", "INTESA SANPAOLO"), - BICK("BICKNL2A", "BICK", "BINCKBANK"), + BICK("BICKNL2A", "BICK", "BINCKBANK"), - BINK("BINKNL21", "BINK", "BINCKBANK, PROF"), + BINK("BINKNL21", "BINK", "BINCKBANK, PROF"), - BKCH("BKCHNL2R", "BKCH", "BANK OF CHINA"), + BKCH("BKCHNL2R", "BKCH", "BANK OF CHINA"), - BKMG("BKMGNL2A", "BKMG", "BANK MENDES GANS"), + BKMG("BKMGNL2A", "BKMG", "BANK MENDES GANS"), - BLGW("BLGWNL21", "BLGW", "BLG WONEN"), + BLGW("BLGWNL21", "BLGW", "BLG WONEN"), - BMEU("BMEUNL21", "BMEU", "BMCE EUROSERVICES"), + BMEU("BMEUNL21", "BMEU", "BMCE EUROSERVICES"), - BNDA("BNDANL2A", "BNDA", "BRAND NEW DAY BANK"), + BNDA("BNDANL2A", "BNDA", "BRAND NEW DAY BANK"), - BNGH("BNGHNL2G", "BNGH", "BANK NEDERLANDSE GEMEENTEN"), + BNGH("BNGHNL2G", "BNGH", "BANK NEDERLANDSE GEMEENTEN"), - BNPA("BNPANL2A", "BNPA", "BNP PARIBAS"), + BNPA("BNPANL2A", "BNPA", "BNP PARIBAS"), - BOFA("BOFANLNX", "BOFA", "BANK OF AMERICA"), + BOFA("BOFANLNX", "BOFA", "BANK OF AMERICA"), - BOFS("BOFSNL21002", "BOFS", "BANK OF SCOTLAND, AMSTERDAM"), + BOFS("BOFSNL21002", "BOFS", "BANK OF SCOTLAND, AMSTERDAM"), - BOTK("BOTKNL2X", "BOTK", "MUFG BANK"), + BOTK("BOTKNL2X", "BOTK", "MUFG BANK"), - BUNQ("BUNQNL2A", "BUNQ", "BUNQ"), + BUNQ("BUNQNL2A", "BUNQ", "BUNQ"), - CHAS("CHASNL2X", "CHAS", "JPMORGAN CHASE"), + CHAS("CHASNL2X", "CHAS", "JPMORGAN CHASE"), - CITC("CITCNL2A", "CITC", "CITCO BANK"), + CITC("CITCNL2A", "CITC", "CITCO BANK"), - CITI("CITINL2X", "CITI", "CITIBANK INTERNATIONAL"), + CITI("CITINL2X", "CITI", "CITIBANK INTERNATIONAL"), - COBA("COBANL2X", "COBA", "COMMERZBANK"), + COBA("COBANL2X", "COBA", "COMMERZBANK"), - DEUT("DEUTNL2A", "DEUT", "DEUTSCHE BANK (bij alle SEPA transacties)"), + DEUT("DEUTNL2A", "DEUT", "DEUTSCHE BANK (bij alle SEPA transacties)"), - DHBN("DHBNNL2R", "DHBN", "DEMIR-HALK BANK"), + DHBN("DHBNNL2R", "DHBN", "DEMIR-HALK BANK"), - DLBK("DLBKNL2A", "DLBK", "DELTA LLOYD BANK"), + DLBK("DLBKNL2A", "DLBK", "DELTA LLOYD BANK"), - DNIB("DNIBNL2G", "DNIB", "NIBC"), + DNIB("DNIBNL2G", "DNIB", "NIBC"), - EBUR("EBURNL21", "EBUR", "EBURY NETHERLANDS"), + EBUR("EBURNL21", "EBUR", "EBURY NETHERLANDS"), - FBHL("FBHLNL2A", "FBHL", "CREDIT EUROPE BANK"), + FBHL("FBHLNL2A", "FBHL", "CREDIT EUROPE BANK"), - FLOR("FLORNL2A", "FLOR", "DE NEDERLANDSCHE BANK"), + FLOR("FLORNL2A", "FLOR", "DE NEDERLANDSCHE BANK"), - FRGH("FRGHNL21", "FRGH", "FGH BANK"), + FRGH("FRGHNL21", "FRGH", "FGH BANK"), - FRNX("FRNXNL2A", "FRNX", "FRANX"), + FRNX("FRNXNL2A", "FRNX", "FRANX"), - FVLB("FVLBNL22", "FVLB", "VAN LANSCHOT"), + FVLB("FVLBNL22", "FVLB", "VAN LANSCHOT"), - GILL("GILLNL2A", "GILL", "INSINGERGILISSEN"), + GILL("GILLNL2A", "GILL", "INSINGERGILISSEN"), - HAND("HANDNL2A", "HAND", "SVENSKA HANDELSBANKEN"), + HAND("HANDNL2A", "HAND", "SVENSKA HANDELSBANKEN"), - HHBA("HHBANL22", "HHBA", "HOF HOORNEMAN BANKIERS"), + HHBA("HHBANL22", "HHBA", "HOF HOORNEMAN BANKIERS"), - HSBC("HSBCNL2A", "HSBC", "HSBC BANK"), + HSBC("HSBCNL2A", "HSBC", "HSBC BANK"), - ICBK("ICBKNL2A", "ICBK", "INDUSTRIAL & COMMERCIAL BANK OF CHINA"), + ICBK("ICBKNL2A", "ICBK", "INDUSTRIAL & COMMERCIAL BANK OF CHINA"), - INGB("INGBNL2A", "INGB", "ING"), + INGB("INGBNL2A", "INGB", "ING"), - ISAE("ISAENL2A", "ISAE", "CACEIS BANK, Netherlands Branch"), + ISAE("ISAENL2A", "ISAE", "CACEIS BANK, Netherlands Branch"), - ISBK("ISBKNL2A", "ISBK", "ISBANK"), + ISBK("ISBKNL2A", "ISBK", "ISBANK"), - KABA("KABANL2A", "KABA", "YAPI KREDI BANK"), + KABA("KABANL2A", "KABA", "YAPI KREDI BANK"), - KASA("KASANL2A", "KASA", "KAS BANK"), + KASA("KASANL2A", "KASA", "KAS BANK"), - KNAB("KNABNL2H", "KNAB", "KNAB"), + KNAB("KNABNL2H", "KNAB", "KNAB"), - KOEX("KOEXNL2A", "KOEX", "KOREA EXCHANGE BANK"), + KOEX("KOEXNL2A", "KOEX", "KOREA EXCHANGE BANK"), - KRED("KREDNL2X", "KRED", "KBC BANK"), + KRED("KREDNL2X", "KRED", "KBC BANK"), - LOCY("LOCYNL2A", "LOCY", "LOMBARD ODIER DARIER HENTSCH & CIE"), + LOCY("LOCYNL2A", "LOCY", "LOMBARD ODIER DARIER HENTSCH & CIE"), - LOYD("LOYDNL2A", "LOYD", "LLOYDS TSB BANK"), + LOYD("LOYDNL2A", "LOYD", "LLOYDS TSB BANK"), - LPLN("LPLNNL2F", "LPLN", "LEASEPLAN CORPORATION"), + LPLN("LPLNNL2F", "LPLN", "LEASEPLAN CORPORATION"), - MHCB("MHCBNL2A", "MHCB", "MIZUHO BANK EUROPE"), + MHCB("MHCBNL2A", "MHCB", "MIZUHO BANK EUROPE"), - MOYO("MOYONL21", "MOYO", "MONEYOU"), + MOYO("MOYONL21", "MOYO", "MONEYOU"), - NNBA("NNBANL2G", "NNBA", "NATIONALE-NEDERLANDEN BANK"), + NNBA("NNBANL2G", "NNBA", "NATIONALE-NEDERLANDEN BANK"), - NWAB("NWABNL2G", "NWAB", "NEDERLANDSE WATERSCHAPSBANK"), + NWAB("NWABNL2G", "NWAB", "NEDERLANDSE WATERSCHAPSBANK"), - PCBC("PCBCNL2A", "PCBC", "CHINA CONSTRUCTION BANK, AMSTERDAM BRANCH"), + PCBC("PCBCNL2A", "PCBC", "CHINA CONSTRUCTION BANK, AMSTERDAM BRANCH"), - RABO("RABONL2U", "RABO", "RABOBANK"), + RABO("RABONL2U", "RABO", "RABOBANK"), - RBRB("RBRBNL21", "RBRB", "REGIOBANK"), + RBRB("RBRBNL21", "RBRB", "REGIOBANK"), - SOGE("SOGENL2A", "SOGE", "SOCIETE GENERALE"), + SOGE("SOGENL2A", "SOGE", "SOCIETE GENERALE"), - TEBU("TEBUNL2A", "TEBU", "THE ECONOMY BANK"), + TEBU("TEBUNL2A", "TEBU", "THE ECONOMY BANK"), - TRIO("TRIONL2U", "TRIO", "TRIODOS BANK"), + TRIO("TRIONL2U", "TRIO", "TRIODOS BANK"), - UBSW("UBSWNL2A", "UBSW", "UBS EUROPE SE, NETHERLANDS BRANCH"), + UBSW("UBSWNL2A", "UBSW", "UBS EUROPE SE, NETHERLANDS BRANCH"), - UGBI("UGBINL2A", "UGBI", "GARANTIBANK INTERNATIONAL"), + UGBI("UGBINL2A", "UGBI", "GARANTIBANK INTERNATIONAL"), - VOWA("VOWANL21", "VOWA", "VOLKSWAGEN BANK"), + VOWA("VOWANL21", "VOWA", "VOLKSWAGEN BANK"), - ZWLB("ZWLBNL21", "ZWLB", "SNS (ex ZWITSERLEVENBANK)"); + ZWLB("ZWLBNL21", "ZWLB", "SNS (ex ZWITSERLEVENBANK)"); - private final String bic; - private final String bankCode; - private final String bankNaam; + private final String bic; + private final String bankCode; + private final String bankNaam; - DutchBankCode(String bic, String bankCode, String bankNaam) { - this.bic = bic; - this.bankCode = bankCode; - this.bankNaam = bankNaam; - } - } + DutchBankCode(String bic, String bankCode, String bankNaam) { + this.bic = bic; + this.bankCode = bankCode; + this.bankNaam = bankNaam; + } + } } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizer.java index 0d3f0a0..00e733d 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizer.java @@ -37,13 +37,9 @@ public String getType() { } @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { String result = buildZipCode(); - - StringSynonym stringSynonym = new StringSynonym(); - stringSynonym.setFrom(from); - stringSynonym.setType(TYPE); - stringSynonym.setTo(result); + StringSynonym stringSynonym = new StringSynonym(TYPE, (String) from, result, shortlived); return stringSynonym; } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/EmailAddressAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/EmailAddressAnonymizer.java index c00c57a..de17ccb 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/EmailAddressAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/EmailAddressAnonymizer.java @@ -8,15 +8,10 @@ public class EmailAddressAnonymizer implements Anonymizer { private static final String TYPE = "EMAIL_ADDRESS"; @Override - public Synonym anonymize(Object from, int size) { - StringSynonym s = new StringSynonym(); - s.setType(TYPE); - s.setFrom(from); - - if (from == null) { - s.setTo(null); - } else if (from instanceof String) { - String randomHexString = Long.toHexString(Double + public Synonym anonymize(Object from, int size, boolean shortlived) { + String randomHexString = null; + if (from instanceof String) { + randomHexString = Long.toHexString(Double .doubleToLongBits(Math.random())); randomHexString += EMAIL_DOMAIN; @@ -26,13 +21,17 @@ public Synonym anonymize(Object from, int size) { + "."); } - s.setTo(randomHexString); } else { throw new UnsupportedOperationException( "Can not anonymize objects of type " + from.getClass()); } - return s; + return new StringSynonym( + getType(), + (String) from, + randomHexString, + shortlived + ); } @Override diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizer.java index 6ae0120..937334d 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizer.java @@ -54,17 +54,17 @@ public String getType() { } @Override - public Synonym anonymize(Object from, int size) { + public Synonym anonymize(Object from, int size, boolean shortlived) { CountryCode countryCode = getCountryCode(from); String result = generateIban(countryCode); - StringSynonym stringSynonym = new StringSynonym(); - stringSynonym.setFrom(from); - stringSynonym.setType(TYPE); - stringSynonym.setTo(result); - - return stringSynonym; + return new StringSynonym( + getType(), + (String) from, + result, + shortlived + ); } String generateIban(CountryCode countryCode) { diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/StringAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/StringAnonymizer.java index 02e9ddf..ef129b3 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/StringAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/StringAnonymizer.java @@ -4,34 +4,35 @@ import com.rolfje.anonimatron.synonyms.Synonym; public class StringAnonymizer implements Anonymizer { - private static final String TYPE = "STRING"; + private static final String TYPE = "STRING"; - @Override - public Synonym anonymize(Object from, int size) { - StringSynonym s = new StringSynonym(); - s.setType(TYPE); - s.setFrom(from); + @Override + public Synonym anonymize(Object from, int size, boolean shortlived) { + String randomHexString = null; - if (from == null) { - s.setTo(null); - } else if (from instanceof String) { - String randomHexString = Long.toHexString(Double.doubleToLongBits(Math.random())); - - if (randomHexString.length() > size){ - throw new UnsupportedOperationException("Can not generate a random hex string with length "+size - +". Generated String size is "+randomHexString.length()+" characters."); - } - - s.setTo(randomHexString); - } else { - throw new UnsupportedOperationException("Can not anonymize objects of type " + from.getClass()); - } + if (from == null) { + randomHexString = null; + } else if (from instanceof String) { + randomHexString = Long.toHexString(Double.doubleToLongBits(Math.random())); - return s; - } + if (randomHexString.length() > size) { + throw new UnsupportedOperationException("Can not generate a random hex string with length " + size + + ". Generated String size is " + randomHexString.length() + " characters."); + } + } else { + throw new UnsupportedOperationException("Can not anonymize objects of type " + from.getClass()); + } - @Override - public String getType() { - return TYPE; - } + return new StringSynonym( + getType(), + (String) from, + randomHexString, + shortlived + ); + } + + @Override + public String getType() { + return TYPE; + } } diff --git a/src/main/java/com/rolfje/anonimatron/anonymizer/UUIDAnonymizer.java b/src/main/java/com/rolfje/anonimatron/anonymizer/UUIDAnonymizer.java index a54eea6..5383f8b 100644 --- a/src/main/java/com/rolfje/anonimatron/anonymizer/UUIDAnonymizer.java +++ b/src/main/java/com/rolfje/anonimatron/anonymizer/UUIDAnonymizer.java @@ -1,41 +1,41 @@ package com.rolfje.anonimatron.anonymizer; -import java.util.UUID; - import com.rolfje.anonimatron.synonyms.StringSynonym; import com.rolfje.anonimatron.synonyms.Synonym; -public class UUIDAnonymizer implements Anonymizer { - private static final String TYPE = "UUID"; - - @Override - public Synonym anonymize(Object from, int size) { - StringSynonym s = new StringSynonym(); - s.setType(TYPE); - s.setFrom(from); - - if (from == null) { - s.setTo(null); - } else if (from != null && from instanceof String) { - String uuidString = UUID.randomUUID().toString(); - - if (uuidString.length() > size) { - throw new UnsupportedOperationException( - "Can not generate a UUID smaller than " + size - + " characters."); - } - - s.setTo(uuidString); - } else { - throw new UnsupportedOperationException( - "Can not anonymize objects of type " + from.getClass()); - } - - return s; - } +import java.util.UUID; - @Override - public String getType() { - return TYPE; - } +public class UUIDAnonymizer implements Anonymizer { + private static final String TYPE = "UUID"; + + @Override + public Synonym anonymize(Object from, int size, boolean shortlived) { + String to = null; + if (from == null) { + to = null; + } else if (from instanceof String) { + to = UUID.randomUUID().toString(); + + if (to.length() > size) { + throw new UnsupportedOperationException( + "Can not generate a UUID smaller than " + size + + " characters."); + } + + } else { + throw new UnsupportedOperationException( + "Can not anonymize objects of type " + from.getClass()); + } + return new StringSynonym( + getType(), + (String) from, + to, + shortlived + ); + } + + @Override + public String getType() { + return TYPE; + } } diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java index f4de60d..1ba7c8d 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/DateSynonym.java @@ -37,6 +37,10 @@ public void setFrom(Object from) { this.from = (Date) from; } + public void setShortlived(boolean shortlived) { + this.shortlived = shortlived; + } + @Override public boolean isShortLived() { return shortlived; diff --git a/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java b/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java index 07cb82a..fd503b5 100644 --- a/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java +++ b/src/main/java/com/rolfje/anonimatron/synonyms/StringSynonym.java @@ -14,20 +14,24 @@ public class StringSynonym implements Synonym { public StringSynonym() { } - public StringSynonym(String type, String from, String to) { + public StringSynonym(String type, String from, String to, boolean shortlived) { this.type = type; this.from = from; this.to = to; + this.shortlived = shortlived; } + @Override public String getType() { return type; } + @Override public Object getFrom() { return from; } + @Override public Object getTo() { return to; } @@ -36,12 +40,16 @@ public void setType(String type) { this.type = type; } - public void setTo(Object to) { - this.to = (String) to; + public void setFrom(String from) { + this.from = from; + } + + public void setTo(String to) { + this.to = to; } - public void setFrom(Object from) { - this.from = (String) from; + public void setShortlived(boolean shortlived) { + this.shortlived = shortlived; } @Override diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizerTest.java index 36d31ec..ae5e32a 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/CharacterStringPrefetchAnonymizerTest.java @@ -1,41 +1,40 @@ package com.rolfje.anonimatron.anonymizer; import com.rolfje.anonimatron.synonyms.Synonym; - import junit.framework.TestCase; public class CharacterStringPrefetchAnonymizerTest extends TestCase { - CharacterStringPrefetchAnonymizer anonimyzer; - - @Override - protected void setUp() throws Exception { - super.setUp(); - anonimyzer = new CharacterStringPrefetchAnonymizer(); - } - - public void testPrefetch() throws Exception { - String sourceData = "ABC"; - anonimyzer.prefetch(sourceData); - - String from = "TEST1"; - Synonym synonym = anonimyzer.anonymize(from, 5); - - String to = (String)synonym.getTo(); - assertEquals("from and to string lengths did not match", from.length(), to.length()); - - for (int i = 0; i < to.length(); i++) { - assertTrue("'to' string contained charachters which were not in the source data." - , sourceData.indexOf(to.charAt(i)) > -1); - } - } - - public void testPrefetchNull() throws Exception { - anonimyzer.prefetch(null); - String from = "DUMMY"; - Synonym synonym = anonimyzer.anonymize(from, 5); - - String to = (String)synonym.getTo(); - assertEquals("from and to string lengths did not match", from.length(), to.length()); - } + CharacterStringPrefetchAnonymizer anonimyzer; + + @Override + protected void setUp() throws Exception { + super.setUp(); + anonimyzer = new CharacterStringPrefetchAnonymizer(); + } + + public void testPrefetch() throws Exception { + String sourceData = "ABC"; + anonimyzer.prefetch(sourceData); + + String from = "TEST1"; + Synonym synonym = anonimyzer.anonymize(from, 5, false); + + String to = (String) synonym.getTo(); + assertEquals("from and to string lengths did not match", from.length(), to.length()); + + for (int i = 0; i < to.length(); i++) { + assertTrue("'to' string contained charachters which were not in the source data." + , sourceData.indexOf(to.charAt(i)) > -1); + } + } + + public void testPrefetchNull() throws Exception { + anonimyzer.prefetch(null); + String from = "DUMMY"; + Synonym synonym = anonimyzer.anonymize(from, 5, false); + + String to = (String) synonym.getTo(); + assertEquals("from and to string lengths did not match", from.length(), to.length()); + } } diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java index 6c6b399..4d6d887 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/CountryCodeAnonymizerTest.java @@ -4,21 +4,21 @@ import junit.framework.TestCase; public class CountryCodeAnonymizerTest extends TestCase { - public void testAnonymize() throws Exception { + public void testAnonymize() throws Exception { - testInternal(2, "EN"); - testInternal(3, "NLD"); - testInternal(4, "BLR"); - } + testInternal(2, "EN"); + testInternal(3, "NLD"); + testInternal(4, "BLR"); + } - private void testInternal(int size, String from) { - CountryCodeAnonymizer countryCodeAnonymizer = new CountryCodeAnonymizer(); - Synonym nld = countryCodeAnonymizer.anonymize(from, size); - assertEquals(countryCodeAnonymizer.getType(), nld.getType()); - assertEquals(from, nld.getFrom()); - assertFalse(from.equals(nld.getTo())); - assertEquals(size, ((String) nld.getTo()).length()); - assertFalse(nld.isShortLived()); - } + private void testInternal(int size, String from) { + CountryCodeAnonymizer countryCodeAnonymizer = new CountryCodeAnonymizer(); + Synonym nld = countryCodeAnonymizer.anonymize(from, size, false); + assertEquals(countryCodeAnonymizer.getType(), nld.getType()); + assertEquals(from, nld.getFrom()); + assertFalse(from.equals(nld.getTo())); + assertEquals(size, ((String) nld.getTo()).length()); + assertFalse(nld.isShortLived()); + } } \ No newline at end of file diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizerTest.java index e9d5e8f..b58f753 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/DutchBSNAnononymizerTest.java @@ -19,7 +19,7 @@ public void testAnonymize() { for (int i = 0; i < 1000; i++) { String from = bsnAnonymizer.generateBSN(9); - Synonym s = bsnAnonymizer.anonymize(from, 12); + Synonym s = bsnAnonymizer.anonymize(from, 12, false); assertEquals(from, s.getFrom()); assertFalse(s.getFrom().equals(s.getTo())); @@ -30,11 +30,11 @@ public void testAnonymize() { } public void testLength() throws Exception { - bsnAnonymizer.anonymize("dummy", 10000); - bsnAnonymizer.anonymize("dummy", 9); + bsnAnonymizer.anonymize("dummy", 10000, false); + bsnAnonymizer.anonymize("dummy", 9, false); try { - bsnAnonymizer.anonymize("dummy", 8); + bsnAnonymizer.anonymize("dummy", 8, false); fail("should throw exception"); } catch (UnsupportedOperationException e) { // ok diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizerTest.java index 3dcb10d..994611b 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/DutchZipCodeAnonymizerTest.java @@ -1,14 +1,13 @@ package com.rolfje.anonimatron.anonymizer; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.sameInstance; -import static org.junit.Assert.assertThat; +import com.rolfje.anonimatron.synonyms.Synonym; +import org.junit.Test; import java.util.regex.Pattern; -import org.junit.Test; - -import com.rolfje.anonimatron.synonyms.Synonym; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.junit.Assert.assertThat; /** * Tests for {@link DutchZipCodeAnonymizer}. @@ -17,30 +16,31 @@ */ public class DutchZipCodeAnonymizerTest { - private DutchZipCodeAnonymizer anonymizer = new DutchZipCodeAnonymizer(); - private Pattern pattern = Pattern.compile("[1-9][0-9]{3} ?(?!SA|SD|SS)[A-Z]{2}$"); + private DutchZipCodeAnonymizer anonymizer = new DutchZipCodeAnonymizer(); + private Pattern pattern = Pattern.compile("[1-9][0-9]{3} ?(?!SA|SD|SS)[A-Z]{2}$"); - @Test - public void anonymize() { - for (int i = 0; i < 1000000; i++) { - String source = anonymizer.buildZipCode(); - assertThat(isValidZipCode(source), is(true)); + @Test + public void anonymize() { + for (int i = 0; i < 1000000; i++) { + String source = anonymizer.buildZipCode(); + assertThat(isValidZipCode(source), is(true)); - assertThat(source.length(), is(6)); - testInternal(6, source); - } - } + assertThat(source.length(), is(6)); + testInternal(6, source); + } + } - private void testInternal(int size, String from) { - Synonym synonym = anonymizer.anonymize(from, size); - assertThat(synonym.getType(), sameInstance(anonymizer.getType())); + private void testInternal(int size, String from) { + Synonym synonym = anonymizer.anonymize(from, size, false); + assertThat(synonym.getType(), sameInstance(anonymizer.getType())); - String value = (String) synonym.getTo(); - assertThat(isValidZipCode(value), is(true)); - } + String value = (String) synonym.getTo(); + assertThat(isValidZipCode(value), is(true)); + assertThat(synonym.isShortLived(), is(false)); + } - private boolean isValidZipCode(String value) { - return pattern.matcher(value).matches(); - } + private boolean isValidZipCode(String value) { + return pattern.matcher(value).matches(); + } } \ No newline at end of file diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizerTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizerTest.java index 5dd249e..ca0cd87 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizerTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/IbanAnonymizerTest.java @@ -52,7 +52,7 @@ private void testAnonymize(CountryCode countryCode) { } private void testInternal(int size, String from, CountryCode countryCode) { - Synonym synonym = anonymizer.anonymize(from, size); + Synonym synonym = anonymizer.anonymize(from, size, false); assertThat(synonym.getType(), sameInstance(anonymizer.getType())); String value = (String) synonym.getTo(); diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/RomanNameGeneratorTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/RomanNameGeneratorTest.java index 16bd3da..de0def6 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/RomanNameGeneratorTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/RomanNameGeneratorTest.java @@ -15,7 +15,7 @@ public void testUniqueness() throws Exception { Set names = new HashSet(); for (int i = 0; i < 10000; i++) { - String name = (String) r.anonymize("fakename", 100).getTo(); + String name = (String) r.anonymize("fakename", 100, false).getTo(); assertFalse("The name " + name + " was already generated. This is iteration " + i, names.contains(name)); @@ -25,7 +25,7 @@ public void testUniqueness() throws Exception { public void testNullFrom() throws Exception { RomanNameGenerator r = new RomanNameGenerator(); - assertNull(r.anonymize(null, 100).getTo()); + assertNull(r.anonymize(null, 100, false).getTo()); } // commented out for speed reasons @@ -38,7 +38,7 @@ public void xxxtestMaxNames() throws Exception { String name; boolean wasInSet = false; do { - name = (String) r.anonymize("fakename", 100).getTo(); + name = (String) r.anonymize("fakename", 100, false).getTo(); wasInSet = names.contains(name); names.add(name); } while (!wasInSet); diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java b/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java index 19a7375..2d8d428 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/SynonymCacheTest.java @@ -19,7 +19,7 @@ public void testNoStorageOfShortLivedSynonyms() { public void testNoHashing() throws Exception { SynonymCache synonymCache = new SynonymCache(); - StringSynonym originalSynonym = new StringSynonym("type", "from", "to"); + StringSynonym originalSynonym = new StringSynonym("type", "from", "to", false); // Store and retrieve synonymCache.put(originalSynonym); @@ -35,7 +35,7 @@ public void testHashing() throws Exception { SynonymCache synonymCache = new SynonymCache(); synonymCache.setHasher(new Hasher("testhash")); - StringSynonym originalSynonym = new StringSynonym("type", "from", "to"); + StringSynonym originalSynonym = new StringSynonym("type", "from", "to", false); // Store and retrieve synonymCache.put(originalSynonym); diff --git a/src/test/java/com/rolfje/anonimatron/anonymizer/ToLowerAnonymizer.java b/src/test/java/com/rolfje/anonimatron/anonymizer/ToLowerAnonymizer.java index 04c575a..749feb5 100644 --- a/src/test/java/com/rolfje/anonimatron/anonymizer/ToLowerAnonymizer.java +++ b/src/test/java/com/rolfje/anonimatron/anonymizer/ToLowerAnonymizer.java @@ -5,16 +5,18 @@ public class ToLowerAnonymizer implements Anonymizer { - @Override - public String getType() { - return "TO_LOWER_CASE"; - } + @Override + public String getType() { + return "TO_LOWER_CASE"; + } - @Override - public Synonym anonymize(Object from, int size) { - StringSynonym s = new StringSynonym(); - s.setFrom(from); - s.setTo(((String)from).toLowerCase()); - return s; - } + @Override + public Synonym anonymize(Object from, int size, boolean shortlived) { + return new StringSynonym( + getType(), + (String) from, + ((String) from).toLowerCase(), + shortlived + ); + } } diff --git a/src/test/java/com/rolfje/anonimatron/synonyms/SynonymMapperTest.java b/src/test/java/com/rolfje/anonimatron/synonyms/SynonymMapperTest.java index 1242724..9772fe7 100644 --- a/src/test/java/com/rolfje/anonimatron/synonyms/SynonymMapperTest.java +++ b/src/test/java/com/rolfje/anonimatron/synonyms/SynonymMapperTest.java @@ -1,63 +1,70 @@ package com.rolfje.anonimatron.synonyms; +import junit.framework.TestCase; + import java.io.File; -import java.math.BigDecimal; import java.sql.Date; import java.util.ArrayList; import java.util.List; -import junit.framework.TestCase; - public class SynonymMapperTest extends TestCase { - public static final char[] ILLEGALSTRINGCHARACTERS = new char[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, - 0x15, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x16, 0x17, 0x18, 0x19, 0x7F }; - - public void testSynonymMapper() throws Exception { - List synonyms = new ArrayList(); - - StringSynonym s = new StringSynonym(); - s.setFrom("Foo"); - s.setTo("Bar"); - s.setType("Bunk"); - synonyms.add(s); - - s = new StringSynonym(); - s.setFrom("<>!@#$%^&*()"); - s.setTo("<>!@#$%^&*()"); - s.setType("XMLCHARS"); - synonyms.add(s); - - s = new StringSynonym(); - s.setFrom(""); - s.setTo(""); - s.setType(""); - synonyms.add(s); - - String illegalcharString = String.copyValueOf(ILLEGALSTRINGCHARACTERS); - s = new StringSynonym(); - s.setFrom(illegalcharString); - s.setTo(""); - s.setType(""); - synonyms.add(s); - - DateSynonym d = new DateSynonym(); - d.setFrom(new Date(System.currentTimeMillis())); - d.setTo(new Date(System.currentTimeMillis()-1000)); - d.setType(""); - synonyms.add(d); - - File tempFile = File.createTempFile("Anonimatron-SynonymMapperTest-", ".xml"); - tempFile.deleteOnExit(); - - SynonymMapper.writeToFile(synonyms, tempFile.getAbsolutePath()); - List synonymsFromFile = SynonymMapper.readFromFile(tempFile.getAbsolutePath()); - - assertEquals("Not all synonyms were serialized.", synonyms.size(), synonymsFromFile.size()); - - synonyms.removeAll(synonymsFromFile); - assertEquals("Some synonyms were serialized incorrectly.", 0, - synonyms.size()); - } + public static final char[] ILLEGALSTRINGCHARACTERS = new char[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x16, 0x17, 0x18, 0x19, 0x7F}; + + public void testSynonymMapper() throws Exception { + List synonyms = new ArrayList(); + + StringSynonym s = new StringSynonym( + "Bunk", + "Foo", + "Bar", + false + ); + synonyms.add(s); + + s = new StringSynonym( + "XMLCHARS", + "<>!@#$%^&*()", + "<>!@#$%^&*()", + false + ); + synonyms.add(s); + + s = new StringSynonym( + "", + "", + "", + false + ); + synonyms.add(s); + + String illegalcharString = String.copyValueOf(ILLEGALSTRINGCHARACTERS); + s = new StringSynonym( + "", + illegalcharString, + "", + false + ); + synonyms.add(s); + + DateSynonym d = new DateSynonym(); + d.setFrom(new Date(System.currentTimeMillis())); + d.setTo(new Date(System.currentTimeMillis() - 1000)); + d.setType(""); + synonyms.add(d); + + File tempFile = File.createTempFile("Anonimatron-SynonymMapperTest-", ".xml"); + tempFile.deleteOnExit(); + + SynonymMapper.writeToFile(synonyms, tempFile.getAbsolutePath()); + List synonymsFromFile = SynonymMapper.readFromFile(tempFile.getAbsolutePath()); + + assertEquals("Not all synonyms were serialized.", synonyms.size(), synonymsFromFile.size()); + + synonyms.removeAll(synonymsFromFile); + assertEquals("Some synonyms were serialized incorrectly.", 0, + synonyms.size()); + } } diff --git a/src/test/java/com/rolfje/anonimatron/synonyms/SynonymTest.java b/src/test/java/com/rolfje/anonimatron/synonyms/SynonymTest.java index 7e3b6c1..2a57f95 100644 --- a/src/test/java/com/rolfje/anonimatron/synonyms/SynonymTest.java +++ b/src/test/java/com/rolfje/anonimatron/synonyms/SynonymTest.java @@ -4,21 +4,25 @@ public class SynonymTest extends TestCase { - public void testEqualsHashcode() throws Exception { - - StringSynonym a = new StringSynonym(); - a.setType("Bunk"); - a.setFrom("Foo"); - a.setTo("Bar"); - - StringSynonym b = new StringSynonym(); - b.setType("Bunk"); - b.setFrom("Foo"); - b.setTo("Bar"); - - assertNotSame(a, b); - assertEquals(a, b); - - } + public void testEqualsHashcode() throws Exception { + + StringSynonym a = new StringSynonym( + "Bunk", + "Fpp", + "Bar", + false + ); + + StringSynonym b = new StringSynonym( + "Bunk", + "Fpp", + "Bar", + false + ); + + assertNotSame(a, b); + assertEquals(a, b); + + } } From 0502dae40fe1cb573db09ed3b56c91096d7d7b73 Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Fri, 22 Jun 2018 20:57:33 +0200 Subject: [PATCH 6/7] Bumped to 1.10.0-SNAPSHOT because the interface is not compatible with 1.9.x --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3507b86..56d78d4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rolfje.anonimatron anonimatron - 1.9.4-SNAPSHOT + 1.10.0-SNAPSHOT jar anonimatron From bbde08abebdcd25739a3a350e6f2ea7cf0f3f535 Mon Sep 17 00:00:00 2001 From: Rolf <> Date: Fri, 22 Jun 2018 21:07:20 +0200 Subject: [PATCH 7/7] Fixed version mismatch --- src/main/java/com/rolfje/anonimatron/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rolfje/anonimatron/version.txt b/src/main/java/com/rolfje/anonimatron/version.txt index 02b527b..8c29cb4 100644 --- a/src/main/java/com/rolfje/anonimatron/version.txt +++ b/src/main/java/com/rolfje/anonimatron/version.txt @@ -1 +1 @@ -1.9.4-SNAPSHOT +1.10.0-SNAPSHOT