org.waveprotocol.box.server.persistence.mongodb.MongoDbStoreUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.waveprotocol.box.server.persistence.mongodb.MongoDbStoreUtil.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.waveprotocol.box.server.persistence.mongodb;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

import org.waveprotocol.box.server.serialize.OperationSerializer;
import org.waveprotocol.box.server.persistence.PersistenceException;
import org.waveprotocol.box.server.persistence.deltas.WaveletDeltaRecord;
import org.waveprotocol.box.server.persistence.protos.ProtoDeltaStoreDataSerializer;
import org.waveprotocol.box.server.waveserver.ByteStringMessage;
import org.waveprotocol.wave.federation.Proto.ProtocolDocumentOperation;
import org.waveprotocol.wave.model.document.operation.DocOp;
import org.waveprotocol.wave.model.operation.wave.AddParticipant;
import org.waveprotocol.wave.model.operation.wave.BlipContentOperation;
import org.waveprotocol.wave.model.operation.wave.BlipOperation;
import org.waveprotocol.wave.model.operation.wave.NoOp;
import org.waveprotocol.wave.model.operation.wave.RemoveParticipant;
import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation;
import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
import org.waveprotocol.wave.model.operation.wave.WaveletOperationContext;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.wave.ParticipantId;

/**
 * A utility class to serialize/deserialize delta objects to/from MongoDB. The
 * implementation approach is analog to the provided at
 * {@link OperationSerializer} and
 * {@link ProtoDeltaStoreDataSerializer}
 *
 * @author pablojan@gmail.com (Pablo Ojanguren)
 *
 * See release in Apache Wiab.
 */
public class MongoDbStoreUtil {
    public static final String WAVELET_OP_WAVELET_BLIP_OPERATION = "WaveletBlipOperation";
    public static final String WAVELET_OP_REMOVE_PARTICIPANT = "RemoveParticipant";
    public static final String WAVELET_OP_ADD_PARTICIPANT = "AddParticipant";
    public static final String WAVELET_OP_NOOP = "NoOp";
    public static final String FIELD_BYTES = "bytes";
    public static final String FIELD_CONTENTOP = "contentop";
    public static final String FIELD_BLIPOP = "blipop";
    public static final String FIELD_BLIPID = "blipid";
    public static final String FIELD_PARTICIPANT = "participant";
    public static final String FIELD_TYPE = "type";
    public static final String FIELD_OPS = "ops";
    public static final String FIELD_APPLICATIONTIMESTAMP = "applicationtimestamp";
    public static final String FIELD_AUTHOR = "author";
    public static final String FIELD_ADDRESS = "address";
    public static final String FIELD_HISTORYHASH = "historyhash";
    public static final String FIELD_VERSION = "version";
    public static final String FIELD_TRANSFORMED_RESULTINGVERSION_VERSION = "transformed.resultingversion.version";
    public static final String FIELD_TRANSFORMED_APPLIEDATVERSION = "transformed.appliedatversion";
    public static final String FIELD_TRANSFORMED_RESULTINGVERSION = "transformed.resultingversion";
    public static final String FIELD_APPLIEDATVERSION = "appliedatversion";
    public static final String FIELD_RESULTINGVERSION = "resultingversion";
    public static final String FIELD_TRANSFORMED = "transformed";
    public static final String FIELD_APPLIED = "applied";
    public static final String FIELD_WAVELET_ID = "waveletid";
    public static final String FIELD_WAVE_ID = "waveid";

    public static DBObject serialize(WaveletDeltaRecord waveletDelta, String waveId, String waveletId) {

        BasicDBObject mongoWaveletDelta = new BasicDBObject();

        mongoWaveletDelta.append(FIELD_WAVE_ID, waveId);
        mongoWaveletDelta.append(FIELD_WAVELET_ID, waveletId);

        mongoWaveletDelta.append(FIELD_APPLIEDATVERSION, serialize(waveletDelta.getAppliedAtVersion()));
        mongoWaveletDelta.append(FIELD_APPLIED, waveletDelta.getAppliedDelta().getByteArray());
        mongoWaveletDelta.append(FIELD_TRANSFORMED, serialize(waveletDelta.getTransformedDelta()));

        return mongoWaveletDelta;
    }

