More flexible factory - java

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.
}
}

Related

Ways to Avoid if-else, switch-case in Factory design pattern

I am designing a validation module. It has 100 error codes(i.e. errcd_01, errcd_02,..,errcd_100) to be validated. In input I am getting a specific error code(i.e. errcd_01) out of above 100.
Module should perform validation for that specific error code.
I am using factory pattern.
/* Interface */
public interface validateErrCd {
void check_errcd();
}
/* Concrete classes implementing the same interface */
public class validateErrCd_01 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_01
}
}
public class validateErrCd_02 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_02
}
}
.
.
.
public class validateErrCd_100 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_100
}
}
/* Factory */
public class ErrorValidationFactory {
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
if(errorCode.equalsIgnoreCase("errcd_01")){
return new validateErrCd_01();
} else if(errorCode.equalsIgnoreCase("errcd_02")){
return new validateErrCd_02();
} ..
.......
else if(errorCode.equalsIgnoreCase("errcd_100")){
return new validateErrCd_100();
}
else {
return null;
}
}
}
/* I am using the Factory to get object of concrete class by passing an specific error code to be validated (i.e. "errcd_01"). */
public class FactoryPatternDemo {
public static void main(String[] args) {
ErrorValidationFactory errorFactory = new ErrorValidationFactory();
//get an object of validateErrCd_01 and call its check_errcd method.
validateErrCd errcd01 = errorFactory.getValidation("errcd_01");
//call check_errcd method of validateErrCd_01
errcd01.check_errcd();
}
}
Now due to multiple if/else inside Factory class ErrorValidationFactory, I am getting couple of CI/CD errors while performing mvn clean install.
e.g. [MethodLength] - checkstyle, Rule:CyclomaticComplexity - PMD.
So is there a way I can replace if/else, switch case kind of decision making inside factory which does not trigger above CI/CD errors in Java?
Note : If possible I would like to avoid reflection
You could use a Map:
public class ErrorValidationFactory {
private Map<String,Supplier<validateErrCd>> creators=new HashMap<>();
public ErrorValidationFactory(){
creators.put("errcd_100",validateErrCd_100::new);
//Same for others
}
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
return creators.getOrDefault(errorCode,()->null);
}
}
Supplier is a functional interface that contains a method returning an object. SomeClass::new or ()->new SomeClass() means that the constructor of the class will be used for that.
This allows to to create the instances later.
If you want to create the Map only once, you can make it static and populate it in a static initializer.
However, if you really want to dynamically get the constructors, you would need to use reflection.

How to get a single instance for an associated read-only entity with JPA and Hibernate?

I have this two entities:
#Entity
#Immutable
#Cacheable
#Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
public class DoseFrequency{
.....
}
#Entity
public class PrescriptionDrug {
.....
#ManyToOne(optional=false)
#JoinColumn(name="doseFrequency")
public DoseFrequency getDoseFrequency() {
return doseFrequency;
}
}
DoseFrequency is a read only entity, and PrescriptionDrug has associated one DoseFreqyency. I want to achive that each time I load one or many PrescriptionDrug the instances of DoseFrequency don't be repeated.
I know that the DoseFrequency instances will be cached in the first level cache of hibernate, but the load is done in several sessions (it is a web app). I used the second level cache, but that cache doesn't store instances only serializes the entity.
I get this behaivor working using Tuplizer in DoseFrequency, but I don't know if there is any other way to achive this.
#Entity
#Immutable
#Cacheable
#Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
#Tuplizer(impl=DoseFrequencyTuplizer.class)
public class DoseFrequency {
....
}
public class DoseFrequencyTuplizer extends PojoEntityTuplizer {
public DoseFrequencyTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
super(entityMetamodel, mappedEntity);
}
#Override
protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) {
return new DoseFrequencyInstantiator(DoseFrequency.class.getName(),entityMetamodel,persistentClass,null);
}
}
public class DoseFrequencyInstantiator implements Instantiator {
private final Class targetClass;
protected PojoEntityInstantiator pojoEntityInstantiator;
public DoseFrequencyInstantiator(String targetClassName, EntityMetamodel entityMetamodel,
PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) {
try {
this.targetClass = Class.forName(targetClassName);
} catch (ClassNotFoundException e) {
throw new HibernateException(e);
}
pojoEntityInstantiator = new PojoEntityInstantiator(entityMetamodel, persistentClass, optimizer);
}
#Override
public Object instantiate(Serializable id) {
DoseFrequency df = MedereEMRCache.instance.findDoseFrequencyByID(Long.valueOf(id.toString()));
if (df == null) {
return pojoEntityInstantiator.instantiate(id);
}
return df;
}
#Override
public Object instantiate() {
return instantiate(null);
}
#Override
public boolean isInstance(Object object) {
try {
return targetClass.isInstance(object);
} catch (Throwable t) {
throw new HibernateException("could not get handle to entity as interface : " + t);
}
}
}
I'm aware that the instances will be shared among all the threads of the application, but they are treated as read only, so they should not be modified.
Is this approach right?
Thank you
You can also use a LoadEventListener to always serve the same instance. Nevertheless, this functionality is not needed since the entity is immutable, so, even if you have multiple copies of it, it will still be immutable.
More, even if you implement a Singleton pattern, it will only be enforced per JVM, so I don't see why you'd want to implement this request.
Entities are meant to treated as singletons per EntityManager only.

dependency injection Ioc with interface segregation

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());
}
}
}

Dynamicaly instanciate class from name with injector

