1/*
2 *  ReadOnceStrategy.java
3 *  Copyright (C) 2006 Amin Ahmad
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19package org.ahmadsoft.postal;
20
21import java.io.File;
22import java.io.RandomAccessFile;
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.HashMap;
26import java.util.List;
27import java.util.Map;
28
29/**
30 * A retrieval strategy that looks up from disk the first time
31 * and subsequently reads from cache. The Read-Once strategy
32 * is quite acceptable for day to day usage, its main problem
33 * being that memory usage limits cannot be enforced.
34 *
35 * @author Amin Ahmad
36 */
37public class ReadOnceStrategy implements PostalRetrievalStrategy {
38
39	private RandomAccessFile dataFile;
40	private RandomAccessFile indexFile;
41
42	private static Map cache = Collections.synchronizedMap(new HashMap());
43
44	/**
45	 * @inheritDoc
46	 */
47	public void initialize(File _indexFile, File _dataFile) throws Exception {
48		dataFile = new RandomAccessFile(_dataFile, "r");
49		indexFile = new RandomAccessFile(_indexFile, "r");
50	}
51
52	private synchronized List diskLookup(int postalCode) {
53		List result = new ArrayList();
54
55		try {
56			indexFile.seek((postalCode-1) * 8);
57			indexFile.readInt();
58			int loc = indexFile.readInt();
59
60			dataFile.seek(loc);
61			short type=0;
62			while (0 != (type=dataFile.readShort())) {
63				String state = dataFile.readUTF();
64				String city = dataFile.readUTF();
65
66				result.add(new PostalCodeEntry(postalCode,city,state,type));
67			}
68		} catch (Exception e) {
69			throw new RuntimeException(e);
70		}
71
72		return result;
73	}
74
75	/**
76	 * @inheritDoc
77	 */
78	public List getCandidates(int postalCode) {
79		if (postalCode < 1 || postalCode > 99999) {
80			return new ArrayList();
81		}
82
83		List candidates = null;
84		if (!cache.containsKey(new Integer(postalCode))) {
85			candidates = Collections.unmodifiableList(diskLookup(postalCode));
86			cache.put(new Integer(postalCode), candidates);
87		} else {
88			candidates = (List) cache.get(new Integer(postalCode));
89		}
90
91		return candidates;
92	}
93
94	/**
95	 * @inheritDoc
96	 */
97	public void dispose() throws Exception {
98		dataFile.close();
99		indexFile.close();
100		cache = null;
101	}
102
103}
104