001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.bio; 022 023import java.util.regex.Matcher; 024import java.util.regex.Pattern; 025 026/** 027 * An ec (enzyme classification) number. 028 * 029 * 030 * Implementations of this interface should be imutable. This makes them much 031 * more usefull as keys in maps. 032 * 033 * it is a good idea to validate that the data being passed in is a sane ec 034 * number. 035 * 036 * @author Matthew Pocock 037 * @since 1.4 038 */ 039public interface EcNumber { 040 /** 041 * A Pattern that can be used to parse EC strings into the indiidual numbers. 042 */ 043 public static final Pattern EC_PATTERN = 044 Pattern.compile("((\\d*)|(-))\\.((\\d*)|(-))\\.((\\d*)|(-))\\.((\\d*)|(-))"); 045 046 /** 047 * Constant that represents EC number components that are not defined. This 048 * is often represented as a '-' in EC strings. 049 */ 050 public static final int UNDEFINED = -1; 051 052 /** 053 * Constant that represents EC number components that are as yet unclassified. 054 * This is often represented as 99 in EC strings. 055 */ 056 public static final int UNCLASSIFIED = 99; 057 058 /** 059 * Get the class number associated with the particular level of the ec number. 060 * 061 * <p>The index can be between 0 and 3 inclusive. 0 correxpons to the top 062 * level class, 1 to the sub-class and so on. A return value of UNDEFINED 063 * indicates that this field is not populated.</p> 064 * 065 * @param level the level in the ec classification to return the number for 066 * @return the value at that level 067 */ 068 public int getClassNumber(int level); 069 070 /** 071 * A simple implementation of EcNumber. 072 * 073 * @author Matthew Pocock 074 * @since 1.4 075 */ 076 public static class Impl 077 implements EcNumber { 078 private int[] classes; 079 080 /** 081 * Make a new EcNumber.Impl with the data provided. 082 * 083 * @param mainClass the main class number 084 * @param subClass the sub class number 085 * @param subSubClass the sub-sub class number 086 * @param group the group number 087 */ 088 public Impl(int mainClass, int subClass, int subSubClass, int group) { 089 this.classes = new int[] { mainClass, subClass, subSubClass, group }; 090 } 091 092 private Impl(String ecString) { 093 Matcher matcher = EC_PATTERN.matcher(ecString); 094 if(!matcher.matches()) { 095 throw new IllegalArgumentException( 096 "Can't parse ec string: " + ecString ); 097 } 098 099 classes = new int[] { 100 process(matcher.group(1)), 101 process(matcher.group(4)), 102 process(matcher.group(7)), 103 process(matcher.group(10)) 104 }; 105 } 106 107 private int process(String s) { 108 if(s.length() > 0) { 109 if(s.equals("-")) { 110 return UNDEFINED; 111 } else { 112 return Integer.parseInt(s); 113 } 114 } else { 115 return UNDEFINED; 116 } 117 } 118 119 public int getClassNumber(int level) { 120 return classes[level]; 121 } 122 123 public String toString() { 124 StringBuffer sBuf = new StringBuffer(); 125 sBuf.append(process(getClassNumber(0))); 126 for(int i = 1; i < 4; i++) { 127 sBuf.append("."); 128 sBuf.append(process(getClassNumber(i))); 129 } 130 return sBuf.toString(); 131 } 132 133 private String process(int val) { 134 if(val == UNDEFINED) { 135 return ""; 136 } else { 137 return Integer.toString(val); 138 } 139 } 140 141 public boolean equals(Object obj) { 142 if(obj instanceof EcNumber) { 143 EcNumber that = (EcNumber) obj; 144 145 for(int i = 0; i < 4; i++) { 146 if(this.getClassNumber(i) != that.getClassNumber(i)) { 147 return false; 148 } 149 } 150 151 return true; 152 } 153 154 return false; 155 } 156 157 public int hashCode() { 158 return 159 getClassNumber(0) * 1000000 + 160 getClassNumber(1) * 10000 + 161 getClassNumber(2) * 100 + 162 getClassNumber(3); 163 } 164 165 /** 166 * Process a string into an EcNumber. 167 * 168 * <p> 169 * This method uses the {@link EcNumber#EC_PATTERN} regular expression. 170 * </p> 171 * 172 * @param ecString String to parse 173 * @return a new EcNumber 174 * @throws IllegalArgumentException if ecString could not be parsed 175 */ 176 public static Impl valueOf(String ecString) { 177 return new Impl(ecString); 178 } 179 } 180}