* Commander pattern * Fix checkstyle errors * Update Commander.java * Update README.md * Update PaymentService.java * Update Commander.java * Update README.md
This commit is contained in:
committed by
Ilkka Seppälä
parent
a113de6a14
commit
d9a567cf97
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppEmployeeDbFailCases class looks at possible cases when Employee handle service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppEmployeeDbFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void employeeDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void employeeDbSuccessCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppEmployeeDbFailCases aefc = new AppEmployeeDbFailCases();
|
||||
//aefc.employeeDatabaseUnavailableCase();
|
||||
aefc.employeeDbSuccessCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppMessagingFailCases class looks at possible cases when Messaging service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppMessagingFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentSuccess() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentError() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentFailure() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,queueTime,queueTaskTime,
|
||||
paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingSuccessCase() throws Exception {
|
||||
//done here
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppMessagingFailCases amfc = new AppMessagingFailCases();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentSuccess();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentError();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentFailure();
|
||||
amfc.messagingSuccessCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.PaymentDetailsErrorException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppPaymentFailCases class looks at possible cases when Payment service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppPaymentFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void paymentNotPossibleCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new PaymentDetailsErrorException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void paymentDatabaseUnavailableCase() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void paymentSuccessCase() throws Exception {
|
||||
//goes to message after 2 retries maybe - rest is successful for now
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppPaymentFailCases apfc = new AppPaymentFailCases();
|
||||
//apfc.paymentNotPossibleCase();
|
||||
//apfc.paymentDatabaseUnavailableCase();
|
||||
apfc.paymentSuccessCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppQueueFailCases class looks at possible cases when Queue Database is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppQueueFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void queuePaymentTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueMessageTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueEmployeeDbTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueSuccessCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppQueueFailCases aqfc = new AppQueueFailCases();
|
||||
//aqfc.queuePaymentTaskDatabaseUnavailableCase();
|
||||
//aqfc.queueMessageTaskDatabaseUnavailableCase();
|
||||
//aqfc.queueEmployeeDbTaskDatabaseUnavailableCase();
|
||||
aqfc.queueSuccessCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ShippingNotPossibleException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppShippingFailCases class looks at possible cases when Shipping service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppShippingFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void itemUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingNotPossibleCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ShippingNotPossibleException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingDatabaseUnavailableCase() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingSuccessCase() throws Exception {
|
||||
//goes to payment after 2 retries maybe - rest is successful for now
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppShippingFailCases asfc = new AppShippingFailCases();
|
||||
//asfc.itemUnavailableCase();
|
||||
//asfc.shippingNotPossibleCase();
|
||||
//asfc.shippingDatabaseUnavailableCase();
|
||||
asfc.shippingSuccessCase();
|
||||
}
|
||||
}
|
613
commander/src/main/java/com/iluwatar/commander/Commander.java
Normal file
613
commander/src/main/java/com/iluwatar/commander/Commander.java
Normal file
@ -0,0 +1,613 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.apache.log4j.Logger;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.PaymentDetailsErrorException;
|
||||
import com.iluwatar.commander.exceptions.ShippingNotPossibleException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.Order.MessageSent;
|
||||
import com.iluwatar.commander.Order.PaymentStatus;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
import com.iluwatar.commander.queue.QueueTask;
|
||||
import com.iluwatar.commander.queue.QueueTask.TaskType;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
|
||||
/**
|
||||
*<p>Commander pattern is used to handle all issues that can come up while making a
|
||||
* distributed transaction. The idea is to have a commander, which coordinates the
|
||||
* execution of all instructions and ensures proper completion using retries and
|
||||
* taking care of idempotence. By queueing instructions while they haven't been done,
|
||||
* we can ensure a state of 'eventual consistency'.</p>
|
||||
* <p>In our example, we have an e-commerce application. When the user places an order,
|
||||
* the shipping service is intimated first. If the service does not respond for some
|
||||
* reason, the order is not placed. If response is received, the commander then calls
|
||||
* for the payment service to be intimated. If this fails, the shipping still takes
|
||||
* place (order converted to COD) and the item is queued. If the queue is also found
|
||||
* to be unavailable, the payment is noted to be not done and this is added to an
|
||||
* employee database. Three types of messages are sent to the user - one, if payment
|
||||
* succeeds; two, if payment fails definitively; and three, if payment fails in the
|
||||
* first attempt. If the message is not sent, this is also queued and is added to employee
|
||||
* db. We also have a time limit for each instruction to be completed, after which, the
|
||||
* instruction is not executed, thereby ensuring that resources are not held for too long.
|
||||
* In the rare occasion in which everything fails, an individual would have to step in to
|
||||
* figure out how to solve the issue.</p>
|
||||
* <p>We have abstract classes {@link Database} and {@link Service} which are extended
|
||||
* by all the databases and services. Each service has a database to be updated, and
|
||||
* receives request from an outside user (the {@link Commander} class here). There are
|
||||
* 5 microservices - {@link ShippingService}, {@link PaymentService}, {@link MessagingService},
|
||||
* {@link EmployeeHandle} and a {@link QueueDatabase}. We use retries to execute any
|
||||
* instruction using {@link Retry} class, and idempotence is ensured by going through some
|
||||
* checks before making requests to services and making change in {@link Order} class fields
|
||||
* if request succeeds or definitively fails. There are 5 classes -
|
||||
* {@link AppShippingFailCases}, {@link AppPaymentFailCases}, {@link AppMessagingFailCases},
|
||||
* {@link AppQueueFailCases} and {@link AppEmployeeDbFailCases}, which look at the different
|
||||
* scenarios that may be encountered during the placing of an order.</p>
|
||||
*/
|
||||
|
||||
public class Commander {
|
||||
|
||||
private final QueueDatabase queue;
|
||||
private final EmployeeHandle employeeDb;
|
||||
private final PaymentService paymentService;
|
||||
private final ShippingService shippingService;
|
||||
private final MessagingService messagingService;
|
||||
private int queueItems = 0; //keeping track here only so don't need access to queue db to get this
|
||||
private final int numOfRetries;
|
||||
private final long retryDuration;
|
||||
private final long queueTime;
|
||||
private final long queueTaskTime;
|
||||
private final long paymentTime;
|
||||
private final long messageTime;
|
||||
private final long employeeTime;
|
||||
private boolean finalSiteMsgShown;
|
||||
static final Logger LOG = Logger.getLogger(Commander.class);
|
||||
//we could also have another db where it stores all orders
|
||||
|
||||
Commander(EmployeeHandle empDb, PaymentService pService, ShippingService sService,
|
||||
MessagingService mService, QueueDatabase qdb, int numOfRetries, long retryDuration,
|
||||
long queueTime, long queueTaskTime, long paymentTime, long messageTime, long employeeTime) {
|
||||
this.paymentService = pService;
|
||||
this.shippingService = sService;
|
||||
this.messagingService = mService;
|
||||
this.employeeDb = empDb;
|
||||
this.queue = qdb;
|
||||
this.numOfRetries = numOfRetries;
|
||||
this.retryDuration = retryDuration;
|
||||
this.queueTime = queueTime;
|
||||
this.queueTaskTime = queueTaskTime;
|
||||
this.paymentTime = paymentTime;
|
||||
this.messageTime = messageTime;
|
||||
this.employeeTime = employeeTime;
|
||||
this.finalSiteMsgShown = false;
|
||||
}
|
||||
|
||||
void placeOrder(Order order) throws Exception {
|
||||
sendShippingRequest(order);
|
||||
}
|
||||
|
||||
private void sendShippingRequest(Order order) throws Exception {
|
||||
ArrayList<Exception> list = shippingService.exceptionsList;
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to shipping service, trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating shipping request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
String transactionId = shippingService.receiveRequest(order.item, order.user.address);
|
||||
//could save this transaction id in a db too
|
||||
LOG.info("Order " + order.id + ": Shipping placed successfully, transaction id: " + transactionId);
|
||||
System.out.println("Order has been placed and will be shipped to you. Please wait while we make your"
|
||||
+ " payment... ");
|
||||
sendPaymentRequest(order);
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if (ShippingNotPossibleException.class.isAssignableFrom(err.getClass())) {
|
||||
System.out.println("Shipping is currently not possible to your address. We are working on the problem "
|
||||
+ "and will get back to you asap.");
|
||||
finalSiteMsgShown = true;
|
||||
LOG.info("Order " + order.id + ": Shipping not possible to address, trying to add problem to employee db..");
|
||||
employeeHandleIssue(o);
|
||||
} else if (ItemUnavailableException.class.isAssignableFrom(err.getClass())) {
|
||||
System.out.println("This item is currently unavailable. We will inform you as soon as the item becomes "
|
||||
+ "available again.");
|
||||
finalSiteMsgShown = true;
|
||||
LOG.info("Order " + order.id + ": Item " + order.item + " unavailable, trying to add problem to employee "
|
||||
+ "handle..");
|
||||
employeeHandleIssue(o);
|
||||
} else {
|
||||
System.out.println("Sorry, there was a problem in creating your order. Please try later.");
|
||||
LOG.error("Order " + order.id + ": Shipping service unavailable, order not placed..");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
r.perform(list, order);
|
||||
}
|
||||
|
||||
private void sendPaymentRequest(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.paymentTime) {
|
||||
if (order.paid.equals(PaymentStatus.Trying)) {
|
||||
order.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(order);
|
||||
LOG.error("Order " + order.id + ": Payment time for order over, failed and returning..");
|
||||
} //if succeeded or failed, would have been dequeued, no attempt to make payment
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = paymentService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to payment service, trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating payment request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (order.paid.equals(PaymentStatus.Trying)) {
|
||||
String transactionId = paymentService.receiveRequest(order.price);
|
||||
order.paid = PaymentStatus.Done;
|
||||
LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId);
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("Payment made successfully, thank you for shopping with us!!");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
sendSuccessMessage(order);
|
||||
return;
|
||||
}
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) {
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("There was an error in payment. Your account/card details may have been incorrect. "
|
||||
+ "Meanwhile, your order has been converted to COD and will be shipped.");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
LOG.error("Order " + order.id + ": Payment details incorrect, failed..");
|
||||
o.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(o);
|
||||
} else {
|
||||
try {
|
||||
if (o.messageSent.equals(MessageSent.NoneSent)) {
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("There was an error in payment. We are on it, and will get back to you "
|
||||
+ "asap. Don't worry, your order has been placed and will be shipped.");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
LOG.warn("Order " + order.id + ": Payment error, going to queue..");
|
||||
sendPaymentPossibleErrorMsg(o);
|
||||
}
|
||||
if (o.paid.equals(PaymentStatus.Trying) && System.currentTimeMillis() - o.createdTime < paymentTime) {
|
||||
QueueTask qt = new QueueTask(o, TaskType.Payment,-1);
|
||||
updateQueue(qt);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void updateQueue(QueueTask qt) throws InterruptedException {
|
||||
if (System.currentTimeMillis() - qt.order.createdTime >= this.queueTime) {
|
||||
//since payment time is lesser than queuetime it would have already failed..additional check not needed
|
||||
LOG.trace("Order " + qt.order.id + ": Queue time for order over, failed..");
|
||||
return;
|
||||
} else if ((qt.taskType.equals(TaskType.Payment) && !qt.order.paid.equals(PaymentStatus.Trying))
|
||||
|| (qt.taskType.equals(TaskType.Messaging) && ((qt.messageType == 1
|
||||
&& !qt.order.messageSent.equals(MessageSent.NoneSent))
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentFail)
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentSuccessful)))
|
||||
|| (qt.taskType.equals(TaskType.EmployeeDb) && qt.order.addedToEmployeeHandle)) {
|
||||
LOG.trace("Order " + qt.order.id + ": Not queueing task since task already done..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Order " + qt.order.id + ": Error in connecting to queue db, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
queue.add(qt);
|
||||
queueItems++;
|
||||
LOG.info("Order " + qt.order.id + ": " + qt.getType() + " task enqueued..");
|
||||
tryDoingTasksInQueue();
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (qt,err) -> {
|
||||
if (qt.taskType.equals(TaskType.Payment)) {
|
||||
qt.order.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(qt.order);
|
||||
LOG.error("Order " + qt.order.id + ": Unable to enqueue payment task, payment failed..");
|
||||
}
|
||||
LOG.error("Order " + qt.order.id + ": Unable to enqueue task of type " + qt.getType()
|
||||
+ ", trying to add to employee handle..");
|
||||
employeeHandleIssue(qt.order);
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, qt);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void tryDoingTasksInQueue() { //commander controls operations done to queue
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t2 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Error in accessing queue db to do tasks, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
doTasksInQueue();
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (o,err) -> {
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, null);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t2.start();
|
||||
}
|
||||
|
||||
private void tryDequeue() {
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t3 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Error in accessing queue db to dequeue task, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
queue.dequeue();
|
||||
queueItems--;
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (o,err) -> {
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, null);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t3.start();
|
||||
}
|
||||
|
||||
private void sendSuccessMessage(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Order " + order.id + ": Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Success msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Success messaging request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.messageSent.equals(MessageSent.PaymentFail)
|
||||
&& !order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
String requestId = messagingService.receiveRequest(2);
|
||||
order.messageSent = MessageSent.PaymentSuccessful;
|
||||
LOG.info("Order " + order.id + ": Payment Success message sent, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent.equals(MessageSent.PaymentTrying))
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
QueueTask qt = new QueueTask(order, TaskType.Messaging,2);
|
||||
updateQueue(qt);
|
||||
LOG.info("Order " + order.id + ": Error in sending Payment Success message, trying to "
|
||||
+ "queue task and add to employee handle..");
|
||||
employeeHandleIssue(order);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void sendPaymentFailureMessage(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Order " + order.id + ": Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Failure msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Failure message request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.messageSent.equals(MessageSent.PaymentFail)
|
||||
&& !order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
String requestId = messagingService.receiveRequest(0);
|
||||
order.messageSent = MessageSent.PaymentFail;
|
||||
LOG.info("Order " + order.id + ": Payment Failure message sent successfully, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent.equals(MessageSent.PaymentTrying))
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
try {
|
||||
QueueTask qt = new QueueTask(order, TaskType.Messaging,0);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in sending Payment Failure message, "
|
||||
+ "trying to queue task and add to employee handle..");
|
||||
employeeHandleIssue(o);
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void sendPaymentPossibleErrorMsg(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Error msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Error messaging request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (order.paid.equals(PaymentStatus.Trying) && order.messageSent.equals(MessageSent.NoneSent)) {
|
||||
String requestId = messagingService.receiveRequest(1);
|
||||
order.messageSent = MessageSent.PaymentTrying;
|
||||
LOG.info("Order " + order.id + ": Payment Error message sent successfully, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if (o.messageSent.equals(MessageSent.NoneSent) && order.paid.equals(PaymentStatus.Trying)
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
QueueTask qt = new QueueTask(order,TaskType.Messaging,1);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in sending Payment Error message, "
|
||||
+ "trying to queue task and add to employee handle..");
|
||||
employeeHandleIssue(o);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void employeeHandleIssue(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.employeeTime) {
|
||||
LOG.trace("Order " + order.id + ": Employee handle time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = employeeDb.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
LOG.warn("Order " + order.id + ": Error in connecting to employee handle, trying again..");
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.addedToEmployeeHandle) {
|
||||
employeeDb.receiveRequest(order);
|
||||
order.addedToEmployeeHandle = true;
|
||||
LOG.info("Order " + order.id + ": Added order to employee database");
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if (!o.addedToEmployeeHandle && System.currentTimeMillis() - order.createdTime < employeeTime) {
|
||||
QueueTask qt = new QueueTask(order, TaskType.EmployeeDb,-1);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in adding to employee db, trying to queue task..");
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void doTasksInQueue() throws Exception {
|
||||
if (queueItems != 0) {
|
||||
QueueTask qt = queue.peek(); //this should probably be cloned here
|
||||
//this is why we have retry for doTasksInQueue
|
||||
LOG.trace("Order " + qt.order.id + ": Started doing task of type " + qt.getType());
|
||||
if (qt.firstAttemptTime == -1) {
|
||||
qt.firstAttemptTime = System.currentTimeMillis();
|
||||
}
|
||||
if (System.currentTimeMillis() - qt.firstAttemptTime >= queueTaskTime) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This queue task of type " + qt.getType()
|
||||
+ " does not need to be done anymore (timeout), dequeue..");
|
||||
} else {
|
||||
if (qt.taskType.equals(TaskType.Payment)) {
|
||||
if (!qt.order.paid.equals(PaymentStatus.Trying)) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This payment task already done, dequeueing..");
|
||||
} else {
|
||||
sendPaymentRequest(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to payment service..");
|
||||
}
|
||||
} else if (qt.taskType.equals(TaskType.Messaging)) {
|
||||
if (qt.order.messageSent.equals(MessageSent.PaymentFail)
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This messaging task already done, dequeue..");
|
||||
} else if ((qt.messageType == 1 && (!qt.order.messageSent.equals(MessageSent.NoneSent)
|
||||
|| !qt.order.paid.equals(PaymentStatus.Trying)))) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This messaging task does not need to be done, dequeue..");
|
||||
} else if (qt.messageType == 0) {
|
||||
sendPaymentFailureMessage(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
} else if (qt.messageType == 1) {
|
||||
sendPaymentPossibleErrorMsg(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
} else if (qt.messageType == 2) {
|
||||
sendSuccessMessage(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
}
|
||||
} else if (qt.taskType.equals(TaskType.EmployeeDb)) {
|
||||
if (qt.order.addedToEmployeeHandle) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This employee handle task already done, dequeue..");
|
||||
} else {
|
||||
employeeHandleIssue(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to employee handle..");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queueItems == 0) {
|
||||
LOG.trace("Queue is empty, returning..");
|
||||
} else {
|
||||
Thread.sleep(queueTaskTime / 3);
|
||||
tryDoingTasksInQueue();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
37
commander/src/main/java/com/iluwatar/commander/Database.java
Normal file
37
commander/src/main/java/com/iluwatar/commander/Database.java
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* Database abstract class is extended by all databases in our example. The add and get
|
||||
* methods are used by the respective service to add to database or get from database.
|
||||
* @param <T> T is the type of object being held by database.
|
||||
*/
|
||||
|
||||
public abstract class Database<T> {
|
||||
public abstract T add(T obj) throws DatabaseUnavailableException;
|
||||
public abstract T get(String tId) throws DatabaseUnavailableException;
|
||||
}
|
82
commander/src/main/java/com/iluwatar/commander/Order.java
Normal file
82
commander/src/main/java/com/iluwatar/commander/Order.java
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Order class holds details of the order.
|
||||
*/
|
||||
|
||||
public class Order { //can store all transactions ids also
|
||||
|
||||
enum PaymentStatus {
|
||||
NotDone, Trying, Done
|
||||
};
|
||||
|
||||
enum MessageSent {
|
||||
NoneSent, PaymentFail, PaymentTrying, PaymentSuccessful
|
||||
};
|
||||
|
||||
final User user;
|
||||
final String item;
|
||||
public final String id;
|
||||
final float price;
|
||||
final long createdTime;
|
||||
private static final String ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
private static final Hashtable<String, Boolean> USED_IDS = new Hashtable<String, Boolean>();
|
||||
PaymentStatus paid;
|
||||
MessageSent messageSent; //to avoid sending error msg on page and text more than once
|
||||
boolean addedToEmployeeHandle; //to avoid creating more to enqueue
|
||||
|
||||
Order(User user, String item, float price) {
|
||||
this.createdTime = System.currentTimeMillis();
|
||||
this.user = user;
|
||||
this.item = item;
|
||||
this.price = price;
|
||||
String id = createUniqueId();
|
||||
if (USED_IDS.get(id) != null) {
|
||||
while (USED_IDS.get(id)) {
|
||||
id = createUniqueId();
|
||||
}
|
||||
}
|
||||
this.id = id;
|
||||
USED_IDS.put(this.id, true);
|
||||
this.paid = PaymentStatus.Trying;
|
||||
this.messageSent = MessageSent.NoneSent;
|
||||
this.addedToEmployeeHandle = false;
|
||||
}
|
||||
|
||||
String createUniqueId() {
|
||||
StringBuilder random = new StringBuilder();
|
||||
Random rand = new Random();
|
||||
while (random.length() < 12) { // length of the random string.
|
||||
int index = (int) (rand.nextFloat() * ALL_CHARS.length());
|
||||
random.append(ALL_CHARS.charAt(index));
|
||||
}
|
||||
return random.toString();
|
||||
}
|
||||
|
||||
}
|
105
commander/src/main/java/com/iluwatar/commander/Retry.java
Normal file
105
commander/src/main/java/com/iluwatar/commander/Retry.java
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Retry pattern
|
||||
* @param <T> is the type of object passed into HandleErrorIssue as a parameter.
|
||||
*/
|
||||
|
||||
public class Retry<T> {
|
||||
|
||||
/**
|
||||
* Operation Interface will define method to be implemented.
|
||||
*/
|
||||
|
||||
public interface Operation {
|
||||
void operation(ArrayList<Exception> list) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* HandleErrorIssue defines how to handle errors.
|
||||
* @param <T> is the type of object to be passed into the method as parameter.
|
||||
*/
|
||||
|
||||
public interface HandleErrorIssue<T> {
|
||||
void handleIssue(T obj, Exception e);
|
||||
}
|
||||
|
||||
private final Operation op;
|
||||
private final HandleErrorIssue<T> handleError;
|
||||
private final int maxAttempts;
|
||||
private final long maxDelay;
|
||||
private final AtomicInteger attempts;
|
||||
private final Predicate<Exception> test;
|
||||
private final ArrayList<Exception> errors;
|
||||
|
||||
Retry(Operation op, HandleErrorIssue handleError, int maxAttempts,
|
||||
long maxDelay, Predicate<Exception>... ignoreTests) {
|
||||
this.op = op;
|
||||
this.handleError = handleError;
|
||||
this.maxAttempts = maxAttempts;
|
||||
this.maxDelay = maxDelay;
|
||||
this.attempts = new AtomicInteger();
|
||||
this.test = Arrays.stream(ignoreTests).reduce(Predicate::or).orElse(e -> false);
|
||||
this.errors = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performing the operation with retries.
|
||||
* @param list is the exception list
|
||||
* @param obj is the parameter to be passed into handleIsuue method
|
||||
*/
|
||||
|
||||
public void perform(ArrayList<Exception> list, T obj) throws Exception {
|
||||
do {
|
||||
try {
|
||||
op.operation(list);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
this.errors.add(e);
|
||||
if (this.attempts.incrementAndGet() >= this.maxAttempts || !this.test.test(e)) {
|
||||
this.handleError.handleIssue(obj, e);
|
||||
return; //return here...dont go further
|
||||
}
|
||||
try {
|
||||
Random rand = new Random();
|
||||
long testDelay = (long) Math.pow(2, this.attempts.intValue()) * 1000 + rand.nextInt(1000);
|
||||
long delay = testDelay < this.maxDelay ? testDelay : maxDelay;
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException f) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
}
|
72
commander/src/main/java/com/iluwatar/commander/Service.java
Normal file
72
commander/src/main/java/com/iluwatar/commander/Service.java
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Random;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* Service class is an abstract class extended by all services in this example. They
|
||||
* all have a public receiveRequest method to receive requests, which could also contain
|
||||
* details of the user other than the implementation details (though we are not doing
|
||||
* that here) and updateDb method which adds to their respective databases. There is a
|
||||
* method to generate transaction/request id for the transactions/requests, which are
|
||||
* then sent back. These could be stored by the {@link Commander} class in a separate
|
||||
* database for reference (though we are not doing that here).
|
||||
*/
|
||||
|
||||
public abstract class Service {
|
||||
|
||||
protected final Database database;
|
||||
public ArrayList<Exception> exceptionsList;
|
||||
private static final String ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
private static final Hashtable<String, Boolean> USED_IDS = new Hashtable<String, Boolean>();
|
||||
|
||||
protected Service(Database db, Exception...exc) {
|
||||
this.database = db;
|
||||
this.exceptionsList = new ArrayList<Exception>(Arrays.asList(exc));
|
||||
}
|
||||
|
||||
public abstract String receiveRequest(Object...parameters) throws DatabaseUnavailableException;
|
||||
protected abstract String updateDb(Object...parameters) throws DatabaseUnavailableException;
|
||||
|
||||
protected String generateId() {
|
||||
StringBuilder random = new StringBuilder();
|
||||
Random rand = new Random();
|
||||
while (random.length() < 12) { // length of the random string.
|
||||
int index = (int) (rand.nextFloat() * ALL_CHARS.length());
|
||||
random.append(ALL_CHARS.charAt(index));
|
||||
}
|
||||
String id = random.toString();
|
||||
if (USED_IDS.get(id) != null) {
|
||||
while (USED_IDS.get(id)) {
|
||||
id = generateId();
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
39
commander/src/main/java/com/iluwatar/commander/User.java
Normal file
39
commander/src/main/java/com/iluwatar/commander/User.java
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
/**
|
||||
* User class contains details of user who places order.
|
||||
*/
|
||||
|
||||
public class User {
|
||||
String name;
|
||||
String address;
|
||||
|
||||
User(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.employeehandle;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.Order;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The Employee Database is where orders which have encountered some issue(s) are added.
|
||||
*/
|
||||
|
||||
public class EmployeeDatabase extends Database<Order> {
|
||||
private Hashtable<String, Order> data;
|
||||
|
||||
public EmployeeDatabase() {
|
||||
this.data = new Hashtable<String, Order>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order add(Order o) throws DatabaseUnavailableException {
|
||||
return data.put(o.id,o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order get(String oId) throws DatabaseUnavailableException {
|
||||
return data.get(oId);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.employeehandle;
|
||||
|
||||
import com.iluwatar.commander.Order;
|
||||
import com.iluwatar.commander.Service;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The EmployeeHandle class is the middle-man between {@link Commander} and
|
||||
* {@link EmployeeDatabase}.
|
||||
*/
|
||||
|
||||
public class EmployeeHandle extends Service {
|
||||
|
||||
public EmployeeHandle(EmployeeDatabase db, Exception...exc) {
|
||||
super(db, exc);
|
||||
}
|
||||
|
||||
public String receiveRequest(Object...parameters) throws DatabaseUnavailableException {
|
||||
return updateDb((Order)parameters[0]);
|
||||
}
|
||||
|
||||
protected String updateDb(Object...parameters) throws DatabaseUnavailableException {
|
||||
Order o = (Order) parameters[0];
|
||||
if (database.get(o.id) == null) {
|
||||
database.add(o);
|
||||
return o.id; //true rcvd - change addedToEmployeeHandle to true else dont do anything
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* DatabaseUnavailableException is thrown when database is unavailable and nothing
|
||||
* can be added or retrieved.
|
||||
*/
|
||||
|
||||
public class DatabaseUnavailableException extends Exception {
|
||||
private static final long serialVersionUID = 2459603L;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* IsEmptyException is thrown when it is attempted to dequeue from an empty queue.
|
||||
*/
|
||||
|
||||
public class IsEmptyException extends Exception {
|
||||
private static final long serialVersionUID = 123546L;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* ItemUnavailableException is thrown when item is not available for shipping.
|
||||
*/
|
||||
|
||||
public class ItemUnavailableException extends Exception {
|
||||
private static final long serialVersionUID = 575940L;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* PaymentDetailsErrorException is thrown when the details entered are incorrect or
|
||||
* payment cannot be made with the details given.
|
||||
*/
|
||||
|
||||
public class PaymentDetailsErrorException extends Exception {
|
||||
private static final long serialVersionUID = 867203L;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* ShippingNotPossibleException is thrown when the address entered cannot be shipped to
|
||||
* by service currently for some reason.
|
||||
*/
|
||||
|
||||
public class ShippingNotPossibleException extends Exception {
|
||||
private static final long serialVersionUID = 342055L;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.messagingservice;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService.MessageRequest;
|
||||
|
||||
/**
|
||||
* The MessagingDatabase is where the MessageRequest is added.
|
||||
*/
|
||||
|
||||
public class MessagingDatabase extends Database<MessageRequest> {
|
||||
private Hashtable<String, MessageRequest> data;
|
||||
|
||||
public MessagingDatabase() {
|
||||
this.data = new Hashtable<String, MessageRequest>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageRequest add(MessageRequest r) throws DatabaseUnavailableException {
|
||||
return data.put(r.reqId, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageRequest get(String rId) throws DatabaseUnavailableException {
|
||||
return data.get(rId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.messagingservice;
|
||||
|
||||
import com.iluwatar.commander.Service;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The MessagingService is used to send messages to user regarding their order and
|
||||
* payment status. In case an error is encountered in payment and this service is
|
||||
* found to be unavailable, the order is added to the {@link EmployeeDatabase}.
|
||||
*/
|
||||
|
||||
public class MessagingService extends Service {
|
||||
|
||||
enum MessageToSend {
|
||||
PaymentFail, PaymentTrying, PaymentSuccessful
|
||||
};
|
||||
|
||||
class MessageRequest {
|
||||
String reqId;
|
||||
MessageToSend msg;
|
||||
|
||||
MessageRequest(String reqId, MessageToSend msg) {
|
||||
this.reqId = reqId;
|
||||
this.msg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
public MessagingService(MessagingDatabase db, Exception...exc) {
|
||||
super(db, exc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method which will receive request from {@link Commander}.
|
||||
*/
|
||||
|
||||
public String receiveRequest(Object...parameters) throws DatabaseUnavailableException {
|
||||
int messageToSend = (int) parameters[0];
|
||||
String rId = generateId();
|
||||
MessageToSend msg = null;
|
||||
if (messageToSend == 0) {
|
||||
msg = MessageToSend.PaymentFail;
|
||||
} else if (messageToSend == 1) {
|
||||
msg = MessageToSend.PaymentTrying;
|
||||
} else { //messageToSend == 2
|
||||
msg = MessageToSend.PaymentSuccessful;
|
||||
}
|
||||
MessageRequest req = new MessageRequest(rId, msg);
|
||||
return updateDb(req);
|
||||
}
|
||||
|
||||
protected String updateDb(Object...parameters) throws DatabaseUnavailableException {
|
||||
MessageRequest req = (MessageRequest) parameters[0];
|
||||
if (this.database.get(req.reqId) == null) { //idempotence, in case db fails here
|
||||
database.add(req); //if successful:
|
||||
System.out.println(sendMessage(req.msg));
|
||||
return req.reqId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String sendMessage(MessageToSend m) {
|
||||
if (m.equals(MessageToSend.PaymentSuccessful)) {
|
||||
return "Msg: Your order has been placed and paid for successfully! Thank you for shopping with us!";
|
||||
} else if (m.equals(MessageToSend.PaymentTrying)) {
|
||||
return "Msg: There was an error in your payment process, we are working on it and will return back to you"
|
||||
+ " shortly. Meanwhile, your order has been placed and will be shipped.";
|
||||
} else {
|
||||
return "Msg: There was an error in your payment process. Your order is placed and has been converted to COD."
|
||||
+ " Please reach us on CUSTOMER-CARE-NUBER in case of any queries. Thank you for shopping with us!";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.paymentservice;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService.PaymentRequest;
|
||||
|
||||
/**
|
||||
* PaymentDatabase is where the PaymentRequest is added, along with details.
|
||||
*/
|
||||
|
||||
public class PaymentDatabase extends Database<PaymentRequest> {
|
||||
|
||||
private Hashtable<String, PaymentRequest> data;
|
||||
|
||||
public PaymentDatabase() {
|
||||
this.data = new Hashtable<String, PaymentRequest>();
|
||||
//0-fail, 1-error, 2-success
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentRequest add(PaymentRequest r) throws DatabaseUnavailableException {
|
||||
return data.put(r.transactionId, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentRequest get(String tId) throws DatabaseUnavailableException {
|
||||
return data.get(tId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.paymentservice;
|
||||
|
||||
import com.iluwatar.commander.Service;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The PaymentService class receives request from the {@link Commander} and adds
|
||||
* to the {@link PaymentDatabase}.
|
||||
*/
|
||||
|
||||
public class PaymentService extends Service {
|
||||
|
||||
class PaymentRequest {
|
||||
String transactionId;
|
||||
float payment;
|
||||
boolean paid;
|
||||
|
||||
PaymentRequest(String transactionId, float payment) {
|
||||
this.transactionId = transactionId;
|
||||
this.payment = payment;
|
||||
this.paid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public PaymentService(PaymentDatabase db, Exception...exc) {
|
||||
super(db, exc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method which will receive request from {@link Commander}.
|
||||
*/
|
||||
|
||||
public String receiveRequest(Object...parameters) throws DatabaseUnavailableException {
|
||||
//it could also be sending a userid, payment details here or something, not added here
|
||||
String tId = generateId();
|
||||
PaymentRequest req = new PaymentRequest(tId, (float)parameters[0]);
|
||||
return updateDb(req);
|
||||
}
|
||||
|
||||
protected String updateDb(Object...parameters) throws DatabaseUnavailableException {
|
||||
PaymentRequest req = (PaymentRequest) parameters[0];
|
||||
if (database.get(req.transactionId) == null || !req.paid) {
|
||||
database.add(req);
|
||||
req.paid = true;
|
||||
return req.transactionId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.queue;
|
||||
|
||||
import com.iluwatar.commander.exceptions.IsEmptyException;
|
||||
|
||||
/**
|
||||
* Queue data structure implementation.
|
||||
* @param <T> is the type of object the queue will hold.
|
||||
*/
|
||||
|
||||
public class Queue<T> {
|
||||
|
||||
Node<T> front;
|
||||
Node<T> rear;
|
||||
public int size = 0;
|
||||
|
||||
class Node<T> {
|
||||
T value;
|
||||
Node<T> next;
|
||||
|
||||
Node(T obj, Node<T> b) {
|
||||
value = obj;
|
||||
next = b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue constructor
|
||||
*/
|
||||
|
||||
Queue() {
|
||||
front = null;
|
||||
rear = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
if (size == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void enqueue(T obj) {
|
||||
if (front == null) {
|
||||
front = new Node(obj, null);
|
||||
rear = front;
|
||||
} else {
|
||||
Node temp = new Node(obj, null);
|
||||
rear.next = temp;
|
||||
rear = temp;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
|
||||
T dequeue() throws IsEmptyException {
|
||||
if (isEmpty()) {
|
||||
throw new IsEmptyException();
|
||||
} else {
|
||||
Node temp = front;
|
||||
front = front.next;
|
||||
size = size - 1;
|
||||
return ((T) temp.value);
|
||||
}
|
||||
}
|
||||
|
||||
T peek() throws IsEmptyException {
|
||||
if (isEmpty()) {
|
||||
throw new IsEmptyException();
|
||||
} else {
|
||||
return ((T)front.value);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.queue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.IsEmptyException;
|
||||
|
||||
/**
|
||||
* QueueDatabase id where the instructions to be implemented are queued.
|
||||
*/
|
||||
|
||||
public class QueueDatabase extends Database<QueueTask> {
|
||||
|
||||
private Queue<QueueTask> data;
|
||||
public ArrayList<Exception> exceptionsList;
|
||||
|
||||
public QueueDatabase(Exception...exc) {
|
||||
this.data = new Queue<QueueTask>();
|
||||
this.exceptionsList = new ArrayList<Exception>(Arrays.asList(exc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueueTask add(QueueTask t) throws DatabaseUnavailableException {
|
||||
data.enqueue(t);
|
||||
return t;
|
||||
//even if same thing queued twice, it is taken care of in other dbs
|
||||
}
|
||||
|
||||
/**
|
||||
* peek method returns object at front without removing it from queue
|
||||
* @return object at front of queue
|
||||
* @throws IsEmptyException if queue is empty
|
||||
* @throws DatabaseUnavailableException if queue db is unavailable
|
||||
*/
|
||||
|
||||
public QueueTask peek() throws IsEmptyException, DatabaseUnavailableException {
|
||||
QueueTask qt = this.data.peek();
|
||||
return qt;
|
||||
}
|
||||
|
||||
/**
|
||||
* dequeue method removes the object at front and returns it
|
||||
* @return object at front of queue
|
||||
* @throws IsEmptyException if queue is empty
|
||||
* @throws DatabaseUnavailableException if queue db is unavailable
|
||||
*/
|
||||
|
||||
public QueueTask dequeue() throws IsEmptyException, DatabaseUnavailableException {
|
||||
QueueTask qt = this.data.dequeue();
|
||||
return qt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueueTask get(String tId) throws DatabaseUnavailableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.queue;
|
||||
|
||||
import com.iluwatar.commander.Order;
|
||||
|
||||
/**
|
||||
* QueueTask object is the object enqueued in queue.
|
||||
*/
|
||||
|
||||
public class QueueTask {
|
||||
|
||||
/**
|
||||
* TaskType is the type of task to be done.
|
||||
*/
|
||||
|
||||
public enum TaskType {
|
||||
Messaging, Payment, EmployeeDb
|
||||
};
|
||||
|
||||
public Order order;
|
||||
public TaskType taskType;
|
||||
public int messageType; //0-fail, 1-error, 2-success
|
||||
/*we could have varargs Object instead to pass in any parameter instead of just message type
|
||||
but keeping it simple here*/
|
||||
public long firstAttemptTime; //when first time attempt made to do task
|
||||
|
||||
/**
|
||||
* QueueTask constructor
|
||||
* @param o is the order for which the queuetask is being created
|
||||
* @param t is the type of task to be done
|
||||
* @param messageType if it is a message, which type of message - this could have instead been object varargs,
|
||||
* and contained all additional details related to tasktype.
|
||||
*/
|
||||
|
||||
public QueueTask(Order o, TaskType t, int messageType) {
|
||||
this.order = o;
|
||||
this.taskType = t;
|
||||
this.messageType = messageType;
|
||||
this.firstAttemptTime = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* getType method
|
||||
* @return String representing type of task
|
||||
*/
|
||||
|
||||
public String getType() {
|
||||
if (!this.taskType.equals(TaskType.Messaging)) {
|
||||
return this.taskType.toString();
|
||||
} else {
|
||||
if (this.messageType == 0) {
|
||||
return "Payment Failure Message";
|
||||
} else if (this.messageType == 1) {
|
||||
return "Payment Error Message";
|
||||
} else {
|
||||
return "Payment Success Message";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.shippingservice;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService.ShippingRequest;
|
||||
|
||||
/**
|
||||
* ShippingDatabase is where the ShippingRequest objects are added.
|
||||
*/
|
||||
|
||||
public class ShippingDatabase extends Database<ShippingRequest> {
|
||||
|
||||
private Hashtable<String, ShippingRequest> data;
|
||||
|
||||
public ShippingDatabase() {
|
||||
this.data = new Hashtable<String, ShippingRequest>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShippingRequest add(ShippingRequest r) throws DatabaseUnavailableException {
|
||||
return data.put(r.transactionId, r);
|
||||
}
|
||||
|
||||
public ShippingRequest get(String transactionId) throws DatabaseUnavailableException {
|
||||
return data.get(transactionId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.shippingservice;
|
||||
|
||||
import com.iluwatar.commander.Service;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* ShippingService class receives request from {@link Commander} class and adds it
|
||||
* to the {@link ShippingDatabase}.
|
||||
*/
|
||||
|
||||
public class ShippingService extends Service {
|
||||
|
||||
class ShippingRequest {
|
||||
String transactionId;
|
||||
String item;
|
||||
String address;
|
||||
|
||||
ShippingRequest(String transactionId, String item, String address) {
|
||||
this.transactionId = transactionId;
|
||||
this.item = item;
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
public ShippingService(ShippingDatabase db, Exception...exc) {
|
||||
super(db, exc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method which will receive request from {@link Commander}.
|
||||
*/
|
||||
|
||||
public String receiveRequest(Object...parameters) throws DatabaseUnavailableException {
|
||||
String tId = generateId();
|
||||
ShippingRequest req = new ShippingRequest(tId, (String) parameters[0] /*item*/, (String) parameters[1]/*address*/);
|
||||
return updateDb(req);
|
||||
}
|
||||
|
||||
protected String updateDb(Object...parameters) throws DatabaseUnavailableException {
|
||||
ShippingRequest req = (ShippingRequest) parameters[0];
|
||||
if (this.database.get(req.transactionId) == null) {
|
||||
database.add(req);
|
||||
return req.transactionId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.iluwatar.commander.Order;
|
||||
import com.iluwatar.commander.Retry;
|
||||
import com.iluwatar.commander.User;
|
||||
import com.iluwatar.commander.Retry.HandleErrorIssue;
|
||||
import com.iluwatar.commander.Retry.Operation;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
|
||||
class RetryTest {
|
||||
|
||||
@Test
|
||||
void performTest() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
throw l.remove(0);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,e) -> {
|
||||
return;
|
||||
};
|
||||
Retry<Order> r1 = new Retry<Order>(op, handleError, 3, 30000,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
Retry<Order> r2 = new Retry<Order>(op, handleError, 3, 30000,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
ArrayList<Exception> arr1 = new ArrayList<Exception>(Arrays.asList(new Exception[]
|
||||
{new ItemUnavailableException(), new DatabaseUnavailableException()}));
|
||||
try {
|
||||
r1.perform(arr1, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
ArrayList<Exception> arr2 = new ArrayList<Exception>(Arrays.asList(new Exception[]
|
||||
{new DatabaseUnavailableException(), new ItemUnavailableException()}));
|
||||
try {
|
||||
r2.perform(arr2, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
//r1 stops at ItemUnavailableException, r2 retries because it encounters DatabaseUnavailableException
|
||||
assertTrue(arr1.size() == 1 && arr2.size() == 0);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user