/*
* Copyright 2011 Luke Usherwood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.bettyluke.tracinstant.data;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.SwingWorker;
import net.bettyluke.tracinstant.data.TicketLoadTask.Update;
/**
* @param <T> The result of <code>doInBackground</code> and <code>get</code> is a list of
* ticket modification dates, as extracted from all tickets loaded. This will be
* processed in the 'done' method so it is not required for client code to access them
*/
public abstract class TicketLoadTask extends SwingWorker<List<String>, Update> {
/**
* A mutually-exclusive structure (no 'union' in Java) to pass status updates and
* generated ticket data from the publish() method (on background thread) to
* the process() method (on the EDT).
* <p>
* If (ticketProvider != null) then extract the tickets from it, otherwise process the
* status messages.
*/
public static class Update {
public final TicketProvider ticketProvider;
public final String summaryMessage;
public final String detailMessage;
public Update(TicketProvider tp) {
this.detailMessage = null;
this.summaryMessage = null;
this.ticketProvider = tp;
}
public Update(String summaryMessage, String detailMessage) {
this.detailMessage = detailMessage;
this.summaryMessage = summaryMessage;
this.ticketProvider = null;
}
/** A special update meaning "job complete" */
public Update() {
this.detailMessage = null;
this.summaryMessage = null;
this.ticketProvider = null;
}
@Override
public int hashCode() {
return Objects.hash(detailMessage, summaryMessage, ticketProvider);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Update)) {
return false;
}
Update other = (Update) obj;
return Objects.equals(ticketProvider, other.ticketProvider)
&& Objects.equals(summaryMessage, other.summaryMessage)
&& Objects.equals(detailMessage, other.detailMessage);
}
}
private Update statusUpdate = null;
protected Runnable doneCallback = null;
protected final SiteData site;
public TicketLoadTask(SiteData site) {
this.site = site;
}
@Override
protected void process(List<Update> chunks) {
if (isCancelled()) {
return;
}
for (Update newUpdate : chunks) {
Update oldStatus = statusUpdate;
statusUpdate = newUpdate;
if (Objects.equals(oldStatus, statusUpdate)) {
continue;
}
firePropertyChange("status", oldStatus, statusUpdate);
}
}
@Override
protected void done() {
super.done();
try {
List<String> strings = get();
site.setLastModifiedTicketTime(strings);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (CancellationException e) {
System.out.println("Ticket load cancelled");
}
/* A final null status message is used to indicate completion. */
process(Collections.<Update>singletonList(new Update()));
if (doneCallback != null) {
doneCallback.run();
doneCallback = null;
}
}
public void executeWithNotification(Runnable runnable) {
doneCallback = runnable;
execute();
}
protected static List<String> extractModificationDates(Collection<Ticket> tickets) {
return streamChangeTimes(tickets).collect(Collectors.toList());
}
protected static Stream<String> streamChangeTimes(Collection<Ticket> tickets) {
return tickets.stream()
.map(ticket -> ticket.getValue("changetime"))
.filter(Objects::nonNull);
}
}