diff --git a/client/src/main/java/ru/trader/EMDNUpdater.java b/client/src/main/java/ru/trader/EMDNUpdater.java new file mode 100644 index 0000000..09e10ef --- /dev/null +++ b/client/src/main/java/ru/trader/EMDNUpdater.java @@ -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(); + }); + } + } + + +} diff --git a/client/src/main/java/ru/trader/Main.java b/client/src/main/java/ru/trader/Main.java index 21bc57f..eb32c1d 100644 --- a/client/src/main/java/ru/trader/Main.java +++ b/client/src/main/java/ru/trader/Main.java @@ -29,10 +29,10 @@ public class Main extends Application { public void start(Stage primaryStage) throws Exception { SETTINGS = new Settings(new File("profile.properties")); SETTINGS.load(); - World.start(); Main.primaryStage = primaryStage; loadMainScene(); loadResources(); + EMDNUpdater.init(); primaryStage.show(); } @@ -73,7 +73,7 @@ public class Main extends Application { if (res == Dialog.Actions.YES) World.save(); else if (res == Dialog.Actions.CANCEL) we.consume(); } - World.shutdown(); + EMDNUpdater.shutdown(); SETTINGS.save(); Screeners.closeAll(); } catch (FileNotFoundException | UnsupportedEncodingException | XMLStreamException e) { diff --git a/client/src/main/java/ru/trader/World.java b/client/src/main/java/ru/trader/World.java index f430394..118ce9f 100644 --- a/client/src/main/java/ru/trader/World.java +++ b/client/src/main/java/ru/trader/World.java @@ -19,7 +19,6 @@ import java.io.UnsupportedEncodingException; public class World { private static Market world; private static final String STORE_FILE="world.xml"; - private final static EMDN emdn = new EMDN(); static { try { @@ -46,28 +45,4 @@ public class World { public static Market getMarket() { 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(); - } - } diff --git a/client/src/main/java/ru/trader/controllers/SettingsController.java b/client/src/main/java/ru/trader/controllers/SettingsController.java index 195a9e2..40f4745 100644 --- a/client/src/main/java/ru/trader/controllers/SettingsController.java +++ b/client/src/main/java/ru/trader/controllers/SettingsController.java @@ -11,6 +11,7 @@ import org.controlsfx.control.action.Action; import org.controlsfx.dialog.Dialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.trader.EMDNUpdater; import ru.trader.Main; import ru.trader.World; import ru.trader.emdn.EMDN; @@ -30,14 +31,6 @@ public class SettingsController { @FXML 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")) { { ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE); @@ -51,21 +44,31 @@ public class SettingsController { } }; + @FXML + private void initialize(){ + init(); + } + + 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.setEMDNActive(emdnOn.isSelected()); 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()); - EMDN emdn = World.getEmdn(); - emdn.connectTo(emdnSubServ.getText()); - if (emdnOn.isSelected()){ - emdn.start(); - } else { - emdn.shutdown(); - } + EMDNUpdater.setInterval(emdnUpdateTime.getValue().longValue()); } public Action showDialog(Parent parent, Parent content){ + init(); Dialog dlg = new Dialog(parent, Localization.getString("settings.title")); dlg.setContent(content); dlg.getActions().addAll(actSave, Dialog.Actions.CANCEL); diff --git a/client/src/main/java/ru/trader/controllers/VendorEditorController.java b/client/src/main/java/ru/trader/controllers/VendorEditorController.java index 4fc8d5c..a8fc0db 100644 --- a/client/src/main/java/ru/trader/controllers/VendorEditorController.java +++ b/client/src/main/java/ru/trader/controllers/VendorEditorController.java @@ -1,8 +1,5 @@ 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.fxml.FXML; import javafx.scene.Parent; @@ -16,12 +13,11 @@ import org.controlsfx.dialog.DefaultDialogAction; import org.controlsfx.dialog.Dialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.trader.World; -import ru.trader.core.OFFER_TYPE; +import ru.trader.EMDNUpdater; import ru.trader.emdn.ItemData; import ru.trader.emdn.Station; 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.NumberField; import ru.trader.view.support.PriceStringConverter; @@ -34,8 +30,6 @@ import java.util.Optional; public class VendorEditorController { private final static Logger LOG = LoggerFactory.getLogger(VendorEditorController.class); - private VendorModel vendor; - private final Action actSave = new AbstractAction(Localization.getString("dialog.button.save")) { { ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE); @@ -45,7 +39,8 @@ public class VendorEditorController { public void handle(ActionEvent event) { Dialog dlg = (Dialog) event.getSource(); items.getSelectionModel().selectFirst(); - saveChanges(); + updater.commit(); + items.getSelectionModel().clearSelection(); dlg.hide(); } }; @@ -58,6 +53,7 @@ public class VendorEditorController { @Override public void handle(ActionEvent event) { items.getSelectionModel().selectFirst(); + items.getSelectionModel().clearSelection(); super.handle(event); } }; @@ -66,11 +62,11 @@ public class VendorEditorController { private TextField name; @FXML - private TableView items; + private TableView items; @FXML - private TableColumn buy; + private TableColumn buy; @FXML - private TableColumn sell; + private TableColumn sell; @FXML private NumberField x; @@ -79,6 +75,8 @@ public class VendorEditorController { @FXML private NumberField z; + private VendorUpdater updater; + @FXML private void initialize() { @@ -86,7 +84,6 @@ public class VendorEditorController { buy.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), false)); sell.setCellFactory(EditOfferCell.forTable(new PriceStringConverter(), true)); actSave.disabledProperty().bind(x.wrongProperty().or(y.wrongProperty().or(z.wrongProperty()))); - fillItems(); name.setOnAction((v)->x.requestFocus()); x.setOnAction((v) -> z.requestFocus()); z.setOnAction((v) -> y.requestFocus()); @@ -94,14 +91,21 @@ public class VendorEditorController { items.requestFocus(); 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){ - this.vendor = vendor; - reset(); - if (vendor != null) { - fill(); - } + updater.reset(); + updater.init(vendor); Dialog dlg = new Dialog(parent, Localization.getString(vendor == null ? "vEditor.title.add" : "vEditor.title.edit")); dlg.setContent(content); dlg.getActions().addAll(actSave, actCancel); @@ -109,50 +113,10 @@ public class VendorEditorController { 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(){ int index = items.getSelectionModel().getSelectedIndex(); if (index>0){ - FakeOffer offer = items.getItems().remove(index); + VendorUpdater.FakeOffer offer = items.getItems().remove(index); items.getItems().add(index-1, offer); selectRow(index - 1); } @@ -161,7 +125,7 @@ public class VendorEditorController { public void down(){ int index = items.getSelectionModel().getSelectedIndex(); if (index>=0 && index 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(){ - Station emdnData = World.getEMDN(vendor.getName()); - 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 + - '}'; - } + EMDNUpdater.updateFromEMDN(updater); } } diff --git a/client/src/main/java/ru/trader/model/support/VendorUpdater.java b/client/src/main/java/ru/trader/model/support/VendorUpdater.java new file mode 100644 index 0000000..8d33516 --- /dev/null +++ b/client/src/main/java/ru/trader/model/support/VendorUpdater.java @@ -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 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 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 + + '}'; + } + } + +} diff --git a/client/src/main/java/ru/trader/view/support/cells/EditOfferCell.java b/client/src/main/java/ru/trader/view/support/cells/EditOfferCell.java index 4ac7e57..c06dbd1 100644 --- a/client/src/main/java/ru/trader/view/support/cells/EditOfferCell.java +++ b/client/src/main/java/ru/trader/view/support/cells/EditOfferCell.java @@ -1,14 +1,9 @@ package ru.trader.view.support.cells; import javafx.application.Platform; -import javafx.geometry.Pos; -import javafx.scene.Node; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; -import javafx.scene.control.TableRow; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Border; -import javafx.scene.layout.BorderStroke; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.text.Text; @@ -16,9 +11,9 @@ import javafx.util.Callback; import javafx.util.StringConverter; import org.controlsfx.glyphfont.Glyph; import org.controlsfx.glyphfont.GlyphFontRegistry; -import ru.trader.controllers.VendorEditorController; +import ru.trader.model.support.VendorUpdater; -public class EditOfferCell extends TextFieldCell { +public class EditOfferCell extends TextFieldCell { private final static String CSS_CHANGE = "change"; private final static String CSS_ADD = "add"; private final static String CSS_REMOVE = "remove"; @@ -30,16 +25,16 @@ public class EditOfferCell extends TextFieldCell, TableCell> forTable(final StringConverter converter, boolean isSell) { + public static Callback, TableCell> forTable(final StringConverter converter, boolean isSell) { return list -> new EditOfferCell(converter, isSell); } @Override 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(); getStyleClass().removeAll(CSS_ADD, CSS_CHANGE, CSS_REMOVE); - if (d!=0){ + if (d !=0 ){ HBox hBox = new HBox(); hBox.prefWidthProperty().bind(getTableColumn().widthProperty()); Text nTxt = new Text(getConverter().toString(isSell ? offer.getSprice() : offer.getBprice())); diff --git a/core/src/main/java/ru/trader/core/ItemStat.java b/core/src/main/java/ru/trader/core/ItemStat.java index 099c828..12f5031 100644 --- a/core/src/main/java/ru/trader/core/ItemStat.java +++ b/core/src/main/java/ru/trader/core/ItemStat.java @@ -4,26 +4,27 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; +import java.util.concurrent.ConcurrentSkipListSet; public class ItemStat { private final static Logger LOG = LoggerFactory.getLogger(ItemStat.class); private final Item item; private final OFFER_TYPE type; - private final TreeSet offers; - private double sum; - private double avg; + private final NavigableSet offers; + private volatile double sum; + private volatile double avg; public ItemStat(Item item, OFFER_TYPE offerType) { - this.offers = new TreeSet<>(); + this.offers = new ConcurrentSkipListSet<>(); this.item = item; this.type = offerType; this.sum = 0; this.avg = Double.NaN; } - void put(Offer offer){ + synchronized void put(Offer offer){ LOG.trace("Put offer {} to item stat {}", offer, this); assert offer.hasType(type) && offer.hasItem(item); 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); assert offer.hasType(type) && offer.hasItem(item); 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); assert offer.hasType(type) && offer.hasItem(item) && offers.contains(offer); double oldPrice = offer.getPrice(); @@ -69,34 +70,34 @@ public class ItemStat { return item; } - public double getAvg(){ + public synchronized double getAvg(){ return avg; } - public Offer getBest() { + public synchronized Offer getBest() { if (offers.isEmpty()) return getFake(); return type.getOrder() > 0 ? offers.first() : offers.last(); } - public int getOffersCount(){ + public synchronized int getOffersCount(){ return offers.size(); } - public NavigableSet getOffers() { + public synchronized NavigableSet getOffers() { return Collections.unmodifiableNavigableSet(offers); } - public Offer getMin() { + public synchronized Offer getMin() { if (offers.isEmpty()) return getFake(); return offers.first(); } - public Offer getMax() { + public synchronized Offer getMax() { if (offers.isEmpty()) return getFake(); return offers.last(); } - public boolean isEmpty(){ + public synchronized boolean isEmpty(){ return offers.isEmpty(); } diff --git a/core/src/main/java/ru/trader/core/Offer.java b/core/src/main/java/ru/trader/core/Offer.java index 2deb5cd..6649bcb 100644 --- a/core/src/main/java/ru/trader/core/Offer.java +++ b/core/src/main/java/ru/trader/core/Offer.java @@ -12,7 +12,7 @@ public class Offer implements Comparable{ private Vendor vendor; private final Item item; private final OFFER_TYPE type; - private double price; + private volatile double price; Offer(){ item = null; diff --git a/core/src/main/java/ru/trader/core/SimpleVendor.java b/core/src/main/java/ru/trader/core/SimpleVendor.java index 4bfe267..6f0a279 100644 --- a/core/src/main/java/ru/trader/core/SimpleVendor.java +++ b/core/src/main/java/ru/trader/core/SimpleVendor.java @@ -1,6 +1,7 @@ package ru.trader.core; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public class SimpleVendor extends Vendor { @@ -18,8 +19,8 @@ public class SimpleVendor extends Vendor { } protected void initOffers(){ - sell = new HashMap<>(); - buy = new HashMap<>(); + sell = new ConcurrentHashMap<>(20, 0.9f, 2); + buy = new ConcurrentHashMap<>(20, 0.9f, 2); } @Override