Archived
0

implement auto update from EMDN

This commit is contained in:
iMoHax
2014-09-03 16:31:30 +04:00
parent d820666b09
commit 0167b3d52d
10 changed files with 527 additions and 320 deletions

View File

@@ -0,0 +1,137 @@
package ru.trader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.controllers.MainController;
import ru.trader.emdn.EMDN;
import ru.trader.emdn.ItemData;
import ru.trader.emdn.Station;
import ru.trader.model.MarketModel;
import ru.trader.model.support.VendorUpdater;
import java.util.concurrent.*;
public class EMDNUpdater {
private final static Logger LOG = LoggerFactory.getLogger(EMDNUpdater.class);
private final static EMDN emdn = new EMDN();
private static ScheduledExecutorService executor;
private static ScheduledFuture<?> autoupdate;
private static MarketModel market;
private static EMDNUpdate emdnUpdater;
private static long interval;
public static void updateFromEMDN(VendorUpdater updater){
Station emdnData = emdn.getVendor(updater.getName());
LOG.debug("Update {} from EMDN", updater.getName());
if (emdnData == null){
LOG.trace("Not found in EMDN");
return;
}
for (VendorUpdater.FakeOffer offer : updater.getOffers()) {
if (offer.getItem().isMarketItem()){
ItemData data = emdnData.getData(offer.getItem().getId());
LOG.debug("Update item {} to {}", offer.getItem().getName(), data);
if (data != null){
offer.setSprice(data.getBuy());
offer.setBprice(data.getSell());
} else {
offer.setSprice(0);
offer.setBprice(0);
}
} else {
LOG.trace("Is not market item, skip");
}
}
}
static void init(){
setMarket(MainController.getMarket());
setSub(Main.SETTINGS.getEMDNSub());
setActivate(Main.SETTINGS.getEMDNActive());
setUpdateOnly(Main.SETTINGS.getEMDNUpdateOnly());
if (emdn.isActive())
setInterval(Main.SETTINGS.getEMDNAutoUpdate());
}
public static void shutdown(){
if (executor != null) {
LOG.debug("Shutdown auto update");
autoupdate.cancel(true);
executor.shutdown();
}
emdn.shutdown();
}
public static void setMarket(MarketModel market) {
EMDNUpdater.market = market;
EMDNUpdate old = emdnUpdater;
emdnUpdater = new EMDNUpdate();
if (old != null){
setUpdateOnly(old.updater.isUpdateOnly());
}
if (executor != null){
setInterval(interval);
}
}
public static void setSub(String subServer){
emdn.connectTo(subServer);
}
public static void setActivate(boolean activate){
if (activate) {
emdn.start();
}
else {
emdn.shutdown();
setInterval(0);
}
}
public static void setUpdateOnly(boolean updateOnly) {
emdnUpdater.updater.setUpdateOnly(updateOnly);
}
public static void setInterval(long interval) {
if (emdn.isActive()){
if (interval > 0) {
if (executor != null){
LOG.debug("Cancel previous auto update");
autoupdate.cancel(true);
}
if (executor == null) executor = Executors.newSingleThreadScheduledExecutor();
LOG.debug("Start auto update each {} sec", interval);
autoupdate = executor.scheduleAtFixedRate(emdnUpdater, interval, interval, TimeUnit.SECONDS);
} else {
if (executor != null){
LOG.debug("Stop auto update");
autoupdate.cancel(true);
executor.shutdown();
executor = null;
}
}
}
EMDNUpdater.interval = interval;
}
private static class EMDNUpdate implements Runnable {
private final VendorUpdater updater;
private EMDNUpdate() {
updater = new VendorUpdater(market);
}
@Override
public void run() {
market.vendorsProperty().get().forEach((vendor) -> {
LOG.trace("Auto update {}", vendor);
updater.reset();
updater.init(vendor);
updateFromEMDN(updater);
updater.commit();
});
}
}
}

View File

