001/** 002 * Copyright (C) 2010-2015 The Roslin Institute <contact andy.law@roslin.ed.ac.uk> 003 * 004 * This file is part of JEnsembl: a Java API to Ensembl data sources developed by the 005 * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of 006 * Veterinary Studies, University of Edinburgh. 007 * 008 * Project hosted at: http://jensembl.sourceforge.net 009 * 010 * This is free software: you can redistribute it and/or modify 011 * it under the terms of the GNU General Public License (version 3) as published by 012 * the Free Software Foundation. 013 * 014 * This software is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * in this software distribution. If not, see: http://opensource.org/licenses/gpl-3.0.html 021 */ 022package uk.ac.roslin.ensembl.model; 023 024import java.io.Serializable; 025import java.util.Comparator; 026import uk.ac.roslin.ensembl.model.core.CoordinateSystem; 027 028/** 029 * Used to be abstract 030 * @author paterson 031 */ 032public class Mapping implements Serializable { 033 034 protected MappableObject source=null; 035 protected MappableObject target=null; 036 protected Coordinate sourceCoordinates=null; 037 protected Coordinate targetCoordinates=null; 038 protected CoordinateSystem sourceCoordSystem=null; 039 protected CoordinateSystem targetCoordSystem=null; 040 protected Mapping reverseMapping=null; 041 042 public Mapping() { 043 } 044 045 public static boolean addReverseMapping(Mapping originalMapping) { 046 try { 047 //don't add the reverse mapping if we already have it 048// for (Mapping mapping : ((MappingSet) originalMapping.getTarget().getLoadedMappings())) { 049// if (mapping.getTarget().getId().equals(originalMapping.getSource().getId())) { 050// return; 051// } 052// } 053 054 Mapping reverseMapping = new Mapping(); 055 reverseMapping.setReverseMapping(originalMapping); 056 057 reverseMapping.setSource(originalMapping.getTarget()); 058 reverseMapping.setTarget(originalMapping.getSource()); 059 060 reverseMapping.setSourceCoordinates(originalMapping.getTargetCoordinates()); 061 reverseMapping.setTargetCoordinates(originalMapping.getSourceCoordinates()); 062 063 reverseMapping.getSource().addMapping(reverseMapping); 064 originalMapping.setReverseMapping(reverseMapping); 065 066 } catch (Exception e) { 067 return false; 068 } 069 return true; 070 } 071 072 public void setSource(MappableObject source) { 073 this.source = source; 074 } 075 076 public void setTarget(MappableObject target) { 077 this.target = target; 078 } 079 080 public MappableObject getSource() { 081 return source; 082 } 083 084 public MappableObject getTarget() { 085 return target; 086 } 087 088 public ObjectType getTargetType() { 089 return (this.getTarget()!=null) ? this.getTarget().getType() : null; 090 } 091 092 public ObjectType getSourceType() { 093 return (this.getSource()!=null) ? this.getSource().getType() : null; 094 } 095 096 public String getTargetHashID() { 097 //make it an empty string if there is no target set 098 return (this.getTarget()!=null) ? this.getTarget().getHashID() : ""; 099 } 100 101 public String getSourceHashID() { 102 //make it an empty string if there is no source set 103 return (this.getSource()!=null) ? this.getSource().getHashID() : ""; 104 } 105 106 public Coordinate getSourceCoordinates() { 107 return this.sourceCoordinates; 108 } 109 110 public Coordinate getTargetCoordinates() { 111 return this.targetCoordinates; 112 } 113 114 public void setSourceCoordinates(Coordinate coord) { 115 this.sourceCoordinates = coord; 116 } 117 118 public void setTargetCoordinates(Coordinate coord) { 119 this.targetCoordinates = coord; 120 } 121 122 /** 123 * Sets the source coordinate by creating a new Coordinate object form the given parameters. 124 * Note that ZERO and null locations are disallowed and will throw IllegalArgument RuntimeExceptions. 125 * @param start 126 * @param end 127 * @param strand 128 */ 129 public void setSourceCoordinates(Integer start, Integer end, Coordinate.Strand strand) { 130 this.sourceCoordinates = new Coordinate(start, end, strand); 131 } 132 133 /** 134 * Sets the source coordinate by creating a new Coordinate object form the given parameters. 135 * Note that ZERO and null locations are disallowed and will throw IllegalArgument RuntimeExceptions. 136 * @param start 137 * @param end 138 * @param strand 139 */ 140 public void setSourceCoordinates(Integer start, Integer end, Integer strand) { 141 this.sourceCoordinates = new Coordinate(start, end, strand); 142 } 143 144 /** 145 * Sets the target coordinate by creating a new Coordinate object form the given parameters. 146 * Note that ZERO and null locations are disallowed and will throw IllegalArgument RuntimeExceptions. 147 * @param start 148 * @param end 149 * @param strand 150 */ 151 public void setTargetCoordinates(Integer start, Integer end, Coordinate.Strand strand) { 152 this.targetCoordinates = new Coordinate(start, end, strand); 153 } 154 155 /** 156 * Sets the target coordinate by creating a new Coordinate object form the given parameters. 157 * Note that ZERO and null locations are disallowed and will throw IllegalArgument RuntimeExceptions. 158 * @param start 159 * @param end 160 * @param strand 161 */ 162 public void setTargetCoordinates(Integer start, Integer end, Integer strand) { 163 this.targetCoordinates = new Coordinate(start, end, strand); 164 } 165 166 @Override 167 public boolean equals(Object mapping) { 168 169 if (this == mapping ) { 170 return true; 171 } 172 173 //this checks for null too.. 174 if ( ! (mapping instanceof Mapping )) { 175 return false; 176 } 177 178 Mapping m = (Mapping) mapping; 179 180 boolean out = true; 181 182 //this checks for identity if source and target are set on both mappings 183 //and each pair has the same hashcode 184 //the hashcode method will be based on objectID, objectType and probably SpeciesID 185 186 if ( !( !this.getSourceHashID().equals("") 187 && !m.getSourceHashID().equals("") 188 && !this.getTargetHashID().equals("") 189 && !m.getTargetHashID().equals("") 190 && this.getSourceHashID().equals(m.getSourceHashID()) 191 && this.getTargetHashID().equals(m.getTargetHashID()) 192 ) ) { 193 return false; 194 } 195 196 return out; 197 198 } 199 200 @Override 201 public int hashCode() { 202 203 return this.getSourceHashID().hashCode()+this.getTargetHashID().hashCode(); 204 205 } 206 207 public Mapping getReverseMapping() { 208 if (reverseMapping==null) { 209 Mapping.addReverseMapping(this); 210 } 211 return reverseMapping; 212 } 213 214 public void setReverseMapping(Mapping reverseMapping) { 215 this.reverseMapping = reverseMapping; 216 } 217 218 public static final MappingOnSourceComparator mappingOnSourceComparator 219 = new MappingOnSourceComparator(); 220 221 public static final MappingOnTargetComparator mappingOnTargetComparator 222 = new MappingOnTargetComparator(); 223 224} 225 226 /** 227 * Comparator Class for Mappings, based primarily on their source coordinates. 228 * This will sort a set of Mappings on the order of the source coordinates 229 * or failing that on the ids on the target object, then source object. Beware 230 * that this comparison doesn't match the equals logic. 231 * @author tpaterso 232 */ 233 class MappingOnSourceComparator implements Comparator<Mapping>, Serializable { 234 public int compare(Mapping o1, Mapping o2) { 235 // this would only sort mappings with non identical source coordinates 236 // however we want to sort multiple things with the same source coordinates if they are different things! 237 //return o1.getSourceCoordinates().compareTo(o2.getSourceCoordinates()); 238 239 if (o1==null) { 240 if (o2 == null) { 241 return 0; 242 } else { 243 return -1; 244 } 245 } else if (o2==null) { 246 return +1; 247 } 248 249 int out; 250 251 if (o1.getSourceCoordinates()==null) { 252 if (o2.getSourceCoordinates()== null) { 253 out=0; 254 } else { 255 return -1; 256 } 257 } else if (o2.getSourceCoordinates()== null) { 258 return +1; 259 } else { 260 out = o1.getSourceCoordinates().compareTo(o2.getSourceCoordinates()); 261 } 262 263 if (out != 0) { 264 return out; 265 } else { 266 267 //if both pairs of hashIDs are same this could break the contract of equals 268 //for the set - however it could happen cos the mappings are mutable 269 if (o1.getTargetHashID().equals(o2.getTargetHashID()) && 270 o1.getSourceHashID().equals(o2.getSourceHashID()) ) { 271 //it looks like the mappings really are for the same things! 272 //so return this 273 return 0; 274 } else { 275 276 //not the same 277 out = -1; 278 279 try { 280 //try to order them by the Target's ID number 281 out = o1.getTargetHashID().compareTo(o2.getTargetHashID()); 282 // but if they have the same ID ignore this 283 if (out == 0) { 284 out = o1.getSourceHashID().compareTo(o2.getSourceHashID()); 285 } 286 // but if these also have the same ID ignore this and return a random ordering 287 if (out == 0) { 288 out = -1; 289 } 290 } catch (Exception e) { 291 } 292 return out; 293 } 294 } 295 } 296 } 297 298 /** 299 * Comparator Class for Mappings, based primarily on their target coordinates. 300 * This will sort a set of Mappings on the order of the target coordinates 301 * or failing that on the ids on the source object, then target object. Beware 302 * that this comparison doesn't match the equals logic. 303 * @author tpaterso 304 */ 305 class MappingOnTargetComparator implements Comparator<Mapping>, Serializable { 306 public int compare(Mapping o1, Mapping o2) { 307 // this would only sort mappings with non identical source coordinates 308 // however we want to sort multiple things with the same source coordinates if they are different things! 309 //return o1.getSourceCoordinates().compareTo(o2.getSourceCoordinates()); 310 311 if (o1==null) { 312 if (o2 == null) { 313 return 0; 314 } else { 315 return -1; 316 } 317 } else if (o2==null) { 318 return +1; 319 } 320 321 int out; 322 323 if (o1.getTargetCoordinates()==null) { 324 if (o2.getTargetCoordinates()== null) { 325 out=0; 326 } else { 327 return -1; 328 } 329 } else if (o2.getTargetCoordinates()== null) { 330 return +1; 331 } else { 332 out = o1.getTargetCoordinates().compareTo(o2.getTargetCoordinates()); 333 } 334 335 if (out != 0) { 336 return out; 337 } else { 338 339 //if both pairs of hashIDs are same this could break the contract of equals 340 //for the set - however it could happen cos the mappings are mutable 341 if (o1.getTargetHashID().equals(o2.getTargetHashID()) && 342 o1.getSourceHashID().equals(o2.getSourceHashID()) ) { 343 //it looks like the mappings really are for the same things! 344 //so return this 345 return 0; 346 } else { 347 348 //not the same 349 out = -1; 350 351 try { 352 //try to order them by the Target's ID number 353 out = o1.getSourceHashID().compareTo(o2.getSourceHashID()); 354 // but if they have the same ID ignore this 355 if (out == 0) { 356 out = o1.getTargetHashID().compareTo(o2.getTargetHashID()); 357 } 358 // but if these also have the same ID ignore this and return a random ordering 359 if (out == 0) { 360 out = -1; 361 } 362 } catch (Exception e) { 363 } 364 return out; 365 } 366 } 367 } 368 } 369 370