1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.rpc;
17
18 import java.util.List;
19
20 import fulmine.model.field.FieldUtils;
21 import fulmine.model.field.IField;
22 import fulmine.protocol.specification.ByteReader;
23 import fulmine.protocol.specification.ByteWriter;
24 import fulmine.util.Utils;
25 import fulmine.util.collection.CollectionFactory;
26 import fulmine.util.reference.QuadValue;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class RpcCodec implements IRpcCodec
47 {
48
49
50
51
52
53
54 static final String FIELD_NAME = "field#";
55
56
57 private static final String DELIMITER = "|";
58
59
60 final static String DELIMITER_ESCAPE_CODE = "&|";
61
62
63 private enum EncodingKeys
64 {
65 MARKER, RPC_KEY, REMOTE_CONTEXT, ARGS
66 }
67
68
69 private final IRpcRegistry registry;
70
71
72
73
74
75 private String[] rpcTokens;
76
77
78
79
80
81 private final static int META_PART_COUNT = 3;
82
83
84
85
86
87
88
89 public RpcCodec(IRpcRegistry registry)
90 {
91 super();
92 this.registry = registry;
93 }
94
95 public QuadValue<IRpcMarker, String, String, IField[]> decode(byte[] rpcData)
96 {
97 String data = ByteReader.fromBytes(rpcData);
98 final String[] tokens = getTokens(data);
99 IRpcMarker marker =
100 new RpcMarker(
101 Integer.parseInt(tokens[EncodingKeys.MARKER.ordinal()]));
102 String remoteContextIdentity =
103 tokens[EncodingKeys.REMOTE_CONTEXT.ordinal()];
104 final String rpcKey = tokens[EncodingKeys.RPC_KEY.ordinal()];
105 IRpcDefinition definition = getRegistry().getDefinition(rpcKey);
106 if (definition == null)
107 {
108 throw new IllegalArgumentException(
109 "No RPC definition, cannot decode '" + data + "', registry is "
110 + getRegistry());
111 }
112 final Class<? extends IField>[] argumentTypes =
113 definition.getArgumentTypes();
114
115 if (argumentTypes.length + META_PART_COUNT != tokens.length)
116 {
117 throw new IllegalArgumentException(
118 "Invalid argument count, expected " + argumentTypes.length
119 + " but got " + (tokens.length - META_PART_COUNT)
120 + ", cannot decode '" + data + "'");
121 }
122 int length = tokens.length - META_PART_COUNT;
123 List<IField> argValues = CollectionFactory.newList(length);
124 for (int j = 0; j < length; j++)
125 {
126 Class<? extends IField> argType = argumentTypes[j];
127 final String fieldValue = tokens[j + META_PART_COUNT];
128
129 decodeSpecialChars(fieldValue);
130 argValues.add(FieldUtils.createFromString(argType, FIELD_NAME + j,
131 fieldValue));
132 }
133 return new QuadValue<IRpcMarker, String, String, IField[]>(marker,
134 rpcKey, remoteContextIdentity,
135 argValues.toArray(new IField[argValues.size()]));
136 }
137
138 public byte[] encode(IRpcMarker rpcMarker, String rpcKey,
139 String contextIdentity, IField[] args)
140 {
141 StringBuilder sb = new StringBuilder();
142 sb.append(rpcMarker.getId());
143 sb.append(DELIMITER);
144 sb.append(rpcKey);
145 sb.append(DELIMITER);
146 sb.append(contextIdentity);
147 for (IField field : args)
148 {
149 sb.append(DELIMITER);
150 sb.append(encodeSpecialChars(field.getValueAsString()));
151 }
152 return ByteWriter.getBytes(sb.toString());
153 }
154
155
156
157
158
159
160
161 public String getRpcKey()
162 {
163 Utils.nullCheck(this.rpcTokens, "no RPC tokens");
164 return this.rpcTokens[EncodingKeys.RPC_KEY.ordinal()];
165 }
166
167
168
169
170
171
172
173 public String[] getArgs()
174 {
175 Utils.nullCheck(this.rpcTokens, "no RPC tokens");
176 final int length = this.rpcTokens.length - META_PART_COUNT;
177 String[] args = new String[length];
178 if (length > 0)
179 {
180
181
182 System.arraycopy(this.rpcTokens, META_PART_COUNT, args, 0,
183 args.length);
184 }
185 return args;
186 }
187
188
189
190
191
192
193
194
195 public void setData(byte[] rpcData)
196 {
197 this.rpcTokens = getTokens(ByteReader.fromBytes(rpcData));
198 }
199
200
201
202
203
204
205
206
207 private String[] getTokens(String data)
208 {
209 final String[] tokens = data.split("\\" + DELIMITER);
210 return tokens;
211 }
212
213 private IRpcRegistry getRegistry()
214 {
215 return this.registry;
216 }
217
218 String decodeSpecialChars(final String value)
219 {
220 return value.replaceAll(DELIMITER_ESCAPE_CODE, DELIMITER);
221 }
222
223 String encodeSpecialChars(final String value)
224 {
225 return value.replaceAll("\\|", DELIMITER_ESCAPE_CODE);
226 }
227
228 }