aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/gnunet/construct/MessageLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/gnunet/construct/MessageLoader.java')
-rw-r--r--src/main/java/org/gnunet/construct/MessageLoader.java215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/main/java/org/gnunet/construct/MessageLoader.java b/src/main/java/org/gnunet/construct/MessageLoader.java
new file mode 100644
index 0000000..71e2719
--- /dev/null
+++ b/src/main/java/org/gnunet/construct/MessageLoader.java
@@ -0,0 +1,215 @@
1/*
2 *
3 * This file is part of GNUnet.
4 * (C) 2011 Christian Grothoff (and other contributing authors)
5 *
6 * GNUnet is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your
9 * option) any later version.
10 *
11 * GNUnet is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNUnet; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 *
21 */
22
23package org.gnunet.construct;
24
25
26import com.google.common.base.Charsets;
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
30import java.io.BufferedReader;
31import java.io.Closeable;
32import java.io.IOException;
33import java.io.InputStreamReader;
34import java.net.URL;
35import java.util.Enumeration;
36import java.util.HashMap;
37import java.util.Map;
38
39
40/**
41 * Load message maps, which contain the information the parse/write unions.
42 */
43public class MessageLoader {
44 private static final Logger logger = LoggerFactory
45 .getLogger(MessageLoader.class);
46
47
48 /**
49 * Thrown when a trying to serialize an object that is not registered as a union type.
50 */
51 public static class UnknownUnionException extends RuntimeException {
52 public UnknownUnionException(String msg) {
53 super(msg);
54 }
55 }
56
57
58 /**
59 * Thrown when parsing a union whose ID is not known.
60 */
61 public static class UnknownUnionIdException extends RuntimeException {
62
63 }
64
65 /**
66 * Maps a class and tag to the corresponding union case.
67 * <p/>
68 * XXX: how much of generics is too much?
69 */
70 private static Map<Class<? extends MessageUnion>, Map<Integer, Class<? extends MessageUnion>>> unionmap
71 = new HashMap<Class<? extends MessageUnion>, Map<Integer, Class<? extends MessageUnion>>>(100);
72
73 /*
74 * Maps a union interface and union case to the corresponding tag.
75 */
76 private static Map<Class<? extends MessageUnion>, Map<Class<? extends MessageUnion>, Integer>> tagmap
77 = new HashMap<Class<? extends MessageUnion>, Map<Class<? extends MessageUnion>, Integer>>(100);
78
79
80 static {
81 ClassLoader classLoader = MessageLoader.class.getClassLoader();
82 Enumeration<URL> resources;
83 try {
84 resources = classLoader.getResources("org/gnunet/construct/MsgMap.txt");
85 } catch (IOException e) {
86 throw new RuntimeException("something went wrong with loading MsgMap.txt");
87 }
88
89 while (resources.hasMoreElements()) {
90 loadMessageMap(resources.nextElement());
91 }
92
93 if (tagmap.isEmpty()) {
94 logger.warn("message map empty");
95 }
96
97 }
98
99 public static void loadMessageMap(URL loc) {
100 if (loc == null) {
101 throw new RuntimeException("could not load message map");
102 }
103 BufferedReader in = null;
104 try {
105 in = new BufferedReader(new InputStreamReader(loc.openStream(), Charsets.UTF_8));
106 String line;
107 while ((line = in.readLine()) != null) {
108 // skip empty lines and comments
109 if (line.isEmpty() || line.charAt(0) == '#') {
110 continue;
111 }
112 String[] m = line.split("=");
113 if (m.length != 2) {
114 throw new RuntimeException("invalid message map format (separation by '=')");
115 }
116 String[] left = m[0].split("[|]");
117 if (left.length != 2) {
118 logger.debug(m[0]);
119 logger.debug(m[1]);
120 logger.debug("split in " + left.length);
121 throw new RuntimeException("invalid message map format (left hand side)");
122 }
123 int id = java.lang.Integer.parseInt(left[1].trim());
124 String unionCaseName = m[1].trim();
125 String unionInterfaceName = left[0];
126
127 Class<? extends MessageUnion> unionInterface = loadClass(unionInterfaceName);
128 Class<? extends MessageUnion> unionCase = loadClass(unionCaseName);
129
130 if (!unionmap.containsKey(unionInterface)) {
131 unionmap.put(unionInterface, new HashMap<Integer, Class<? extends MessageUnion>>(5));
132 }
133 unionmap.get(unionInterface).put(id, unionCase);
134
135
136 if (!tagmap.containsKey(unionInterface)) {
137 tagmap.put(unionInterface, new HashMap<Class<? extends MessageUnion>, Integer>(5));
138 }
139 tagmap.get(unionInterface).put(unionCase, id);
140
141 }
142 } catch (IOException e) {
143 throw new RuntimeException("could not read message map");
144 } finally {
145 maybeClose(in);
146 }
147 }
148
149 private static void maybeClose(Closeable in) {
150 try {
151 if (in != null) {
152 in.close();
153 }
154 } catch (IOException e) {
155 throw new RuntimeException("error closing stream: " + e.getMessage());
156 }
157 }
158
159
160 @SuppressWarnings("unchecked")
161 private static Class<? extends MessageUnion> loadClass(String className) {
162 ClassLoader cl = Thread.currentThread().getContextClassLoader();
163 Class<MessageUnion> msgClass;
164 try {
165 msgClass = (Class<MessageUnion>) cl.loadClass(className);
166 } catch (ClassNotFoundException e) {
167 throw new AssertionError(String.format("message class '%s' not found in classpath", className));
168 } catch (ClassCastException e) {
169 throw new AssertionError(String.format("Class %s does not inherit from MessageUnion", className));
170 }
171 return msgClass;
172 }
173
174 public static Class<? extends MessageUnion> getUnionClass(Class<? extends MessageUnion> unionInterface, int tag) {
175 Map<Integer, Class<? extends MessageUnion>> map = unionmap.get(unionInterface);
176 if (map == null) {
177 throw new UnknownUnionException("don't know how to handle unions of type '" + unionInterface + "'");
178 }
179
180 Class<? extends MessageUnion> cls = map.get(tag);
181 if (cls == null) {
182 throw new ProtocolViolationException("don't know how to translate message of type " + tag);
183 }
184
185 return cls;
186 }
187
188
189 public static int getUnionTag(Class<? extends MessageUnion> unionInterface, Class<? extends MessageUnion> unionCase) {
190 Map<Class<? extends MessageUnion>, Integer> map = tagmap.get(unionInterface);
191 if (map == null) {
192 throw new AssertionError(String.format("%s is not a known union type", unionInterface));
193 }
194 if (!map.containsKey(unionCase)) {
195 throw new AssertionError(String.format("%s is not a known instance of %s", unionCase, unionInterface));
196 }
197 return map.get(unionCase);
198 }
199
200 public static void registerUnionCase(Class<? extends MessageUnion> unionInterface,
201 Class<? extends MessageUnion> unionCase, int tag) {
202 if (!unionmap.containsKey(unionInterface)) {
203 unionmap.put(unionInterface, new HashMap<Integer, Class<? extends MessageUnion>>(5));
204 }
205 unionmap.get(unionInterface).put(tag, unionCase);
206
207
208 if (!tagmap.containsKey(unionInterface)) {
209 tagmap.put(unionInterface, new HashMap<Class<? extends MessageUnion>, Integer>(5));
210 }
211 tagmap.get(unionInterface).put(unionCase, tag);
212
213
214 }
215}