void PropertySyncer::handleMessage(const GammaRay::Message& msg)
{
    Q_ASSERT(msg.address() == m_address);
    switch (msg.type()) {
        case Protocol::PropertySyncRequest:
        {
            Protocol::ObjectAddress addr;
            msg.payload() >> addr;
            Q_ASSERT(addr != Protocol::InvalidObjectAddress);

            const auto it = std::find_if(m_objects.constBegin(), m_objects.constEnd(), [addr](const ObjectInfo &info) {
                return info.addr == addr;
            });
            if (it == m_objects.constEnd())
                break;

            QVector<QPair<QByteArray, QVariant> > values;
            const auto propCount = (*it).obj->metaObject()->propertyCount();
            values.reserve(propCount);
            for (int i = qobjectPropertyOffset(); i < propCount; ++i) {
                const auto prop = (*it).obj->metaObject()->property(i);
                values.push_back(qMakePair(QByteArray(prop.name()), prop.read((*it).obj)));
            }
            Q_ASSERT(!values.isEmpty());

            Message msg(m_address, Protocol::PropertyValuesChanged);
            msg.payload() << addr << (quint32)values.size();
            foreach (const auto &value, values)
                msg.payload() << value.first << value.second;
            emit message(msg);
            break;
        }
        case Protocol::PropertyValuesChanged:
        {
            Protocol::ObjectAddress addr;
            quint32 changeSize;
            msg.payload() >> addr >> changeSize;
            Q_ASSERT(addr != Protocol::InvalidObjectAddress);
            Q_ASSERT(changeSize > 0);

            auto it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) {
                return info.addr == addr;
            });
            if (it == m_objects.end())
                break;

            for (quint32 i = 0; i < changeSize; ++i) {
                QByteArray propName;
                QVariant propValue;
                msg.payload() >> propName >> propValue;
                (*it).recursionLock = true;
                (*it).obj->setProperty(propName, propValue);

                // it can be invalid if as a result of the above call new objects have been registered for example
                it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) {
                    return info.addr == addr;
                });
                Q_ASSERT(it != m_objects.end());
                (*it).recursionLock = false;
            }
            break;
        }
        default:
            Q_ASSERT(!"We should not get here!");
    }
}