Archived
0

progress dialog prototype

This commit is contained in:
iMoHax
2015-01-11 13:55:48 +03:00
parent 1a327f14a6
commit 62d951a674
11 changed files with 560 additions and 55 deletions

View File

@@ -0,0 +1,250 @@
package ru.trader.controllers;
import javafx.application.Platform;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import ru.trader.core.MarketAnalyzer;
import ru.trader.core.MarketAnalyzerCallBack;
import ru.trader.core.Place;
import ru.trader.core.Vendor;
import ru.trader.graph.Connectable;
import ru.trader.graph.GraphCallBack;
import ru.trader.graph.RouteSearcherCallBack;
import ru.trader.graph.Vertex;
import java.util.concurrent.atomic.AtomicLong;
public class AnalyzerProgress {
private VBox tasks;
private TaskVisual task;
public void show(Parent main, String text, MarketAnalyzer analyzer){
tasks = new VBox(5);
task = new TaskVisual(text);
Button button = new Button("Cancel");
Scene scene = new Scene(tasks, 200, 200);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
MarketAnalyzerCallBack callBack = new AnalyzerCallBack(task);
analyzer.setCallback(callBack);
button.setOnAction(e -> callBack.cancel());
createProgress(task);
tasks.getChildren().add(button);
task.getSubTasks().addListener((ListChangeListener<TaskVisual>)l -> {
while (l.next()) {
if (l.wasRemoved()) {
l.getRemoved().forEach(this::removeProgress);
}
if (l.wasAdded()) {
l.getAddedSubList().forEach(this::createProgress);
}
}
});
}
private void createProgress(TaskVisual task){
HBox hBox = new HBox(10);
hBox.setUserData(task);
Label txt = new Label("Процесс");
ProgressBar bar = new ProgressBar();
txt.textProperty().bind(task.messageProperty());
bar.progressProperty().bind(task.countProperty().divide(task.maxProperty()));
hBox.getChildren().addAll(txt, bar);
tasks.getChildren().addAll(hBox);
}
private void removeProgress(TaskVisual task){
tasks.getChildren().removeIf(n -> task.equals(n.getUserData()));
}
private class TaskVisual {
private final StringProperty message;
private final LongProperty count;
private final LongProperty max;
private final ObservableList<TaskVisual> subTasks;
private TaskVisual(String text) {
message = new SimpleStringProperty(text);
count = new SimpleLongProperty(0);
max = new SimpleLongProperty(1);
subTasks = FXCollections.observableArrayList();
}
public String getMessage() {
return message.get();
}
public StringProperty messageProperty() {
return message;
}
public void setMessage(String message) {
Platform.runLater(() -> this.message.set(message));
}
public long getCount() {
return count.get();
}
public LongProperty countProperty() {
return count;
}
public void setCount(long count) {
Platform.runLater(() -> this.count.set(count));
}
public long getMax() {
return max.get();
}
public LongProperty maxProperty() {
return max;
}
public void setMax(long max) {
Platform.runLater(() -> this.max.set(max));
}
public ObservableList<TaskVisual> getSubTasks() {
return subTasks;
}
public void addSubTask(TaskVisual task){
Platform.runLater(() -> {
synchronized (subTasks) {
subTasks.add(task);
}
});
}
public void removeSubTask(TaskVisual task){
Platform.runLater(() -> {
synchronized (subTasks) {
subTasks.remove(task);
}
});
}
}
private class AnalyzerCallBack extends MarketAnalyzerCallBack {
private final TaskVisual task;
private final AtomicLong count = new AtomicLong();
private AnalyzerCallBack(TaskVisual task) {
this.task = task;
count.set(0);
}
@Override
protected RouteSearcherCallBack getRouteSearcherCallBackInstance() {
return new RSCallBack(task);
}
@Override
protected GraphCallBack<Place> getGraphCallBackInstance() {
TaskVisual subtask = new TaskVisual("Build graph of system");
task.addSubTask(subtask);
return new GCallBack<Place>(subtask, task);
}
@Override
protected void onEnd() {
task.setMessage("Finish");
}
@Override
public void setCount(long count) {
task.setMax(count);
}
@Override
public void inc() {
task.setCount(count.incrementAndGet());
}
}
private class RSCallBack extends RouteSearcherCallBack {
private final TaskVisual task;
private RSCallBack(TaskVisual task) {
this.task = task;
}
@Override
protected GraphCallBack<Vendor> getGraphCallBackInstance() {
TaskVisual subtask = new TaskVisual("Build graph of stations");
task.addSubTask(subtask);
return new GCallBack<>(subtask, task);
}
}
private class GCallBack<T extends Connectable<T>> extends GraphCallBack<T> {
private final TaskVisual task;
private final TaskVisual owner;
private final AtomicLong count = new AtomicLong();
private GCallBack(TaskVisual task, TaskVisual owner) {
this.task = task;
this.owner = owner;
count.set(0);
}
@Override
public void onStartBuild(T from) {
task.setMessage(String.format("Build graph from %s", from));
}
@Override
public void onEndBuild() {
task.setMessage("");
}
@Override
public void onStartFind(Vertex<T> from, Vertex<T> to) {
if (to != null) {
task.setMessage(String.format("Find path from %s graph to %s", from.getEntry(), to.getEntry()));
} else {
task.setMessage(String.format("Find path from %s graph", from.getEntry()));
}
}
@Override
public void onFound() {
task.setMessage("");
}
@Override
public void onEndFind() {
owner.removeSubTask(task);
}
@Override
public void setCount(long count) {
task.setMax(count);
}
@Override
public void inc() {
task.setCount(count.incrementAndGet());
}
}
}

