/*
* Copyright 2008 Google 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.google.jstestdriver;
import static java.lang.String.format;
import org.joda.time.Instant;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* @author jeremiele@google.com (Jeremie Lenfant-Engelmann)
*/
public class SlaveBrowser {
public static final long TIMEOUT = 15000; // 15 seconds
private static final int POLL_RESPONSE_TIMEOUT = 2;
private final Time time;
private final String id;
private final BrowserInfo browserInfo;
private final BlockingQueue<Command> commandsToRun = new LinkedBlockingQueue<Command>();
private long dequeueTimeout = 10;
private TimeUnit timeUnit = TimeUnit.SECONDS;
private volatile Instant lastHeartBeat;
private Set<FileInfo> fileSet = new LinkedHashSet<FileInfo>();
private final BlockingQueue<CommandResponse> responses =
new LinkedBlockingQueue<CommandResponse>();
private Command commandRunning = null;
private Command lastCommandDequeued;
private final long timeout;
public SlaveBrowser(Time time, String id, BrowserInfo browserInfo, long timeout) {
this.time = time;
this.timeout = timeout;
lastHeartBeat = time.now();
this.id = id;
this.browserInfo = browserInfo;
}
public String getId() {
return id;
}
public static class CommandResponse {
private Response response;
private final boolean last;
public CommandResponse(Response response, boolean last) {
this.response = response;
this.last = last;
}
/**
* @return the response
*/
public Response getResponse() {
return response;
}
/**
* @return the isLast
*/
public boolean isLast() {
return last;
}
public void setResponse(Response response) {
this.response = response;
}
}
public void createCommand(String data) {
try {
commandsToRun.put(new Command(data));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public synchronized Command dequeueCommand() {
try {
Command command = commandsToRun.poll(dequeueTimeout, timeUnit);
if (command != null) {
commandRunning = command;
lastCommandDequeued = command;
}
return command;
} catch (InterruptedException e) {
// The server was killed
}
return null;
}
public Command getLastDequeuedCommand() {
return lastCommandDequeued;
}
public BrowserInfo getBrowserInfo() {
return browserInfo;
}
public void setDequeueTimeout(long dequeueTimeout, TimeUnit timeUnit) {
this.dequeueTimeout = dequeueTimeout;
this.timeUnit = timeUnit;
}
public void heartBeat() {
lastHeartBeat = time.now();
}
public Instant getLastHeartBeat() {
return lastHeartBeat;
}
public void addFiles(Collection<FileInfo> fileSet) {
this.fileSet.removeAll(fileSet);
this.fileSet.addAll(fileSet);
}
public Set<FileInfo> getFileSet() {
return fileSet;
}
public synchronized void resetFileSet() {
fileSet.clear();
}
public CommandResponse getResponse() {
try {
return responses.poll(POLL_RESPONSE_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return null;
}
}
public synchronized void addResponse(Response response, boolean isLast) {
if (isLast) {
commandRunning = null;
}
responses.offer(new CommandResponse(response, isLast));
}
public void clearResponseQueue() {
responses.clear();
}
public boolean isCommandRunning() {
return commandRunning != null;
}
public synchronized Command getCommandRunning() {
return commandRunning;
}
public synchronized void removeFiles(Collection<FileSource> errorFiles) {
Set<FileInfo> filesInfoToRemove = new LinkedHashSet<FileInfo>();
for (FileSource f : errorFiles) {
for (FileInfo info : fileSet) {
if (info.getFilePath().equals(f.getBasePath())) {
filesInfoToRemove.add(info);
break;
}
}
}
fileSet.removeAll(filesInfoToRemove);
}
public Command peekCommand() {
return commandsToRun.peek();
}
public void clearCommandRunning() {
if (commandRunning != null) {
commandRunning = null;
commandsToRun.clear();
responses.clear();
}
}
public boolean isAlive() {
return time.now().getMillis() - lastHeartBeat.getMillis() < timeout;
}
@Override
public String toString() {
return format("SlaveBrowser(browserInfo=%s,\nid=%s,\nsinceLastCheck=%s)",
browserInfo, id, time.now().getMillis() - lastHeartBeat.getMillis());
}
}