    public static DBObject serialize(HashedVersion hashedVersion) {
        BasicDBObject mongoHashedVersion = new BasicDBObject();
        mongoHashedVersion.append(FIELD_VERSION, hashedVersion.getVersion());
        mongoHashedVersion.append(FIELD_HISTORYHASH, hashedVersion.getHistoryHash());
        return mongoHashedVersion;
    }

    public static DBObject serialize(ParticipantId participantId) {
        BasicDBObject mongoParticipantId = new BasicDBObject();
        mongoParticipantId.append(FIELD_ADDRESS, participantId.getAddress());
        return mongoParticipantId;
    }

    public static DBObject serialize(TransformedWaveletDelta transformedWaveletDelta) {
        BasicDBObject mongoTransformedWaveletDelta = new BasicDBObject();
        mongoTransformedWaveletDelta.append(FIELD_AUTHOR, serialize(transformedWaveletDelta.getAuthor()));
        mongoTransformedWaveletDelta.append(FIELD_RESULTINGVERSION,
                serialize(transformedWaveletDelta.getResultingVersion()));
        mongoTransformedWaveletDelta.append(FIELD_APPLICATIONTIMESTAMP,
                transformedWaveletDelta.getApplicationTimestamp());

        mongoTransformedWaveletDelta.append(FIELD_APPLIEDATVERSION, transformedWaveletDelta.getAppliedAtVersion());

        BasicDBList mongoWaveletOperations = new BasicDBList();

        for (WaveletOperation op : transformedWaveletDelta) {
            mongoWaveletOperations.add(serialize(op));
        }

        mongoTransformedWaveletDelta.append(FIELD_OPS, mongoWaveletOperations);

        return mongoTransformedWaveletDelta;
    }

    public static DBObject serialize(WaveletOperation waveletOp) {
        final BasicDBObject mongoOp = new BasicDBObject();

        if (waveletOp instanceof NoOp) {
            mongoOp.append(FIELD_TYPE, WAVELET_OP_NOOP);

        } else if (waveletOp instanceof AddParticipant) {
            mongoOp.append(FIELD_TYPE, WAVELET_OP_ADD_PARTICIPANT);
            mongoOp.append(FIELD_PARTICIPANT, serialize(((AddParticipant) waveletOp).getParticipantId()));

        } else if (waveletOp instanceof RemoveParticipant) {
            mongoOp.append(FIELD_TYPE, WAVELET_OP_REMOVE_PARTICIPANT);
            mongoOp.append(FIELD_PARTICIPANT, serialize(((RemoveParticipant) waveletOp).getParticipantId()));
        } else if (waveletOp instanceof WaveletBlipOperation) {
            final WaveletBlipOperation waveletBlipOp = (WaveletBlipOperation) waveletOp;

            mongoOp.append(FIELD_TYPE, WAVELET_OP_WAVELET_BLIP_OPERATION);
            mongoOp.append(FIELD_BLIPID, waveletBlipOp.getBlipId());

            if (waveletBlipOp.getBlipOp() instanceof BlipContentOperation) {
                mongoOp.append(FIELD_BLIPOP, serialize((BlipContentOperation) waveletBlipOp.getBlipOp()));
            } else {
                throw new IllegalArgumentException("Unsupported blip operation: " + waveletBlipOp.getBlipOp());
            }
        } else {
            throw new IllegalArgumentException("Unsupported wavelet operation: " + waveletOp);
        }
        return mongoOp;
    }

    public static DBObject serialize(BlipContentOperation blipContentOp) {
        BasicDBObject mongoBlipContentOp = new BasicDBObject();
        mongoBlipContentOp.append(FIELD_CONTENTOP, serialize(blipContentOp.getContentOp()));
        return mongoBlipContentOp;
    }

    public static DBObject serialize(DocOp docOp) {
        BasicDBObject mongoDocOp = new BasicDBObject();
        mongoDocOp.append(FIELD_BYTES, OperationSerializer.serialize(docOp).toByteArray());
        return mongoDocOp;
    }

