I am using two database oracle and sql server. I am making system generic using dependency injection.Code is following
public interface IDatabases
{
string GetEmployeeFullName();
}
public class OracleDB:IDatabases
{
public string GetEmployeeFullName()
{
return "Name oracle";
}
}
public class SqlServerDB : IDatabases
{
public string GetEmployeeFullName()
{
return "Name sql server";
}
}
public class RegistrationStaff
{
private IDatabases objDatabase;
public RegistrationStaff(IDatabases vobjDataBase)
{
this.objDatabase = vobjDataBase;
}
}
I need another function GetEmployeeId in sql server class which will return employee id which is available in sql server database.I do not want this function implementation in oracle.How can I use interface segregation with dependency injection and implement in RegistrationStaff class .
public interface IsqlServer:IDatabases
{
void GetEmployeeId();
}
I want only dependency injection using constructor
I think you are already on the right way. Make a new interface for the segregation, add the new method and let the SQL server class inherit from it. So after all you have to cast the database object in the Registration class to call the method. But I can't see a way without casting if you don't put the method at top level.
public interface IDatabases
{
string GetEmployeeFullName();
}
public interface ISQLDatabase : IDatabases
{
int GetEmployeeId();
}
public class OracleDB : IDatabases
{
public string GetEmployeeFullName()
{
return "Name oracle";
}
}
public class SqlServerDB : ISQLDatabase
{
public string GetEmployeeFullName()
{
return "Name sql server";
}
public int GetEmployeeId()
{
return 1;
}
}
public class RegistrationStaff
{
private IDatabases objDatabase;
public RegistrationStaff(IDatabases vobjDataBase)
{
this.objDatabase = vobjDataBase;
if (this.objDatabase is ISQLDatabase)
{
Console.WriteLine(((ISQLDatabase)this.objDatabase).GetEmployeeId());
}
}
}
Related
I would like to create an abstract factory. here is what I tried.
//abstract class Worker
public abstract class Worker {
String phoneNumber;
String firstName;
String lastName;
String workerType;
String ifu;
String imageParth;
//....
public String getWorkerType() {
return workerType;
}
}
// Electrician class which extends worker
package worker.domain.worker;
public class Electrician extends Worker{
public Electrician() {}
public Electrician(String phoneNumber, String firstName, String lastName, String ifu, String workerType,
String imageParth) {
super(phoneNumber, firstName, lastName, ifu,workerType, imageParth);
}
public String getWorkerType() {
return "Electrician";
}
}
//Mason class
package worker.domaine.worker;
public class Mason extends Worker{
public Mason() {};
public Mason(String phoneNumber, String firstName, String lastName, String ifu,String workerType,
String imageParth) {
super(phoneNumber, firstName, lastName, ifu, workerType, imageParth);
}
String getworkerType() {
return "Mason";
}
}
// interface WorkerAbstractFactory
package worker.domaine.worker;
public interface WorkerAbstractFactory {
Worker createWorker(String typeWorker);
}
//
public class WorkerFactory implements WorkerAbstractFactory{
#Override
public Worker createWorker(String typeWorker) {
Worker worker = null;
if(worker != null) {
switch (typeWorker) {
case "Electrician":
Electrician electrician =new Electrician();
electrician = new Electrician (electrician.getPhoneNumber(), electrician.getFirstName(), electrician.getLastName(), electrician.getIfu(), electrician.getWorkerType(),electrician.getImageParth());
case "Mason":
Mason mason =new Mason();
mason = new Mason (mason.getPhoneNumber(), mason.getFirstName(), mason.getLastName(), mason.getIfu(), mason.getworkerType(),mason.getImageParth());
}}
//app class
public class WorkerFactoryProvider {
public static WorkerAbstractFactory getWorkerFactory(String workerCategory) {
//WorkerFactory workerFactory = new WorkerFactory();
WorkerFactory workerFactory = new WorkerFactory();
if (workerCategory != null) {
switch (workerCategory) {
case "Electrician":
Worker worker1 = workerFactory.createWorker("Electrician");
worker1.getWorkerType();
String a=worker1.getWorkerType();
System.out.println(a);
case "Mason":
Worker worker2 = workerFactory.createWorker("Mason");
worker2.getWorkerType();
String b=worker2.getWorkerType();
System.out.println(b);
}
}
return null;
}
do you think it could work like that? now, if I really want a concrete object, how could it be done? because I would like to write for example a method to calculate the pay of each worker according to type for example how could I use my abstract Factory in the method to return me each type.
You have a single class hierarchy of Worker types. To instantiate those you can just use a standalone factory class, you don't need an abstract factory here. For example this would be sufficient:
public class WorkerFactory {
public Worker createWorker(String workerType) {
switch (workerType) {
case "Electrician": return new Electrician();
case "Mason": return new Mason();
}
}
}
The abstract factory pattern is more elaborate, and allows injecting different concrete factories for related hierarchies of objects, so that the client doesn't need to be aware of the difference. For example you could have an abstract TransportationFactory:
interface Transportation {
void travelTo(String destination);
}
interface TransportationFactory {
Transportation simple();
Transportation luxurious();
}
And two concrete implementations (matching two different but similar class hierarchies):
class WaterTransportationFactory {
Transportation simple() {
return new Kayak();
}
Transportation luxurious() {
return new Yacht();
}
}
And:
class LandTransportationFactory {
Transportation simple() {
return new Bike();
}
Transportation luxurious() {
return new RaceCar();
}
}
The benefit of this pattern is that the client can be configured to use water or land transportation (or a new air transportation that is added later) without the need to undergo any changes:
class Client {
private TransportationFactory transportationFactory;
public Client(TransportationFactory transportationFactory) {
this.transportationFactory = transportationFactory;
}
public void travel(String destination) {
transportationFactory.simple().travelTo(destination);
}
public void travelInStyle(String destination) {
transportationFactory.luxurious().travelTo(destination);
}
}
EDIT: You could change the simple/luxurious methods to match the style of your example with the getWorkerType method. I prefer to avoid the conditional logic if possible and let the created classes determine their availability themselves. This decouples even further, allowing hierarchy members to be added with minimal code changes:
enum TransportationType {
SIMPLE, LUXURIOUS
}
interface Transportation {
void travelTo(String destination);
// allow the class to specify its own type
TransportationType getType();
}
// intermediate interface to distinguish Water from Land
interface WaterTransportation extends Transportation {
}
class Kayak implements WaterTransportation {
void travelTo(String destination) {
// splash splash
}
TransportationType getType() {
return TransportationType.SIMPLE;
}
}
class WaterTransportationFactory {
private WaterTransportation[] waterTransportations;
// Inject all available beans implementing WaterTransportation
// e.g. using Spring or some other dependency injection mechanism
public WaterTransportationFactory(WaterTransportation[] waterTransportations) {
this.waterTransportations = waterTransportations;
}
public Transportation create(TransportationType type) {
for(WaterTransportation waterTransportation : waterTransportations) {
if (waterTransportation.getType() == type) {
// we are returning the same instance every time
// this could be ok for singleton beans
// but if you really need a fresh instance you could use builders (see below)
return waterTransportation;
}
}
throw new IllegalArgumentException("No implementation for WaterTransportation type=" + type);
}
}
An alternative with builders:
KayakBuilder implements WaterTransportationBuilder {
KayakBuilder name(String name) { ... };
KayakBuilder weight(String weightInKg) { ... };
KayakBuilder year(String yearBuilt) { ... };
KayakBuilder speed(String averageSpeed) { ... };
Kayak build() { return kayak; }
}
For more on Builders see this full exposition of the Builder pattern
class WaterTransportationFactory {
private WaterTransportationBuilder[] builders;
// Inject all available WaterTransportationBuilders
// e.g. using Spring or some other dependency injection mechanism
public WaterTransportationFactory(WaterTransportationBuilder[] builders) {
this.builders = builders;
}
// extra arguments can be passed to build the instance
public Transportation create(TransportationType type, String name, int weightInKg, int yearBuilt, int averageSpeed) {
for(WaterTransportationBuilder builder: builders) {
if (builder.getType() == type) {
return builder
.name(name)
.weight(weightInKg)
.year(yearBuilt)
.speed(averageSpeed)
.build();
}
}
throw new IllegalArgumentException("No implementation for WaterTransportation type=" + type);
}
}
I'm currently doing a MongoDB + spring boot project and got some trouble when I create the mapping.
In my model, there is one class called AllocRequests:
public class AllocRequests {
#Field("ShipmentAllocRequest")
private ShipmentAllocRequest shipmentAllocRequest;
public AllocRequests() {}
public AllocRequests(ShipmentAllocRequest shipmentAllocRequest) {
this.shipmentAllocRequest = shipmentAllocRequest;
}
public ShipmentAllocRequest getShipmentAllocRequest() {
return shipmentAllocRequest;
}
public void setShipmentAllocRequest(ShipmentAllocRequest shipmentAllocRequest) {
this.shipmentAllocRequest = shipmentAllocRequest;
}
}
But when I run the code, I will get 'org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.LinkedHashMap] to type [com.csc.gts.model.ShipmentAllocRequest]'
The problem is because the data's structure
I noticed that some of the 'ShipmentAllocRequest' is an object:
ShipmentAllocRequest is an object
While others could be an Array:
ShipmentAllocRequest is an array
I have tried to change the model class to:
public class AllocRequests {
#Field("ShipmentAllocRequest")
private List<ShipmentAllocRequest> shipmentAllocRequest;
public AllocRequests() {}
public AllocRequests(List<ShipmentAllocRequest> shipmentAllocRequest) {
this.shipmentAllocRequest = shipmentAllocRequest;
}
public List<ShipmentAllocRequest> getShipmentAllocRequest() {
return shipmentAllocRequest;
}
public void setShipmentAllocRequest(List<ShipmentAllocRequest> shipmentAllocRequest) {
this.shipmentAllocRequest = shipmentAllocRequest;
}
}
But then I will get a new problem:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.List]: Specified class is an interface
Can anyone help me to solve this problem?
I have set qualifier name from properties file as isomessage.qualifier=isoMessageMember1:
public class BankBancsConnectImpl implements BankBancsConnect{
#Autowired
#Resource(name="${isomessage.qualifier}")
private Iso8583Message iso8583Message;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail ipsDcBatchDetail) {
bancsxfr = iso8583Message.getFundTransfer(bancsxfr);
}
}
The value of ${isomessage.qualifier} is static as it is defined in the properties file. However i want it to be dynamic and get it's value from database based on certain condition. For instance i have multiple implementation of Iso8583Message (member wise) and has to call respective class of member id that is currently logged in. Please guide me to achieve this in the best and java spring way.
And my implementation class will look like this:
#Service("isoMessageMember1")
public class Iso8583MessageEBLImpl implements Iso8583Message{
public BancsConnectTransferComp getFundTransfer(BancsConnectTransferComp bancsxfr) throws Exception {
...
}
You can use Condition instead Qualifier if you are using Spring4+.
First, you need a ConfigDAO which read the qualifier name which you
need from database.
public class ConfigDAO {
public static String readFromDataSource() {
return " ";
}
}
Suppose there are two implemetions of Iso8583Message, you can
create two Condition objects.
IsoMessageMember1_Condition
public class IsoMessageMember1_Condition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String qualifier = ConfigDAO.readFromDataSource();
if (qualifier.equals("IsoMessageMember1_Condition")) {
return true;
} else {
return false;
}
}
}
IsoMessageMember2_Condition
public class IsoMessageMember2_Condition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String qualifier = ConfigDAO.readFromDataSource();
if (qualifier.equals("IsoMessageMember2_Condition")) {
return true;
} else {
return false;
}
}
}
Return different implemetion according to condition in config class.
#Configuration
public class MessageConfiguration {
#Bean(name = "iso8583Message")
#Conditional(IsoMessageMember1_Condition.class)
public Iso8583Message isoMessageMember1() {
return new Iso8583MessageEBLImpl();
}
#Bean(name = "iso8583Message")
#Conditional(IsoMessageMember2_Condition.class)
public Iso8583Message isoMessageMember2() {
return new OtherMessageEBLImpl();
}
}
Remove the #Qulifier and #Autowire annotations which you do not need anymore, you can retrieve the message from context every time you use it.
public class BankBancsConnectImpl implements BankBancsConnect{
private Iso8583Message iso8583Message;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail ipsDcBatchDetail) {
iso8583Message = (Iso8583Message)context.getBean("iso8583Message");
bancsxfr = iso8583Message.getFundTransfer(bancsxfr);
}
}
In spring it is possible to autowire the application context, and retrieve any bean based on its name.
For example, your interface signature similar to the below syntax
public interface Iso8583Message {
public String getFundDetails(String uniqueId);
}
and 2 different implementations follow below format
#Service("iso8583-message1")
public class Iso8583MessageImpl1 implements Iso8583Message {
#Override
public String getFundDetails(String uniqueId) {
return "Iso8583MessageImpl1 details ";
}
}
and
#Service("iso8583-message2")
public class Iso8583MessageImpl2 implements Iso8583Message {
#Override
public String getFundDetails(String uniqueId) {
return "Iso8583MessageImpl2 details ";
}
}
We can retrieve the beans as follows
public class BankBancsConnectImpl implements BankBancsConnect{
#Autowired
private ApplicationContext applicationContext;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail
ipsDcBatchDetail) {
//for retrieving 1st implementation
Iso8583Message iso8583Message=applicationContext.getBean("iso8583-message1", Iso8583Message.class);
//For retrieving 2nd implementation
Iso8583Message iso8583Message=applicationContext.getBean("iso8583-message2", Iso8583Message.class);
String result = iso8583Message.getFundTransfer(bancsxfr);
}
}
In this case, we can configure the bean names coming from the database instead of hard coded values("iso8583-message1","iso8583-message2").
I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}
I'm currently working on a little project for school. In my Java application I need a database, and I would like to make it possible to make my application capable to use different types of databases. So I currently implemented a txt-database and a PostgreSQL. In the future, it should be possible to add other database types. Like XML or MySQL, ...
To create a database instance, I designed a factory that uses an enum. It works perfectly, but Itsn't really flexibel in my opionio. So, I did some research, but didn't find a real good example that is clear for me.
This is my enum:
public enum DatabaseType {
TXT,
SQL,
XML;
}
This is my factory:
public class DatabaseFactory {
public Database createDatabase(DatabaseType type, String databaseName) throws DatabaseException {
if(type.equals(DatabaseType.TXT)) {
return new FileDatabase(databaseName);
}else if(type.equals(DatabaseType.SQL)) {
return new SQLDatabase(databaseName);
}else if(type.equals(DatabaseType.XML)) {
return new XMLDatabase(databaseName);
}else {
//default
return new FileDatabase(databaseName);
}
}
}
My aim is to only edit the enum in the future, without touching the factory itself. This should give me enough flexibility, but I've no idea how I could do this.
You could put the factories in the enum itself.
public enum DatabaseType {
TXT {
#Override
public Database createDatabase(String databaseName) {
return new FileDatabase(databaseName);
}
},
SQL {
#Override
public Database createDatabase(String databaseName) {
return new SQLDatabase(databaseName);
}
},
XML {
#Override
public Database createDatabase(String databaseName) {
return new XMLDatabase(databaseName);
}
};
public abstract Database createDatabase(String databaseName);
}
In Java, enums are not just nice names for integral values (like in C). A better way to think of an enum is as a class with a fixed number of instances. Together with the concept of anonymous classes, you can give each value in the enumeration different properties and methods specific for that value.
Use reflection:
Your enum:
public enum DatabaseType {
FILE(FileDatabase.class),
SQL(SQLDatabase.class);
private Database db;
DatabaseType(Class<Database> db) {
this.db = db;
}
/*package friendly*/ Class<Database> getDatabase() {
return this.db;
}
}
Your factory:
public class DatabaseFactory {
public static Database create(DatabaseType type, String dbName) throws Exception {
Database db = null;
Constructor cons = type.getDatabase().getDeclaredConstructor(new Class[] { String.class });
cons.setAccessible(true);
db = cons.newInstance(dbName);
return db;
}
}
Your Database implementors:
public class FileDatabase extends Database {
/* can only be instantiated via reflection */
private FileDatabase(String databaseName) {
// init db.
}
}