/*
* Copyright 2015 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 io.atomix.collections.internal;
import io.atomix.copycat.server.Commit;
import io.atomix.resource.ResourceStateMachine;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Properties;
import java.util.Queue;
import static io.atomix.collections.DistributedQueue.Events;
import static io.atomix.collections.DistributedQueue.ValueEvent;
/**
* Distributed set state machine.
*
* @author <a href="http://github.com/kuujo">Jordan Halterman</a>
*/
public class QueueState extends ResourceStateMachine {
private final Queue<Commit<? extends QueueCommands.ValueCommand>> queue = new ArrayDeque<>();
public QueueState(Properties properties) {
super(properties);
}
/**
* Handles a contains commit.
*/
public boolean contains(Commit<QueueCommands.Contains> commit) {
try {
for (Commit<? extends QueueCommands.ValueCommand> value : queue) {
if (value.operation().value().equals(commit.operation().value()))
return true;
}
return false;
} finally {
commit.release();
}
}
/**
* Handles an add commit.
*/
public boolean add(Commit<QueueCommands.Add> commit) {
try {
queue.add(commit);
notify(new ValueEvent<>(Events.ADD, commit.command().value()));
} catch (Exception e) {
commit.release();
throw e;
}
return true;
}
/**
* Handles an offer commit.
*/
public boolean offer(Commit<QueueCommands.Offer> commit) {
try {
if (queue.offer(commit)) {
notify(new ValueEvent<>(Events.ADD, commit.command().value()));
return true;
} else {
commit.release();
return false;
}
} catch (Exception e) {
commit.release();
throw e;
}
}
/**
* Handles a peek commit.
*/
public Object peek(Commit<QueueCommands.Peek> commit) {
try {
Commit<? extends QueueCommands.ValueCommand> value = queue.peek();
if (value != null) {
return value.operation().value();
}
return null;
} finally {
commit.release();
}
}
/**
* Handles a poll commit.
*/
public Object poll(Commit<QueueCommands.Poll> commit) {
try {
Commit<? extends QueueCommands.ValueCommand> value = queue.poll();
if (value != null) {
try {
notify(new ValueEvent<>(Events.REMOVE, value.command().value()));
return value.operation().value();
} finally {
value.release();
}
}
return null;
} finally {
commit.release();
}
}
/**
* Handles an element commit.
*/
public Object element(Commit<QueueCommands.Element> commit) {
try {
Commit<? extends QueueCommands.ValueCommand> value = queue.element();
if (value != null) {
try {
return value.operation().value();
} finally {
value.release();
}
}
return null;
} finally {
commit.release();
}
}
/**
* Handles a remove commit.
*/
public Object remove(Commit<QueueCommands.Remove> commit) {
try {
if (commit.operation().value() != null) {
Iterator<Commit<? extends QueueCommands.ValueCommand>> iterator = queue.iterator();
while (iterator.hasNext()) {
Commit<? extends QueueCommands.ValueCommand> value = iterator.next();
if (value.operation().value().equals(commit.operation().value())) {
iterator.remove();
notify(new ValueEvent<>(Events.REMOVE, value.command().value()));
value.release();
return true;
}
}
return false;
} else {
Commit<? extends QueueCommands.ValueCommand> value = queue.remove();
if (value != null) {
try {
notify(new ValueEvent<>(Events.REMOVE, value.command().value()));
return value.operation().value();
} finally {
value.release();
}
}
return null;
}
} finally {
commit.release();
}
}
/**
* Handles a count commit.
*/
public int size(Commit<QueueCommands.Size> commit) {
try {
return queue.size();
} finally {
commit.release();
}
}
/**
* Handles an is empty commit.
*/
public boolean isEmpty(Commit<QueueCommands.IsEmpty> commit) {
try {
return queue.isEmpty();
} finally {
commit.release();
}
}
/**
* Handles a clear commit.
*/
public void clear(Commit<QueueCommands.Clear> commit) {
try {
delete();
} finally {
commit.release();
}
}
@Override
public void delete() {
Iterator<Commit<? extends QueueCommands.ValueCommand>> iterator = queue.iterator();
while (iterator.hasNext()) {
Commit<? extends QueueCommands.ValueCommand> value = iterator.next();
value.release();
iterator.remove();
}
}
}