/*
* 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;
}
}