Context
I develop, for my company a software that classifies phishing and malware containing website thanks to multiple feature extraction algorithm.
Once features are extracted we use a pool of empirical and machine learning classifiers. We choose among them thanks to election function of our own.
the code
Basically we have our classifier classes that implement the AnalysisFunction contract.
public abstract class AnalysisFunction {
abstract public StatusType analyze(List<TokenEntity> tokens);
abstract public double getPhishingProbability(List<TokenEntity> tokens);
}
Our pool of classifier is contained by a "pool" that implements AnalysisFunction.
public class PoolAnalysisFunction extends AnalysisFunction{
private final List<AnalysisFunction> candidates;
private final ChoiceFunction choice;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
public PoolAnalysisFunction(List<AnalysisFunction> candidates, ChoiceFunction choice) {
this.candidates = candidates;
this.choice = choice;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).analyze(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return StatusType.CLEAN;
}
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).getPhishingProbability(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return 0;
}
}
}
To ease the deployment and testing of new function, we want to make our pool fully customizable and instanciate every function by its name. To achieve this purpose we have a key in our property file that is like analysis.pool.functions=com.vadesecure.analysis.empirical.Function1,com.vadesecure.analysis.machine.AutomaticClassifier1.
I want to instantiate my functions thanks to that.
My problem is that those classifiers depend on different things such as custom configuration object and machine learning model.
I would like to inject those dependencies that are already bound in my hk2 injector.
import org.glassfish.hk2.api.Factory;
public class PoolFunctionFactory implements Factory<AnalysisFunction> {
private final PoolAnalysisParameters parameters;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
#Inject
public PoolFunctionFactory(PoolAnalysisParameters parameters) {
this.parameters = parameters;
}
#Override
public AnalysisFunction provide() {
try {
Class<?> choice = Class.forName(parameters.getChoiceFunctionFQDN());
ChoiceFunction choiceFunction = new PhishingPriorityChoiceFunction(); // default choice
if(choice.getSuperclass().isInstance(ChoiceFunction.class)){
choiceFunction = (ChoiceFunction) choice.newInstance();
}
List<AnalysisFunction> analysisFunctions = new LinkedList<>();
// I want to instantiate here
}
return new PoolAnalysisFunction(analysisFunctions, choiceFunction);
} catch (ClassNotFoundException|IllegalAccessException|InstantiationException e){
LOG.fatal(e, e);
}
return null;
}
#Override
public void dispose(AnalysisFunction analysisFunction) {
LOG.trace(String.format("%s end of life", analysisFunction));
}
}
On example of model-dependant classifier is :
public class SVMF2AnalysisFunction extends AnalysisFunction {
private final SVMContainer modelContainer;
private double probability = 0.0;
private double threshold = 0.9;
#Inject // i build this model in a parallel thread
public SVMF2AnalysisFunction(SVMContainer modelContainer) {
this.modelContainer = modelContainer;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
if (modelContainer.getModel() == null) {
return null;
}
probability = modelContainer.getModel().analyse(tokens.stream());
return probability >= threshold ? StatusType.PHISHING : StatusType.CLEAN;
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
return probability;
}
}
How can I achieve those instanciations.
My first approach was to inject the serviceLocator but i found no documentations for doing this and a colleague said me it was not good.
He told be to document myself about proxies but it doesn't seem to be a good thing for me or perhaps I missed something.
You could just configure all this in your binder. This way you don't need to worry about trying to instantiate everything yourself. Just let HK2 do all the work
#Override
protected void configure() {
bindAsContract(PoolAnalysisFunction.class).in(Singleton.class);
bind(choiceFnClass).to(ChoiceFunction.class);
for (Class<AnalysisFunction> analysisFnClass: analyisFnClasses) {
bind(analysisFnClass).to(AnalysisFunction.class).in(Singleton.class);
}
}
Then you can just inject everything into the PoolAnalysisFunction class, without the need to use a factory.
#Inject
public PoolAnalysisFunction(IterableProvider<AnalysisFunction> candidates,
ChoiceFunction choice) {
this.choice = choice;
this.candidates = new ArrayList<>();
candidates.forEach(this.candidates::add);
}
Notice the IterableProvider class. This is an HK2 class for injecting multiple services bound to the same contract.
Or if you want to use the factory, you could, and just inject the functions into the factory. That way you can make the PoolAnalysisFunction class independent of an HK2 classes (i.e. the InjectableProvider).

Static variable usage in Java - object never changes

I have been assigned an IT project in which we have to program various different GUI's to do various things. We are also using a database. Let's assume we are accessing an "EntityManager" in a class called "Database":
public class GUI1 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI2 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI3 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
etc...
Lets say I'm in "GUI1" and I want to switch to "GUI3". After initializing "GUI3" I would have to pass "myDatabase" reference to it via the "setDatabase()" method, but if I want to go back to "GUI1", I would have to pass back the database reference again...
By now I have around 15 GUIs and it get's annoying to copy and paste the same code around when I know it could be replaced easily. In this case, wouldn't it be correct to just use a static reference to whatever I want inside the "Database" class instead of passing around the reference between all my "GUI*" classes?
Create a singleton database object, where everybody access the same object:
public class Database {
private Database(){ // privatize the constructor
// your code here
}
private static Database INSTANCE;
public static Database getInstance() {
if(INSTANCE == null) {
// let's make it thread-safe
synchronized(Database.class) {
if(INSTANCE == null) // may have changed in the mean while
// by other thread
INSTANCE = new Database();
}
}
return INSTANCE;
}
}
EDIT: Even better, from a thread-safe perspective is the enum:
public enum Database {
INSTANCE(); // pair of parenthesis, for constructor
Database() { // constructor
// your code here
}
public static Database getInstance() {
return INSTANCE;// initialization controlled by system
}
public void someMethod(){
// even allows you to add custom methods
}
}

Categories