1 |
package net.oni2.moddepot; |
2 |
|
3 |
import java.io.BufferedReader; |
4 |
import java.io.FileInputStream; |
5 |
import java.io.FileNotFoundException; |
6 |
import java.io.FileOutputStream; |
7 |
import java.io.IOException; |
8 |
import java.io.InputStreamReader; |
9 |
import java.io.UnsupportedEncodingException; |
10 |
import java.net.UnknownHostException; |
11 |
import java.util.Date; |
12 |
import java.util.Enumeration; |
13 |
import java.util.HashMap; |
14 |
import java.util.Vector; |
15 |
import java.util.zip.ZipEntry; |
16 |
import java.util.zip.ZipFile; |
17 |
|
18 |
import net.oni2.moddepot.model.File; |
19 |
import net.oni2.moddepot.model.Node; |
20 |
import net.oni2.moddepot.model.NodeField_Body; |
21 |
import net.oni2.moddepot.model.NodeField_Upload; |
22 |
import net.oni2.moddepot.model.NodeMod; |
23 |
import net.oni2.moddepot.model.TaxonomyTerm; |
24 |
import net.oni2.moddepot.model.TaxonomyVocabulary; |
25 |
import net.oni2.httpfiledownloader.FileDownloader; |
26 |
|
27 |
import org.apache.http.HttpResponse; |
28 |
import org.apache.http.client.methods.HttpHead; |
29 |
import org.apache.http.client.methods.HttpRequestBase; |
30 |
import org.apache.http.impl.client.DefaultHttpClient; |
31 |
import org.json.JSONArray; |
32 |
import org.json.JSONException; |
33 |
import org.json.JSONObject; |
34 |
|
35 |
import com.thoughtworks.xstream.XStream; |
36 |
import com.thoughtworks.xstream.XStreamException; |
37 |
import com.thoughtworks.xstream.io.xml.StaxDriver; |
38 |
|
39 |
/** |
40 |
* @author Christian Illy |
41 |
*/ |
42 |
public class DepotManager { |
43 |
private static DepotManager instance = null; |
44 |
|
45 |
private HashMap<Integer, TaxonomyVocabulary> taxonomyVocabulary = new HashMap<Integer, TaxonomyVocabulary>(); |
46 |
private HashMap<Integer, TaxonomyTerm> taxonomyTerms = new HashMap<Integer, TaxonomyTerm>(); |
47 |
|
48 |
private HashMap<Integer, Node> nodes = new HashMap<Integer, Node>(); |
49 |
private HashMap<String, HashMap<Integer, Node>> nodesByType = new HashMap<String, HashMap<Integer, Node>>(); |
50 |
|
51 |
private HashMap<Integer, File> files = new HashMap<Integer, File>(); |
52 |
|
53 |
/** |
54 |
* Caching the vocab id for the package type vocabulary |
55 |
*/ |
56 |
public int vocabId_type = -1; |
57 |
/** |
58 |
* Caching the vocab id for the platform vocabulary |
59 |
*/ |
60 |
public int vocabId_platform = -1; |
61 |
/** |
62 |
* Caching the vocab id for the install method vocabulary |
63 |
*/ |
64 |
public int vocabId_instmethod = -1; |
65 |
|
66 |
/** |
67 |
* @return Singleton instance |
68 |
*/ |
69 |
public static DepotManager getInstance() { |
70 |
if (instance == null) |
71 |
instance = new DepotManager(); |
72 |
return instance; |
73 |
} |
74 |
|
75 |
/** |
76 |
* Update local Depot information cache |
77 |
* |
78 |
* @return Update successfully done? |
79 |
*/ |
80 |
public boolean updateInformation() { |
81 |
try { |
82 |
java.io.File zipName = new java.io.File( |
83 |
System.getProperty("java.io.tmpdir"), "aei_jsoncache.zip"); |
84 |
FileDownloader fd = new FileDownloader(DepotConfig.depotUrl |
85 |
+ "jsoncache/jsoncache.zip?ts=" |
86 |
+ (new Date().getTime() / 1000), zipName); |
87 |
fd.start(); |
88 |
while (fd.getState() != FileDownloader.EState.FINISHED) { |
89 |
Thread.sleep(50); |
90 |
} |
91 |
|
92 |
String jsonVocab = null; |
93 |
String jsonTerms = null; |
94 |
String jsonNodes = null; |
95 |
String jsonFiles = null; |
96 |
|
97 |
ZipFile zf = null; |
98 |
try { |
99 |
zf = new ZipFile(zipName); |
100 |
|
101 |
for (Enumeration<? extends ZipEntry> e = zf.entries(); e |
102 |
.hasMoreElements();) { |
103 |
ZipEntry ze = e.nextElement(); |
104 |
if (!ze.isDirectory()) { |
105 |
BufferedReader input = new BufferedReader( |
106 |
new InputStreamReader(zf.getInputStream(ze))); |
107 |
StringBuffer json = new StringBuffer(); |
108 |
|
109 |
char data[] = new char[1024]; |
110 |
int dataRead; |
111 |
while ((dataRead = input.read(data, 0, 1024)) != -1) { |
112 |
json.append(data, 0, dataRead); |
113 |
} |
114 |
|
115 |
if (ze.getName().toLowerCase().contains("vocabulary")) |
116 |
jsonVocab = json.toString(); |
117 |
if (ze.getName().toLowerCase().contains("terms")) |
118 |
jsonTerms = json.toString(); |
119 |
if (ze.getName().toLowerCase().contains("nodes")) |
120 |
jsonNodes = json.toString(); |
121 |
if (ze.getName().toLowerCase().contains("files")) |
122 |
jsonFiles = json.toString(); |
123 |
} |
124 |
} |
125 |
} finally { |
126 |
if (zf != null) |
127 |
zf.close(); |
128 |
zipName.delete(); |
129 |
} |
130 |
|
131 |
initVocabulary(new JSONArray(jsonVocab)); |
132 |
|
133 |
vocabId_type = getVocabulary(DepotConfig.vocabName_ModType) |
134 |
.getVid(); |
135 |
vocabId_platform = getVocabulary(DepotConfig.vocabName_Platform) |
136 |
.getVid(); |
137 |
vocabId_instmethod = getVocabulary( |
138 |
DepotConfig.vocabName_InstallType).getVid(); |
139 |
|
140 |
initTerms(new JSONArray(jsonTerms)); |
141 |
initFiles(new JSONArray(jsonFiles)); |
142 |
initNodes(new JSONArray(jsonNodes)); |
143 |
|
144 |
return true; |
145 |
} catch (JSONException e) { |
146 |
e.printStackTrace(); |
147 |
} catch (IOException e1) { |
148 |
e1.printStackTrace(); |
149 |
} catch (InterruptedException e) { |
150 |
e.printStackTrace(); |
151 |
} |
152 |
return false; |
153 |
} |
154 |
|
155 |
private void initFiles(JSONArray ja) throws JSONException { |
156 |
files = new HashMap<Integer, File>(); |
157 |
JSONObject jo; |
158 |
for (int i = 0; i < ja.length(); i++) { |
159 |
jo = ja.getJSONObject(i); |
160 |
int fid = jo.getInt("fid"); |
161 |
|
162 |
File f = new File(jo); |
163 |
files.put(fid, f); |
164 |
} |
165 |
} |
166 |
|
167 |
private void initNodes(JSONArray ja) throws JSONException { |
168 |
nodes = new HashMap<Integer, Node>(); |
169 |
nodesByType = new HashMap<String, HashMap<Integer, Node>>(); |
170 |
JSONObject jo; |
171 |
for (int i = 0; i < ja.length(); i++) { |
172 |
jo = ja.getJSONObject(i); |
173 |
|
174 |
int nid = jo.getInt("nid"); |
175 |
String type = jo.getString("type"); |
176 |
|
177 |
Node n = null; |
178 |
if (type.equalsIgnoreCase(DepotConfig.nodeType_Package)) |
179 |
n = new NodeMod(jo); |
180 |
else |
181 |
n = new Node(jo); |
182 |
|
183 |
if (n.getStatus() > 0) { |
184 |
nodes.put(nid, n); |
185 |
if (!nodesByType.containsKey(type)) |
186 |
nodesByType.put(type, new HashMap<Integer, Node>()); |
187 |
nodesByType.get(type).put(nid, n); |
188 |
} |
189 |
} |
190 |
} |
191 |
|
192 |
private void initTerms(JSONArray ja) throws JSONException { |
193 |
taxonomyTerms.clear(); |
194 |
JSONObject jo; |
195 |
for (int i = 0; i < ja.length(); i++) { |
196 |
jo = ja.getJSONObject(i); |
197 |
TaxonomyTerm tt = new TaxonomyTerm(jo); |
198 |
taxonomyTerms.put(tt.getTid(), tt); |
199 |
} |
200 |
} |
201 |
|
202 |
private void initVocabulary(JSONArray ja) throws JSONException { |
203 |
taxonomyVocabulary.clear(); |
204 |
JSONObject jo; |
205 |
for (int i = 0; i < ja.length(); i++) { |
206 |
jo = ja.getJSONObject(i); |
207 |
TaxonomyVocabulary tv = new TaxonomyVocabulary(jo); |
208 |
taxonomyVocabulary.put(tv.getVid(), tv); |
209 |
} |
210 |
} |
211 |
|
212 |
/** |
213 |
* @return Can we connect to the Depot? |
214 |
*/ |
215 |
public boolean checkConnection() { |
216 |
HttpRequestBase httpQuery = null; |
217 |
|
218 |
try { |
219 |
DefaultHttpClient httpclient = new DefaultHttpClient(); |
220 |
httpQuery = new HttpHead(DepotConfig.depotUrl); |
221 |
HttpResponse response = httpclient.execute(httpQuery); |
222 |
int code = response.getStatusLine().getStatusCode(); |
223 |
return (code >= 200) && (code <= 299); |
224 |
} catch (UnknownHostException e) { |
225 |
} catch (UnsupportedEncodingException e) { |
226 |
e.printStackTrace(); |
227 |
} catch (IOException e) { |
228 |
e.printStackTrace(); |
229 |
} finally { |
230 |
if (httpQuery != null) |
231 |
httpQuery.releaseConnection(); |
232 |
} |
233 |
return false; |
234 |
} |
235 |
|
236 |
private TaxonomyVocabulary getVocabulary(String name) { |
237 |
for (TaxonomyVocabulary v : taxonomyVocabulary.values()) { |
238 |
if (v.getName().equalsIgnoreCase(name)) |
239 |
return v; |
240 |
} |
241 |
return null; |
242 |
} |
243 |
|
244 |
/** |
245 |
* @param vocabId |
246 |
* Get all taxonomy terms of a given vocabulary |
247 |
* @return TaxTerms |
248 |
*/ |
249 |
private Vector<TaxonomyTerm> getTaxonomyTermsByVocabulary(int vocabId) { |
250 |
Vector<TaxonomyTerm> res = new Vector<TaxonomyTerm>(); |
251 |
for (TaxonomyTerm t : taxonomyTerms.values()) { |
252 |
if (t.getVid() == vocabId) |
253 |
res.add(t); |
254 |
} |
255 |
return res; |
256 |
} |
257 |
|
258 |
/** |
259 |
* @return All defined types |
260 |
*/ |
261 |
public Vector<TaxonomyTerm> getTypes() { |
262 |
return getTaxonomyTermsByVocabulary(vocabId_type); |
263 |
} |
264 |
|
265 |
/** |
266 |
* @param id |
267 |
* Get taxonomy term by given ID |
268 |
* @return TaxTerm |
269 |
*/ |
270 |
public TaxonomyTerm getTaxonomyTerm(int id) { |
271 |
return taxonomyTerms.get(id); |
272 |
} |
273 |
|
274 |
/** |
275 |
* Get all nodes of given node type |
276 |
* |
277 |
* @param nodeType |
278 |
* Node type |
279 |
* @return Nodes of type nodeType |
280 |
*/ |
281 |
public Vector<Node> getNodesByType(String nodeType) { |
282 |
if (nodesByType.get(nodeType) == null) |
283 |
return new Vector<Node>(); |
284 |
return new Vector<Node>(nodesByType.get(nodeType).values()); |
285 |
} |
286 |
|
287 |
/** |
288 |
* @return Mod-Nodes |
289 |
*/ |
290 |
public Vector<NodeMod> getModPackageNodes() { |
291 |
Vector<NodeMod> result = new Vector<NodeMod>(); |
292 |
String instMethName = DepotConfig.taxName_InstallType_Package; |
293 |
|
294 |
Vector<Node> files = getNodesByType(DepotConfig.nodeType_Package); |
295 |
for (Node n : files) { |
296 |
if (n instanceof NodeMod) { |
297 |
NodeMod nm = (NodeMod) n; |
298 |
if (nm.getInstallMethod().equalsIgnoreCase(instMethName)) { |
299 |
if (nm.getPackageNumber() >= 0) |
300 |
result.add(nm); |
301 |
else |
302 |
System.err.println("Node " + nm.getNid() |
303 |
+ " does not have a package number!!!"); |
304 |
} |
305 |
} |
306 |
} |
307 |
return result; |
308 |
} |
309 |
|
310 |
/** |
311 |
* @param id |
312 |
* ID of file to get |
313 |
* @return the file |
314 |
*/ |
315 |
public File getFile(int id) { |
316 |
return files.get(id); |
317 |
} |
318 |
|
319 |
private static XStream getXStream() { |
320 |
XStream xs = new XStream(new StaxDriver()); |
321 |
xs.alias("Depot", DepotManager.class); |
322 |
xs.alias("File", net.oni2.moddepot.model.File.class); |
323 |
xs.alias("Node", Node.class); |
324 |
xs.alias("NodeField_Body", NodeField_Body.class); |
325 |
xs.alias("NodeField_Upload", NodeField_Upload.class); |
326 |
xs.alias("NodeMod", NodeMod.class); |
327 |
xs.alias("TaxonomyTerm", TaxonomyTerm.class); |
328 |
xs.alias("TaxonomyVocabulary", TaxonomyVocabulary.class); |
329 |
return xs; |
330 |
} |
331 |
|
332 |
/** |
333 |
* Save Depot cache instance to file |
334 |
* |
335 |
* @param cacheFile |
336 |
* File to save to |
337 |
*/ |
338 |
public void saveToCacheFile(java.io.File cacheFile) { |
339 |
try { |
340 |
FileOutputStream fos = new FileOutputStream(cacheFile); |
341 |
XStream xs = getXStream(); |
342 |
xs.toXML(this, fos); |
343 |
fos.close(); |
344 |
} catch (FileNotFoundException e) { |
345 |
e.printStackTrace(); |
346 |
} catch (IOException e) { |
347 |
e.printStackTrace(); |
348 |
} |
349 |
} |
350 |
|
351 |
/** |
352 |
* Load cache from file |
353 |
* |
354 |
* @param cacheFile |
355 |
* File to load |
356 |
*/ |
357 |
public static void loadFromCacheFile(java.io.File cacheFile) { |
358 |
try { |
359 |
FileInputStream fis = new FileInputStream(cacheFile); |
360 |
XStream xs = getXStream(); |
361 |
Object obj = xs.fromXML(fis); |
362 |
fis.close(); |
363 |
if (obj instanceof DepotManager) |
364 |
instance = (DepotManager) obj; |
365 |
} catch (XStreamException e) { |
366 |
} catch (FileNotFoundException e) { |
367 |
} catch (IOException e) { |
368 |
} |
369 |
} |
370 |
} |