Java tutorial
/** * Copyright 2013 Stockholm County Council * * This file is part of APIGW * * APIGW is free software; you can redistribute it and/or modify * it under the terms of version 2.1 of the GNU Lesser General Public * License as published by the Free Software Foundation. * * APIGW is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with APIGW; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * */ package org.apigw.commons.logging.logback; import ch.qos.logback.classic.pattern.ClassicConverter; import ch.qos.logback.classic.spi.ILoggingEvent; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by martin on 17/12/14. * * Will first detect possible Swedish personnummer or samordningsnummer and, if anything found, * check the control number to see if it might be valid and if so, check the birth date against today. * * If found to be a possible valid SSN, replace it with replacement string * * Might result in false positives * * Handles birth years from 1800 to 2199, if this code lives beyond that, GREAT! */ public class ApigwStripSwedishSSNFromMessageConverter extends ClassicConverter { private static final Pattern ssnPattern = Pattern.compile( "\\b(((1[89]{1})|(2[01]{1}))[0-9]{2}((0[1-9]{1})|(1[0-2]{1}))(([06]{1}[1-9]{1})|([1278]{1}[0-9]{1})|([39]{1}[01]{1}))[-]?[0-9]{4})\\b"); private static final DateTimeFormatter yearMonthDayFormat = DateTimeFormat.forPattern("yyyyMMdd"); private String replacement = "***"; //default to *** @Override public void start() { String firstOption = getFirstOption(); if (firstOption != null && !firstOption.isEmpty()) { replacement = firstOption; } super.start(); } @Override public void stop() { replacement = null; super.stop(); } @Override public String convert(ILoggingEvent event) { String formattedMessage = event.getFormattedMessage(); Matcher matcher = ssnPattern.matcher(formattedMessage); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String possibleSsn = matcher.group(0); boolean validSsn = isValidSsn(possibleSsn); matcher.appendReplacement(sb, validSsn ? replacement : possibleSsn); } matcher.appendTail(sb); return sb.toString(); } private static boolean isValidSsn(final String ssn) { String controlSsn; if (ssn.contains("-")) { controlSsn = ssn.replace("-", ""); } else { controlSsn = ssn; } int controlSsnLength = controlSsn.length(); return (controlSsnLength == 10 || controlSsnLength == 12) && isSsnControlValid(controlSsn) && isSsnBirthdayInThePast(controlSsn); } private static boolean isSsnControlValid(String ssn) { String tenDigitSsn = ssn.substring(2); int[] digits = new int[10]; for (int i = 0; i < tenDigitSsn.length(); i += 1) { digits[i] = Integer.parseInt(String.valueOf(tenDigitSsn.charAt(i))); } return digits[digits.length - 1] == calculateControl(digits); } private static int calculateControl(int[] ssnArr) { int checkSum = 0; int temp = 0; int controlNumber; for (int i = 0; i < 9; i += 1) { if (i % 2 == 0) { temp = 2 * ssnArr[i]; if (temp >= 10) { checkSum = checkSum + 1 + (temp - 10); } else { checkSum = checkSum + temp; } } else { checkSum = checkSum + ssnArr[i]; } } controlNumber = 10 - checkSum % 10; if (controlNumber == 10) { controlNumber = 0; } return controlNumber; } private static boolean isSsnBirthdayInThePast(String ssn) { return !getBirthday(ssn).isAfter(LocalDate.now()); } private static LocalDate getBirthday(String ssn) { int firstDayNumber = Integer.parseInt(ssn.substring(6, 7)); String yearMonthDay; if (firstDayNumber >= 6) { //Samordningsnummer, need to lessen the day of month by 60 firstDayNumber = firstDayNumber - 6; yearMonthDay = ssn.substring(0, 6) + firstDayNumber + ssn.substring(7, 8); } else { yearMonthDay = ssn.substring(0, 8); } return LocalDate.parse(yearMonthDay, yearMonthDayFormat); } }