diff --git a/core/src/main/java/ru/trader/store/berkeley/BDBItemStat.java b/core/src/main/java/ru/trader/store/berkeley/BDBItemStat.java index 8131a34..d263824 100644 --- a/core/src/main/java/ru/trader/store/berkeley/BDBItemStat.java +++ b/core/src/main/java/ru/trader/store/berkeley/BDBItemStat.java @@ -1,31 +1,94 @@ package ru.trader.store.berkeley; -import ru.trader.core.AbstractItemStat; -import ru.trader.core.Item; -import ru.trader.core.OFFER_TYPE; -import ru.trader.core.Offer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.core.*; +import java.util.Collections; import java.util.NavigableSet; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.DoubleAdder; -//TODO: implement public class BDBItemStat extends AbstractItemStat { + private final static Logger LOG = LoggerFactory.getLogger(BDBItemStat.class); + private final ItemProxy item; private final OFFER_TYPE type; private final BDBStore store; + private NavigableSet offers; + private volatile double sum; + private volatile double avg; + private AtomicLong count; + public BDBItemStat(ItemProxy item, OFFER_TYPE type, BDBStore store) { this.item = item; this.type = type; this.store = store; + offers = new TreeSet<>(store.getOfferAccessor().getAllByItem(item.getId(), type)); + this.sum = 0; + this.avg = Double.NaN; + this.count = new AtomicLong(0); + init(); + } + + void init(){ + sum = 0; + count.set(0); + offers.forEach(o -> { + sum += o.getPrice(); + count.incrementAndGet(); + }); + avg = sum / count.get(); } synchronized void put(Offer offer){ + LOG.trace("Put offer {} to item stat {}", offer, this); + assert offer.hasType(type) && offer.hasItem(item); + double price = offer.getPrice(); + sum += price; + avg = sum / count.incrementAndGet(); + if (offers != null){ + offers.add(offer); + } + LOG.trace("After this = {}", this); } synchronized void remove(Offer offer){ + LOG.trace("Remove offer {} from item stat {}", offer, this); + assert offer.hasType(type) && offer.hasItem(item); + double price = offer.getPrice(); + sum -= price; + if (count.decrementAndGet() > 0){ + avg = sum / count.get(); + } else { + sum = 0; avg = Double.NaN; + } + if (offers != null){ + offers.remove(offer); + } + LOG.trace("After this = {}", this); } + @Override + protected synchronized void updatePrice(AbstractOffer offer, double price) { + LOG.trace("Update offer {} from item stat {}", offer, this); + assert offer.hasType(type) && offer.hasItem(item); + double oldPrice = offer.getPrice(); + if (offers != null){ + offers.remove(offer); + } + super.updatePrice(offer, price); + if (offers != null){ + offers.add(offer); + } + sum += price - oldPrice; + avg = sum / offers.size(); + LOG.trace("After update this = {}", this); + } @Override public OFFER_TYPE getType() { @@ -39,31 +102,69 @@ public class BDBItemStat extends AbstractItemStat { @Override public Offer getMin() { - return null; + if (count.get() == 0) return getFake(); + return offers.first(); } @Override public double getAvg() { - return 0; + return avg; } @Override public Offer getMax() { - return null; + if (offers.isEmpty()) return getFake(); + return offers.last(); } @Override public Offer getBest() { - return null; + if (offers.isEmpty()) return getFake(); + return type.getOrder() > 0 ? offers.first() : offers.last(); } @Override public NavigableSet getOffers() { - return null; + return Collections.unmodifiableNavigableSet(offers); } @Override public boolean isEmpty() { - return false; + return count.get() == 0; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBItemStat)) return false; + + BDBItemStat itemStat = (BDBItemStat) o; + return type == itemStat.type && item.equals(itemStat.item); + } + + @Override + public int hashCode() { + int result = item.hashCode(); + result = 31 * result + type.hashCode(); + return result; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("{"); + sb.append(getItem()); + sb.append(", ").append(getType()); + if (BDBItemStat.LOG.isTraceEnabled()){ + sb.append(", count=").append(offers.size()); + sb.append(", sum=").append(sum); + } + sb.append(", avg=").append(getAvg()); + sb.append(", best=").append(getBest()); + sb.append(", min=").append(getMin()); + sb.append(", max=").append(getMax()); + + sb.append("}"); + return sb.toString(); + } + } diff --git a/core/src/main/java/ru/trader/store/berkeley/BDBMarket.java b/core/src/main/java/ru/trader/store/berkeley/BDBMarket.java index da9f9d7..9902c5f 100644 --- a/core/src/main/java/ru/trader/store/berkeley/BDBMarket.java +++ b/core/src/main/java/ru/trader/store/berkeley/BDBMarket.java @@ -1,5 +1,7 @@ package ru.trader.store.berkeley; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ru.trader.core.*; import ru.trader.store.berkeley.entities.BDBGroup; import ru.trader.store.berkeley.entities.BDBItem; @@ -8,12 +10,17 @@ import ru.trader.store.berkeley.entities.BDBPlace; import java.util.*; public class BDBMarket extends AbstractMarket { + private final static Logger LOG = LoggerFactory.getLogger(BDBMarket.class); private final BDBStore store; //caching private final Map sellItems = new HashMap<>(); private final Map buyItems = new HashMap<>(); + public BDBMarket(BDBStore store) { + this.store = store; + store.setMarket(this); + } private Map getItemCache(OFFER_TYPE offerType){ switch (offerType) { @@ -30,8 +37,9 @@ public class BDBMarket extends AbstractMarket { if (entry == null){ entry = new BDBItemStat((ItemProxy) item, offer.getType(), store); cache.put(item, entry); + } else { + entry.put(offer); } - entry.put(offer); } private void remove(Map cache, Offer offer){ @@ -44,10 +52,6 @@ public class BDBMarket extends AbstractMarket { } } - public BDBMarket(BDBStore store) { - this.store = store; - } - @Override protected Place createPlace(String name, double x, double y, double z) { return new PlaceProxy(new BDBPlace(name, x, y, z), store); @@ -70,6 +74,9 @@ public class BDBMarket extends AbstractMarket { @Override protected void removePlace(Place place) { + for (Vendor vendor : place.get()) { + onRemove(vendor); + } store.getPlaceAccessor().delete(((PlaceProxy) place).getEntity()); } @@ -91,6 +98,8 @@ public class BDBMarket extends AbstractMarket { @Override protected void removeItem(Item item) { store.getItemAccessor().delete(((ItemProxy) item).getEntity()); + sellItems.remove(item); + buyItems.remove(item); } @Override @@ -110,8 +119,50 @@ public class BDBMarket extends AbstractMarket { @Override public ItemStat getStat(OFFER_TYPE type, Item item) { - //TODO: добавить - return null; + ItemStat entry = getItemCache(type).get(item); + if (entry == null){ + entry = new BDBItemStat((ItemProxy) item, type, store); + getItemCache(type).put(item, (BDBItemStat) entry); + } + return entry; + } + + @Override + protected void onAdd(Vendor vendor) { + LOG.trace("Cached on add vendor {}", vendor); + Collection offers = vendor.getAllSellOffers(); + for (Offer offer : offers) { + put(sellItems, offer); + } + offers = vendor.getAllBuyOffers(); + for (Offer offer : offers) { + put(buyItems, offer); + } + } + + @Override + protected void onRemove(Vendor vendor) { + LOG.trace("Remove cache of vendor {}", vendor); + Collection offers = vendor.getAllSellOffers(); + for (Offer offer : offers) { + remove(sellItems, offer); + } + offers = vendor.getAllBuyOffers(); + for (Offer offer : offers) { + remove(buyItems, offer); + } + } + + @Override + protected void onAdd(Offer offer) { + LOG.trace("Cached on add offer {}", offer); + put(getItemCache(offer.getType()), offer); + } + + @Override + protected void onRemove(Offer offer) { + LOG.trace("Remove cache of offer {}", offer); + remove(getItemCache(offer.getType()), offer); } } diff --git a/core/src/main/java/ru/trader/store/berkeley/BDBStore.java b/core/src/main/java/ru/trader/store/berkeley/BDBStore.java index 037957d..42ec19c 100644 --- a/core/src/main/java/ru/trader/store/berkeley/BDBStore.java +++ b/core/src/main/java/ru/trader/store/berkeley/BDBStore.java @@ -23,6 +23,7 @@ public class BDBStore { private final ItemDA iDA; private final GroupDA gDA; private final PlaceDA pDA; + private BDBMarket market; public BDBStore(String path){ EnvironmentConfig envConfig = new EnvironmentConfig(); @@ -39,7 +40,7 @@ public class BDBStore { oDA = new OfferDA<>(store, o -> new OfferProxy(o, this)); iDA = new ItemDA<>(store, i -> new ItemProxy(i, this)); gDA = new GroupDA<>(store, g -> g); - pDA = new PlaceDA<>(store, p -> new PlaceProxy(p, this)); + pDA = new PlaceDA<>(store, p -> new PlaceProxy(p, null, this)); } catch (DatabaseException e){ LOG.error("Error on open DB, path {}", path); @@ -48,6 +49,12 @@ public class BDBStore { } } + void setMarket(BDBMarket market) { + assert this.market == null; + this.market = market; + pDA.setConvertFunc(p -> new PlaceProxy(p, market, this)); + } + public VendorDA getVendorAccessor() { return vDA; } diff --git a/core/src/main/java/ru/trader/store/berkeley/ItemProxy.java b/core/src/main/java/ru/trader/store/berkeley/ItemProxy.java index fef2692..b44f84d 100644 --- a/core/src/main/java/ru/trader/store/berkeley/ItemProxy.java +++ b/core/src/main/java/ru/trader/store/berkeley/ItemProxy.java @@ -7,11 +7,10 @@ import ru.trader.store.berkeley.entities.BDBItem; public class ItemProxy extends AbstractItem { private final BDBItem item; private final BDBStore store; - private final Group group; + private Group group; public ItemProxy(BDBItem item, BDBStore store) { this.item = item; - this.group = store.getGroupAccessor().get(item.getGroupId()); this.store = store; } @@ -36,7 +35,26 @@ public class ItemProxy extends AbstractItem { @Override public Group getGroup() { + if (group == null){ + group = store.getGroupAccessor().get(item.getGroupId()); + } return group; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ItemProxy)) return false; + + ItemProxy itemProxy = (ItemProxy) o; + + if (!item.equals(itemProxy.item)) return false; + + return true; + } + + @Override + public int hashCode() { + return item.hashCode(); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/OfferProxy.java b/core/src/main/java/ru/trader/store/berkeley/OfferProxy.java index 084134e..ee54f8d 100644 --- a/core/src/main/java/ru/trader/store/berkeley/OfferProxy.java +++ b/core/src/main/java/ru/trader/store/berkeley/OfferProxy.java @@ -5,13 +5,12 @@ import ru.trader.store.berkeley.entities.BDBOffer; public class OfferProxy extends AbstractOffer { private final BDBOffer offer; - private final Item item; + private Item item; private BDBStore store; private Vendor vendor; public OfferProxy(BDBOffer offer, BDBStore store) { this.offer = offer; - this.item = store.getItemAccessor().get(offer.getItemId()); this.store = store; } @@ -43,6 +42,9 @@ public class OfferProxy extends AbstractOffer { @Override public Item getItem() { + if (item == null){ + item = store.getItemAccessor().get(offer.getItemId()); + } return item; } @@ -69,4 +71,20 @@ public class OfferProxy extends AbstractOffer { return offer.getCount(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OfferProxy)) return false; + + OfferProxy that = (OfferProxy) o; + + if (!offer.equals(that.offer)) return false; + + return true; + } + + @Override + public int hashCode() { + return offer.hashCode(); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/PlaceProxy.java b/core/src/main/java/ru/trader/store/berkeley/PlaceProxy.java index b766201..59950bd 100644 --- a/core/src/main/java/ru/trader/store/berkeley/PlaceProxy.java +++ b/core/src/main/java/ru/trader/store/berkeley/PlaceProxy.java @@ -16,6 +16,11 @@ public class PlaceProxy extends AbstractPlace { this.store = store; } + public PlaceProxy(BDBPlace place, BDBMarket market, BDBStore store) { + this(place, store); + setMarket(market); + } + protected long getId(){ return place.getId(); } @@ -76,4 +81,20 @@ public class PlaceProxy extends AbstractPlace { return store.getVendorAccessor().getAllByPlace(place.getId()); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PlaceProxy)) return false; + + PlaceProxy that = (PlaceProxy) o; + + if (!place.equals(that.place)) return false; + + return true; + } + + @Override + public int hashCode() { + return place.hashCode(); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/VendorProxy.java b/core/src/main/java/ru/trader/store/berkeley/VendorProxy.java index 7df7c9d..b21e99a 100644 --- a/core/src/main/java/ru/trader/store/berkeley/VendorProxy.java +++ b/core/src/main/java/ru/trader/store/berkeley/VendorProxy.java @@ -114,4 +114,21 @@ public class VendorProxy extends AbstractVendor { public boolean has(OFFER_TYPE type, Item item) { return store.getOfferAccessor().has(vendor.getId(), type, ((ItemProxy)item).getId()); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VendorProxy)) return false; + + VendorProxy that = (VendorProxy) o; + + if (!vendor.equals(that.vendor)) return false; + + return true; + } + + @Override + public int hashCode() { + return vendor.hashCode(); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/dao/OfferDA.java b/core/src/main/java/ru/trader/store/berkeley/dao/OfferDA.java index 63ac14b..ceaaffc 100644 --- a/core/src/main/java/ru/trader/store/berkeley/dao/OfferDA.java +++ b/core/src/main/java/ru/trader/store/berkeley/dao/OfferDA.java @@ -6,6 +6,7 @@ import ru.trader.store.berkeley.entities.BDBOffer; import java.util.Collection; import java.util.LinkedList; +import java.util.TreeSet; import java.util.function.Function; public class OfferDA { @@ -78,6 +79,20 @@ public class OfferDA { return res; } + public Collection getAllByItem(long itemId, OFFER_TYPE type){ + EntityJoin join = new EntityJoin<>(indexById); + join.addCondition(indexByItemId, itemId); + join.addCondition(indexByType, type); + Collection res = new LinkedList<>(); + try (ForwardCursor cursor = join.entities()) + { + for(BDBOffer entity : cursor){ + res.add(convertFunc.apply(entity)); + } + } + return res; + } + public BDBOffer put(BDBOffer offer){ return indexById.put(offer); diff --git a/core/src/main/java/ru/trader/store/berkeley/dao/PlaceDA.java b/core/src/main/java/ru/trader/store/berkeley/dao/PlaceDA.java index 24da937..23914ac 100644 --- a/core/src/main/java/ru/trader/store/berkeley/dao/PlaceDA.java +++ b/core/src/main/java/ru/trader/store/berkeley/dao/PlaceDA.java @@ -13,7 +13,7 @@ import java.util.function.Function; public class PlaceDA { private final PrimaryIndex indexById; private final SecondaryIndex indexByDistance; - private final Function convertFunc; + private Function convertFunc; public PlaceDA(EntityStore store, Function convertFunc) { this.convertFunc = convertFunc; @@ -21,6 +21,10 @@ public class PlaceDA { this.indexByDistance = store.getSecondaryIndex(indexById, Double.class, "distance"); } + public void setConvertFunc(Function convertFunc) { + this.convertFunc = convertFunc; + } + public T get(long id){ return DAUtils.get(indexById, id, convertFunc); } diff --git a/core/src/main/java/ru/trader/store/berkeley/entities/BDBGroup.java b/core/src/main/java/ru/trader/store/berkeley/entities/BDBGroup.java index 24192cc..77f5e7f 100644 --- a/core/src/main/java/ru/trader/store/berkeley/entities/BDBGroup.java +++ b/core/src/main/java/ru/trader/store/berkeley/entities/BDBGroup.java @@ -31,4 +31,24 @@ public class BDBGroup implements Group { public GROUP_TYPE getType() { return type; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBGroup)) return false; + + BDBGroup bdbGroup = (BDBGroup) o; + + if (!name.equals(bdbGroup.name)) return false; + if (type != bdbGroup.type) return false; + + return true; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + type.hashCode(); + return result; + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/entities/BDBItem.java b/core/src/main/java/ru/trader/store/berkeley/entities/BDBItem.java index aeed4a0..932d0cc 100644 --- a/core/src/main/java/ru/trader/store/berkeley/entities/BDBItem.java +++ b/core/src/main/java/ru/trader/store/berkeley/entities/BDBItem.java @@ -38,4 +38,22 @@ public class BDBItem { return groupId; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBItem)) return false; + + BDBItem bdbItem = (BDBItem) o; + + if (id != bdbItem.id) return false; + if (!groupId.equals(bdbItem.groupId)) return false; + if (!name.equals(bdbItem.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (id ^ (id >>> 32)); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/entities/BDBOffer.java b/core/src/main/java/ru/trader/store/berkeley/entities/BDBOffer.java index 598afc2..bcaa749 100644 --- a/core/src/main/java/ru/trader/store/berkeley/entities/BDBOffer.java +++ b/core/src/main/java/ru/trader/store/berkeley/entities/BDBOffer.java @@ -10,21 +10,22 @@ public class BDBOffer { private long id; @SecondaryKey(relate = Relationship.MANY_TO_ONE, - relatedEntity = BDBItem.class, - onRelatedEntityDelete = DeleteAction.NULLIFY) + relatedEntity = BDBItem.class, onRelatedEntityDelete = DeleteAction.CASCADE) private long itemId; @SecondaryKey(relate = Relationship.MANY_TO_ONE, - relatedEntity = BDBVendor.class, - onRelatedEntityDelete = DeleteAction.NULLIFY) + relatedEntity = BDBVendor.class, onRelatedEntityDelete = DeleteAction.CASCADE) private long vendorId; - @SecondaryKey(relate = Relationship.ONE_TO_ONE) + @SecondaryKey(relate = Relationship.MANY_TO_ONE) private OFFER_TYPE type; private double price; private long count; + private BDBOffer() { + } + public BDBOffer(OFFER_TYPE type, long itemId, double price, long count, long vendorId) { this.type = type; this.itemId = itemId; @@ -69,4 +70,24 @@ public class BDBOffer { this.vendorId = vendorId; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBOffer)) return false; + + BDBOffer bdbOffer = (BDBOffer) o; + + if (count != bdbOffer.count) return false; + if (id != bdbOffer.id) return false; + if (itemId != bdbOffer.itemId) return false; + if (Double.compare(bdbOffer.price, price) != 0) return false; + if (type != bdbOffer.type) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (id ^ (id >>> 32)); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/entities/BDBPlace.java b/core/src/main/java/ru/trader/store/berkeley/entities/BDBPlace.java index d78a513..b1410f0 100644 --- a/core/src/main/java/ru/trader/store/berkeley/entities/BDBPlace.java +++ b/core/src/main/java/ru/trader/store/berkeley/entities/BDBPlace.java @@ -59,4 +59,25 @@ public class BDBPlace { this.distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBPlace)) return false; + + BDBPlace bdbPlace = (BDBPlace) o; + + if (id != bdbPlace.id) return false; + if (Double.compare(bdbPlace.x, x) != 0) return false; + if (Double.compare(bdbPlace.y, y) != 0) return false; + if (Double.compare(bdbPlace.z, z) != 0) return false; + if (!name.equals(bdbPlace.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (id ^ (id >>> 32)); + } } diff --git a/core/src/main/java/ru/trader/store/berkeley/entities/BDBVendor.java b/core/src/main/java/ru/trader/store/berkeley/entities/BDBVendor.java index 689bd3d..7828599 100644 --- a/core/src/main/java/ru/trader/store/berkeley/entities/BDBVendor.java +++ b/core/src/main/java/ru/trader/store/berkeley/entities/BDBVendor.java @@ -4,7 +4,7 @@ import com.sleepycat.persist.model.*; import ru.trader.core.SERVICE_TYPE; import java.util.Collection; -import java.util.EnumSet; +import java.util.HashSet; @Entity(version = 1) public class BDBVendor { @@ -13,14 +13,13 @@ public class BDBVendor { private long id; @SecondaryKey(relate = Relationship.MANY_TO_ONE, - relatedEntity = BDBPlace.class, - onRelatedEntityDelete = DeleteAction.NULLIFY) + relatedEntity = BDBPlace.class, onRelatedEntityDelete = DeleteAction.CASCADE) private long placeId; private String name; private double distance; - @SecondaryKey(relate=Relationship.ONE_TO_MANY) - EnumSet services = EnumSet.noneOf(SERVICE_TYPE.class); + @SecondaryKey(relate=Relationship.MANY_TO_MANY) + Collection services = new HashSet<>(); private BDBVendor() { } @@ -73,4 +72,25 @@ public class BDBVendor { public Collection getServices() { return services; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BDBVendor)) return false; + + BDBVendor bdbVendor = (BDBVendor) o; + + if (Double.compare(bdbVendor.distance, distance) != 0) return false; + if (id != bdbVendor.id) return false; + if (placeId != bdbVendor.placeId) return false; + if (!name.equals(bdbVendor.name)) return false; + if (!services.equals(bdbVendor.services)) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (id ^ (id >>> 32)); + } } diff --git a/core/src/test/java/ru/trader/store/berkeley/MarketTest.java b/core/src/test/java/ru/trader/store/berkeley/MarketTest.java new file mode 100644 index 0000000..d2b6560 --- /dev/null +++ b/core/src/test/java/ru/trader/store/berkeley/MarketTest.java @@ -0,0 +1,550 @@ +package ru.trader.store.berkeley; + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.core.*; +import ru.trader.store.simple.SimpleMarket; + +import java.io.File; +import java.util.Collection; + + +public class MarketTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(MarketTest.class); + private BDBStore store; + private Market market; + + @Before + public void setUp() throws Exception { + File f = new File("test-bd"); + if (!f.exists()){ + f.mkdir(); + } + store = new BDBStore("test-bd"); + market = new BDBMarket(store); + + } + + @Test + public void testGroup(){ + LOG.info("Start test group"); + Group group1 = market.addGroup("Group 1", GROUP_TYPE.MARKET); + Group group2 = market.addGroup("Group 2", GROUP_TYPE.OUTFIT); + Group group3 = market.addGroup("Group 3", GROUP_TYPE.MARKET); + int c = 3; + for (Group group : market.getGroups()) { + if ("Group 1".equals(group.getName())){ + assertEquals(group1, group); + assertEquals(GROUP_TYPE.MARKET, group.getType()); + c--; + } else + if ("Group 2".equals(group.getName())){ + assertEquals(group2, group); + assertEquals(GROUP_TYPE.OUTFIT, group.getType()); + c--; + } else + if ("Group 3".equals(group.getName())){ + assertEquals(group3, group); + assertEquals(GROUP_TYPE.MARKET, group.getType()); + c--; + } else c = -1; + } + assertEquals("Wrong group count", 0, c); + + market.remove(group1); + market.remove(group2); + market.remove(group3); + + assertEquals(0, market.getGroups().size()); + } + + + @Test + public void testItem(){ + LOG.info("Start test item"); + Group group1 = market.addGroup("Group 1", GROUP_TYPE.MARKET); + Group group2 = market.addGroup("Group 2", GROUP_TYPE.OUTFIT); + + Item item1 = market.addItem("Item 1", group1); + Item item2 = market.addItem("Item 2", group2); + Item item3 = market.addItem("Item 3", group1); + int c = 3; + for (Item item : market.getItems()) { + if ("Item 1".equals(item.getName())){ + assertEquals(item1, item); + assertEquals(group1, item.getGroup()); + c--; + } else + if ("Item 2".equals(item.getName())){ + assertEquals(item2, item); + assertEquals(group2, item.getGroup()); + c--; + } else + if ("Item 3".equals(item.getName())){ + assertEquals(item3, item); + assertEquals(group1, item.getGroup()); + c--; + } else c = -1; + + } + assertEquals("Wrong item count", 0, c); + + + market.remove(group1); + market.remove(group2); + + assertEquals(0, market.getGroups().size()); + + market.remove(item1); + market.remove(item2); + market.remove(item3); + + assertEquals(0, market.getItems().size()); + + + } + + + @Test + public void testPlace(){ + LOG.info("Start test place"); + Place place1 = market.addPlace("Place 1", 1, 2, 3); + Place place2 = market.addPlace("Place 2", 3, 1, 2); + + int c = 2; + for (Place place : market.get()) { + if ("Place 1".equals(place.getName())){ + assertEquals(place1, place); + assertEquals(1, place.getX(), 0.01); + assertEquals(2, place.getY(), 0.01); + assertEquals(3, place.getZ(), 0.01); + c--; + } else + if ("Place 2".equals(place.getName())){ + assertEquals(place2, place); + assertEquals(3, place.getX(), 0.01); + assertEquals(1, place.getY(), 0.01); + assertEquals(2, place.getZ(), 0.01); + c--; + } else c = -1; + + } + assertEquals("Wrong item count", 0, c); + + market.remove(place1); + market.remove(place2); + + assertEquals(0, market.get().size()); + + } + + + @Test + public void testVendor(){ + LOG.info("Start test vendor"); + Place place1 = market.addPlace("Place 1", 1, 2, 3); + Place place2 = market.addPlace("Place 2", 3, 1, 2); + Vendor vendor1 = place1.addVendor("Vendor 1"); + vendor1.setDistance(100); + vendor1.add(SERVICE_TYPE.MARKET); + vendor1.add(SERVICE_TYPE.OUTFIT); + + Vendor vendor2 = place1.addVendor("Vendor 2"); + vendor2.setDistance(40); + + + Vendor vendor3 = place2.addVendor("Vendor 3"); + vendor3.add(SERVICE_TYPE.OUTFIT); + vendor3.add(SERVICE_TYPE.LARGE_LANDPAD); + vendor3.add(SERVICE_TYPE.MEDIUM_LANDPAD); + vendor3.remove(SERVICE_TYPE.LARGE_LANDPAD); + + int c = 3; + for (Vendor vendor : market.getVendors()) { + if ("Transit".equals(vendor.toString())) continue; + if ("Vendor 1".equals(vendor.getName())){ + assertEquals(vendor1, vendor); + assertEquals(place1, vendor.getPlace()); + assertEquals(100, vendor.getDistance(), 0.001); + assertTrue(vendor.has(SERVICE_TYPE.MARKET)); + assertTrue(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.LARGE_LANDPAD)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.MEDIUM_LANDPAD)); + c--; + } else + if ("Vendor 2".equals(vendor.getName())){ + assertEquals(vendor2, vendor); + assertEquals(place1, vendor.getPlace()); + assertEquals(40, vendor.getDistance(), 0.001); + assertFalse(vendor.has(SERVICE_TYPE.MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.LARGE_LANDPAD)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.MEDIUM_LANDPAD)); + c--; + } else + if ("Vendor 3".equals(vendor.getName())){ + assertEquals(vendor3, vendor); + assertEquals(place2, vendor.getPlace()); + assertEquals(0, vendor.getDistance(), 0.001); + assertFalse(vendor.has(SERVICE_TYPE.MARKET)); + assertTrue(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.LARGE_LANDPAD)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertTrue(vendor.has(SERVICE_TYPE.MEDIUM_LANDPAD)); + c--; + } else c = -1; + + } + assertEquals("Wrong vendors count", 0, c); + + place1.remove(vendor1); + place1.remove(vendor2); + place2.remove(vendor3); + + assertEquals(2, market.getVendors().size()); + + market.remove(place1); + market.remove(place2); + + assertEquals(0, market.getVendors().size()); + } + + @Test + public void testOffer(){ + LOG.info("Start test offer"); + Group group1 = market.addGroup("Group 1", GROUP_TYPE.MARKET); + Group group2 = market.addGroup("Group 2", GROUP_TYPE.OUTFIT); + Item item1 = market.addItem("Item 1", group1); + Item item2 = market.addItem("Item 2", group2); + Item item3 = market.addItem("Item 3", group1); + Place place1 = market.addPlace("Place 1", 1, 2, 3); + Vendor vendor1 = place1.addVendor("Vendor 1"); + + Offer offer1 = vendor1.addOffer(OFFER_TYPE.SELL, item1, 254, 10); + Offer offer2 = vendor1.addOffer(OFFER_TYPE.BUY, item1, 300, 15); + Offer offer3 = vendor1.addOffer(OFFER_TYPE.BUY, item3, 100, 100); + Offer offer4 = vendor1.addOffer(OFFER_TYPE.SELL, item2, 10, -1); + + int c = 2; + for (Offer offer : vendor1.getAllSellOffers()) { + if (item1.equals(offer.getItem())){ + assertEquals(offer1, offer); + assertEquals(OFFER_TYPE.SELL, offer.getType()); + assertEquals(254, offer.getPrice(), 0.01); + assertEquals(10, offer.getCount()); + c--; + } else + if (item2.equals(offer.getItem())){ + assertEquals(offer4, offer); + assertEquals(OFFER_TYPE.SELL, offer.getType()); + assertEquals(10, offer.getPrice(), 0.01); + assertEquals(-1, offer.getCount()); + c--; + } else c = -1; + } + assertEquals("Wrong buy offers count", 0, c); + + + c = 2; + for (Offer offer : vendor1.getAllBuyOffers()) { + if (item1.equals(offer.getItem())){ + assertEquals(offer2, offer); + assertEquals(OFFER_TYPE.BUY, offer.getType()); + assertEquals(300, offer.getPrice(), 0.01); + assertEquals(15, offer.getCount()); + c--; + } else + if (item3.equals(offer.getItem())){ + assertEquals(offer3, offer); + assertEquals(OFFER_TYPE.BUY, offer.getType()); + assertEquals(100, offer.getPrice(), 0.01); + assertEquals(100, offer.getCount()); + c--; + } else c = -1; + } + assertEquals("Wrong buy offers count", 0, c); + + vendor1.remove(offer1); + vendor1.remove(offer2); + vendor1.remove(offer3); + vendor1.remove(offer4); + assertEquals(0, vendor1.getAllBuyOffers().size()); + assertEquals(0, vendor1.getAllSellOffers().size()); + + place1.remove(vendor1); + market.remove(place1); + market.remove(item1); + market.remove(item2); + market.remove(item3); + market.remove(group1); + market.remove(group2); + } + + + @Test + public void testItemStat(){ + LOG.info("Start item stat test"); + Group group1 = market.addGroup("Group 1", GROUP_TYPE.MARKET); + Item item1 = market.addItem("Item 1", group1); + Item item2 = market.addItem("Item 2", group1); + Place place1 = market.addPlace("Place 1", 1, 2, 3); + Vendor vendor1 = place1.addVendor("Vendor 1"); + Vendor vendor2 = place1.addVendor("Vendor 2"); + Vendor vendor3 = place1.addVendor("Vendor 3"); + Vendor vendor4 = place1.addVendor("Vendor 4"); + + Offer offer1 = vendor1.addOffer(OFFER_TYPE.SELL, item1, 10, 1); + Offer offer2 = vendor2.addOffer(OFFER_TYPE.SELL, item1, 20, 1); + Offer offer3 = vendor3.addOffer(OFFER_TYPE.SELL, item1, 30, 1); + Offer offer4 = vendor4.addOffer(OFFER_TYPE.SELL, item1, 40, 1); + + Offer offer5 = vendor1.addOffer(OFFER_TYPE.BUY, item1, 100, 1); + Offer offer6 = vendor2.addOffer(OFFER_TYPE.BUY, item1, 200, 1); + Offer offer7 = vendor3.addOffer(OFFER_TYPE.BUY, item1, 300, 1); + Offer offer8 = vendor4.addOffer(OFFER_TYPE.BUY, item1, 400, 1); + + Offer offer9 = vendor1.addOffer(OFFER_TYPE.BUY, item2, 1, 30); + Offer offer10 = vendor2.addOffer(OFFER_TYPE.BUY, item2, 500, 10); + + + ItemStat sellStat = market.getStat(OFFER_TYPE.SELL, item1); + assertEquals((10+20+30+40)/4, sellStat.getAvg(), 0); + assertEquals(offer1, sellStat.getBest()); + assertEquals(offer1, sellStat.getMin()); + assertEquals(offer4, sellStat.getMax()); + assertEquals(4, sellStat.getOffers().size()); + + ItemStat buyStat = market.getStat(OFFER_TYPE.BUY, item1); + assertEquals((100+200+300+400)/4, buyStat.getAvg(), 0); + assertEquals(offer8, buyStat.getBest()); + assertEquals(offer5, buyStat.getMin()); + assertEquals(offer8, buyStat.getMax()); + assertEquals(4, buyStat.getOffers().size()); + + vendor1.remove(offer1); + vendor4.remove(offer4); + assertEquals((20+30)/2, sellStat.getAvg(), 0); + assertEquals(offer2, sellStat.getBest()); + assertEquals(offer2, sellStat.getMin()); + assertEquals(offer3, sellStat.getMax()); + assertEquals(2, sellStat.getOffers().size()); + + market.remove(place1); + + assertEquals(0, market.getSell(item1).size()); + assertEquals(0, market.getBuy(item1).size()); + assertEquals(0, vendor1.getAllBuyOffers().size()); + assertEquals(0, vendor1.getAllSellOffers().size()); + assertEquals(0, market.getVendors().size()); + assertEquals(0, market.get().size()); + assertEquals(0, sellStat.getOffers().size()); + assertEquals(0, buyStat.getOffers().size()); + + market.remove(item1); + market.remove(item2); + market.remove(group1); + assertTrue(market.getStatBuy(item1).isEmpty()); + assertTrue(market.getStatBuy(item2).isEmpty()); + } + + + private void assertGroup(Group group1, Group group2){ + assertEquals(group1.getName(), group2.getName()); + assertEquals(group1.getType(), group2.getType()); + } + + private void assertItem(Item item1, Item item2){ + assertEquals(item1.getName(), item2.getName()); + assertGroup(item1.getGroup(), item2.getGroup()); + } + + private void assertPlace(Place place1, Place place2){ + assertEquals(place1.getName(), place2.getName()); + assertEquals(place1.getX(), place2.getX(), 0.00001); + assertEquals(place1.getY(), place2.getY(), 0.00001); + assertEquals(place1.getZ(), place2.getZ(), 0.00001); + } + + private void assertVendor(Vendor vendor1, Vendor vendor2){ + assertEquals(vendor1.getName(), vendor2.getName()); + assertEquals(vendor1.getDistance(), vendor2.getDistance(), 0.00001); + } + + private void assertOffer(Offer offer1, Offer offer2){ + assertEquals(offer1.getType(), offer2.getType()); + assertItem(offer1.getItem(), offer2.getItem()); + assertEquals(offer1.getPrice(), offer2.getPrice(), 0.000001); + assertEquals(offer1.getCount(), offer2.getCount()); + } + + @Test + public void testImport(){ + LOG.info("Start import test"); + + Market world = new SimpleMarket(); + Group group1 = world.addGroup("Group 1", GROUP_TYPE.MARKET); + Group group2 = world.addGroup("Group 2", GROUP_TYPE.MARKET); + Group group3 = world.addGroup("Group 3", GROUP_TYPE.OUTFIT); + Item item1 = world.addItem("Item 1", group1); + Item item2 = world.addItem("Item 2", group1); + Item item3 = world.addItem("Item 3", group2); + Item item4 = world.addItem("Item 4", group2); + Item item5 = world.addItem("Item 5", group3); + Place place1 = world.addPlace("Place 1", 0, 1, 3); + Place place2 = world.addPlace("Place 2",4,0,5); + Place place3 = world.addPlace("Place 3",0,0,0); + Vendor vendor1 = place1.addVendor("Vendor 1"); + Vendor vendor2 = place1.addVendor("Vendor 2"); + Vendor vendor3 = place2.addVendor("Vendor 3"); + vendor1.setDistance(10); + vendor1.add(SERVICE_TYPE.MARKET); + vendor1.add(SERVICE_TYPE.OUTFIT); + Offer offer1 = vendor1.addOffer(OFFER_TYPE.SELL, item1, 10,43); + Offer offer2 = vendor1.addOffer(OFFER_TYPE.BUY, item1, 12,1); + Offer offer3 = vendor1.addOffer(OFFER_TYPE.SELL, item2, 1012,1000); + Offer offer4 = vendor1.addOffer(OFFER_TYPE.SELL, item3, 110,0); + Offer offer5 = vendor1.addOffer(OFFER_TYPE.SELL, item4, 1112,12); + Offer offer6 = vendor1.addOffer(OFFER_TYPE.BUY, item5, 11,10); + vendor2.setDistance(100.4); + vendor3.setDistance(200000.4); + vendor3.add(SERVICE_TYPE.OUTFIT); + + LOG.info("add market"); + market.add(world); + + LOG.info("check groups"); + Collection groups = world.getGroups(); + int i=0; + for (Group group : groups) { + if (group1.getName().equals(group.getName())) {assertGroup(group, group1);i++;} + if (group2.getName().equals(group.getName())) {assertGroup(group, group2);i++;} + if (group3.getName().equals(group.getName())) {assertGroup(group, group3);i++;} + } + assertEquals(3, i); + + LOG.info("check items"); + Collection items = world.getItems(); + i=0; + for (Item item : items) { + if (item1.getName().equals(item.getName())) {assertItem(item, item1);i++;} + if (item2.getName().equals(item.getName())) {assertItem(item, item2);i++;} + if (item3.getName().equals(item.getName())) {assertItem(item, item3);i++;} + if (item4.getName().equals(item.getName())) {assertItem(item, item4);i++;} + if (item5.getName().equals(item.getName())) {assertItem(item, item5);i++;} + } + assertEquals(5, i); + + LOG.info("check places"); + Collection places = world.get(); + i=0; + for (Place place : places) { + if (place1.getName().equals(place.getName())) { + assertPlace(place, place1); + i++; + Collection vendors = place.get(); + int j=0; + for (Vendor vendor : vendors) { + if (vendor1.getName().equals(vendor.getName())) { + LOG.info("check vendor 1"); + assertVendor(vendor, vendor1);j++; + Collection offers = vendor.getAllSellOffers(); + int o = 0; + for (Offer offer : offers) { + if (offer1.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer1);o++;} + if (offer3.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer3);o++;} + if (offer4.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer4);o++;} + if (offer5.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer5);o++;} + } + assertEquals(4, o); + offers = vendor.getAllBuyOffers(); + o = 0; + for (Offer offer : offers) { + if (offer2.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer2);o++;} + if (offer6.getItem().getName().equals(offer.getItem().getName())) {assertOffer(offer, offer6);o++;} + } + assertEquals(2, o); + assertTrue(vendor.has(SERVICE_TYPE.MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.REPAIR)); + assertFalse(vendor.has(SERVICE_TYPE.MUNITION)); + assertTrue(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.SHIPYARD)); + } + if (vendor2.getName().equals(vendor.getName())) { + LOG.info("check vendor 2"); + assertVendor(vendor, vendor2);j++; + assertTrue(vendor.getAllBuyOffers().isEmpty()); + assertTrue(vendor.getAllSellOffers().isEmpty()); + assertFalse(vendor.has(SERVICE_TYPE.MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.REPAIR)); + assertFalse(vendor.has(SERVICE_TYPE.MUNITION)); + assertFalse(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.SHIPYARD)); + } + } + assertEquals(2, j); + assertTrue(place.canRefill()); + } + if (place2.getName().equals(place.getName())) { + assertPlace(place, place2); + i++; + Collection vendors = place.get(); + int j=0; + for (Vendor vendor : vendors) { + if (vendor3.getName().equals(vendor.getName())) { + LOG.info("check vendor 3"); + assertVendor(vendor, vendor3);j++; + assertTrue(vendor.getAllBuyOffers().isEmpty()); + assertTrue(vendor.getAllSellOffers().isEmpty()); + assertFalse(vendor.has(SERVICE_TYPE.MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.BLACK_MARKET)); + assertFalse(vendor.has(SERVICE_TYPE.REPAIR)); + assertFalse(vendor.has(SERVICE_TYPE.MUNITION)); + assertTrue(vendor.has(SERVICE_TYPE.OUTFIT)); + assertFalse(vendor.has(SERVICE_TYPE.SHIPYARD)); + } + } + assertEquals(1, j); + assertTrue(place.canRefill()); + } + if (place3.getName().equals(place.getName())) { + assertPlace(place, place3); + i++; + assertTrue(place.get().isEmpty()); + assertFalse(place.canRefill()); + } + + } + assertEquals(3, i); + market.clear(); + } + + + @After + public void tearDown() throws Exception { + store.close(); + deleteFolder(new File("test-bd")); + } + + public static void deleteFolder(File folder) { + File[] files = folder.listFiles(); + if(files!=null) { //some JVMs return null for empty dirs + for(File f: files) { + if(f.isDirectory()) { + deleteFolder(f); + } else { + f.delete(); + } + } + } + folder.delete(); + } +}