001 package com.skype.ipc;
002
003 import java.io.IOException;
004 import java.util.ArrayList;
005 import java.util.Arrays;
006
007 public abstract class SidObject implements SidGetResponding {
008 protected SidObject(final Integer oid, final SidRoot session, final int numProps) {
009 mSidOid = oid;
010 mSidRoot = session;
011 mSidTimestamp = session.mSidTimestamp;
012 }
013
014 protected void finalize() {
015 if (mSidRoot.mSidTimestamp == mSidTimestamp)
016 mSidRoot.sidRemove(mSidOid);
017 }
018
019 // SidGetResponding interface
020 public SidObject sidGetObject() { return this; }
021 public boolean sidGetBoolProperty(final PropertyEnumConverting property) { return false; }
022 public String sidGetStringProperty(final PropertyEnumConverting property) { return ""; }
023 public String sidGetXmlProperty(final PropertyEnumConverting property) { return sidGetStringProperty(property); }
024 public String sidGetFilenameProperty(final PropertyEnumConverting property) { return sidGetStringProperty(property); }
025 public int sidGetIntProperty(final PropertyEnumConverting property) { return 0; }
026 public int sidGetUintProperty(final PropertyEnumConverting property) { return sidGetIntProperty(property); }
027 public long sidGetLongProperty(final PropertyEnumConverting property) { return 0; }
028 public SidObject sidGetObjectProperty(final PropertyEnumConverting property) { return null; }
029 public EnumConverting sidGetEnumProperty(final PropertyEnumConverting property) { return null; }
030 public byte[] sidGetBinaryProperty(final PropertyEnumConverting property) { return null; }
031
032 public void sidSetProperty(final PropertyEnumConverting property, final SidObject value) { }
033 public void sidSetProperty(final PropertyEnumConverting property, final int value) { }
034 public void sidSetProperty(final PropertyEnumConverting property, final String value) { }
035 public void sidSetProperty(final PropertyEnumConverting property, final byte[] value) { }
036 public void sidSetProperty(final PropertyEnumConverting property, final long value) { }
037 // end SidGetResponding interface
038
039 protected SidObject sidRequestObjectProperty(final PropertyEnumConverting property) {
040 // int expected = 1;
041 SidObject value = null;
042 try {
043 int oid = 0;
044 Decoding decoder = mSidRoot.sidDoGetRequest(property.getRequest(), mSidOid);
045 while (decoder.hasNextProperty(true)) {
046 PropertyInfo info = decoder.getNextProperty();
047 int kind = info.kind;
048 // assert ( expected-- > 0
049 // && info.moduleId == moduleId()
050 // && info.propertyId == property.getId()
051 // && info.objectId == mSidOid
052 // && (kind == 'N' || kind == 'O')
053 // );
054 if (kind != 'N') {
055 oid = decoder.decodeUint();
056 }
057 }
058 if (oid != 0) {
059 value = mSidRoot.sidGetObject(property.getModuleId(), oid);
060 }
061 if (property.isCached()) {
062 sidSetProperty(property, value); // synchronized
063 }
064 } catch (IOException e) {
065 mSidRoot.sidOnFatalError(e);
066 }
067 return value;
068 }
069 protected String sidRequestStringProperty(final PropertyEnumConverting property) {
070 String value = "";
071 // int expected = 1;
072 try {
073 Decoding decoder = mSidRoot.sidDoGetRequest(property.getRequest(), mSidOid);
074 while (decoder.hasNextProperty(true)) {
075 PropertyInfo info = decoder.getNextProperty();
076 int kind = info.kind;
077 // assert ( expected-- > 0
078 // && info.moduleId == moduleId()
079 // && info.propertyId == property.getId()
080 // && info.objectId == mSidOid
081 // && (kind == 'N' || kind == 'S' || kind == 'f' || kind == 'X')
082 // );
083 if (kind != 'N') {
084 value = decoder.decodeString();
085 }
086 }
087 if (property.isCached()) {
088 sidSetProperty(property, value); // synchronized
089 }
090 } catch (IOException e) {
091 mSidRoot.sidOnFatalError(e);
092 }
093 return value;
094 }
095 protected byte[] sidRequestBinaryProperty(final PropertyEnumConverting property) {
096 byte[] value = null;
097 try {
098 Decoding decoder = mSidRoot.sidDoGetRequest(property.getRequest(), mSidOid);
099 // int expected = 1;
100 while (decoder.hasNextProperty(true)) {
101 PropertyInfo info = decoder.getNextProperty();
102 int kind = info.kind;
103 // assert ( expected-- > 0
104 // && info.moduleId == moduleId()
105 // && info.propertyId == property.getId()
106 // && info.objectId == mSidOid
107 // && (kind == 'N' || kind == 'B')
108 // );
109 if (kind != 'N') {
110 value = decoder.decodeBinary();
111 }
112 }
113 if (property.isCached()) {
114 sidSetProperty(property, value); // synchronized
115 }
116 } catch (IOException e) {
117 mSidRoot.sidOnFatalError(e);
118 }
119 return value;
120 }
121 protected int sidRequestIntProperty(final PropertyEnumConverting property) {
122 return sidRequestProperty(property);
123 }
124 protected int sidRequestUintProperty(final PropertyEnumConverting property) {
125 return sidRequestProperty(property);
126 }
127 protected int sidRequestProperty(final PropertyEnumConverting property) {
128 // int expected = 1;
129 int value = 0;
130 try {
131 Decoding decoder = mSidRoot.sidDoGetRequest(property.getRequest(), mSidOid);
132 while (decoder.hasNextProperty(true)) {
133 PropertyInfo info = decoder.getNextProperty();
134 int kind = info.kind;
135 // assert ( expected-- > 0
136 // && info.moduleId == moduleId()
137 // && info.propertyId == property.getId()
138 // && info.objectId == mSidOid
139 // && (kind == 'N' || kind == 'T' || kind == 'F' || kind == 'u' || kind == 'i' || kind == 'e')
140 // );
141 switch (kind) {
142 case 'i':
143 value = decoder.decodeInt();
144 break;
145 case 'u': case 'e':
146 value = decoder.decodeUint();
147 break;
148 case 'T':
149 value = 1;
150 break;
151 }
152 }
153 if (property.isCached()) {
154 sidSetProperty(property, value); // synchronized
155 }
156 } catch (IOException e) {
157 mSidRoot.sidOnFatalError(e);
158 }
159 return value;
160 }
161 protected boolean sidRequestBoolProperty(final PropertyEnumConverting property) {
162 return sidRequestProperty(property) != 0;
163 }
164 protected EnumConverting sidRequestEnumProperty(final PropertyEnumConverting property) {
165 EnumConverting converter = property.getEnumConverter();
166 return converter.convert(sidRequestProperty(property));
167 }
168 protected String sidRequestXmlProperty(final PropertyEnumConverting property) {
169 return sidRequestStringProperty(property);
170 }
171 protected String sidRequestFilenameProperty(final PropertyEnumConverting property) {
172 return sidRequestStringProperty(property);
173 }
174 abstract protected void sidOnChangedProperty(final int propertyId, final int value, final String svalue);
175 abstract public int moduleId();
176 public int getOid() {
177 return mSidOid;
178 }
179 protected Encoding sidDoRequest(final byte[] header) throws IOException {
180 return mSidRoot.sidDoRequest(header, mSidOid);
181 }
182
183 public static SidGetResponding[] sidMultiGet(final PropertyEnumConverting[] properties, final SidObject[] objects) {
184 // normally would like to write
185 // SidGetResponding[] response = objects;
186 // which works as expected with regular java but dalvik VM raises a VerifyError...
187 SidGetResponding[] response = new SidGetResponding[objects.length];
188 boolean allCached = true;
189 for (PropertyEnumConverting p : properties) {
190 if (!p.isCached()) {
191 allCached = false;
192 response = new GenericGetResponse[objects.length];
193 for (int i = 0, e = objects.length; i < e; i++) {
194 response[i] = new GenericGetResponse(objects[i]);
195 }
196 break;
197 }
198 }
199 if (allCached) {
200 for (int i = 0, e = objects.length; i < e; i++) {
201 response[i] = objects[i];
202 }
203 }
204 return sidMultiGet(properties, objects, response);
205 }
206
207 /***
208 * invalidateCache: the next time the property is get, it will be querried to the runtime, meanwhile it can be discarded.
209 * This allows fine grained cache management. Note that this doesn't delete the property, you still have to set it to null
210 * to get a chance having this behavior. The rationale if that the generated properties being public, you can directly assign it to null
211 * whilst a generated invalidateCache would require switching on the values to do so.
212 * C o; o.invalidate(C.Property.P_MY_PROP); o.mMyProp = null;
213 * @param property the property to be invalidated
214 */
215 public void invalidateCache(final PropertyEnumConverting property) {
216 int idx = property.getIdx();
217 if (idx-- > 0) {
218 mSidCached&=~(1<<(idx%32));
219 }
220 }
221
222 protected boolean isCached(final PropertyEnumConverting property) {
223 int idx = property.getIdx();
224 if (idx-- > 0) {
225 return (mSidCached&(1<<(idx%32))) != 0;
226 }
227 return false;
228 }
229
230 protected boolean hasCached() {
231 return mSidCached != 0;
232 }
233
234 private PropertyInfo sidDecodeMultiGet(PropertyInfo info, final PropertyEnumConverting converter, final SidGetResponding response, final Decoding decoder) throws IOException {
235 synchronized(this) {
236 do {
237 int kind = info.kind;
238 PropertyEnumConverting property = (PropertyEnumConverting) converter.convert(info.propertyId);
239 switch (kind) {
240 case 'i': response.sidSetProperty(property, decoder.decodeInt()); break;
241 case 'u': case 'e': response.sidSetProperty(property, decoder.decodeUint()); break;
242 case 'O': response.sidSetProperty(property, decoder.decodeUint()); break;
243 case 'F': response.sidSetProperty(property, 0); break;
244 case 'T': response.sidSetProperty(property, 1); break;
245 case 'X': case 'S': case 'f': response.sidSetProperty(property, decoder.decodeString()); break;
246 case 'B': response.sidSetProperty(property, decoder.decodeBinary()); break;
247 }
248 if (!decoder.hasNextProperty(true))
249 return null;
250 info = decoder.getNextProperty();
251 } while (info.objectId == mSidOid); // shall add moduleId comparison as soon as objectId definition changes
252 }
253 return info;
254 }
255
256 protected SidGetResponding sidMultiGet(PropertyEnumConverting[] requested) {
257 SidGetResponding response = this;
258 for (PropertyEnumConverting p : requested) {
259 if (!p.isCached()) {
260 response = new GenericGetResponse(this);
261 break;
262 }
263 }
264 return sidMultiGet(requested, response);
265 }
266
267 protected SidGetResponding sidMultiGet(PropertyEnumConverting[] requested, SidGetResponding response) {
268 PropertyEnumConverting[] to_be_querried = sidComputeToBeQuerried(requested);
269 if (to_be_querried != null) {
270 try {
271 Decoding decoder = mSidRoot.sidBeginMultiGet(to_be_querried, moduleId(), mSidOid).endMultiGet();
272 if (decoder.hasNextProperty(true)) { // shall always be true...
273 PropertyEnumConverting converter = to_be_querried[0];
274 sidDecodeMultiGet(decoder.getNextProperty(), converter, response, decoder);
275 }
276 } catch (IOException e) {
277 mSidRoot.sidOnFatalError(e);
278 }
279 }
280 return response;
281 }
282
283 private PropertyEnumConverting[] sidComputeToBeQuerried(PropertyEnumConverting[] requested) {
284 PropertyEnumConverting[] to_be_querried = null;
285 if (hasCached()) {
286 ArrayList<PropertyEnumConverting> missed = null;
287 for (PropertyEnumConverting p : requested) {
288 if (!isCached(p)) {
289 if (missed == null)
290 missed = new ArrayList<PropertyEnumConverting>(requested.length);
291 missed.add(p);
292 }
293 }
294 if (missed != null) {
295 to_be_querried = missed.size() == requested.length ? requested : missed.toArray(new PropertyEnumConverting[missed.size()]);
296 }
297 } else {
298 to_be_querried = requested;
299 }
300 return to_be_querried;
301 }
302
303 protected static SidGetResponding[] sidMultiGet(PropertyEnumConverting[] requested, SidObject[] objects, SidGetResponding[] response) {
304 if (objects.length == 0 || requested.length == 0) return response;
305 PropertyEnumConverting[] previous_to_be_querried = null;
306 PropertyEnumConverting converter = requested[0];
307 Encoding encoder = null;
308 SidRoot root = objects[0].mSidRoot;
309 for (SidObject o : objects) {
310 PropertyEnumConverting[] to_be_querried = o.sidComputeToBeQuerried(requested);
311 if (to_be_querried != null) {
312 try {
313 if (previous_to_be_querried == null) {
314 encoder = root.sidBeginMultiGet(to_be_querried, o.moduleId(), o.getOid());
315 } else if (Arrays.equals(previous_to_be_querried, to_be_querried)) {
316 encoder.addMultiGet(o.getOid());
317 continue;
318 } else {
319 encoder.addMultiGet(to_be_querried, o.moduleId(), o.getOid());
320 }
321 } catch (IOException e) {
322 root.sidOnFatalError(e);
323 }
324 previous_to_be_querried = to_be_querried;
325 }
326 }
327 if (encoder != null) {
328 try {
329 Decoding decoder = encoder.endMultiGet();
330 int r = 0;
331 if (decoder.hasNextProperty(true)) { // shall always be true...
332 PropertyInfo info = decoder.getNextProperty();
333 do {
334 SidObject o = response[r].sidGetObject();
335 while (o.getOid() != info.objectId) {
336 o = response[++r].sidGetObject(); // some responses may already be processed.
337 }
338 info = o.sidDecodeMultiGet(info, converter, response[r++], decoder);
339 } while (info != null);
340 }
341 } catch (IOException e) { // catch NullPointerException?
342 root.sidOnFatalError(e);
343 }
344 }
345 return response;
346 }
347
348 protected int mSidCached;
349 protected int mSidOid;
350 protected SidRoot mSidRoot;
351 protected int mSidTimestamp;
352 };
353