Module Client : ajout code QueryExecutor + ajout code AccountService; Modif services et dao de service existants pour utiliser le nouveau QueryExecutor

This commit is contained in:
Notmoo-PC\Notmoo 2017-08-25 16:07:08 +02:00
parent d2c89a31ae
commit 57b950e465
22 changed files with 461 additions and 153 deletions

View File

@ -1,48 +1,123 @@
package com.pqt.client.module.account;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.client.module.query.query_callback.ICollectionItemMessageCallback;
import com.pqt.client.module.query.query_callback.INoItemMessageCallback;
import com.pqt.core.entities.product.Product;
import com.pqt.core.entities.user_account.Account;
import com.pqt.client.module.account.listeners.IAccountListener;
import javax.swing.event.EventListenerList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
//TODO écrire contenu méthodes
//TODO écrire javadoc
//TODO add log lines
public class AccountService {
private QueryExecutor executor;
private Account currentAccount;
private boolean connected;
private Collection<Account> accounts;
private EventListenerList listenerList;
public AccountService(QueryExecutor executor){
this.executor = executor;
listenerList = new EventListenerList();
accounts = new ArrayList<>();
refreshAccounts();
}
public Account getCurrentAccount() {
return null;
return currentAccount;
}
public void setCurrentAccount(Account account) {
if(connected)
logOutCurrentAccount();
this.currentAccount = account;
}
public boolean isCurrentAccountLoggedIn() {
return false;
return connected;
}
public void logInCurrentAccount(String password) {
setCurrentAccountState(password, true);
}
public void logOutCurrentAccount() {
setCurrentAccountState(null, false);
}
public List<Account> getRecentAccounts() {
return null;
}
private void setCurrentAccountState(String password, boolean state){
if(currentAccount!=null && connected!=state) {
Account acc = new Account(currentAccount);
acc.setPassword(password);
executor.executeConnectAccountQuery(acc, state, new INoItemMessageCallback() {
@Override
public void ack() {
if (currentAccount != null
&& connected != state
&& currentAccount.getUsername().equals(acc.getUsername())
&& currentAccount.getPermissionLevel().equals(acc.getPermissionLevel())) {
connected = state;
Arrays.stream(listenerList.getListeners(IAccountListener.class))
.forEach(l->l.onAccountStatusChangedEvent(connected));
}else
Arrays.stream(listenerList.getListeners(IAccountListener.class))
.forEach(l->l.onAccountStatusNotChangedEvent(
new IllegalStateException("Account service not in the right state")
));
}
@Override
public void err(Throwable cause) {
Arrays.stream(listenerList.getListeners(IAccountListener.class))
.forEach(l->l.onAccountStatusNotChangedEvent(cause));
}
@Override
public void ref(Throwable cause) {
Arrays.stream(listenerList.getListeners(IAccountListener.class))
.forEach(l->l.onAccountStatusNotChangedEvent(cause));
}
});
}
}
public void addListener(IAccountListener listener) {
listenerList.add(IAccountListener.class, listener);
}
public void removeListener(IAccountListener listener) {
listenerList.remove(IAccountListener.class, listener);
}
public List<Account> getAllAccounts() {
return null;
public Collection<Account> getAllAccounts() {
return accounts;
}
public void refreshAccounts(){
executor.executeAccountListQuery(new ICollectionItemMessageCallback<Account>() {
@Override
public void err(Throwable cause) {
}
@Override
public void ref(Throwable cause) {
}
@Override
public void ack(Collection<Account> obj) {
accounts = obj;
Arrays.stream(listenerList.getListeners(IAccountListener.class))
.forEach(IAccountListener::onAccountListChangedEvent);
}
});
}
}

View File

@ -8,13 +8,23 @@ public class AccountListenerAdapter implements IAccountListener {
/**
* @see com.pqt.client.module.account.listeners.IAccountListener#onAccountStatusChangedEvent(boolean)
*/
@Override
public void onAccountStatusChangedEvent(boolean status) {
}
/**
* @see com.pqt.client.module.account.listeners.IAccountListener#onAccountStatusNotChangedEvent(Throwable)
*/
@Override
public void onAccountStatusNotChangedEvent(Throwable cause) {
}
/**
* @see com.pqt.client.module.account.listeners.IAccountListener#onAccountListChangedEvent()
*/
@Override
public void onAccountListChangedEvent() {
}

View File

@ -5,5 +5,6 @@ import java.util.EventListener;
public interface IAccountListener extends EventListener {
void onAccountStatusChangedEvent(boolean status);
void onAccountStatusNotChangedEvent(Throwable cause);
void onAccountListChangedEvent();
}

View File

@ -1,35 +1,170 @@
package com.pqt.client.module.query;
import com.pqt.client.module.query.query_callback.IIdQueryCallback;
import com.pqt.core.entities.query.IQuery;
import com.pqt.client.module.query.query_callback.ISimpleQueryCallback;
import com.pqt.client.module.query.query_callback.IStatQueryCallback;
import com.pqt.client.module.query.query_callback.IStockQueryCallback;
import com.pqt.client.module.connection.ConnectionService;
import com.pqt.client.module.connection.listeners.IConnectionListener;
import com.pqt.client.module.query.exceptions.HeaderNotFoundException;
import com.pqt.client.module.query.exceptions.MessageTimeoutException;
import com.pqt.client.module.query.query_callback.*;
import com.pqt.core.communication.GSonMessageToolFactory;
import com.pqt.core.communication.IMessageToolFactory;
import com.pqt.core.entities.messages.Message;
import com.pqt.core.entities.messages.MessageType;
import com.pqt.core.entities.product.Product;
import com.pqt.core.entities.product.ProductUpdate;
import com.pqt.core.entities.sale.Sale;
import com.pqt.core.entities.user_account.Account;
import java.util.List;
//TODO écrire contenu méthodes
//TODO écrire javadoc
public class QueryExecutor {
public static final QueryExecutor INSTANCE = new QueryExecutor();
private QueryExecutor(){
private IMessageToolFactory messageToolFactory;
private ConnectionService connectionService;
private QueryMessageFactory messageFactory;
public QueryExecutor(ConnectionService connectionService){
messageToolFactory = new GSonMessageToolFactory();
this.connectionService = connectionService;
this.messageFactory = new QueryMessageFactory(messageToolFactory);
}
public long execute(IQuery query, ISimpleQueryCallback callback) {
return 0;
}
public long execute(IQuery query, IStatQueryCallback callback) {
return 0;
}
public long execute(IQuery query, IStockQueryCallback callback) {
return 0;
}
public long execute(IQuery query, IIdQueryCallback callback) {
return 0;
public void executeSaleQuery(Sale sale, INoItemMessageCallback callback) {
sendMessage(messageFactory.newSaleMessage(sale), callback, MessageType.ACK_SALE);
}
public void executePingQuery(INoItemMessageCallback callback){
sendMessage(messageFactory.newPingMessage(), callback, MessageType.ACK_PING);
}
public void executeUpdateQuery(List<ProductUpdate> updates, INoItemMessageCallback callback) {
sendMessage(messageFactory.newUpdateMessage(updates), callback, MessageType.ACK_UPDATE);
}
public void executeConnectAccountQuery(Account account, boolean desiredState, INoItemMessageCallback callback){
sendMessage(messageFactory.newConnectAccountMessage(account,desiredState), callback, MessageType.ACK_CONNECT_ACCOUNT);
}
private void sendMessage(Message message, INoItemMessageCallback callback, MessageType responseType){
connectionService.sendText(messageToolFactory.getObjectFormatter(Message.class).format(message), new IConnectionListener() {
@Override
public void onMessageReceivedEvent(String msg) {
Message response = messageToolFactory.getObjectParser(Message.class).parse(msg);
if(response.getType().equals(responseType))
callback.ack();
else
handleUnexpectedTypeInResponse(response, callback);
}
@Override
public void onConnectedEvent() {
}
@Override
public void onDisconnectedEvent() {
}
@Override
public void onTimeOutEvent() {
callback.err(new MessageTimeoutException());
}
});
}
public void executeStockQuery(ICollectionItemMessageCallback<Product> callback) {
sendMessage(messageFactory.newStockMessage(), callback, Product.class, MessageType.MSG_STOCK, "stock");
}
public void executeAccountListQuery(ICollectionItemMessageCallback<Account> callback){
sendMessage(messageFactory.newAccountListMessage(), callback, Account.class, MessageType.MSG_ACCOUNT_LIST, "accounts");
}
private <T> void sendMessage(Message message, ICollectionItemMessageCallback<T> callback, Class<T> clazz, MessageType responseType, String itemHeader){
connectionService.sendText(messageToolFactory.getObjectFormatter(Message.class).format(message), new IConnectionListener() {
@Override
public void onMessageReceivedEvent(String msg) {
Message response = messageToolFactory.getObjectParser(Message.class).parse(msg);
if(response.getType().equals(responseType)) {
String item = response.getField(itemHeader);
if (item != null)
callback.ack(messageToolFactory.getListParser(clazz).parse(item));
else
callback.err(new HeaderNotFoundException("Missing expected header \""+
itemHeader+"\" in response \""+responseType.name()+"\""));
}else
handleUnexpectedTypeInResponse(response, callback);
}
@Override
public void onConnectedEvent() {
}
@Override
public void onDisconnectedEvent() {
}
@Override
public void onTimeOutEvent() {
callback.err(new MessageTimeoutException());
}
});
}
public void executeStatQuery(IMapItemMessageCallback<String, String> callback) {
sendMessage(messageFactory.newStatMessage(), callback, MessageType.MSG_STAT);
}
public void executeConfigListQuery(IMapItemMessageCallback<String, String> callback){
sendMessage(messageFactory.newConfigListMessage(), callback, MessageType.MSG_CONFIG_LIST);
}
//TODO à rendre générique pour toute Map<T, U> au lieu de Map<String, String>
private void sendMessage(Message message, IMapItemMessageCallback<String, String> callback, MessageType responseType){
connectionService.sendText(messageToolFactory.getObjectFormatter(Message.class).format(message), new IConnectionListener() {
@Override
public void onMessageReceivedEvent(String msg) {
Message response = messageToolFactory.getObjectParser(Message.class).parse(msg);
if(response.getType().equals(responseType)){
callback.ack(response.getFields());
}else
handleUnexpectedTypeInResponse(response, callback);
}
@Override
public void onConnectedEvent() {
}
@Override
public void onDisconnectedEvent() {
}
@Override
public void onTimeOutEvent() {
callback.err(new MessageTimeoutException());
}
});
}
private void handleUnexpectedTypeInResponse(Message response, IMessageCallback callback){
switch (response.getType()) {
case ERROR_QUERY:
callback.err(messageToolFactory.getObjectParser(Throwable.class).parse(response.getField("Detail_erreur")));
break;
case REFUSED_QUERY:
callback.ref(messageToolFactory.getObjectParser(Throwable.class).parse(response.getField("Detail_refus")));
break;
default:
callback.err(new IllegalArgumentException(
"Illegal message type for response : " +
"expected \"ACK_SALE\"`, found \"" + response.getType().name() + "\""
));
break;
}
}
}

View File

@ -1,38 +0,0 @@
package com.pqt.client.module.query;
import com.pqt.core.entities.product.ProductUpdate;
import com.pqt.core.entities.query.IQuery;
import com.pqt.core.entities.sale.Sale;
import com.pqt.core.entities.user_account.Account;
import java.util.List;
//TODO écrire contenu méthodes
//TODO écrire javadoc
public class QueryFactory {
public static IQuery newConnectQuery(String serverAddress) {
return null;
}
public static IQuery newSaleQuery(Sale sale) {
return null;
}
public static IQuery newStockQuery() {
return null;
}
public static IQuery newStatQuery() {
return null;
}
public static IQuery newLogQuery(Account account, boolean state) {
return null;
}
public static IQuery newUpdateQuery(List<ProductUpdate> updates) {
return null;
}
}

View File

@ -0,0 +1,69 @@
package com.pqt.client.module.query;
import com.pqt.core.communication.IMessageToolFactory;
import com.pqt.core.entities.messages.Message;
import com.pqt.core.entities.messages.MessageType;
import com.pqt.core.entities.product.ProductUpdate;
import com.pqt.core.entities.sale.Sale;
import com.pqt.core.entities.user_account.Account;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//TODO écrire javadoc
class QueryMessageFactory {
private final IMessageToolFactory messageToolFactory;
QueryMessageFactory(IMessageToolFactory messageToolFactory) {
this.messageToolFactory = messageToolFactory;
}
Message newSaleMessage(Sale sale) {
Map<String, String> fields = new HashMap<>();
fields.put("sale", messageToolFactory.getObjectFormatter(Sale.class).format(sale));
return newSimpleMessage(MessageType.QUERY_SALE, fields);
}
Message newStockMessage() {
return newSimpleMessage(MessageType.QUERY_STOCK);
}
Message newStatMessage() {
return newSimpleMessage(MessageType.QUERY_STAT);
}
Message newUpdateMessage(List<ProductUpdate> updates) {
Map<String, String> fields = new HashMap<>();
fields.put("updates", messageToolFactory.getListFormatter(ProductUpdate.class).format(updates));
return newSimpleMessage(MessageType.QUERY_UPDATE, fields);
}
Message newAccountListMessage(){
return newSimpleMessage(MessageType.QUERY_ACCOUNT_LIST);
}
Message newConnectAccountMessage(Account account, boolean desiredState){
Map<String, String> fields = new HashMap<>();
fields.put("account", messageToolFactory.getObjectFormatter(Account.class).format(account));
fields.put("desired_state", messageToolFactory.getObjectFormatter(Boolean.class).format(desiredState));
return newSimpleMessage(MessageType.QUERY_CONNECT_ACCOUNT, fields);
}
Message newPingMessage(){
return newSimpleMessage(MessageType.QUERY_PING);
}
Message newConfigListMessage(){
return newSimpleMessage(MessageType.QUERY_CONFIG_LIST);
}
private Message newSimpleMessage(MessageType type, Map<String, String> fields){
return new Message(type, null, null, null, null, fields);
}
private Message newSimpleMessage(MessageType type){
return newSimpleMessage(type, null);
}
}

View File

@ -0,0 +1,19 @@
package com.pqt.client.module.query.exceptions;
public class HeaderNotFoundException extends Exception {
public HeaderNotFoundException() {
super();
}
public HeaderNotFoundException(String message) {
super(message);
}
public HeaderNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public HeaderNotFoundException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,19 @@
package com.pqt.client.module.query.exceptions;
public class MessageTimeoutException extends Exception {
public MessageTimeoutException() {
super();
}
public MessageTimeoutException(String message) {
super(message);
}
public MessageTimeoutException(String message, Throwable cause) {
super(message, cause);
}
public MessageTimeoutException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,6 @@
package com.pqt.client.module.query.query_callback;
import java.util.Collection;
public interface ICollectionItemMessageCallback<T> extends IItemMessageCallback<Collection<T>> {
}

View File

@ -1,7 +0,0 @@
package com.pqt.client.module.query.query_callback;
public interface IIdQueryCallback {
public void ack(long id);
public void err(long id, Throwable cause);
public void ref(long id, Throwable cause);
}

View File

@ -0,0 +1,5 @@
package com.pqt.client.module.query.query_callback;
public interface IItemMessageCallback<T> extends IMessageCallback {
void ack(T obj);
}

View File

@ -0,0 +1,7 @@
package com.pqt.client.module.query.query_callback;
import java.util.Map;
public interface IMapItemMessageCallback<T, U> extends IItemMessageCallback<Map<T, U>> {
}

View File

@ -0,0 +1,6 @@
package com.pqt.client.module.query.query_callback;
public interface IMessageCallback {
void err(Throwable cause);
void ref(Throwable cause);
}

View File

@ -0,0 +1,5 @@
package com.pqt.client.module.query.query_callback;
public interface INoItemMessageCallback extends IMessageCallback {
void ack();
}

View File

@ -1,7 +0,0 @@
package com.pqt.client.module.query.query_callback;
public interface ISimpleQueryCallback {
public void ack();
public void err(Throwable cause);
public void ref(Throwable cause);
}

View File

@ -1,10 +0,0 @@
package com.pqt.client.module.query.query_callback;
import java.util.Map;
public interface IStatQueryCallback {
public void ack(Map<String,String> stats);
public void err(Throwable cause);
public void ref(Throwable cause);
}

View File

@ -1,11 +0,0 @@
package com.pqt.client.module.query.query_callback;
import com.pqt.core.entities.product.Product;
import java.util.List;
public interface IStockQueryCallback {
public void ack(List<Product> products);
public void err(Throwable cause);
public void ref(Throwable cause);
}

View File

@ -1,8 +1,9 @@
package com.pqt.client.module.sale;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.client.module.query.QueryFactory;
import com.pqt.client.module.query.query_callback.IIdQueryCallback;
import com.pqt.client.module.query.QueryMessageFactory;
import com.pqt.client.module.query.query_callback.ICollectionItemMessageCallback;
import com.pqt.client.module.query.query_callback.INoItemMessageCallback;
import com.pqt.client.module.sale.listeners.ISaleFirerer;
import com.pqt.client.module.sale.listeners.ISaleListener;
import com.pqt.client.module.sale.listeners.SimpleSaleFirerer;
@ -14,10 +15,14 @@ import java.util.List;
//TODO add log lines
public class SaleService {
private long saleId;
private ISaleFirerer eventFirerer;
private QueryExecutor executor;
public SaleService() {
public SaleService(QueryExecutor executor) {
saleId = 0;
eventFirerer = new SimpleSaleFirerer();
this.executor = executor;
}
public SaleBuilder getNewSaleBuilder() {
@ -25,22 +30,30 @@ public class SaleService {
}
public long commitSale(SaleBuilder saleBuilder) {
return QueryExecutor.INSTANCE.execute(QueryFactory.newSaleQuery(saleBuilder.build()), new IIdQueryCallback() {
final long currentSaleId = saleId;
if(saleId<Long.MAX_VALUE)
saleId++;
else
saleId = 0;
executor.executeSaleQuery(saleBuilder.build(), new INoItemMessageCallback() {
@Override
public void ack(long id) {
eventFirerer.fireSaleValidationSuccess(id);
public void ack() {
eventFirerer.fireSaleValidationSuccess(currentSaleId);
}
@Override
public void err(long id, Throwable cause) {
eventFirerer.fireSaleValidationError(id, cause);
public void err(Throwable cause) {
eventFirerer.fireSaleValidationError(currentSaleId, cause);
}
@Override
public void ref(long id, Throwable cause) {
eventFirerer.fireSaleValidationRefused(id, cause);
public void ref(Throwable cause) {
eventFirerer.fireSaleValidationRefused(currentSaleId, cause);
}
});
return currentSaleId;
}
/*

View File

@ -1,8 +1,8 @@
package com.pqt.client.module.stat;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.client.module.query.QueryFactory;
import com.pqt.client.module.query.query_callback.IStatQueryCallback;
import com.pqt.client.module.query.QueryMessageFactory;
import com.pqt.client.module.query.query_callback.IMapItemMessageCallback;
import com.pqt.client.module.stat.listeners.IStatFirerer;
import com.pqt.client.module.stat.listeners.IStatListener;
import com.pqt.client.module.stat.listeners.SimpleStatFirerer;
@ -15,11 +15,13 @@ public class StatDao {
private Date lastRefreshTimestamp;
private Map<String, String> stats;
private IStatFirerer eventFirerer;
private QueryExecutor executor;
public StatDao() {
public StatDao(QueryExecutor executor) {
eventFirerer = new SimpleStatFirerer();
stats = new HashMap<>();
lastRefreshTimestamp = null;
this.executor = executor;
}
public synchronized Map<String, String> getStats() {
@ -27,14 +29,7 @@ public class StatDao {
}
public void refreshStats() {
QueryExecutor.INSTANCE.execute(QueryFactory.newStockQuery(), new IStatQueryCallback() {
@Override
public void ack(Map<String, String> stats) {
replaceStats(stats);
eventFirerer.fireGetStatSuccess();
//TODO add log line
}
executor.executeStatQuery(new IMapItemMessageCallback<String, String>() {
@Override
public void err(Throwable cause) {
eventFirerer.fireGetStatError(cause);
@ -46,6 +41,13 @@ public class StatDao {
eventFirerer.fireGetStatRefused(cause);
//TODO add log line
}
@Override
public void ack(Map<String, String> stats) {
replaceStats(stats);
eventFirerer.fireGetStatSuccess();
//TODO add log line
}
});
}

View File

@ -1,5 +1,6 @@
package com.pqt.client.module.stat;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.client.module.stat.listeners.IStatListener;
import java.util.Map;
@ -10,8 +11,8 @@ public class StatService {
private StatDao dao;
public StatService() {
dao = new StatDao();
public StatService(QueryExecutor executor) {
dao = new StatDao(executor);
}
public Map<String,String> getStats() {

View File

@ -1,9 +1,8 @@
package com.pqt.client.module.stock;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.client.module.query.QueryFactory;
import com.pqt.client.module.query.query_callback.IStockQueryCallback;
import com.pqt.client.module.query.query_callback.IIdQueryCallback;
import com.pqt.client.module.query.query_callback.ICollectionItemMessageCallback;
import com.pqt.client.module.query.query_callback.INoItemMessageCallback;
import com.pqt.client.module.stock.Listeners.IStockFirerer;
import com.pqt.client.module.stock.Listeners.IStockListener;
import com.pqt.client.module.stock.Listeners.SimpleStockFirerer;
@ -11,18 +10,22 @@ import com.pqt.core.entities.product.Product;
import com.pqt.core.entities.product.ProductUpdate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Optional;
//TODO écrire javadoc
public class StockDao {
private long updateId;
private IStockFirerer eventFirerer;
private Date lastRefreshTimestamp;
private List<Product> products;
private QueryExecutor executor;
public StockDao() {
public StockDao(QueryExecutor executor) {
this.executor = executor;
updateId = 0;
eventFirerer = new SimpleStockFirerer();
products = new ArrayList<>();
lastRefreshTimestamp = null;
@ -37,9 +40,9 @@ public class StockDao {
}
public void refreshProductList() {
QueryExecutor.INSTANCE.execute(QueryFactory.newStockQuery(), new IStockQueryCallback() {
executor.executeStockQuery(new ICollectionItemMessageCallback<Product>() {
@Override
public void ack(List<Product> products) {
public void ack(Collection<Product> obj) {
replaceProductList(products);
eventFirerer.fireGetProductListSuccessEvent();
//TODO add log line
@ -71,27 +74,33 @@ public class StockDao {
}
public long commitUpdate(List<ProductUpdate> updates){
return QueryExecutor.INSTANCE.execute(QueryFactory.newUpdateQuery(updates),new IIdQueryCallback(){
final long currentUpdateId = updateId;
if(updateId<Long.MAX_VALUE)
updateId++;
else
updateId = 0;
executor.executeUpdateQuery(updates, new INoItemMessageCallback() {
@Override
public void ack(long id) {
public void ack() {
//TODO add log line
refreshProductList();
eventFirerer.fireProductListUpdateSuccessEvent(id);
eventFirerer.fireProductListUpdateSuccessEvent(currentUpdateId);
}
@Override
public void err(long id, Throwable cause) {
//TODO add log line
eventFirerer.fireProductListUpdateErrorEvent(id, cause);
public void err(Throwable cause) {
//TODO add log line
eventFirerer.fireProductListUpdateErrorEvent(currentUpdateId, cause);
}
@Override
public void ref(long id, Throwable cause) {
//TODO add log line
eventFirerer.fireProductListUpdateRefusedEvent(id, cause);
public void ref(Throwable cause) {
//TODO add log line
eventFirerer.fireProductListUpdateRefusedEvent(currentUpdateId, cause);
}
});
return currentUpdateId;
}
/**

View File

@ -1,5 +1,6 @@
package com.pqt.client.module.stock;
import com.pqt.client.module.query.QueryExecutor;
import com.pqt.core.entities.product.Product;
import com.pqt.client.module.stock.Listeners.IStockListener;
@ -9,12 +10,10 @@ import java.util.List;
//TODO Add log lines
public class StockService {
public static final StockService INSTANCE = new StockService();
private StockDao dao;
public StockService() {
dao = new StockDao();
public StockService(QueryExecutor executor) {
dao = new StockDao(executor);
}
/**