com.netflix.curator.framework.imps.CuratorTransactionImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.curator.framework.imps.CuratorTransactionImpl.java

Source

/*
 *
 *  Copyright 2011 Netflix, Inc.
 *
 *     Licensed 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 com.netflix.curator.framework.imps;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.netflix.curator.RetryLoop;
import com.netflix.curator.framework.api.Pathable;
import com.netflix.curator.framework.api.transaction.CuratorTransaction;
import com.netflix.curator.framework.api.transaction.CuratorTransactionBridge;
import com.netflix.curator.framework.api.transaction.CuratorTransactionFinal;
import com.netflix.curator.framework.api.transaction.CuratorTransactionResult;
import com.netflix.curator.framework.api.transaction.OperationType;
import com.netflix.curator.framework.api.transaction.TransactionCheckBuilder;
import com.netflix.curator.framework.api.transaction.TransactionCreateBuilder;
import com.netflix.curator.framework.api.transaction.TransactionDeleteBuilder;
import com.netflix.curator.framework.api.transaction.TransactionSetDataBuilder;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Op;
import org.apache.zookeeper.OpResult;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

class CuratorTransactionImpl implements CuratorTransaction, CuratorTransactionBridge, CuratorTransactionFinal {
    private final CuratorFrameworkImpl client;
    private final CuratorMultiTransactionRecord transaction;

    private boolean isCommitted = false;

    CuratorTransactionImpl(CuratorFrameworkImpl client) {
        this.client = client;
        transaction = new CuratorMultiTransactionRecord();
    }

    @Override
    public CuratorTransactionFinal and() {
        return this;
    }

    @Override
    public TransactionCreateBuilder create() {
        Preconditions.checkState(!isCommitted, "transaction already committed");

        return new CreateBuilderImpl(client).asTransactionCreateBuilder(this, transaction);
    }

    @Override
    public TransactionDeleteBuilder delete() {
        Preconditions.checkState(!isCommitted, "transaction already committed");

        return new DeleteBuilderImpl(client).asTransactionDeleteBuilder(this, transaction);
    }

    @Override
    public TransactionSetDataBuilder setData() {
        Preconditions.checkState(!isCommitted, "transaction already committed");

        return new SetDataBuilderImpl(client).asTransactionSetDataBuilder(this, transaction);
    }

    @Override
    public TransactionCheckBuilder check() {
        Preconditions.checkState(!isCommitted, "transaction already committed");

        return new TransactionCheckBuilder() {
            private int version = -1;

            @Override
            public CuratorTransactionBridge forPath(String path) throws Exception {
                String fixedPath = client.fixForNamespace(path);
                transaction.add(Op.check(fixedPath, version), OperationType.CHECK, path);

                return CuratorTransactionImpl.this;
            }

            @Override
            public Pathable<CuratorTransactionBridge> withVersion(int version) {
                this.version = version;
                return this;
            }
        };
    }

    @Override
    public Collection<CuratorTransactionResult> commit() throws Exception {
        Preconditions.checkState(!isCommitted, "transaction already committed");
        isCommitted = true;

        final AtomicBoolean firstTime = new AtomicBoolean(true);
        List<OpResult> resultList = RetryLoop.callWithRetry(client.getZookeeperClient(),
                new Callable<List<OpResult>>() {
                    @Override
                    public List<OpResult> call() throws Exception {
                        return doOperation(firstTime);
                    }
                });

        if (resultList.size() != transaction.metadataSize()) {
            throw new IllegalStateException(String.format("Result size (%d) doesn't match input size (%d)",
                    resultList.size(), transaction.metadataSize()));
        }

        ImmutableList.Builder<CuratorTransactionResult> builder = ImmutableList.builder();
        for (int i = 0; i < resultList.size(); ++i) {
            OpResult opResult = resultList.get(i);
            CuratorMultiTransactionRecord.TypeAndPath metadata = transaction.getMetadata(i);
            CuratorTransactionResult curatorResult = makeCuratorResult(opResult, metadata);
            builder.add(curatorResult);
        }

        return builder.build();
    }

    private List<OpResult> doOperation(AtomicBoolean firstTime) throws Exception {
        boolean localFirstTime = firstTime.getAndSet(false);
        if (!localFirstTime) {

        }

        List<OpResult> opResults = client.getZooKeeper().multi(transaction);
        if (opResults.size() > 0) {
            OpResult firstResult = opResults.get(0);
            if (firstResult.getType() == ZooDefs.OpCode.error) {
                OpResult.ErrorResult error = (OpResult.ErrorResult) firstResult;
                KeeperException.Code code = KeeperException.Code.get(error.getErr());
                if (code == null) {
                    code = KeeperException.Code.UNIMPLEMENTED;
                }
                throw KeeperException.create(code);
            }
        }
        return opResults;
    }

    private CuratorTransactionResult makeCuratorResult(OpResult opResult,
            CuratorMultiTransactionRecord.TypeAndPath metadata) {
        String resultPath = null;
        Stat resultStat = null;
        switch (opResult.getType()) {
        default: {
            // NOP
            break;
        }

        case ZooDefs.OpCode.create: {
            OpResult.CreateResult createResult = (OpResult.CreateResult) opResult;
            resultPath = client.unfixForNamespace(createResult.getPath());
            break;
        }

        case ZooDefs.OpCode.setData: {
            OpResult.SetDataResult setDataResult = (OpResult.SetDataResult) opResult;
            resultStat = setDataResult.getStat();
            break;
        }
        }

        return new CuratorTransactionResult(metadata.type, metadata.forPath, resultPath, resultStat);
    }
}