    public static WaveletDeltaRecord deserializeWaveletDeltaRecord(DBObject dbObject) throws PersistenceException {
        try {
            return new WaveletDeltaRecord(deserializeHashedVersion((DBObject) dbObject.get(FIELD_APPLIEDATVERSION)),
                    ByteStringMessage.parseProtocolAppliedWaveletDelta(
                            ByteString.copyFrom((byte[]) dbObject.get(FIELD_APPLIED))),
                    deserializeTransformedWaveletDelta((DBObject) dbObject.get(FIELD_TRANSFORMED)));

        } catch (InvalidProtocolBufferException e) {
            throw new PersistenceException(e);
        }
    }

    public static HashedVersion deserializeHashedVersion(DBObject dbObject) {
        return HashedVersion.of((Long) dbObject.get(FIELD_VERSION), (byte[]) dbObject.get(FIELD_HISTORYHASH));
    }

    public static ParticipantId deserializeParicipantId(DBObject dbObject) {
        return ParticipantId.ofUnsafe((String) dbObject.get(FIELD_ADDRESS));
    }

    public static TransformedWaveletDelta deserializeTransformedWaveletDelta(DBObject dbObject)
            throws PersistenceException {

        ParticipantId author = deserializeParicipantId((DBObject) dbObject.get(FIELD_AUTHOR));
        HashedVersion resultingVersion = deserializeHashedVersion((DBObject) dbObject.get(FIELD_RESULTINGVERSION));
        long applicationTimestamp = (Long) dbObject.get(FIELD_APPLICATIONTIMESTAMP);

        BasicDBList dbOps = (BasicDBList) dbObject.get(FIELD_OPS);
        ImmutableList.Builder<WaveletOperation> operations = ImmutableList.builder();

        int numOperations = dbOps.size();

        // Code analog to ProtoDeltaStoreDataSerializer.deserialize
        for (int i = 0; i < numOperations; i++) {

            WaveletOperationContext context;
            if (i == numOperations - 1) {
                context = new WaveletOperationContext(author, applicationTimestamp, resultingVersion.getVersion(),
                        resultingVersion);
            } else {
                context = new WaveletOperationContext(author, applicationTimestamp, resultingVersion.getVersion());
            }
            operations.add(deserializeWaveletOperation((DBObject) dbOps.get(i), context));
        }

        return new TransformedWaveletDelta(author, resultingVersion, applicationTimestamp, operations.build());
    }

    public static WaveletOperation deserializeWaveletOperation(DBObject dbObject, WaveletOperationContext context)
            throws PersistenceException {
        String type = (String) dbObject.get(FIELD_TYPE);
        if (type.equals(WAVELET_OP_NOOP)) {
            return new NoOp(context);
        } else if (type.equals(WAVELET_OP_ADD_PARTICIPANT)) {
            return new AddParticipant(context, deserializeParicipantId((DBObject) dbObject.get(FIELD_PARTICIPANT)));
        } else if (type.equals(WAVELET_OP_REMOVE_PARTICIPANT)) {
            return new RemoveParticipant(context,
                    deserializeParicipantId((DBObject) dbObject.get(FIELD_PARTICIPANT)));
        } else if (type.equals(WAVELET_OP_WAVELET_BLIP_OPERATION)) {
            return new WaveletBlipOperation((String) dbObject.get(FIELD_BLIPID),
                    deserializeBlipContentOperation((DBObject) dbObject.get(FIELD_BLIPOP), context));
        } else {
            throw new IllegalArgumentException("Unsupported operation: " + type);
        }
    }

    public static BlipOperation deserializeBlipContentOperation(DBObject dbObject, WaveletOperationContext context)
            throws PersistenceException {
        return new BlipContentOperation(context, deserializeDocOp((DBObject) dbObject.get(FIELD_CONTENTOP)));
    }

    private static DocOp deserializeDocOp(DBObject dbObject) throws PersistenceException {
        try {
            return OperationSerializer
                    .deserialize(ProtocolDocumentOperation.parseFrom(((byte[]) dbObject.get(FIELD_BYTES))));
        } catch (InvalidProtocolBufferException e) {
            throw new PersistenceException(e);
        }
    }
}