View File

@@ -1,6 +1,8 @@
package ru.trader.controllers;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.TableView;
@@ -29,7 +31,7 @@ public class PathsController {
}
public PathRouteModel showDialog(Parent parent, Parent content, Collection<PathRouteModel> paths) {
public PathRouteModel showDialog(Parent parent, Parent content, ObservableList<PathRouteModel> paths) {
init(paths);
@@ -46,10 +48,17 @@ public class PathsController {
return tblPaths.getSelectionModel().getSelectedItem();
}
private void init(Collection<PathRouteModel> paths) {
private void init(ObservableList<PathRouteModel> paths) {
tblPaths.getSelectionModel().clearSelection();
this.paths.clear();
this.paths.addAll(paths);
paths.addListener((ListChangeListener<PathRouteModel>) l -> {
while (l.next()) {
if (l.wasAdded()) {
this.paths.addAll(l.getAddedSubList());
}
}
});
}
}

View File

@@ -1,6 +1,7 @@
package ru.trader.controllers;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
@@ -227,11 +228,12 @@ public class RouterController {
SystemModel t = target.getValue();
StationModel sS = sStation.getValue();
StationModel tS = tStation.getValue();
Platform.runLater(() -> {
PathRouteModel path = Screeners.showRouters(market.getRoutes(s, sS, t, tS, totalBalance.getValue().doubleValue()));
if (path!=null){
orders.addAll(path.getOrders());
addRouteToPath(path);
}
}});
}
public void showTopRoutes(){

View File

@@ -9,12 +9,17 @@ import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.World;
import ru.trader.controllers.AnalyzerProgress;
import ru.trader.controllers.Screeners;
import ru.trader.core.*;
import ru.trader.graph.PathRoute;
import ru.trader.model.support.BindingsHelper;
import ru.trader.model.support.Notificator;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.*;
import java.util.stream.Collectors;
public class MarketModel {
@@ -167,29 +172,37 @@ public class MarketModel {
}
public ObservableList<PathRouteModel> getRoutes(SystemModel from, StationModel stationFrom, SystemModel to, StationModel stationTo, double balance) {
AnalyzerProgress progress = new AnalyzerProgress();
progress.show(Screeners.getMainScreen(), "Get routes", analyzer);
ExecutorService executor = Executors.newSingleThreadExecutor();
ObservableList<PathRouteModel> res = FXCollections.observableArrayList();
executor.execute(() -> {
Collection<PathRoute> routes;
if (stationFrom != null && stationFrom != ModelFabric.NONE_STATION){
if (stationTo != null && stationTo != ModelFabric.NONE_STATION){
if (stationFrom != null && stationFrom != ModelFabric.NONE_STATION) {
if (stationTo != null && stationTo != ModelFabric.NONE_STATION) {
routes = analyzer.getPaths(stationFrom.getStation(), stationTo.getStation(), balance);
} else {
if (to != null && to != ModelFabric.NONE_SYSTEM){
if (to != null && to != ModelFabric.NONE_SYSTEM) {
routes = analyzer.getPaths(stationFrom.getStation(), to.getSystem(), balance);
} else {
routes = analyzer.getPaths(stationFrom.getStation(), balance);
}
}
} else {
if (stationTo != null && stationTo != ModelFabric.NONE_STATION){
if (stationTo != null && stationTo != ModelFabric.NONE_STATION) {
routes = analyzer.getPaths(from.getSystem(), stationTo.getStation(), balance);
} else {
if (to != null && to != ModelFabric.NONE_SYSTEM){
if (to != null && to != ModelFabric.NONE_SYSTEM) {
routes = analyzer.getPaths(from.getSystem(), to.getSystem(), balance);
} else {
routes = analyzer.getPaths(from.getSystem(), balance);
}
}
}
return BindingsHelper.observableList(routes, modeler::get);
routes.stream().map(modeler::get).forEach(res::add);
});
return res;
}

View File

@@ -10,6 +10,7 @@ public class MarketAnalyzer {
private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class);
private final Market market;
private MarketAnalyzerCallBack callback;
private MarketFilter filter;
private double tank;
private double maxDistance;
@@ -21,11 +22,20 @@ public class MarketAnalyzer {
private final static Comparator<Order> orderComparator = (o1, o2) -> o2.compareTo(o1);
public MarketAnalyzer(Market market) {
this(market, new MarketAnalyzerCallBack());
}
public MarketAnalyzer(Market market, MarketAnalyzerCallBack callback) {
this.market = market;
this.callback = callback;
this.limit = 100;
this.segmentSize = 0;
}
public void setCallback(MarketAnalyzerCallBack callback) {
this.callback = callback;
}
public void setFilter(MarketFilter filter) {
this.filter = filter;
}
@@ -56,19 +66,23 @@ public class MarketAnalyzer {
public Collection<Order> getTop(double balance){
LOG.debug("Get top {}", limit);
Iterable<Place> places = getPlaces();
Collection<Place> places = getPlaces();
List<Order> top = new ArrayList<>(limit);
callback.setCount(places.size());
for (Place place : places) {
if (callback.isCancel()) break;
LOG.trace("Check place {}", place);
Collection<Order> orders = getOrders(place, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit());
TopList.addAllToTop(top, orders, limit, orderComparator);
callback.inc();
}
callback.onEnd();
return top;
}
public Collection<Order> getOrders(Vendor vendor, double balance) {
Collection<Place> places = getPlaces();
Graph<Place> graph = new Graph<Place>(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new);
Graph<Place> graph = new Graph<Place>(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph());
return getOrders(graph, Collections.singleton(vendor), balance, 0);
}
@@ -78,18 +92,22 @@ public class MarketAnalyzer {
private Collection<Order> getOrders(Place place, double balance, double lowProfit) {
Collection<Place> places = getPlaces();
Graph<Place> graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new);
Graph<Place> graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph());
return getOrders(graph, place.get(), balance, lowProfit);
}
private Collection<Order> getOrders(Graph<Place> graph, Collection<Vendor> sellers, double balance, double lowProfit) {
List<Order> res = new ArrayList<>(20);
callback.setCount(sellers.size());
for (Vendor vendor : sellers) {
if (callback.isCancel()) break;
if (isFiltered(vendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
for (Offer sell : vendor.getAllSellOffers()) {
if (callback.isCancel()) break;
LOG.trace("Sell offer {}", sell);
if (sell.getCount() == 0) continue;
long count = Order.getMaxCount(sell, balance, cargo);
@@ -97,6 +115,7 @@ public class MarketAnalyzer {
if (count == 0) continue;
Iterator<Offer> buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator();
while (buyers.hasNext()){
if (callback.isCancel()) break;
Offer buy = buyers.next();
if (isFiltered(buy.getVendor())){
LOG.trace("Is filtered, skip");
@@ -116,6 +135,7 @@ public class MarketAnalyzer {
res.add(order);
}
}
callback.inc();
}
res.sort(orderComparator);
return res;
@@ -123,17 +143,22 @@ public class MarketAnalyzer {
private Collection<Order> getOrders(Collection<Vendor> sellers, Collection<Vendor> buyers, double balance, double lowProfit) {
List<Order> res = new ArrayList<>();
callback.setCount(sellers.size());
for (Vendor seller : sellers) {
if (callback.isCancel()) break;
if (isFiltered(seller)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
for (Offer sell : seller.getAllSellOffers()) {
if (callback.isCancel()) break;
if (sell.getCount() == 0) continue;
long count = Order.getMaxCount(sell, balance, cargo);
LOG.trace("Sell offer {}, count = {}", sell, count);
if (count == 0) continue;
for (Vendor buyer : buyers) {
if (callback.isCancel()) break;
if (isFiltered(buyer)){
LOG.trace("Is filtered, skip");
continue;
@@ -150,6 +175,7 @@ public class MarketAnalyzer {
}
}
}
callback.inc();
}
res.sort(orderComparator);
return res;
@@ -209,98 +235,131 @@ public class MarketAnalyzer {
}
public Collection<PathRoute> getPaths(Vendor from, double balance){
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
callback.setCount(1);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
Collection<Vendor> vendors = getVendors();
return searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
Collection<PathRoute> res = searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
callback.inc();
callback.onEndSearch();
return res;
}
public Collection<PathRoute> getPaths(Place from, double balance){
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
List<PathRoute> top = new ArrayList<>(limit);
Collection<Vendor> vendors = getVendors();
callback.setCount(vendors.size());
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
for (Vendor vendor : from.get()) {
if (callback.isCancel()) break;
if (isFiltered(vendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
Collection<PathRoute> paths = searcher.getPaths(vendor, vendors, jumps, balance, cargo, limit);
if (paths.size()>0){
return paths;
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
callback.inc();
}
}
return Collections.emptyList();
callback.onEndSearch();
return top;
}
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
return searcher.getPaths(from, to, getVendors(), jumps, balance, cargo, limit);
callback.setCount(1);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
Collection<PathRoute> res = searcher.getPaths(from, to, getVendors(), jumps, balance, cargo, limit);
callback.inc();
callback.onEndSearch();
return res;
}
public Collection<PathRoute> getPaths(Place from, Place to, double balance){
List<PathRoute> top = new ArrayList<>(limit);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
Collection<Vendor> vendors = getVendors();
Collection<Vendor> fVendors = from.get();
Collection<Vendor> toVendors = to.get();
int count = (int) Math.ceil(limit / fVendors.size());
callback.setCount(fVendors.size() * toVendors.size());
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
for (Vendor fromVendor : fVendors) {
if (callback.isCancel()) break;
if (isFiltered(fromVendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
for (Vendor toVendor : toVendors) {
if (callback.isCancel()) break;
if (isFiltered(toVendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
Collection<PathRoute> paths = searcher.getPaths(fromVendor, toVendor, vendors, jumps, balance, cargo, count);
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
callback.inc();
}
}
callback.onEndSearch();
return top;
}
public Collection<PathRoute> getPaths(Vendor from, Place to, double balance){
List<PathRoute> top = new ArrayList<>(limit);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
Collection<Vendor> vendors = getVendors();
Collection<Vendor> toVendors = to.get();
int count = (int) Math.ceil(limit / toVendors.size());
callback.setCount(toVendors.size());
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
for (Vendor toVendor : toVendors) {
if (callback.isCancel()) break;
if (isFiltered(toVendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
Collection<PathRoute> paths = searcher.getPaths(from, toVendor, vendors, jumps, balance, cargo, count);
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
callback.inc();
}
callback.onEndSearch();
return top;
}
public Collection<PathRoute> getPaths(Place from, Vendor to, double balance){
List<PathRoute> top = new ArrayList<>(limit);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
Collection<Vendor> vendors = getVendors();
Collection<Vendor> fVendors = from.get();
int count = (int) Math.ceil(limit / fVendors.size());
callback.setCount(fVendors.size());
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
for (Vendor fromVendor : fVendors) {
if (callback.isCancel()) break;
if (isFiltered(fromVendor)){
LOG.trace("Is filtered, skip");
callback.inc();
continue;
}
Collection<PathRoute> paths = searcher.getPaths(fromVendor, to, vendors, jumps, balance, cargo, count);
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
callback.inc();
}
callback.onEndSearch();
return top;
}
public Collection<PathRoute> getTopPaths(double balance){
List<PathRoute> top = new ArrayList<>(limit);
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
Collection<Vendor> vendors = getVendors();
callback.setCount(vendors.size());
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
for (Vendor vendor : vendors) {
if (callback.isCancel()) break;
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
callback.inc();
}
callback.onEndSearch();
return top;
}

View File

@@ -0,0 +1,62 @@
package ru.trader.core;
import ru.trader.graph.GraphCallBack;
import ru.trader.graph.RouteSearcherCallBack;
public class MarketAnalyzerCallBack {
private volatile boolean cancel = false;
private RouteSearcherCallBack callbackRoute;
private GraphCallBack<Place> callbackGraph;
protected RouteSearcherCallBack getRouteSearcherCallBackInstance(){
return new RouteSearcherCallBack();
}
protected GraphCallBack<Place> getGraphCallBackInstance(){
return new GraphCallBack<>();
}
public final GraphCallBack<Place> onStartGraph(){
callbackGraph = getGraphCallBackInstance();
return callbackGraph;
}
public final void onEndGraph(){
callbackGraph = null;
}
public final RouteSearcherCallBack onStartSearch(){
callbackRoute = getRouteSearcherCallBackInstance();
return callbackRoute;
}
public final void onEndSearch(){
callbackRoute = null;
onEnd();
}
protected void onEnd(){}
public void setCount(long count){}
public void inc(){}
public final boolean isCancel() {
return cancel;
}
public final void cancel(){
if (cancel) return;
this.cancel = true;
if (callbackRoute != null){
callbackRoute.cancel();
callbackRoute = null;
}
if (callbackGraph != null){
callbackGraph.cancel();
callbackGraph = null;
}
}
}

View File

@@ -23,6 +23,7 @@ public class Graph<T extends Connectable<T>> {
protected final Vertex<T> root;
protected final Map<T,Vertex<T>> vertexes;
private final GraphCallBack<T> callback;
protected final double stock;
protected final double maxDistance;
@@ -48,15 +49,22 @@ public class Graph<T extends Connectable<T>> {
}
public Graph(T start, Collection<T> set, double stock, double maxDistance, boolean withRefill, int maxDeep, PathConstructor<T> pathFabric) {
this(start, set, stock, maxDistance, withRefill, maxDeep, pathFabric, new GraphCallBack<>());
}
public Graph(T start, Collection<T> set, double stock, double maxDistance, boolean withRefill, int maxDeep, PathConstructor<T> pathFabric, GraphCallBack<T> callback) {
this.maxDistance = maxDistance;
this.stock = stock;
this.withRefill = withRefill;
this.pathFabric = pathFabric;
this.callback = callback;
root = new Vertex<>(start);
root.setLevel(maxDeep);
vertexes = new ConcurrentHashMap<>(50, 0.9f, THRESHOLD);
vertexes.put(root.getEntry(), root);
callback.onStartBuild(start);
build(root, set, maxDeep, stock);
callback.onEndBuild();
}
private void build(Vertex<T> root, Collection<T> set, int maxDeep, double stock) {
@@ -81,7 +89,9 @@ public class Graph<T extends Connectable<T>> {
}
private void findPathsTo(Vertex<T> target, TopList<Path<T>> res, int deep){
callback.onStartFind(root, target);
POOL.invoke(new PathFinder(res, pathFabric.build(root), target, deep-1, stock));
callback.onEndFind();
}
public List<Path<T>> getPathsTo(T entry){
@@ -95,7 +105,9 @@ public class Graph<T extends Connectable<T>> {
public TopList<Path<T>> getPathsTo(T entry, int max, int deep){
Vertex<T> target = getVertex(entry);
TopList<Path<T>> paths = newTopList(max);
callback.setCount(1);
findPathsTo(target, paths, deep);
callback.inc();
paths.finish();
return paths;
}
@@ -106,12 +118,15 @@ public class Graph<T extends Connectable<T>> {
public TopList<Path<T>> getPaths(int count, int deep){
TopList<Path<T>> paths = newTopList(count);
callback.setCount(vertexes.size());
for (Vertex<T> target : vertexes.values()) {
if (callback.isCancel()) break;
TopList<Path<T>> p = newTopList(minJumps);
findPathsTo(target, p, deep);
for (Path<T> path : p.getList()) {
paths.add(path);
}
callback.inc();
}
paths.finish();
return paths;
@@ -204,6 +219,7 @@ public class Graph<T extends Connectable<T>> {
ArrayList<GraphBuilder> subTasks = new ArrayList<>(set.size());
Iterator<T> iterator = set.iterator();
while (iterator.hasNext()) {
if (callback.isCancel()) break;
T entry = iterator.next();
if (entry == vertex.getEntry()) continue;
double distance = vertex.getEntry().getDistance(entry);
@@ -236,15 +252,23 @@ public class Graph<T extends Connectable<T>> {
}
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
for (GraphBuilder subTask : subTasks) {
if (callback.isCancel()){
subTask.cancel(true);
} else {
subTask.join();
}
}
subTasks.clear();
}
}
if (!subTasks.isEmpty()){
for (GraphBuilder subTask : subTasks) {
if (callback.isCancel()){
subTask.cancel(true);
} else {
subTask.join();
}
}
subTasks.clear();
}
LOG.trace("End build graph from {} on deep {}", vertex, deep);
@@ -282,6 +306,7 @@ public class Graph<T extends Connectable<T>> {
synchronized (paths){
if (!paths.add(path)) complete(null);
}
callback.onFound();
}
}
if (deep > 0 ){
@@ -291,7 +316,7 @@ public class Graph<T extends Connectable<T>> {
Iterator<Edge<T>> iterator = source.getEdges().iterator();
while (iterator.hasNext()) {
Edge<T> next = iterator.next();
if (isDone()) break;
if (isDone() || callback.isCancel()) break;
// target already added if source consist edge
if (next.isConnect(target)) continue;
if (!distanceFilter.test(next.getLength())) continue;
@@ -305,8 +330,8 @@ public class Graph<T extends Connectable<T>> {
subTasks.add(task);
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
for (PathFinder subTask : subTasks) {
if (isDone()) {
subTask.cancel(false);
if (isDone() || callback.isCancel()) {
subTask.cancel(callback.isCancel());
} else {
subTask.join();
}
@@ -316,8 +341,8 @@ public class Graph<T extends Connectable<T>> {
}
if (!subTasks.isEmpty()){
for (PathFinder subTask : subTasks) {
if (isDone()) {
subTask.cancel(false);
if (isDone() || callback.isCancel()) {
subTask.cancel(callback.isCancel());
} else {
subTask.join();
}

View File

@@ -0,0 +1,27 @@
package ru.trader.graph;
public class GraphCallBack<T extends Connectable<T>> {
private volatile boolean cancel = false;
public void onStartBuild(T from){}
public void onEndBuild(){}
public void onStartFind(Vertex<T> from, Vertex<T> to){}
public void onFound(){}
public void onEndFind(){}
public void setCount(long count){}
public void inc(){}
public final boolean isCancel() {
return cancel;
}
public final void cancel(){
this.cancel = true;
}
}

View File

@@ -31,9 +31,12 @@ public class RouteGraph extends Graph<Vendor> {
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep) {
this(start, set, stock, maxDistance, withRefill, maxDeep, false);
}
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep, boolean groupRes) {
super(start, set, stock, maxDistance, withRefill, maxDeep, groupRes ? PathRoute::buildAvg : PathRoute::new);
this(start, set, stock, maxDistance, withRefill, maxDeep, groupRes, new GraphCallBack<>());
}
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep, boolean groupRes, GraphCallBack<Vendor> callback) {
super(start, set, stock, maxDistance, withRefill, maxDeep, groupRes ? PathRoute::buildAvg : PathRoute::new, callback);
if (groupRes){
this.groupRes = maxDeep > minJumps;
}

View File

@@ -14,17 +14,19 @@ public class RouteSearcher {
private final static ForkJoinPool POOL = new ForkJoinPool();
private final static int THRESHOLD = (int) Math.ceil(Runtime.getRuntime().availableProcessors()/2.0);
private final RouteSearcherCallBack callback;
private final double maxDistance;
private final double stock;
private final int segmentSize;
public RouteSearcher(double maxDistance, double stock) {
this(maxDistance, stock, 0);
this(maxDistance, stock, 0, new RouteSearcherCallBack());
}
public RouteSearcher(double maxDistance, double stock, int segmentSize) {
public RouteSearcher(double maxDistance, double stock, int segmentSize, RouteSearcherCallBack callback) {
this.maxDistance = maxDistance;
this.stock = stock;
this.segmentSize = segmentSize;
this.callback = callback;
}
public List<PathRoute> getPaths(Vendor from, Vendor to, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
@@ -56,8 +58,10 @@ public class RouteSearcher {
@Override
protected List<PathRoute> compute() {
if (callback.isCancel()) return Collections.emptyList();
LOG.trace("Start search route to {} from {}, jumps {}", source, target, jumps);
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, jumps, true);
GraphCallBack<Vendor> gCallBack = callback.onStart();
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, jumps, true, gCallBack);
int jumpsToAll = sGraph.getMinJumps();
LOG.trace("Segment jumps {}", jumpsToAll);
sGraph.setCargo(cargo);
@@ -87,8 +91,10 @@ public class RouteSearcher {
res.add(path);
}
}
if (callback.isCancel()) break;
subTasks.clear();
for (int taskIndex = 0; taskIndex < THRESHOLD && i+taskIndex < paths.size(); taskIndex++) {
if (callback.isCancel()) break;
PathRoute path = (PathRoute) paths.get(i+taskIndex);
double newBalance = balance + path.getRoot().getProfit();
SegmentSearcher task = new SegmentSearcher(path.get(), target, vendors, jumps - path.getLength(), newBalance, cargo, 1);
@@ -103,6 +109,7 @@ public class RouteSearcher {
}
}
res.finish();
callback.onEnd(gCallBack);
return res.getList();
}
@@ -116,6 +123,10 @@ public class RouteSearcher {
private void add(SegmentSearcher task, PathRoute path, TopList<PathRoute> res){
if (callback.isCancel()){
task.cancel(true);
return;
}
List<PathRoute> tail = task.join();
if (tail.isEmpty()){
LOG.trace("Not found route from {} to {}, jumps {}", task.source, task.target, task.jumps);

View File

@@ -0,0 +1,44 @@
package ru.trader.graph;
import ru.trader.core.Vendor;
import java.util.LinkedList;
import java.util.List;
public class RouteSearcherCallBack {
private volatile boolean cancel = false;
private final List<GraphCallBack<Vendor>> callbacks = new LinkedList<>();
public final GraphCallBack<Vendor> onStart(){
GraphCallBack<Vendor> callback = getGraphCallBackInstance();
if (cancel) return callback;
synchronized (callbacks) {
callbacks.add(callback);
}
return callback;
}
public final void onEnd( GraphCallBack<Vendor> callback){
synchronized (callbacks) {
callbacks.remove(callback);
}
}
protected GraphCallBack<Vendor> getGraphCallBackInstance(){
return new GraphCallBack<>();
}
public final boolean isCancel() {
return cancel;
}
public final void cancel(){
if (cancel) return;
this.cancel = true;
synchronized (callbacks){
callbacks.forEach(GraphCallBack::cancel);
callbacks.clear();
}
}
}