/*
* Copyright 2011 the original author or authors.
*
* 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 org.gradle.launcher.daemon.registry;
import org.gradle.internal.remote.Address;
import org.gradle.internal.remote.internal.inet.MultiChoiceAddress;
import org.gradle.internal.remote.internal.inet.MultiChoiceAddressSerializer;
import org.gradle.internal.remote.internal.inet.SocketInetAddress;
import org.gradle.internal.serialize.Decoder;
import org.gradle.internal.serialize.Encoder;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DaemonRegistryContent implements Serializable {
public static final org.gradle.internal.serialize.Serializer<DaemonRegistryContent> SERIALIZER = new Serializer();
private static final MultiChoiceAddressSerializer MULTI_CHOICE_ADDRESS_SERIALIZER = new MultiChoiceAddressSerializer();
private final Map<Address, DaemonInfo> infosMap;
private final List<DaemonStopEvent> stopEvents;
public DaemonRegistryContent() {
infosMap = new HashMap<Address, DaemonInfo>();
stopEvents = new ArrayList<DaemonStopEvent>();
}
private DaemonRegistryContent(Map<Address, DaemonInfo> infosMap, List<DaemonStopEvent> stopEvents) {
this.infosMap = infosMap;
this.stopEvents = stopEvents;
}
/**
* returns all statuses. May be empty.
*/
public List<DaemonInfo> getInfos() {
return new LinkedList<DaemonInfo>(infosMap.values());
}
/**
* Gets the status for given address. May return null.
*/
public DaemonInfo getInfo(Address address) {
return infosMap.get(address);
}
/**
* Removes the status
*/
public void removeInfo(Address address) {
infosMap.remove(address);
}
/**
* Returns all stop events. May be empty.
*/
public List<DaemonStopEvent> getStopEvents() {
return stopEvents;
}
/**
* Add stop event to our collection
*/
public void addStopEvent(DaemonStopEvent stopEvent) {
stopEvents.add(stopEvent);
}
/**
* Removes all stop events.
*/
public void removeStopEvents(Collection<DaemonStopEvent> events) {
stopEvents.removeAll(events);
}
/**
* sets the daemonInfo for given address
*/
public void setStatus(Address address, DaemonInfo daemonInfo) {
infosMap.put(address, daemonInfo);
}
/**
* Data layout:
* 0 - number of daemon infos
* 1 - addresses
* 2 - daemon infos
* 3 - number of stop events
* 4 - stop events
*/
private static class Serializer implements org.gradle.internal.serialize.Serializer<DaemonRegistryContent> {
@Override
public DaemonRegistryContent read(Decoder decoder) throws Exception {
if (decoder.readBoolean()) {
List<Address> addresses = readAdresses(decoder);
Map<Address, DaemonInfo> infosMap = readInfosMap(decoder, addresses);
List<DaemonStopEvent> stopEvents = readStopEvents(decoder);
return new DaemonRegistryContent(infosMap, stopEvents);
}
return null;
}
private List<DaemonStopEvent> readStopEvents(Decoder decoder) throws Exception {
int len = decoder.readInt();
List<DaemonStopEvent> out = new ArrayList<DaemonStopEvent>(len);
for (int i=0; i<len; i++) {
out.add(DaemonStopEvent.SERIALIZER.read(decoder));
}
return out;
}
private Map<Address, DaemonInfo> readInfosMap(Decoder decoder, List<Address> addresses) throws Exception {
Map<Address, DaemonInfo> infosMap = new HashMap<Address, DaemonInfo>(addresses.size());
DaemonInfo.Serializer daemonInfoSerializer = new DaemonInfo.Serializer(addresses);
for (Address address : addresses) {
infosMap.put(address, daemonInfoSerializer.read(decoder));
}
return infosMap;
}
@Override
public void write(Encoder encoder, DaemonRegistryContent registry) throws Exception {
if (registry != null) {
encoder.writeBoolean(true);
Map<Address, DaemonInfo> infosMap = registry.infosMap;
int infosSize = infosMap.size();
// make sure we can store it in order or we'll have surprises on deserialization
List<Address> addresses = new ArrayList<Address>(infosMap.keySet());
writeAddresses(encoder, infosSize, addresses);
writeDaemonInfos(encoder, infosMap, addresses);
writeStopEvents(encoder, registry);
} else {
encoder.writeBoolean(false);
}
}
private void writeStopEvents(Encoder encoder, DaemonRegistryContent registry) throws Exception {
List<DaemonStopEvent> stopEvents = registry.stopEvents;
encoder.writeInt(stopEvents.size());
for (DaemonStopEvent stopEvent : stopEvents) {
DaemonStopEvent.SERIALIZER.write(encoder, stopEvent);
}
}
private void writeDaemonInfos(Encoder encoder, Map<Address, DaemonInfo> infosMap, List<Address> addresses) throws Exception {
DaemonInfo.Serializer daemonInfoSerializer = new DaemonInfo.Serializer(addresses);
for (Address address : addresses) {
DaemonInfo info = infosMap.get(address);
daemonInfoSerializer.write(encoder, info);
}
}
private void writeAddresses(Encoder encoder, int infosSize, List<Address> addresses) throws Exception {
encoder.writeInt(infosSize);
ObjectOutputStream oos = new ObjectOutputStream(encoder.getOutputStream());
for (Address address : addresses) {
byte type = (byte) (address instanceof SocketInetAddress ? 0
: address instanceof MultiChoiceAddress ? 1
: 2);
encoder.writeByte(type);
switch (type) {
case 0:
SocketInetAddress.SERIALIZER.write(encoder, (SocketInetAddress) address);
break;
case 1:
MULTI_CHOICE_ADDRESS_SERIALIZER.write(encoder, (MultiChoiceAddress) address);
break;
default:
oos.writeObject(address);
}
}
}
private List<Address> readAdresses(Decoder decoder) throws Exception {
int infosSize = decoder.readInt();
List<Address> out = new ArrayList<Address>();
ObjectInputStream ois = new ObjectInputStream(decoder.getInputStream());
for (int i=0; i<infosSize; i++) {
byte type = decoder.readByte();
switch (type) {
case 0:
out.add(SocketInetAddress.SERIALIZER.read(decoder));
break;
case 1:
out.add(MULTI_CHOICE_ADDRESS_SERIALIZER.read(decoder));
break;
default:
out.add((Address) ois.readObject());
}
}
return out;
}
}
}