Jasenet.java |
1 package kerho; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.IOException; 6 import java.io.PrintWriter; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.Collection; 10 import java.util.Collections; 11 import java.util.Iterator; 12 import java.util.List; 13 import java.util.NoSuchElementException; 14 15 import fi.jyu.mit.ohj2.Tiedosto; 16 import fi.jyu.mit.ohj2.WildChars; 17 18 /** 19 * Kerhon jäsenistö joka osaa mm. lisätä uuden jäsenen 20 * 21 * @author Vesa Lappalainen 22 * @version 1.0, 22.02.2003 23 * @version 1.1, 19.02.2012 24 * @version 1.2, 15.03.2012 25 */ 26 public class Jasenet implements Iterable<Jasen> { 27 private boolean muutettu = false; 28 private int MAX_JASENIA = Integer.MAX_VALUE; 29 private String kokoNimi = ""; 30 private String tiedostonPerusNimi = ""; 31 private int lkm = 0; 32 private Jasen alkiot[] = new Jasen[5]; 33 34 35 /** 36 * Oletusmuodostaja jolla tulee täysin dynaaminen koko. 37 */ 38 public Jasenet() { 39 // Attribuuttien oma alustus riittää 40 } 41 42 43 /** 44 * Muodostaja jolla maxkoko voidaan asettaa. 45 * Tällöin ei koskaan lisätä enempää kuin maksimi. 46 * @param koko jäsenistön maxkoko 47 * 48 */ 49 public Jasenet(int koko) { 50 MAX_JASENIA = koko; 51 alkiot = new Jasen[MAX_JASENIA]; 52 } 53 54 55 /** 56 * Lisää uuden jäsenen tietorakenteeseen. Ottaa jäsenen omistukseensa. 57 * @param jasen lisättävän jäsenen viite. Huom tietorakenne muuttuu omistajaksi 58 * @throws SailoException jos määrä ylittää pyydetyn maksimirajan 59 * @example 60 * <pre name="test"> 61 * #THROWS SailoException 62 * #PACKAGEIMPORT 63 * Jasenet jasenet = new Jasenet(5); 64 * Jasen aku1 = new Jasen(), aku2 = new Jasen(); 65 * jasenet.getLkm() === 0; 66 * jasenet.lisaa(aku1); jasenet.getLkm() === 1; 67 * jasenet.lisaa(aku2); jasenet.getLkm() === 2; 68 * jasenet.lisaa(aku1); jasenet.getLkm() === 3; 69 * jasenet.anna(0) === aku1; 70 * jasenet.anna(1) === aku2; 71 * jasenet.anna(2) === aku1; 72 * jasenet.anna(1) == aku1 === false; 73 * jasenet.anna(1) == aku2 === true; 74 * jasenet.anna(3) === aku1; #THROWS IndexOutOfBoundsException 75 * jasenet.lisaa(aku1); jasenet.getLkm() === 4; 76 * jasenet.lisaa(aku1); jasenet.getLkm() === 5; 77 * jasenet.lisaa(aku1); #THROWS SailoException 78 * 79 * jasenet = new Jasenet(); 80 * for (int i=0; i<200; i++) { 81 * jasenet.lisaa(aku1); jasenet.getLkm() === 2*i+1; 82 * jasenet.lisaa(aku2); jasenet.getLkm() === 2*i+2; 83 * } 84 * </pre> 85 */ 86 public void lisaa(Jasen jasen) throws SailoException { 87 if (lkm >= MAX_JASENIA) throw new SailoException("Liikaa alkioita"); 88 if (lkm >= alkiot.length) alkiot = Arrays.copyOf(alkiot, lkm+20); 89 alkiot[lkm] = jasen; 90 lkm++; 91 muutettu = true; 92 } 93 94 95 /** 96 * Poistaa jäsenen jolla on valittu tunnusnumero 97 * @param id poistettavan jäsenen tunnusnumero 98 * @return 1 jos poistettiin, 0 jos ei löydy 99 * @example 100 * <pre name="test"> 101 * #THROWS SailoException 102 * Jasenet jasenet = new Jasenet(5); 103 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen(); 104 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi(); 105 * int id1 = aku1.getTunnusNro(); 106 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3); 107 * jasenet.poista(id1+1) === 1; 108 * jasenet.etsiId(id1+1) === -1; jasenet.getLkm() === 2; 109 * jasenet.poista(id1) === 1; jasenet.getLkm() === 1; 110 * jasenet.poista(id1+3) === 0; jasenet.getLkm() === 1; 111 * </pre> 112 * 113 */ 114 public int poista(int id) { 115 int ind = etsiId(id); 116 if (ind < 0) return 0; 117 lkm--; 118 for (int i = ind; i < lkm; i++) 119 alkiot[i] = alkiot[i + 1]; 120 alkiot[lkm] = null; 121 muutettu = true; 122 return 1; 123 } 124 125 126 /** 127 * Korvaa jäsenen tietorakenteessa. Ottaa jäsenen omistukseensa. 128 * Etsitään samalla tunnusnumerolla oleva jäsen. Jos ei läydy, 129 * niin lisätään uutena jäsenenä. 130 * @param jasen lisätäävän jäsenen viite. Huom tietorakenne muuttuu omistajaksi 131 * @throws SailoException jos tietorakennen on jo täynnä 132 * <pre name="test"> 133 * #THROWS SailoException,CloneNotSupportedException 134 * #PACKAGEIMPORT 135 * Jasenet jasenet = new Jasenet(); 136 * Jasen aku1 = new Jasen(), aku2 = new Jasen(); 137 * aku1.rekisteroi(); aku2.rekisteroi(); 138 * jasenet.getLkm() === 0; 139 * jasenet.korvaaTaiLisaa(aku1); jasenet.getLkm() === 1; 140 * jasenet.korvaaTaiLisaa(aku2); jasenet.getLkm() === 2; 141 * Jasen aku3 = aku1.clone(); 142 * aku3.aseta(3,"kkk"); 143 * jasenet.anna(0) == aku1 === true; 144 * jasenet.korvaaTaiLisaa(aku3); jasenet.getLkm() === 2; 145 * jasenet.anna(0) === aku3; 146 * jasenet.anna(0) == aku3 === true; 147 * jasenet.anna(0) == aku1 === false; 148 * </pre> 149 */ 150 public void korvaaTaiLisaa(Jasen jasen) throws SailoException { 151 int id = jasen.getTunnusNro(); 152 for (int i = 0; i < lkm; i++) { 153 if (alkiot[i].getTunnusNro() == id) { 154 alkiot[i] = jasen; 155 muutettu = true; 156 return; 157 } 158 } 159 lisaa(jasen); 160 } 161 162 163 /** 164 * Palauttaa viitteen i:teen jäseneen. 165 * @param i monennenko jäsenen viite halutaan 166 * @return viite jäseneen, jonka indeksi on i 167 * @throws IndexOutOfBoundsException jos i ei ole sallitulla alueella 168 */ 169 public Jasen anna(int i) throws IndexOutOfBoundsException { 170 if (i < 0 || lkm <= i) throw new IndexOutOfBoundsException("Laiton indeksi: " + i); 171 return alkiot[i]; 172 } 173 174 175 /** 176 * Lukee jäsenistön tiedostosta. 177 * @param tied tiedoston nimen alkuosa 178 * @throws SailoException jos lukeminen epäonnistuu 179 * 180 * @example 181 * <pre name="test"> 182 * #THROWS SailoException 183 * #import java.io.File; 184 * 185 * Jasenet jasenet = new Jasenet(); 186 * Jasen aku1 = new Jasen(), aku2 = new Jasen(); 187 * aku1.vastaaAkuAnkka(); 188 * aku2.vastaaAkuAnkka(); 189 * String tiedNimi = "testikelmit"; 190 * File ftied = new File(tiedNimi+".dat"); 191 * ftied.delete(); 192 * jasenet.lueTiedostosta(tiedNimi); #THROWS SailoException 193 * jasenet.lisaa(aku1); 194 * jasenet.lisaa(aku2); 195 * jasenet.talleta(); 196 * jasenet = new Jasenet(); // Poistetaan vanhat luomalla uusi 197 * jasenet.lueTiedostosta(tiedNimi); // johon ladataan tiedot tiedostosta. 198 * Iterator<Jasen> i = jasenet.iterator(); 199 * i.next().toString() === aku1.toString(); 200 * i.next().toString() === aku2.toString(); 201 * i.hasNext() === false; 202 * jasenet.lisaa(aku2); 203 * jasenet.talleta(); 204 * ftied.delete() === true; 205 * File fbak = new File(tiedNimi+".bak"); 206 * fbak.delete() === true; 207 * </pre> 208 */ 209 public void lueTiedostosta(String tied) throws SailoException { 210 setTiedostonPerusNimi(tied); 211 BufferedReader fi = Tiedosto.avaa_lukemista_varten(getTiedostonNimi()); 212 if (fi == null) throw new SailoException("Tiedosto " + getTiedostonNimi() + " ei aukea"); 213 214 try { 215 kokoNimi = fi.readLine(); 216 if (kokoNimi == null) throw new SailoException("Kerhon nimi puuttuu"); 217 String rivi = fi.readLine(); 218 if (rivi == null) throw new SailoException("Maksimikoko puuttuu"); 219 // int maxKoko = Mjonot.erotaInt(rivi,10); // tehdään jotakin 220 221 while ((rivi = fi.readLine()) != null) { 222 rivi = rivi.trim(); 223 if ("".equals(rivi) || rivi.charAt(0) == ';') continue; 224 Jasen jasen = new Jasen(); 225 jasen.parse(rivi); // voisi olla virhekäsittely 226 lisaa(jasen); 227 } 228 muutettu = false; 229 230 } catch (IOException e) { 231 throw new SailoException("Ongelmia tiedoston kanssa: " + e.getMessage()); 232 } finally { 233 try { 234 fi.close(); 235 } catch (IOException e) { 236 throw new SailoException("Tiedoston sulkeminen ei onnistu: " + e.getMessage()); 237 } 238 } 239 } 240 241 242 /** 243 * Tallentaa jäsenistän tiedostoon. 244 * Tiedoston muoto: 245 * <pre> 246 * Kelmien kerho 247 * 20 248 * ; kommenttirivi 249 * 2|Ankka Aku|121103-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle 250 * 3|Ankka Tupu|121153-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle 251 * </pre> 252 * @throws SailoException jos talletus epäonnistuu 253 */ 254 public void talleta() throws SailoException { 255 if (!muutettu) return; 256 257 File fbak = new File(getBakNimi()); 258 File ftied = new File(getTiedostonNimi()); 259 fbak.delete(); // if .. System.err.println("Ei voi tuhota"); 260 ftied.renameTo(fbak); // if .. System.err.println("Ei voi nimetä"); 261 262 PrintWriter fo = Tiedosto.avaa_kirjoittamista_varten(ftied.getName()); 263 if (fo == null) throw new SailoException("Tiedosto " + ftied.getName() + " ei aukea"); 264 try { 265 fo.println(getKokoNimi()); 266 fo.println(alkiot.length); 267 for (Jasen jasen : this) { 268 fo.println(jasen.toString()); 269 } 270 //} catch ( IOException e ) { // ei heitä poikkeusta 271 // throw new SailoException("Tallettamisessa ongelmia: " + e.getMessage()); 272 } finally { 273 fo.close(); 274 } 275 276 muutettu = false; 277 } 278 279 280 /** 281 * Palauttaa Kerhon koko nimen 282 * @return Kerhon koko nimi merkkijononna 283 */ 284 public String getKokoNimi() { 285 return kokoNimi; 286 } 287 288 289 /** 290 * Palauttaa kerhon jäsenten lukumäärän 291 * @return jäsenten lukumäärä 292 */ 293 public int getLkm() { 294 return lkm; 295 } 296 297 298 /** 299 * Palauttaa tiedoston nimen, jota käytetään tallennukseen 300 * @return tallennustiedoston nimi 301 */ 302 public String getTiedostonPerusNimi() { 303 return tiedostonPerusNimi; 304 } 305 306 307 /** 308 * Asettaa tiedoston perusnimen ilan tarkenninta 309 * @param tied tallennustiedoston perusnimi 310 */ 311 public void setTiedostonPerusNimi(String tied) { 312 tiedostonPerusNimi = tied; 313 } 314 315 316 /** 317 * Palauttaa tiedoston nimen, jota käytetään tallennukseen 318 * @return tallennustiedoston nimi 319 */ 320 public String getTiedostonNimi() { 321 return getTiedostonPerusNimi() + ".dat"; 322 } 323 324 325 /** 326 * Palauttaa varakopiotiedoston nimen 327 * @return varakopiotiedoston nimi 328 */ 329 public String getBakNimi() { 330 return tiedostonPerusNimi + ".bak"; 331 } 332 333 334 /** 335 * Luokka jäsenten iteroimiseksi. 336 * @example 337 * <pre name="test"> 338 * #THROWS SailoException 339 * #PACKAGEIMPORT 340 * #import java.util.*; 341 * 342 * Jasenet jasenet = new Jasenet(); 343 * Jasen aku1 = new Jasen(), aku2 = new Jasen(); 344 * aku1.rekisteroi(); aku2.rekisteroi(); 345 * 346 * jasenet.lisaa(aku1); 347 * jasenet.lisaa(aku2); 348 * jasenet.lisaa(aku1); 349 * 350 * StringBuffer ids = new StringBuffer(30); 351 * for (Jasen jasen:jasenet) // Kokeillaan for-silmukan toimintaa 352 * ids.append(" "+jasen.getTunnusNro()); 353 * 354 * String tulos = " " + aku1.getTunnusNro() + " " + aku2.getTunnusNro() + " " + aku1.getTunnusNro(); 355 * 356 * ids.toString() === tulos; 357 * 358 * ids = new StringBuffer(30); 359 * for (Iterator<Jasen> i=jasenet.iterator(); i.hasNext(); ) { // ja iteraattorin toimintaa 360 * Jasen jasen = i.next(); 361 * ids.append(" "+jasen.getTunnusNro()); 362 * } 363 * 364 * ids.toString() === tulos; 365 * 366 * Iterator<Jasen> i=jasenet.iterator(); 367 * i.next() == aku1 === true; 368 * i.next() == aku2 === true; 369 * i.next() == aku1 === true; 370 * 371 * i.next(); #THROWS NoSuchElementException 372 * 373 * </pre> 374 */ 375 public class JasenetIterator implements Iterator<Jasen> { 376 private int kohdalla = -1; 377 378 379 /** 380 * Onko olemassa vielä seuraavaa jäsentä 381 * @see java.util.Iterator#hasNext() 382 * @return true jos on vielä jäseniä 383 */ 384 @Override 385 public boolean hasNext() { 386 // if ( kohdalla + 1 >= lkm ) return false; 387 // return true; 388 return kohdalla + 1 < getLkm(); 389 } 390 391 392 /** 393 * Annetaan seuraava jäsen 394 * @return seuraava jäsen 395 * @throws NoSuchElementException jos seuraava alkiota ei enää ole 396 * @see java.util.Iterator#next() 397 */ 398 @Override 399 public Jasen next() throws NoSuchElementException { 400 if (!hasNext()) throw new NoSuchElementException("Ei oo"); 401 kohdalla++; 402 return anna(kohdalla); 403 } 404 405 406 /** 407 * Tuhoamista ei ole toteutettu 408 * @throws UnsupportedOperationException aina 409 * @see java.util.Iterator#remove() 410 */ 411 @Override 412 public void remove() throws UnsupportedOperationException { 413 throw new UnsupportedOperationException("Me ei poisteta"); 414 } 415 } 416 417 418 /** 419 * Palautetaan iteraattori jäsenistään. 420 * @return jäsen iteraattori 421 */ 422 @Override 423 public Iterator<Jasen> iterator() { 424 return new JasenetIterator(); 425 } 426 427 428 /** 429 * Palauttaa "taulukossa" hakuehtoon vastaavien jäsenten viitteet 430 * @param hakuehto hakuehto 431 * @param k etsittävän kentän indeksi 432 * @return tietorakenteen löytyneistä jäsenistä 433 * @example 434 * <pre name="test"> 435 * #THROWS SailoException 436 * Jasenet jasenet = new Jasenet(); 437 * Jasen jasen1 = new Jasen(); jasen1.parse("1|Ankka Aku|030201-115H|Ankkakuja 6|"); 438 * Jasen jasen2 = new Jasen(); jasen2.parse("2|Ankka Tupu||030552-123B|"); 439 * Jasen jasen3 = new Jasen(); jasen3.parse("3|Susi Sepe|121237-121V||131313|Perämetsä"); 440 * Jasen jasen4 = new Jasen(); jasen4.parse("4|Ankka Iines|030245-115V|Ankkakuja 9"); 441 * Jasen jasen5 = new Jasen(); jasen5.parse("5|Ankka Roope|091007-408U|Ankkakuja 12"); 442 * jasenet.lisaa(jasen1); jasenet.lisaa(jasen2); jasenet.lisaa(jasen3); jasenet.lisaa(jasen4); jasenet.lisaa(jasen5); 443 * List<Jasen> loytyneet; 444 * loytyneet = (List<Jasen>)jasenet.etsi("*s*",1); 445 * loytyneet.size() === 2; 446 * loytyneet.get(0) == jasen4 === true; 447 * loytyneet.get(1) == jasen3 === true; 448 * 449 * loytyneet = (List<Jasen>)jasenet.etsi("*7-*",2); 450 * loytyneet.size() === 2; 451 * loytyneet.get(0) == jasen5 === true; 452 * loytyneet.get(1) == jasen3 === true; 453 * </pre> 454 */ 455 public Collection<Jasen> etsi(String hakuehto, int k) { 456 List<Jasen> loytyneet = new ArrayList<Jasen>(); 457 for (Jasen jasen : this) { 458 // if ( jasen.anna(k).toUpperCase().startsWith(hakuehto.toUpperCase()) ) loytyneet.add(jasen); // NOPMD 459 if (WildChars.onkoSamat(jasen.anna(k), hakuehto)) loytyneet.add(jasen); // NOPMD 460 } 461 Collections.sort(loytyneet, new Jasen.Vertailija(k)); 462 return loytyneet; 463 } 464 465 466 /** 467 * Etsii jäsenen id:n perusteella 468 * @param id tunnusnumero, jonka mukaan etsitään 469 * @return jäsen jolla etsittävä id tai null 470 * <pre name="test"> 471 * #THROWS SailoException 472 * Jasenet jasenet = new Jasenet(5); 473 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen(); 474 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi(); 475 * int id1 = aku1.getTunnusNro(); 476 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3); 477 * jasenet.annaId(id1 ) == aku1 === true; 478 * jasenet.annaId(id1+1) == aku2 === true; 479 * jasenet.annaId(id1+2) == aku3 === true; 480 * </pre> 481 */ 482 public Jasen annaId(int id) { 483 for (Jasen jasen : this) { 484 if (id == jasen.getTunnusNro()) return jasen; 485 } 486 return null; 487 } 488 489 490 /** 491 * Etsii jäsenen id:n perusteella 492 * @param id tunnusnumero, jonka mukaan etsitään 493 * @return löytyneen jäsenen indeksi tai -1 jos ei löydy 494 * <pre name="test"> 495 * #THROWS SailoException 496 * Jasenet jasenet = new Jasenet(5); 497 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen(); 498 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi(); 499 * int id1 = aku1.getTunnusNro(); 500 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3); 501 * jasenet.etsiId(id1+1) === 1; 502 * jasenet.etsiId(id1+2) === 2; 503 * </pre> 504 */ 505 public int etsiId(int id) { 506 for (int i = 0; i < lkm; i++) 507 if (id == alkiot[i].getTunnusNro()) return i; 508 return -1; 509 } 510 511 512 /** 513 * Testiohjelma jäsenistölle 514 * @param args ei käytössä 515 */ 516 public static void main(String args[]) { 517 Jasenet jasenet = new Jasenet(); 518 519 Jasen aku = new Jasen(), aku2 = new Jasen(); 520 aku.rekisteroi(); 521 aku.vastaaAkuAnkka(); 522 aku2.rekisteroi(); 523 aku2.vastaaAkuAnkka(); 524 525 try { 526 jasenet.lisaa(aku); 527 jasenet.lisaa(aku2); 528 529 System.out.println("============= Jäsenet testi ================="); 530 531 for (int i = 0; i < jasenet.getLkm(); i++) { 532 Jasen jasen = jasenet.anna(i); 533 System.out.println("Jäsen nro: " + i); 534 jasen.tulosta(System.out); 535 } 536 537 } catch (SailoException ex) { 538 System.out.println(ex.getMessage()); 539 } 540 } 541 542 } 543