/* * 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.apache.zookeeper; import org.apache.jute.InputArchive; import org.apache.jute.OutputArchive; import org.apache.jute.Record; import org.apache.zookeeper.proto.*; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Encodes a composite transaction. In the wire format, each transaction * consists of a single MultiHeader followed by the appropriate request. * Each of these MultiHeaders has a type which indicates * the type of the following transaction or a negative number if no more transactions * are included. */ public class MultiTransactionRecord implements Record, Iterable<Op> { private List<Op> ops = new ArrayList<Op>(); public MultiTransactionRecord() { } public MultiTransactionRecord(Iterable<Op> ops) { for (Op op : ops) { add(op); } } @Override public Iterator<Op> iterator() { return ops.iterator() ; } public void add(Op op) { ops.add(op); } public int size() { return ops.size(); } @Override public void serialize(OutputArchive archive, String tag) throws IOException { archive.startRecord(this, tag); int index = 0 ; for (Op op : ops) { MultiHeader h = new MultiHeader(op.getType(), false, -1); h.serialize(archive, tag); switch (op.getType()) { case ZooDefs.OpCode.create: op.toRequestRecord().serialize(archive, tag); break; case ZooDefs.OpCode.delete: op.toRequestRecord().serialize(archive, tag); break; case ZooDefs.OpCode.setData: op.toRequestRecord().serialize(archive, tag); break; case ZooDefs.OpCode.check: op.toRequestRecord().serialize(archive, tag); break; default: throw new IOException("Invalid type of op"); } } new MultiHeader(-1, true, -1).serialize(archive, tag); archive.endRecord(this, tag); } @Override public void deserialize(InputArchive archive, String tag) throws IOException { archive.startRecord(tag); MultiHeader h = new MultiHeader(); h.deserialize(archive, tag); while (!h.getDone()) { switch (h.getType()) { case ZooDefs.OpCode.create: CreateRequest cr = new CreateRequest(); cr.deserialize(archive, tag); add(Op.create(cr.getPath(), cr.getData(), cr.getAcl(), cr.getFlags())); break; case ZooDefs.OpCode.delete: DeleteRequest dr = new DeleteRequest(); dr.deserialize(archive, tag); add(Op.delete(dr.getPath(), dr.getVersion())); break; case ZooDefs.OpCode.setData: SetDataRequest sdr = new SetDataRequest(); sdr.deserialize(archive, tag); add(Op.setData(sdr.getPath(), sdr.getData(), sdr.getVersion())); break; case ZooDefs.OpCode.check: CheckVersionRequest cvr = new CheckVersionRequest(); cvr.deserialize(archive, tag); add(Op.check(cvr.getPath(), cvr.getVersion())); break; default: throw new IOException("Invalid type of op"); } h.deserialize(archive, tag); } archive.endRecord(tag); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MultiTransactionRecord)) return false; MultiTransactionRecord that = (MultiTransactionRecord) o; if (ops != null) { Iterator<Op> other = that.ops.iterator(); for (Op op : ops) { boolean hasMoreData = other.hasNext(); if (!hasMoreData) { return false; } Op otherOp = other.next(); if (!op.equals(otherOp)) { return false; } } return !other.hasNext(); } else { return that.ops == null; } } @Override public int hashCode() { int h = 1023; for (Op op : ops) { h = h * 25 + op.hashCode(); } return h; } }