@@ -29,10 +29,10 @@ public class Main extends Application {
public void start(Stage primaryStage) throws Exception { public void start(Stage primaryStage) throws Exception {
SETTINGS = new Settings(new File("profile.properties")); SETTINGS = new Settings(new File("profile.properties"));
SETTINGS.load(); SETTINGS.load();
World.start();
Main.primaryStage = primaryStage; Main.primaryStage = primaryStage;
loadMainScene(); loadMainScene();
loadResources(); loadResources();
EMDNUpdater.init();
primaryStage.show(); primaryStage.show();
} }
@@ -73,7 +73,7 @@ public class Main extends Application {
if (res == Dialog.Actions.YES) World.save(); if (res == Dialog.Actions.YES) World.save();
else if (res == Dialog.Actions.CANCEL) we.consume(); else if (res == Dialog.Actions.CANCEL) we.consume();
} }
World.shutdown(); EMDNUpdater.shutdown();
SETTINGS.save(); SETTINGS.save();
Screeners.closeAll(); Screeners.closeAll();
} catch (FileNotFoundException | UnsupportedEncodingException | XMLStreamException e) { } catch (FileNotFoundException | UnsupportedEncodingException | XMLStreamException e) {

View File

@@ -19,7 +19,6 @@ import java.io.UnsupportedEncodingException;
public class World { public class World {
private static Market world; private static Market world;
private static final String STORE_FILE="world.xml"; private static final String STORE_FILE="world.xml";
private final static EMDN emdn = new EMDN();
static { static {
try { try {
@@ -46,28 +45,4 @@ public class World {
public static Market getMarket() { public static Market getMarket() {
return world; return world;
} }
public static Station getEMDN(String name){
return emdn.getVendor(name);
}
private static void initEmdn(){
emdn.connectTo(Main.SETTINGS.getEMDNSub());
if (Main.SETTINGS.getEMDNActive()){
emdn.start();
}
}
public static EMDN getEmdn(){
return emdn;
}
public static void start(){
initEmdn();
}
public static void shutdown(){
emdn.shutdown();
}
} }

View File

@@ -11,6 +11,7 @@ import org.controlsfx.control.action.Action;
import org.controlsfx.dialog.Dialog; import org.controlsfx.dialog.Dialog;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ru.trader.EMDNUpdater;
import ru.trader.Main; import ru.trader.Main;
import ru.trader.World; import ru.trader.World;
import ru.trader.emdn.EMDN; import ru.trader.emdn.EMDN;
@@ -30,14 +31,6 @@ public class SettingsController {
@FXML @FXML
private NumberField emdnUpdateTime; private NumberField emdnUpdateTime;
@FXML
private void initialize(){
emdnOn.setSelected(Main.SETTINGS.getEMDNActive());
emdnSubServ.setText(Main.SETTINGS.getEMDNSub());
emdnUpdateOnly.setSelected(Main.SETTINGS.getEMDNUpdateOnly());
emdnUpdateTime.setValue(Main.SETTINGS.getEMDNAutoUpdate());
}
private final Action actSave = new AbstractAction(Localization.getString("dialog.button.save")) { private final Action actSave = new AbstractAction(Localization.getString("dialog.button.save")) {
{ {
ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE); ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE);
@@ -51,21 +44,31 @@ public class SettingsController {
} }
}; };
private void save() { @FXML
Main.SETTINGS.setEMDNActive(emdnOn.isSelected()); private void initialize(){
Main.SETTINGS.setEMDNSub(emdnSubServ.getText()); init();
Main.SETTINGS.setEMDNUpdateOnly(emdnUpdateOnly.isSelected());
Main.SETTINGS.setEMDNAutoUpdate(emdnUpdateTime.getValue().longValue());
EMDN emdn = World.getEmdn();
emdn.connectTo(emdnSubServ.getText());
if (emdnOn.isSelected()){
emdn.start();
} else {
emdn.shutdown();
} }
private void init(){
emdnSubServ.setText(Main.SETTINGS.getEMDNSub());
emdnOn.setSelected(Main.SETTINGS.getEMDNActive());
emdnUpdateOnly.setSelected(Main.SETTINGS.getEMDNUpdateOnly());
emdnUpdateTime.setValue(Main.SETTINGS.getEMDNAutoUpdate());
}
private void save() {
Main.SETTINGS.setEMDNSub(emdnSubServ.getText());
EMDNUpdater.setSub(emdnSubServ.getText());
Main.SETTINGS.setEMDNActive(emdnOn.isSelected());
EMDNUpdater.setActivate(emdnOn.isSelected());
Main.SETTINGS.setEMDNUpdateOnly(emdnUpdateOnly.isSelected());
EMDNUpdater.setUpdateOnly(emdnUpdateOnly.isSelected());
Main.SETTINGS.setEMDNAutoUpdate(emdnUpdateTime.getValue().longValue());
EMDNUpdater.setInterval(emdnUpdateTime.getValue().longValue());
} }
public Action showDialog(Parent parent, Parent content){ public Action showDialog(Parent parent, Parent content){
init();
Dialog dlg = new Dialog(parent, Localization.getString("settings.title")); Dialog dlg = new Dialog(parent, Localization.getString("settings.title"));
dlg.setContent(content); dlg.setContent(content);
dlg.getActions().addAll(actSave, Dialog.Actions.CANCEL); dlg.getActions().addAll(actSave, Dialog.Actions.CANCEL);

View File

@@ -1,8 +1,5 @@
package ru.trader.controllers; package ru.trader.controllers;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.Parent; import javafx.scene.Parent;
@@ -16,12 +13,11 @@ import org.controlsfx.dialog.DefaultDialogAction;
import org.controlsfx.dialog.Dialog; import org.controlsfx.dialog.Dialog;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ru.trader.World; import ru.trader.EMDNUpdater;
import ru.trader.core.OFFER_TYPE;
import ru.trader.emdn.ItemData; import ru.trader.emdn.ItemData;
import ru.trader.emdn.Station; import ru.trader.emdn.Station;
import ru.trader.model.*; import ru.trader.model.*;
import ru.trader.model.support.BindingsHelper; import ru.trader.model.support.VendorUpdater;
import ru.trader.view.support.Localization; import ru.trader.view.support.Localization;
import ru.trader.view.support.NumberField; import ru.trader.view.support.NumberField;
import ru.trader.view.support.PriceStringConverter; import ru.trader.view.support.PriceStringConverter;
@@ -34,8 +30,6 @@ import java.util.Optional;
public class VendorEditorController { public class VendorEditorController {
private final static Logger LOG = LoggerFactory.getLogger(VendorEditorController.class); private final static Logger LOG = LoggerFactory.getLogger(VendorEditorController.class);
private VendorModel vendor;
private final Action actSave = new AbstractAction(Localization.getString("dialog.button.save")) { private final Action actSave = new AbstractAction(Localization.getString("dialog.button.save")) {
{ {
ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE); ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE);
@@ -45,7 +39,8 @@ public class VendorEditorController {
public void handle(ActionEvent event) { public void handle(ActionEvent event) {
Dialog dlg = (Dialog) event.getSource(); Dialog dlg = (Dialog) event.getSource();
items.getSelectionModel().selectFirst(); items.getSelectionModel().selectFirst();
saveChanges(); updater.commit();
items.getSelectionModel().clearSelection();
dlg.hide(); dlg.hide();
} }
}; };
@@ -58,6 +53,7 @@ public class VendorEditorController {
@Override @Override
public void handle(ActionEvent event) { public void handle(ActionEvent event) {
items.getSelectionModel().selectFirst(); items.getSelectionModel().selectFirst();
items.getSelectionModel().clearSelection();
super.handle(event); super.handle(event);
} }
}; };
@@ -66,11 +62,11 @@ public class VendorEditorController {
private TextField name; private TextField name;
@FXML @FXML
private TableView<FakeOffer> items; private TableView<VendorUpdater.FakeOffer> items;
@FXML @FXML
private TableColumn<FakeOffer, Double> buy; private TableColumn<VendorUpdater.FakeOffer, Double> buy;
@FXML @FXML
private TableColumn<FakeOffer, Double> sell; private TableColumn<VendorUpdater.FakeOffer, Double> sell;
@FXML @FXML
private NumberField x; private NumberField x;
@@ -79,6 +75,8 @@ public class VendorEditorController {
@FXML @FXML
private NumberField z; private NumberField z;
private VendorUpdater updater;
@FXML @FXML
private void initialize() { private void initialize() {
@@ -86,7 +84,6 @@ public class VendorEditorController {
buy.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), false)); buy.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), false));
sell.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), true)); sell.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), true));
actSave.disabledProperty().bind(x.wrongProperty().or(y.wrongProperty().or(z.wrongProperty()))); actSave.disabledProperty().bind(x.wrongProperty().or(y.wrongProperty().or(z.wrongProperty())));
fillItems();
name.setOnAction((v)->x.requestFocus()); name.setOnAction((v)->x.requestFocus());
x.setOnAction((v) -> z.requestFocus()); x.setOnAction((v) -> z.requestFocus());
z.setOnAction((v) -> y.requestFocus()); z.setOnAction((v) -> y.requestFocus());
@@ -94,14 +91,21 @@ public class VendorEditorController {
items.requestFocus(); items.requestFocus();
items.getSelectionModel().select(0, buy); items.getSelectionModel().select(0, buy);
}); });
init();
}
private void init(){
updater = new VendorUpdater(MainController.getMarket());
name.textProperty().bindBidirectional(updater.nameProperty());
x.numberProperty().bindBidirectional(updater.xProperty());
y.numberProperty().bindBidirectional(updater.yProperty());
z.numberProperty().bindBidirectional(updater.zProperty());
items.setItems(updater.getOffers());
} }
public Action showDialog(Parent parent, Parent content, VendorModel vendor){ public Action showDialog(Parent parent, Parent content, VendorModel vendor){
this.vendor = vendor; updater.reset();
reset(); updater.init(vendor);
if (vendor != null) {
fill();
}
Dialog dlg = new Dialog(parent, Localization.getString(vendor == null ? "vEditor.title.add" : "vEditor.title.edit")); Dialog dlg = new Dialog(parent, Localization.getString(vendor == null ? "vEditor.title.add" : "vEditor.title.edit"));
dlg.setContent(content); dlg.setContent(content);
dlg.getActions().addAll(actSave, actCancel); dlg.getActions().addAll(actSave, actCancel);
@@ -109,50 +113,10 @@ public class VendorEditorController {
return dlg.show(); return dlg.show();
} }
private void fill(){
name.setText(vendor.getName());
x.setValue(vendor.getX());
y.setValue(vendor.getY());
z.setValue(vendor.getZ());
vendor.getSells().forEach(this::fillOffer);
vendor.getBuys().forEach(this::fillOffer);
}
private void reset(){
name.setText("");
x.setValue(0);
y.setValue(0);
z.setValue(0);
items.getItems().forEach(FakeOffer::reset);
items.getSelectionModel().clearSelection();
}
private void fillItems() {
items.setItems(BindingsHelper.observableList(MainController.getMarket().itemsProperty(), (item) -> new FakeOffer(item.getItem())));
}
private void fillOffer(OfferModel offer) {
for (FakeOffer o : items.getItems()) {
if (offer.hasItem(o.item)) {
switch (offer.getType()) {
case SELL:
o.setSell(offer);
break;
case BUY:
o.setBuy(offer);
break;
}
return;
}
}
}
public void up(){ public void up(){
int index = items.getSelectionModel().getSelectedIndex(); int index = items.getSelectionModel().getSelectedIndex();
if (index>0){ if (index>0){
FakeOffer offer = items.getItems().remove(index); VendorUpdater.FakeOffer offer = items.getItems().remove(index);
items.getItems().add(index-1, offer); items.getItems().add(index-1, offer);
selectRow(index - 1); selectRow(index - 1);
} }
@@ -161,7 +125,7 @@ public class VendorEditorController {
public void down(){ public void down(){
int index = items.getSelectionModel().getSelectedIndex(); int index = items.getSelectionModel().getSelectedIndex();
if (index>=0 && index<items.getItems().size()-1){ if (index>=0 && index<items.getItems().size()-1){
FakeOffer offer = items.getItems().remove(index); VendorUpdater.FakeOffer offer = items.getItems().remove(index);
items.getItems().add(index+1, offer); items.getItems().add(index+1, offer);
selectRow(index + 1); selectRow(index + 1);
} }
@@ -172,7 +136,7 @@ public class VendorEditorController {
if (item.isPresent()){ if (item.isPresent()){
int index = items.getSelectionModel().getSelectedIndex(); int index = items.getSelectionModel().getSelectedIndex();
if (index<0) index = items.getItems().size()-1; if (index<0) index = items.getItems().size()-1;
items.getItems().add(index, new FakeOffer(item.get())); updater.add(index, item.get());
selectRow(index); selectRow(index);
} }
} }
@@ -183,195 +147,7 @@ public class VendorEditorController {
ViewUtils.show(items, index); ViewUtils.show(items, index);
} }
public void saveChanges(){
LOG.info("Save vendor changes");
items.getSelectionModel().clearSelection();
final MarketModel market = MainController.getMarket();
if (vendor == null) {
market.setAlert(false);
vendor = market.newVendor(name.getText());
vendor.setPosition(x.getValue().doubleValue(), y.getValue().doubleValue(), z.getValue().doubleValue());
items.getItems().forEach((o) -> commit(market, vendor, o));
market.setAlert(true);
market.add(vendor);
} else {
vendor.setName(name.getText());
vendor.setPosition(x.getValue().doubleValue(), y.getValue().doubleValue(), z.getValue().doubleValue());
items.getItems().forEach((o) -> commit(market, vendor, o));
}
}
private void commit(MarketModel market, VendorModel vendor, FakeOffer offer){
LOG.trace("Commit changes of offers {}", offer);
if (offer.isBlank()){
LOG.trace("Is blank offer, skip");
return;
}
if (offer.isNewBuy()){
LOG.trace("Is new buy offer");
vendor.add(market.newOffer(OFFER_TYPE.BUY, offer.item, offer.getBprice()));
} else if (offer.isRemoveBuy()) {
LOG.trace("Is remove buy offer");
vendor.remove(offer.buy);
} else if (offer.isChangeBuy()){
LOG.trace("Is change buy price to {}", offer.getBprice());
offer.buy.setPrice(offer.getBprice());
} else {
LOG.trace("No change buy offer");
}
if (offer.isNewSell()){
LOG.trace("Is new sell offer");
vendor.add(market.newOffer(OFFER_TYPE.SELL, offer.item, offer.getSprice()));
} else if (offer.isRemoveSell()) {
LOG.trace("Is remove sell offer");
vendor.remove(offer.sell);
} else if (offer.isChangeSell()){
LOG.trace("Is change sell price to {}", offer.getSprice());
offer.sell.setPrice(offer.getSprice());
} else {
LOG.trace("No change sell offer");
}
}
public void updateFromEMDN(){ public void updateFromEMDN(){
Station emdnData = World.getEMDN(vendor.getName()); EMDNUpdater.updateFromEMDN(updater);
LOG.debug("Update {} from EMDN", vendor.getName());
if (emdnData == null){
LOG.trace("Not found in EMDN");
return;
}
for (FakeOffer offer : items.getItems()) {
if (offer.item.isMarketItem()){
ItemData data = emdnData.getData(offer.item.getId());
LOG.debug("Update item {} to {}", offer.item.getName(), data);
if (data != null){
offer.setSprice(data.getBuy());
offer.setBprice(data.getSell());
} else {
offer.setSprice(0);
offer.setBprice(0);
}
} else {
LOG.trace("Is not market item, skip");
}
}
}
public class FakeOffer {
private final ItemModel item;
private DoubleProperty sprice;
private DoubleProperty bprice;
private OfferModel sell;
private OfferModel buy;
public FakeOffer(ItemModel item){
this.item = item;
this.sprice = new SimpleDoubleProperty(0);
this.bprice = new SimpleDoubleProperty(0);
}
public ReadOnlyStringProperty nameProperty(){
return item.nameProperty();
}
public double getSprice() {
return sprice.get();
}
public void setSprice(double sprice) {
this.sprice.set(sprice);
}
public double getBprice() {
return bprice.get();
}
public void setBprice(double bprice) {
this.bprice.set(bprice);
}
public DoubleProperty bpriceProperty() {
return bprice;
}
public DoubleProperty spriceProperty() {
return sprice;
}
public boolean isChangeSell() {
return sell!=null && getSprice() != sell.getPrice();
}
public boolean isChangeBuy() {
return buy!=null && getBprice() != buy.getPrice();
}
public boolean isNewSell() {
return sell == null && getSprice() != 0;
}
public boolean isNewBuy() {
return buy == null && getBprice() != 0;
}
public boolean isRemoveSell() {
return sell != null && getSprice() ==0;
}
public boolean isRemoveBuy() {
return buy != null && getBprice() ==0;
}
public boolean isBlank(){
return sell == null && getSprice() == 0 && buy == null && getBprice() == 0;
}
public boolean hasItem(ItemModel item){
return this.item.equals(item);
}
public double getOldSprice() {
return sell != null ? sell.getPrice() : 0;
}
public double getOldBprice() {
return buy != null ? buy.getPrice() : 0;
}
public void setSell(OfferModel sell) {
this.sell = sell;
sprice.set(sell.getPrice());
}
public void setBuy(OfferModel buy) {
this.buy = buy;
bprice.set(buy.getPrice());
}
public void reset(){
this.sell = null;
this.buy = null;
sprice.setValue(0);
bprice.setValue(0);
}
@Override
public String toString() {
return "FakeOffer{" +
"item=" + item +
", sprice=" + sprice.get() +
", bprice=" + bprice.get() +
", sell=" + sell +
", buy=" + buy +
'}';
}
} }
} }

View File

@@ -0,0 +1,319 @@
package ru.trader.model.support;
import javafx.beans.property.*;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.controllers.MainController;
import ru.trader.core.OFFER_TYPE;
import ru.trader.model.ItemModel;
import ru.trader.model.MarketModel;
import ru.trader.model.OfferModel;
import ru.trader.model.VendorModel;
public class VendorUpdater {
private final static Logger LOG = LoggerFactory.getLogger(VendorUpdater.class);
private final ObservableList<FakeOffer> offers;
private final StringProperty name;
private final DoubleProperty x;
private final DoubleProperty y;
private final DoubleProperty z;
private final MarketModel market;
private VendorModel vendor;
private boolean updateOnly;
public VendorUpdater(MarketModel market) {
this.market = market;
this.offers = BindingsHelper.observableList(MainController.getMarket().itemsProperty(), (item) -> new FakeOffer(item.getItem()));
this.name = new SimpleStringProperty();
this.x = new SimpleDoubleProperty(0);
this.y = new SimpleDoubleProperty(0);
this.z = new SimpleDoubleProperty(0);
this.updateOnly = false;
}
public void init(VendorModel vendor){
LOG.debug("Init update of {}", vendor);
this.vendor = vendor;
if (vendor != null){
name.setValue(vendor.getName());
x.setValue(vendor.getX());
y.setValue(vendor.getY());
z.setValue(vendor.getZ());
vendor.getSells().forEach(this::fillOffer);
vendor.getBuys().forEach(this::fillOffer);
} else {
name.setValue("");
x.setValue(0);
y.setValue(0);
z.setValue(0);
}
}
private void fillOffer(OfferModel offer) {
for (FakeOffer o : offers) {
if (offer.hasItem(o.item)) {
switch (offer.getType()) {
case SELL:
o.setSell(offer);
break;
case BUY:
o.setBuy(offer);
break;
}
return;
}
}
}
public ObservableList<FakeOffer> getOffers() {
return offers;
}
public VendorModel getVendor() {
return vendor;
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public double getX() {
return x.get();
}
public DoubleProperty xProperty() {
return x;
}
public double getY() {
return y.get();
}
public DoubleProperty yProperty() {
return y;
}
public double getZ() {
return z.get();
}
public DoubleProperty zProperty() {
return z;
}
public void add(int index, ItemModel item){
offers.add(index, new FakeOffer(item));
}
public void commit(){
LOG.debug("Save changes of {}", vendor);
if (isNew()) {
market.setAlert(false);
vendor = market.newVendor(name.get());
vendor.setPosition(x.get(), y.get(), z.get());
offers.forEach(FakeOffer::commit);
market.setAlert(true);
market.add(vendor);
} else {
vendor.setName(name.get());
vendor.setPosition(x.get(), y.get(), z.get());
offers.forEach(FakeOffer::commit);
}
}
public void reset(){
offers.forEach(FakeOffer::reset);
vendor = null;
}
public boolean isNew() {
return vendor == null;
}
public void setUpdateOnly(boolean updateOnly) {
this.updateOnly = updateOnly;
}
public boolean isUpdateOnly() {
return updateOnly;
}
public class FakeOffer {
private final ItemModel item;
private DoubleProperty sprice;
private DoubleProperty bprice;
private OfferModel sell;
private OfferModel buy;
public FakeOffer(ItemModel item){
this.item = item;
this.sprice = new SimpleDoubleProperty(0);
this.bprice = new SimpleDoubleProperty(0);
}
public ReadOnlyStringProperty nameProperty(){
return item.nameProperty();
}
public double getSprice() {
return sprice.get();
}
public void setSprice(double sprice) {
this.sprice.set(sprice);
}
public double getBprice() {
return bprice.get();
}
public void setBprice(double bprice) {
this.bprice.set(bprice);
}
public DoubleProperty bpriceProperty() {
return bprice;
}
public DoubleProperty spriceProperty() {
return sprice;
}
public boolean isChangeSell() {
return sell!=null && getSprice() != sell.getPrice();
}
public boolean isChangeBuy() {
return buy!=null && getBprice() != buy.getPrice();
}
public boolean isNewSell() {
return sell == null && getSprice() != 0;
}
public boolean isNewBuy() {
return buy == null && getBprice() != 0;
}
public boolean isRemoveSell() {
return sell != null && getSprice() == 0;
}
public boolean isRemoveBuy() {
return buy != null && getBprice() == 0;
}
public boolean isBlank(){
return sell == null && getSprice() == 0 && buy == null && getBprice() == 0;
}
public boolean hasItem(ItemModel item){
return this.item.equals(item);
}
public ItemModel getItem() {
return item;
}
public double getOldSprice() {
return sell != null ? sell.getPrice() : 0;
}
public double getOldBprice() {
return buy != null ? buy.getPrice() : 0;
}
public void setSell(OfferModel sell) {
this.sell = sell;
sprice.set(sell.getPrice());
}
public void setBuy(OfferModel buy) {
this.buy = buy;
bprice.set(buy.getPrice());
}
public void reset(){
if (sell != null){
sell = null;
sprice.setValue(Double.NaN);
}
if (buy != null){
buy = null;
bprice.setValue(Double.NaN);
}
sprice.setValue(0);
bprice.setValue(0);
}
private void commit(){
LOG.trace("Commit changes of offers {}", this);
if (isBlank()){
LOG.trace("Is blank offer, skip");
return;
}
if (isNewBuy()){
LOG.trace("Is new buy offer");
if (updateOnly) {
LOG.trace("Is update only, skip");
} else {
vendor.add(market.newOffer(OFFER_TYPE.BUY, item, getBprice()));
}
} else if (isRemoveBuy()) {
LOG.trace("Is remove buy offer");
if (updateOnly) {
LOG.trace("Is update only, skip");
} else {
vendor.remove(buy);
}
} else if (isChangeBuy()){
LOG.trace("Is change buy price to {}", getBprice());
buy.setPrice(getBprice());
} else {
LOG.trace("No change buy offer");
}
if (isNewSell()){
LOG.trace("Is new sell offer");
if (updateOnly) {
LOG.trace("Is update only, skip");
} else {
vendor.add(market.newOffer(OFFER_TYPE.SELL, item, getSprice()));
}
} else if (isRemoveSell()) {
LOG.trace("Is remove sell offer");
if (updateOnly) {
LOG.trace("Is update only, skip");
} else {
vendor.remove(sell);
}
} else if (isChangeSell()){
LOG.trace("Is change sell price to {}", getSprice());
sell.setPrice(getSprice());
} else {
LOG.trace("No change sell offer");
}
}
@Override
public String toString() {
return "FakeOffer{" +
"item=" + item +
", sprice=" + sprice.get() +
", bprice=" + bprice.get() +
", sell=" + sell +
", buy=" + buy +
'}';
}
}
}

View File

@@ -1,14 +1,9 @@
package ru.trader.view.support.cells; package ru.trader.view.support.cells;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.TableCell; import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.text.Text; import javafx.scene.text.Text;
@@ -16,9 +11,9 @@ import javafx.util.Callback;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.controlsfx.glyphfont.Glyph; import org.controlsfx.glyphfont.Glyph;
import org.controlsfx.glyphfont.GlyphFontRegistry; import org.controlsfx.glyphfont.GlyphFontRegistry;
import ru.trader.controllers.VendorEditorController; import ru.trader.model.support.VendorUpdater;
public class EditOfferCell extends TextFieldCell<VendorEditorController.FakeOffer, Double> { public class EditOfferCell extends TextFieldCell<VendorUpdater.FakeOffer, Double> {
private final static String CSS_CHANGE = "change"; private final static String CSS_CHANGE = "change";
private final static String CSS_ADD = "add"; private final static String CSS_ADD = "add";
private final static String CSS_REMOVE = "remove"; private final static String CSS_REMOVE = "remove";
@@ -30,16 +25,16 @@ public class EditOfferCell extends TextFieldCell<VendorEditorController.FakeOffe
this.isSell = isSell; this.isSell = isSell;
} }
public static Callback<TableColumn<VendorEditorController.FakeOffer,Double>, TableCell<VendorEditorController.FakeOffer,Double>> forTable(final StringConverter<Double> converter, boolean isSell) { public static Callback<TableColumn<VendorUpdater.FakeOffer,Double>, TableCell<VendorUpdater.FakeOffer,Double>> forTable(final StringConverter<Double> converter, boolean isSell) {
return list -> new EditOfferCell(converter, isSell); return list -> new EditOfferCell(converter, isSell);
} }
@Override @Override
protected void outItem() { protected void outItem() {
VendorEditorController.FakeOffer offer = (VendorEditorController.FakeOffer) getTableRow().getItem(); VendorUpdater.FakeOffer offer = (VendorUpdater.FakeOffer) getTableRow().getItem();
double d = isSell? offer.getSprice() - offer.getOldSprice() : offer.getBprice() - offer.getOldBprice(); double d = isSell? offer.getSprice() - offer.getOldSprice() : offer.getBprice() - offer.getOldBprice();
getStyleClass().removeAll(CSS_ADD, CSS_CHANGE, CSS_REMOVE); getStyleClass().removeAll(CSS_ADD, CSS_CHANGE, CSS_REMOVE);
if (d!=0){ if (d !=0 ){
HBox hBox = new HBox(); HBox hBox = new HBox();
hBox.prefWidthProperty().bind(getTableColumn().widthProperty()); hBox.prefWidthProperty().bind(getTableColumn().widthProperty());
Text nTxt = new Text(getConverter().toString(isSell ? offer.getSprice() : offer.getBprice())); Text nTxt = new Text(getConverter().toString(isSell ? offer.getSprice() : offer.getBprice()));

View File

@@ -4,26 +4,27 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
public class ItemStat { public class ItemStat {
private final static Logger LOG = LoggerFactory.getLogger(ItemStat.class); private final static Logger LOG = LoggerFactory.getLogger(ItemStat.class);
private final Item item; private final Item item;
private final OFFER_TYPE type; private final OFFER_TYPE type;
private final TreeSet<Offer> offers; private final NavigableSet<Offer> offers;
private double sum; private volatile double sum;
private double avg; private volatile double avg;
public ItemStat(Item item, OFFER_TYPE offerType) { public ItemStat(Item item, OFFER_TYPE offerType) {
this.offers = new TreeSet<>(); this.offers = new ConcurrentSkipListSet<>();
this.item = item; this.item = item;
this.type = offerType; this.type = offerType;
this.sum = 0; this.sum = 0;
this.avg = Double.NaN; this.avg = Double.NaN;
} }
void put(Offer offer){ synchronized void put(Offer offer){
LOG.trace("Put offer {} to item stat {}", offer, this); LOG.trace("Put offer {} to item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item); assert offer.hasType(type) && offer.hasItem(item);
if (offers.add(offer)){ if (offers.add(offer)){
@@ -34,7 +35,7 @@ public class ItemStat {
} }
} }
void remove(Offer offer){ synchronized void remove(Offer offer){
LOG.trace("Remove offer {} from item stat {}", offer, this); LOG.trace("Remove offer {} from item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item); assert offer.hasType(type) && offer.hasItem(item);
if (offers.remove(offer)){ if (offers.remove(offer)){
@@ -49,7 +50,7 @@ public class ItemStat {
} }
} }
void update(Offer offer, double price){ synchronized void update(Offer offer, double price){
LOG.trace("Update offer {} from item stat {}", offer, this); LOG.trace("Update offer {} from item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item) && offers.contains(offer); assert offer.hasType(type) && offer.hasItem(item) && offers.contains(offer);
double oldPrice = offer.getPrice(); double oldPrice = offer.getPrice();
@@ -69,34 +70,34 @@ public class ItemStat {
return item; return item;
} }
public double getAvg(){ public synchronized double getAvg(){
return avg; return avg;
} }
public Offer getBest() { public synchronized Offer getBest() {
if (offers.isEmpty()) return getFake(); if (offers.isEmpty()) return getFake();
return type.getOrder() > 0 ? offers.first() : offers.last(); return type.getOrder() > 0 ? offers.first() : offers.last();
} }
public int getOffersCount(){ public synchronized int getOffersCount(){
return offers.size(); return offers.size();
} }
public NavigableSet<Offer> getOffers() { public synchronized NavigableSet<Offer> getOffers() {
return Collections.unmodifiableNavigableSet(offers); return Collections.unmodifiableNavigableSet(offers);
} }
public Offer getMin() { public synchronized Offer getMin() {
if (offers.isEmpty()) return getFake(); if (offers.isEmpty()) return getFake();
return offers.first(); return offers.first();
} }
public Offer getMax() { public synchronized Offer getMax() {
if (offers.isEmpty()) return getFake(); if (offers.isEmpty()) return getFake();
return offers.last(); return offers.last();
} }
public boolean isEmpty(){ public synchronized boolean isEmpty(){
return offers.isEmpty(); return offers.isEmpty();
} }

View File

@@ -12,7 +12,7 @@ public class Offer implements Comparable<Offer>{
private Vendor vendor; private Vendor vendor;
private final Item item; private final Item item;
private final OFFER_TYPE type; private final OFFER_TYPE type;
private double price; private volatile double price;
Offer(){ Offer(){
item = null; item = null;

View File

@@ -1,6 +1,7 @@
package ru.trader.core; package ru.trader.core;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class SimpleVendor extends Vendor { public class SimpleVendor extends Vendor {
@@ -18,8 +19,8 @@ public class SimpleVendor extends Vendor {
} }
protected void initOffers(){ protected void initOffers(){
sell = new HashMap<>(); sell = new ConcurrentHashMap<>(20, 0.9f, 2);
buy = new HashMap<>(); buy = new ConcurrentHashMap<>(20, 0.9f, 2);
} }
@Override @Override