| PerusTietue.java |
1 package kanta;
2
3 import java.io.*;
4
5 import fi.jyu.mit.ohj2.Mjonot;
6
7 /**
8 * Tietue joka osaa mm. itse huolehtia tunnus_nro:staan.
9 * Oikean tietueen tekemiseksi tämä on perittävä ja lisättävä mm.
10 * Kentta-taulukko. 0's kenttä on aina id-numero.
11 *
12 * @author Vesa Lappalainen
13 * @version 1.0, 22.02.2003
14 * @version 1.1, 23.02.2012
15 * @example
16 * <pre name="testJAVA">
17 * public static class Harrastus extends PerusTietue {
18 * private Kentta kentat[] = {
19 * new IntKentta("id"),
20 * new IntKentta("jäsenId"),
21 * new JonoKentta("ala"),
22 * new IntKentta("aloitusvuosi"),
23 * new IntKentta("h/vko")
24 * };
25 * private static int seuraavaNro = 1;
26 * @Override public int ekaKentta() { return 2; }
27 * @Override public Kentta[] getKentat() { return kentat; }
28 * @Override public int getSeuraavaNro() { return seuraavaNro; }
29 * @Override protected void setSeuraavaNro(int i) { seuraavaNro = i; }
30 * @Override protected void setKentat(Kentta[] kentat) { this.kentat = kentat; }
31 * @Override public Harrastus clone() throws CloneNotSupportedException {return (Harrastus)super.clone(); }
32 * public int getJasenNro() { return ((IntKentta)getKentta(1)).getValue(); }
33 * }
34 * </pre>
35 */
36 public abstract class PerusTietue implements Cloneable,Tietue {
37
38 /**
39 * @param i seuraava id-numero jota tästä lähiten käytetään
40 */
41 abstract protected void setSeuraavaNro(int i);
42
43
44 /**
45 * Asetetaan kentät. Käytetään lähinnä kloonaamisessa
46 * @param kentat uudet kentät tietueelle
47 */
48 abstract protected void setKentat(Kentta[] kentat);
49
50
51 /**
52 * @return tietueen kenttien lukumäärä
53 * @example
54 * <pre name="test">
55 * Harrastus har = new Harrastus();
56 * har.getKenttia() === 5;
57 * </pre>
58 */
59 @Override
60 public int getKenttia() {
61 return getKentat().length;
62 }
63
64
65 /**
66 * @return ensimmäinen käyttäjän syötettävän kentän indeksi
67 * @example
68 * <pre name="test">
69 * Harrastus har = new Harrastus();
70 * har.ekaKentta() === 2;
71 * </pre>
72 */
73 @Override
74 public int ekaKentta() {
75 return 1;
76 }
77
78
79 /**
80 * @param k Mikä kenttä halutaan
81 * @return k.s kenttä
82 * @example
83 * <pre name="test">
84 * Harrastus har = new Harrastus();
85 * har.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
86 * IntKentta kentta = (IntKentta)har.getKentta(3);
87 * kentta.getValue() === 1949;
88 * </pre>
89 */
90 @Override
91 public Kentta getKentta(int k) {
92 return getKentat()[k];
93 }
94
95
96 /**
97 * @param k minkä kentän kysymys halutaan
98 * @return valitun kentän kysymysteksti
99 * @example
100 * <pre name="test">
101 * Harrastus har = new Harrastus();
102 * har.getKysymys(2) === "ala";
103 * </pre>
104 */
105 @Override
106 public String getKysymys(int k) {
107 try {
108 return getKentta(k).getKysymys();
109 } catch (Exception ex) {
110 return "Ääliö";
111 }
112 }
113
114
115 /**
116 * @return kaikkien näytettävien kysymysten otsikot merkkijonotaulukkona
117 * @example
118 * <pre name="test">
119 * #import java.util.Arrays;
120 * Harrastus har = new Harrastus();
121 * Arrays.toString(har.getOtsikot()) =R= "\\[ala, aloitusvuosi, h/vko.*";
122 * </pre>
123 */
124 @Override
125 public String[] getOtsikot() {
126 int n = getKenttia() - ekaKentta();
127 String[] otsikot = new String[n];
128 for (int i=0,k=ekaKentta(); i<n; i++,k++)
129 otsikot[i] = getKysymys(k);
130 return otsikot;
131 }
132
133
134 /**
135 * @param k Minkä kentän sisältö halutaan
136 * @return valitun kentän sisältö
137 * @example
138 * <pre name="test">
139 * Harrastus har = new Harrastus();
140 * har.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
141 * har.anna(0) === "2";
142 * har.anna(1) === "10";
143 * har.anna(2) === "Kalastus";
144 * har.anna(3) === "1949";
145 * har.anna(4) === "22";
146 * </pre>
147 */
148 @Override
149 public String anna(int k) {
150 try {
151 return getKentta(k).toString();
152 } catch (Exception ex) {
153 return "";
154 }
155 }
156
157
158 /**
159 * Kentän sisältö kokonaislukuna. Jos ei ole IntKentta,
160 * niin -1.
161 * @param k Minkä kentän sisältö halutaan
162 * @return valitun kentän sisältö kokonaislukuna.
163 * @example
164 * <pre name="test">
165 * Harrastus har = new Harrastus();
166 * har.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
167 * har.annaInt(0) === 2;
168 * har.annaInt(1) === 10;
169 * har.annaInt(2) === -1;
170 * har.annaInt(3) === 1949;
171 * har.annaInt(4) === 22;
172 * </pre>
173 */
174 @Override
175 public int annaInt(int k) {
176 Kentta kentta = getKentta(k);
177 if ( !(kentta instanceof IntKentta) ) return -1;
178 return ((IntKentta)kentta).getValue();
179 }
180
181
182
183 /**
184 * Asetetaan valitun kentän sisältö. Mikäli asettaminen onnistuu,
185 * palautetaan null, muutoin virheteksti.
186 * @param k minkä kentän sisältö asetetaan
187 * @param s asetettava sisältö merkkijonona
188 * @return null jos ok, muuten virheteksti
189 * @example
190 * <pre name="test">
191 * Harrastus har = new Harrastus();
192 * har.aseta(3,"kissa") === "aloitusvuosi: Ei kokonaisluku (kissa)";
193 * har.aseta(3,"1940") === null;
194 * har.aseta(4,"kissa") === "h/vko: Ei kokonaisluku (kissa)";
195 * har.aseta(4,"20") === null;
196 * </pre>
197 */
198 @Override
199 public String aseta(int k, String s) {
200 try {
201 String virhe = getKentta(k).aseta(s.trim());
202 if ( virhe == null && k == 0 ) setTunnusNro(getTunnusNro());
203 if ( virhe == null ) return virhe;
204 return getKysymys(k) +": " + virhe;
205 } catch (Exception ex) {
206 return "Virhe: " + ex.getMessage();
207 }
208 }
209
210
211 /**
212 * Tehdään identtinen klooni tietueesta
213 * @return Object kloonattu tietue
214 * @example
215 * <pre name="test">
216 * #THROWS CloneNotSupportedException
217 * Harrastus har = new Harrastus();
218 * har.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
219 * Harrastus kopio = har.clone();
220 * kopio.toString() === har.toString();
221 * har.parse(" 1 | 11 | Uinti | 1949 | 22 t ");
222 * kopio.toString().equals(har.toString()) === false;
223 * kopio instanceof Harrastus === true;
224 * </pre>
225 */
226 @Override
227 public Tietue clone() throws CloneNotSupportedException { // NOPMD
228 PerusTietue uusi;
229 uusi = (PerusTietue)super.clone();
230 uusi.setKentat(getKentat().clone());
231
232 for (int k = 0; k < getKenttia(); k++)
233 uusi.getKentat()[k] = getKentta(k).clone();
234 return uusi;
235 }
236
237
238 /**
239 * Tulostetaan tietueen tiedot
240 * @param out tietovirta johon tulostetaan
241 */
242 @Override
243 public void tulosta(PrintWriter out) {
244 String erotin = "";
245 for (int k=ekaKentta(); k<getKenttia(); k++) {
246 out.print(erotin + anna(k));
247 erotin = " ";
248 }
249 out.println();
250 }
251
252
253 /**
254 * Tulostetaan tietueen tiedot
255 * @param os tietovirta johon tulostetaan
256 */
257 @Override
258 public void tulosta(OutputStream os) {
259 tulosta(new PrintStream(os));
260 }
261
262
263 /**
264 * Tulostetaan tietueen tiedot
265 * @param out tietovirta johon tulostetaan
266 */
267 @Override
268 public void tulosta(PrintStream out) {
269 tulosta(new PrintWriter(out, true)); // ilman autoflushia ei mitään
270 // tulostu!
271 }
272
273
274 /**
275 * Antaa tietueelle seuraavan rekisterinumeron
276 * @return tietueen uusi tunnus_nro
277 * @example
278 * <pre name="test">
279 * Harrastus pitsi1 = new Harrastus();
280 * pitsi1.getTunnusNro() === 0;
281 * pitsi1.rekisteroi();
282 * int n1 = pitsi1.getTunnusNro();
283 * Harrastus pitsi2 = new Harrastus();
284 * pitsi2.rekisteroi() === n1 + 1;
285 * int n2 = pitsi2.getTunnusNro();
286 * n1 === n2-1;
287 * </pre>
288 */
289 @Override
290 public int rekisteroi() {
291 return setTunnusNro(getSeuraavaNro());
292 }
293
294
295 /**
296 * Palautetaan tietueen oma id
297 * @return tietueen id
298 * @example
299 * <pre name="test">
300 * Harrastus harrastus = new Harrastus();
301 * harrastus.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
302 * harrastus.getTunnusNro() === 2;
303 * </pre>
304 */
305 @Override
306 public int getTunnusNro() {
307 return ((IntKentta)(getKentta(0))).getValue();
308 }
309
310
311 /**
312 * Asettaa tunnusnumeron ja samalla varmistaa että
313 * seuraava numero on aina suurempi kuin tähän mennessä suurin.
314 * @param nr asetettava tunnusnumero
315 */
316 private int setTunnusNro(int nr) {
317 IntKentta k = ((IntKentta)(getKentta(0)));
318 k.setValue(nr);
319 if (nr >= getSeuraavaNro()) setSeuraavaNro(nr + 1);
320 return k.getValue();
321 }
322
323
324 /**
325 * Palauttaa tietueen tiedot merkkijonona jonka voi tallentaa tiedostoon.
326 * @return tietue tolppaeroteltuna merkkijonona
327 * @example
328 * <pre name="test">
329 * Harrastus harrastus = new Harrastus();
330 * harrastus.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
331 * harrastus.toString() =R= "2\\|10\\|Kalastus\\|1949\\|22.*";
332 * </pre>
333 */
334 @Override
335 public String toString() {
336 StringBuffer sb = new StringBuffer("");
337 String erotin = "";
338 for (int k = 0; k < getKenttia(); k++) {
339 sb.append(erotin);
340 sb.append(anna(k));
341 erotin = "|";
342 }
343 return sb.toString();
344 }
345
346
347 /**
348 * Selvittää tietueen tiedot | erotellusta merkkijonosta.
349 * Pitää huolen että seuraavaNro on suurempi kuin tuleva tunnusnro.
350 * @param rivi josta harrastuksen tiedot otetaan
351 * @example
352 * <pre name="test">
353 * Harrastus harrastus = new Harrastus();
354 * harrastus.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
355 * harrastus.getJasenNro() === 10;
356 * harrastus.toString() =R= "2\\|10\\|Kalastus\\|1949\\|22.*";
357 *
358 * harrastus.rekisteroi();
359 * int n = harrastus.getTunnusNro();
360 * harrastus.parse(""+(n+20));
361 * harrastus.rekisteroi();
362 * harrastus.getTunnusNro() === n+20+1;
363 * harrastus.toString() =R= "" + (n+20+1) + "\\|10\\|\\|1949\\|22.*";
364 * </pre>
365 */
366 @Override
367 public void parse(String rivi) {
368 StringBuffer sb = new StringBuffer(rivi);
369 for (int k = 0; k < getKenttia(); k++)
370 aseta(k, Mjonot.erota(sb, '|'));
371 }
372
373
374 /**
375 * Antaa k:n kentän sisällön avain-merkkijonona
376 * jonka perusteella voi lajitella
377 * @param k monenenko kentän sisältö palautetaan
378 * @return kentän sisältö merkkijonona
379 *
380 * @example
381 * <pre name="test">
382 * Harrastus har = new Harrastus();
383 * har.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
384 * har.getAvain(0) === " 2";
385 * har.getAvain(1) === " 10";
386 * har.getAvain(2) === "KALASTUS";
387 * har.getAvain(20) === "";
388 * </pre>
389 */
390 @Override
391 public String getAvain(int k) {
392 try {
393 return getKentta(k).getAvain();
394 } catch (Exception ex) {
395 return "";
396 }
397 }
398
399
400 /**
401 * Tutkii onko tietueen tiedot samat kuin parametrina tuodun tietueen tiedot
402 * @param tietue johon verrataan
403 * @return true jos kaikki tiedot samat, false muuten
404 * @example
405 * <pre name="test">
406 * Harrastus har1 = new Harrastus();
407 * har1.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
408 * Harrastus har2 = new Harrastus();
409 * har2.parse(" 2 | 10 | Kalastus | 1949 | 22 t ");
410 * Harrastus har3 = new Harrastus();
411 * har3.parse(" 3 | 12 | Kalastus | 1949 | 22 t ");
412 *
413 *
414 * har1.equals(har2) === true;
415 * har2.equals(har1) === true;
416 * har1.equals(har3) === false;
417 * har3.equals(har2) === false;
418 * </pre>
419 */
420 @Override
421 public boolean equals(Tietue tietue) {
422 if ( getKenttia() != tietue.getKenttia() ) return false;
423 for (int k = 0; k < getKenttia(); k++)
424 if (!anna(k).equals(tietue.anna(k))) return false;
425 return true;
426 }
427
428 }
429