Crossfire JXClient, Trunk  R20561
ServerCache.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.metaserver;
23 
24 import java.io.BufferedWriter;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.io.InputStreamReader;
31 import java.io.LineNumberReader;
32 import java.io.OutputStreamWriter;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39 
44 public class ServerCache {
45 
49  @NotNull
50  public static final CharSequence DEFAULT_ENTRY_LOCALHOST = "0|localhost|0|--|Local server. Start server before you try to connect.|0|0|0|||";
51 
56  @NotNull
57  private final Map<String, Info> entries = new HashMap<>();
58 
62  @Nullable
63  private final File file;
64 
69  public ServerCache(@Nullable final File file) {
70  this.file = file;
71 
72  load();
73  }
74 
80  public void put(@NotNull final MetaserverEntry metaserverEntry) {
81  entries.put(makeKey(metaserverEntry), new Info(metaserverEntry));
82  }
83 
88  public void expire(final long timestamp) {
89  final long now = System.currentTimeMillis();
90 
91  final Iterator<Info> it = entries.values().iterator();
92  while (it.hasNext()) {
93  final Info info = it.next();
94  if (now-info.getTimestamp() > timestamp) {
95  it.remove();
96  }
97  }
98  }
99 
105  @NotNull
106  public Map<String, MetaserverEntry> getAll() {
107  final Map<String, MetaserverEntry> result = new HashMap<>();
108  for (final Entry<String, Info> entry : entries.entrySet()) {
109  result.put(entry.getKey(), entry.getValue().getMetaserverEntry());
110  }
111  return result;
112  }
113 
119  @NotNull
120  public static String makeKey(@NotNull final MetaserverEntry metaserverEntry) {
121  return metaserverEntry.getHostname();
122  }
123 
127  private void load() {
128  if (file == null) {
129  return;
130  }
131 
132  try {
133  try (final FileInputStream fis = new FileInputStream(file)) {
134  try (final InputStreamReader isr = new InputStreamReader(fis, "UTF-8")) {
135  try (final LineNumberReader lnr = new LineNumberReader(isr)) {
136  while (true) {
137  final String line = lnr.readLine();
138  if (line == null) {
139  break;
140  }
141 
142  final String[] tmp = line.split(" ", 2);
143  if (tmp.length != 2) {
144  System.err.println(file+":"+lnr.getLineNumber()+": syntax error");
145  continue;
146  }
147 
148  final long timestamp;
149  try {
150  timestamp = Long.parseLong(tmp[0]);
151  } catch (final NumberFormatException ignored) {
152  System.err.println(file+":"+lnr.getLineNumber()+": syntax error");
153  continue;
154  }
155  if (!addEntry(tmp[1], timestamp)) {
156  System.err.println(file+":"+lnr.getLineNumber()+": syntax error");
157  //noinspection UnnecessaryContinue
158  continue;
159  }
160  }
161  }
162  }
163  }
164  } catch (final FileNotFoundException ignored) {
165  // add default entries if the cache files does not exist
166  final long now = System.currentTimeMillis()-1;
167  addEntry(DEFAULT_ENTRY_LOCALHOST, now);
168  addEntry("0|crossfire.metalforge.net|0|--|Latest SVN 1.x branch.<br>Eden Prairie, MN US<br>4.65Mb link<br><a href=\"http://crossfire.real-time.com\">crossfire.real-time.com</a>|0|0|0|Standard|Standard|Standard", now);
169  addEntry("0|invidious.meflin.net|0|--|<b>Welcome, we are testing 2.0 come on in the water is fine.</b>|0|0|0|Standard|Standard|Standard + Testing", now);
170  } catch (final IOException ex) {
171  System.err.println(file+": "+ex.getMessage());
172  }
173  }
174 
181  private boolean addEntry(@NotNull final CharSequence metaserverEntryLine, final long timestamp) {
182  final MetaserverEntry metaserverEntry = MetaserverEntryParser.parseEntry(metaserverEntryLine);
183  if (metaserverEntry == null) {
184  return false;
185  }
186 
187  entries.put(makeKey(metaserverEntry), new Info(metaserverEntry, timestamp));
188  return true;
189  }
190 
194  public void save() {
195  if (file == null) {
196  return;
197  }
198 
199  try {
200  saveInternal(file);
201  } catch (final IOException ex) {
202  System.err.println(file+": "+ex.getMessage());
203  }
204  }
205 
211  private void saveInternal(@NotNull final File file) throws IOException {
212  try (final FileOutputStream fos = new FileOutputStream(file)) {
213  try (final OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8")) {
214  try (final BufferedWriter bw = new BufferedWriter(osw)) {
215  for (final Info info : entries.values()) {
216  bw.write(Long.toString(info.getTimestamp()));
217  bw.write(' ');
218  bw.write(MetaserverEntryParser.format(info.getMetaserverEntry()));
219  bw.write('\n');
220  }
221  }
222  }
223  }
224  }
225 
226 }
boolean addEntry(@NotNull final CharSequence metaserverEntryLine, final long timestamp)
Parses a metaserver entry line and adds the result to entries.
long getTimestamp()
Returns the timestamp.
Definition: Info.java:75
void load()
Loads the entries from the backing file.
Map< String, MetaserverEntry > getAll()
Returns all cached entries.
static String makeKey(@NotNull final MetaserverEntry metaserverEntry)
Returns the key for a metaserver entry.
Maintains a set of known servers backed up in a file.
void saveInternal(@NotNull final File file)
Saves all entries to the backing file.
void expire(final long timestamp)
Expires entries older than a given timestamp from the cache.
Represents a response line from the metaserver.
static final CharSequence DEFAULT_ENTRY_LOCALHOST
The default entry for the "localhost" server.
static String format(@NotNull final MetaserverEntry entry)
Formats a metaserver entry that returns the metaserver entry when parse with parseEntry(CharSequence)...
Parser for response lines of metaserver response lines.
final Map< String, Info > entries
The cached entries.
static MetaserverEntry parseEntry(@NotNull final CharSequence entry)
Parses a metaserver response line.
void put(@NotNull final MetaserverEntry metaserverEntry)
Adds an entry to the cache.
void save()
Saves all entries to the backing file.
ServerCache(@Nullable final File file)
Creates a new instance.