/** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations under * the License. * * The Original Code is OpenELIS code. * * Copyright (C) The Minnesota Department of Health. All Rights Reserved. * * Contributor(s): CIRG, University of Washington, Seattle WA. */ package us.mn.state.health.lims.common.provider.validation; import us.mn.state.health.lims.common.util.DateUtil; import us.mn.state.health.lims.common.util.StringUtil; import us.mn.state.health.lims.common.util.SystemConfiguration; import us.mn.state.health.lims.common.util.resources.ResourceLocator; import us.mn.state.health.lims.sample.dao.SampleDAO; import us.mn.state.health.lims.sample.daoimpl.SampleDAOImpl; import java.util.HashSet; import java.util.Locale; import java.util.Set; public class YearNumAccessionValidator implements IAccessionNumberValidator { private String incrementStartingValue = "000001"; private static int upperIncrementValue = 999999; private static final int INCREMENT_START = 2; private static final int YEAR_START = 0; private static final int YEAR_END = 2; private int acccessionLength = 8; private static final boolean NEED_PROGRAM_CODE = false; private static Set<String> REQUESTED_NUMBERS = new HashSet<String>(); private final boolean useSeparator; private final String separator; private final int separatorLength; private String incrementFormat; public YearNumAccessionValidator( int length, Character separator){ useSeparator = separator != null; this.separator = useSeparator ? separator.toString() : ""; separatorLength = useSeparator ? 1 : 0; incrementFormat = "%0" + String.valueOf(length) + "d"; incrementStartingValue = String.format(incrementFormat, 1); String upper = incrementStartingValue.replace("0", "9").replace("1", "9"); upperIncrementValue = Integer.parseInt(upper); acccessionLength = length + YEAR_END + (useSeparator ? 1 : 0); } public boolean needProgramCode() { return NEED_PROGRAM_CODE; } public String createFirstAccessionNumber(String programCode) { return DateUtil.getTwoDigitYear() + separator + incrementStartingValue; } public String incrementAccessionNumber(String currentHighAccessionNumber) { int increment = Integer.parseInt(currentHighAccessionNumber.substring(INCREMENT_START + separatorLength)); String incrementAsString = incrementStartingValue; String year = DateUtil.getTwoDigitYear(); if (year.equals(currentHighAccessionNumber.substring(YEAR_START, YEAR_END))) { if (increment < upperIncrementValue) { increment++; incrementAsString = String.format(incrementFormat, increment); } else { throw new IllegalArgumentException("AccessionNumber has no next value"); } } return year + separator + incrementAsString; } public ValidationResults validFormat(String accessionNumber, boolean checkDate) { // The rule is 2 digit year code and incremented numbers if (accessionNumber.length() != acccessionLength) { return ValidationResults.LENGTH_FAIL; } if(checkDate){ if( !DateUtil.getTwoDigitYear().equals(accessionNumber.substring(YEAR_START, YEAR_END))){ return ValidationResults.YEAR_FAIL; } } try { Integer.parseInt(accessionNumber.substring(INCREMENT_START + separatorLength)); } catch (NumberFormatException e) { return ValidationResults.FORMAT_FAIL; } return ValidationResults.SUCCESS; } public String getInvalidMessage(ValidationResults results) { switch (results) { case LENGTH_FAIL: return StringUtil.getMessageForKey("sample.entry.invalid.accession.number.length"); case USED_FAIL: return StringUtil.getMessageForKey("sample.entry.invalid.accession.number.suggestion") + " " + getNextAvailableAccessionNumber(null); case YEAR_FAIL: case FORMAT_FAIL: return getInvalidFormatMessage(results); default: return StringUtil.getMessageForKey("sample.entry.invalid.accession.number"); } } public String getNextAvailableAccessionNumber(String prefix) { String nextAccessionNumber; SampleDAO accessionNumberDAO = new SampleDAOImpl(); String curLargestAccessionNumber = accessionNumberDAO.getLargestAccessionNumberWithPrefix(prefix); if (curLargestAccessionNumber == null) { if( REQUESTED_NUMBERS.isEmpty()){ nextAccessionNumber = createFirstAccessionNumber(prefix); }else{ nextAccessionNumber = REQUESTED_NUMBERS.iterator().next(); } } else { nextAccessionNumber = incrementAccessionNumber(curLargestAccessionNumber); } while( REQUESTED_NUMBERS.contains(nextAccessionNumber) ){ nextAccessionNumber = incrementAccessionNumber(nextAccessionNumber); } REQUESTED_NUMBERS.add(nextAccessionNumber); return nextAccessionNumber; } public int getMaxAccessionLength() { return acccessionLength; } // recordType parameter is not used in this case public boolean accessionNumberIsUsed(String accessionNumber, String recordType) { SampleDAO sampleDAO = new SampleDAOImpl(); return sampleDAO.getSampleByAccessionNumber(accessionNumber) != null; } public ValidationResults checkAccessionNumberValidity(String accessionNumber, String recordType, String isRequired, String projectFormName) { ValidationResults results = validFormat(accessionNumber, true); //TODO refactor accessionNumberIsUsed into two methods so the null isn't needed. (Its only used for program accession number) if (results == ValidationResults.SUCCESS && accessionNumberIsUsed(accessionNumber, null)) { results = ValidationResults.USED_FAIL; } return results; } @Override public String getInvalidFormatMessage( ValidationResults results ){ return StringUtil.getMessageForKey( "sample.entry.invalid.accession.number.format.corrected", getFormatPattern(), getFormatExample() ); } private String getFormatExample(){ StringBuilder format = new StringBuilder( DateUtil.getTwoDigitYear() ); if( useSeparator){format.append( separator );} for( int i = 0; i < getChangeableLength() - 1; i++){ format.append( "0" ); } format.append( "1" ); return format.toString(); } private String getFormatPattern(){ StringBuilder format = new StringBuilder( StringUtil.getMessageForKey( "date.two.digit.year" ) ); if( useSeparator){format.append( separator );} for( int i = 0; i < getChangeableLength(); i++){ format.append( "#" ); } return format.toString(); } @Override public int getInvarientLength() { return 0; } @Override public int getChangeableLength() { return getMaxAccessionLength() - getInvarientLength(); } @Override public String getPrefix(){ return null; //no single prefix } }