    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