blob: 2e678c93c7dcfeba8b94cf446119fcf7a9135aab [file] [log] [blame]
/*
* 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 java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record;
import org.apache.zookeeper.proto.Create2Response;
import org.apache.zookeeper.proto.CreateResponse;
import org.apache.zookeeper.proto.ErrorResponse;
import org.apache.zookeeper.proto.GetChildrenResponse;
import org.apache.zookeeper.proto.GetDataResponse;
import org.apache.zookeeper.proto.MultiHeader;
import org.apache.zookeeper.proto.SetDataResponse;
/**
* Handles the response from a multi request. Such a response consists of
* a sequence of responses each prefixed by a MultiResponse that indicates
* the type of the response. The end of the list is indicated by a MultiHeader
* with a negative type. Each individual response is in the same format as
* with the corresponding operation in the original request list.
*/
public class MultiResponse implements Record, Iterable<OpResult> {
private List<OpResult> results = new ArrayList<>();
public void add(OpResult x) {
results.add(x);
}
@Override
public Iterator<OpResult> iterator() {
return results.iterator();
}
public int size() {
return results.size();
}
@Override
public void serialize(OutputArchive archive, String tag) throws IOException {
archive.startRecord(this, tag);
for (OpResult result : results) {
int err = result.getType() == ZooDefs.OpCode.error ? ((OpResult.ErrorResult) result).getErr() : 0;
new MultiHeader(result.getType(), false, err).serialize(archive, tag);
switch (result.getType()) {
case ZooDefs.OpCode.create:
new CreateResponse(((OpResult.CreateResult) result).getPath()).serialize(archive, tag);
break;
case ZooDefs.OpCode.create2:
OpResult.CreateResult createResult = (OpResult.CreateResult) result;
new Create2Response(createResult.getPath(), createResult.getStat()).serialize(archive, tag);
break;
case ZooDefs.OpCode.delete:
case ZooDefs.OpCode.check:
break;
case ZooDefs.OpCode.setData:
new SetDataResponse(((OpResult.SetDataResult) result).getStat()).serialize(archive, tag);
break;
case ZooDefs.OpCode.getChildren:
new GetChildrenResponse(((OpResult.GetChildrenResult) result).getChildren()).serialize(archive, tag);
break;
case ZooDefs.OpCode.getData:
new GetDataResponse(
((OpResult.GetDataResult) result).getData(),
((OpResult.GetDataResult) result).getStat())
.serialize(archive, tag);
break;
case ZooDefs.OpCode.error:
new ErrorResponse(((OpResult.ErrorResult) result).getErr()).serialize(archive, tag);
break;
default:
throw new IOException("Invalid type " + result.getType() + " in MultiResponse");
}
}
new MultiHeader(-1, true, -1).serialize(archive, tag);
archive.endRecord(this, tag);
}
@Override
public void deserialize(InputArchive archive, String tag) throws IOException {
results = new ArrayList<>();
archive.startRecord(tag);
MultiHeader h = new MultiHeader();
h.deserialize(archive, tag);
while (!h.getDone()) {
switch (h.getType()) {
case ZooDefs.OpCode.create:
CreateResponse cr = new CreateResponse();
cr.deserialize(archive, tag);
results.add(new OpResult.CreateResult(cr.getPath()));
break;
case ZooDefs.OpCode.create2:
Create2Response cr2 = new Create2Response();
cr2.deserialize(archive, tag);
results.add(new OpResult.CreateResult(cr2.getPath(), cr2.getStat()));
break;
case ZooDefs.OpCode.delete:
results.add(new OpResult.DeleteResult());
break;
case ZooDefs.OpCode.setData:
SetDataResponse sdr = new SetDataResponse();
sdr.deserialize(archive, tag);
results.add(new OpResult.SetDataResult(sdr.getStat()));
break;
case ZooDefs.OpCode.check:
results.add(new OpResult.CheckResult());
break;
case ZooDefs.OpCode.getChildren:
GetChildrenResponse gcr = new GetChildrenResponse();
gcr.deserialize(archive, tag);
results.add(new OpResult.GetChildrenResult(gcr.getChildren()));
break;
case ZooDefs.OpCode.getData:
GetDataResponse gdr = new GetDataResponse();
gdr.deserialize(archive, tag);
results.add(new OpResult.GetDataResult(gdr.getData(), gdr.getStat()));
break;
case ZooDefs.OpCode.error:
// TODO: need way to more cleanly serialize/deserialize exceptions
ErrorResponse er = new ErrorResponse();
er.deserialize(archive, tag);
results.add(new OpResult.ErrorResult(er.getErr()));
break;
default:
throw new IOException("Invalid type " + h.getType() + " in MultiResponse");
}
h.deserialize(archive, tag);
}
archive.endRecord(tag);
}
public List<OpResult> getResultList() {
return results;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MultiResponse)) {
return false;
}
MultiResponse other = (MultiResponse) o;
if (results != null) {
Iterator<OpResult> i = other.results.iterator();
for (OpResult result : results) {
if (i.hasNext()) {
if (!result.equals(i.next())) {
return false;
}
} else {
return false;
}
}
return !i.hasNext();
} else {
return other.results == null;
}
}
@Override
public int hashCode() {
int hash = results.size();
for (OpResult result : results) {
hash = (hash * 35) + result.hashCode();
}
return hash;
}
}