get #Qualifier name from database based on condition at runtime - java

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").

Related

Spring custom Scope with timed refresh of beans

I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}

Object inheritance - refactoring problem - possibility to create flexible service

It should be pretty easy but obviously I am lacking of basic knowlege.
I have a service which is ment to create ticket in BugTracking systems.
Creating plugins is pretty stright forward. there is an interface
public interface BugTracker {
boolean createAndSendIssue(Issue issue);
boolean updateAndSendIssue(Issue issue);
boolean closeIssue(Issue issue);
}
and API client for JIRA:
#Component
public class JiraClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
}
API CLient for Bugzilla:
#Component
public class BugzillaClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
}
Problem occurs on the Service which is handling MVC. Piece of it looks like:
#Service
public class BugTrackerService {
private final BugzillaClient bugzillaClient;
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
#Autowired
BugTrackerService(BugzillaClient bugzillaClient, JiraClient jiraClient) {
this.bugzillaClient = bugzillaClient;
this.jiraClient = jiraClient;
}
boolean processIssueTicketRequest(Issue issue){
if ( issue.getBugTrackerType().bugTrackingSystemType.name.equals(JIRA_TYPE)) {
return jiraClient.createAndSendIssue(issue);
} else if (issue.getBugTrackerType().bugTrackingSystemType.name.equals(BUGZILLA_TYPE)){
return bugzillaClient.createAndSendIssue(issue);
} else {
return false;
}
}
}
is it somehow possible to create method BugTrackerService.processIssueTicketRequest without all clients autowired? At this moment it is not so much of a problem but after integrating with more and more systems this service will become complex.
Depending on how reusable you want implementations to be, I'd probably put the logic of checking whether the given issue is of matching typing into the interface, eg
boolean canWorkWithGivenIssue(Issue issue);
With that in place then you don't need to know actual types of trackers you dispatch on, and merely aggregate them into the list. Spring will do that for you if you annotate a collection with #Autowired, in which cases it will provide you all the beans with matching type. Your service then could look like this
#Autowired List<BugTracker> trackers; //autowired on field for brevity
boolean processIssueTicketRequest(Issue issue){
for (BugTracker t : trackers)
if (t.canWorkWithGivenIssue(issue))
return t.createAndSendIssue(issue);
return false;
}
Turn the type into an enum and let the BugTracker decide if it can handle it. Then inject a collection of all BugTracker instances, iterate over them and if it supports the type call the appropriate method.
public enum SystemType { JIRA, BUGZILLA }
Then add a method, for instance supports(Issue issue), to your BugTracker.
boolean supports(Issue issue);
In the implementations check if it can be handled, for instance in the JiraClient do something like this.
public boolean supports(Issue issue) {
return JIRA == issue.getBugTrackerType();
}
Then in your BugTrackerService get a list of all BugTracker instances, iterate and call the appropriate one.
#Service
public class BugTrackerService {
private final List<BugTracker> bugTrackers;
BugTrackerService(List<BugTracker> bugTrackers) {
this.bugTrackers=bugTrackers;
}
boolean processIssueTicketRequest(Issue issue){
for (BugTracker bugTracker : this.bugTrackers) {
if (bugTracker.supports(issue) ) {
bugTracker.createAndSendIssue(issue);
return true;
}
}
return false;
}
}
Now you are as flexible as you want to be and can support as many as you want.
You can pass on the responsibility of finding out the correct implementation of BugTracker to a BugTrackerFactory.
#Component
class BugTrackerFactory {
#Autowired
private final BugzillaClient bugzillaClient;
#Autowired
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
public BugTracker getBugTracker(String type) {
if (JIRA_TYPE.equals(type)) {
return jiraClient;
} else if (BUGZILLA_TYPE.equals(type)) {
return bugzillaClient;
} else {
// throw some exception
}
}
}
BugTrackerService :
#Service
public class BugTrackerService {
private final BugTrackerFactory bugTrackerFactory;
#Autowired
BugTrackerService(BugTrackerFactory bugTrackerFactory) {
this.bugTrackerFactory = bugTrackerFactory;
}
boolean processIssueTicketRequest(Issue issue){
return bugTrackerFactory.getBugTracker(issue.getBugTrackerType().bugTrackingSystemType.name).createAndSendIssue(issue);
}
}

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

Spring: How to get bean implementation dynamically?

Let's say we have interface:
public interface IAuthentication { }
and two implementations:
public class LdapAuthentication implements IAuthentication {}
public class DbAuthentication implements IAuthentication {}
And finally we have a bean that is responsible for processing authentication. This bean should use one of the implementations shown above (based on configuration specified in for example db).
#Service
public class AuthenticationService {
public boolean authenticate(...) {
boolean useDb = ...; //got from db
//my problem here
//how to get right implementation: either LdapAuthentication or DbAuthentication?
IAuthentication auth = ...;
return auth.authenticate(...);
}
}
Question:
How to get the right implementation?
If parameter value does not change:
#Service
public class AuthenticationService {
private IAuthentication auth;
#PostConstruct
protected void init() {
boolean useDb = ...; //got from db
this.auth = ...; //choose correct one
}
public boolean authenticate(...) {
return auth.authenticate(...);
}
}
If parameter is dynamic
#Service
public class AuthenticationService {
#Autowired
private ApplicationContext сontext;
public boolean authenticate(...) {
boolean useDb = ...; //got from db
IAuthentication auth = context.getBean(useDb ? DbAuthentication.class : LdapAuthentication.class);
return auth.authenticate(...);
}
}

Can't make messageSource work in the Pojo classes

I am not being able to make messageSource work in the Pojo classes,its throwing a nullpointerexception. However in all the other classes namely controller,service messageSource is working alright. Could someone please suggest what needs to be done ?
#Autowired
private MessageSource messageSource;
I have autowired the MessageSource using the above code snippet.
public class ProposalWiseSelectionForm implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Autowired
private MessageSource messageSource;
private String txtPageHierarchy="";
private String txtLineOfBusiness;
private String txtProduct;
private String btn;
private String clickedGo="N";
private List arrLineOfBusiness=new ArrayList();
private List arrProduct=new ArrayList();
#Valid
private ArrayList documentList=initiateDocumentList();
private String txtPageMode="I";
private String enableDiscardBtn="N";
private String enableInsertBtn="N";
private String isDivVisible="N";
private int numApplicationType=1;
public ProposalWiseSelectionForm() {
}
public String getTxtPageHierarchy() {
return txtPageHierarchy;
}
public void setTxtPageHierarchy(String txtPageHierarchy) {
this.txtPageHierarchy = txtPageHierarchy;
}
public String getTxtLineOfBusiness() {
return txtLineOfBusiness;
}
public void setTxtLineOfBusiness(String txtLineOfBusiness) {
this.txtLineOfBusiness = txtLineOfBusiness;
}
public String getTxtProduct() {
return txtProduct;
}
public void setTxtProduct(String txtProduct) {
this.txtProduct = txtProduct;
}
public String getBtn() {
return btn;
}
public void setBtn(String btn) {
this.btn = btn;
}
public String getClickedGo() {
return clickedGo;
}
public void setClickedGo(String clickedGo) {
this.clickedGo = clickedGo;
}
public List getArrLineOfBusiness() {
return arrLineOfBusiness;
}
public void setArrLineOfBusiness(List arrLineOfBusiness) {
this.arrLineOfBusiness = arrLineOfBusiness;
}
public List getArrProduct() {
return arrProduct;
}
public void setArrProduct(List arrProduct) {
this.arrProduct = arrProduct;
}
public void setArrProduct(ArrayList arrProduct) {
this.arrProduct = arrProduct;
}
public ArrayList getDocumentList() {
return documentList;
}
public void setDocumentList(ArrayList documentList) {
this.documentList = documentList;
}
public String getTxtPageMode() {
return txtPageMode;
}
public void setTxtPageMode(String txtPageMode) {
this.txtPageMode = txtPageMode;
}
public String getEnableDiscardBtn() {
return enableDiscardBtn;
}
public void setEnableDiscardBtn(String enableDiscardBtn) {
this.enableDiscardBtn = enableDiscardBtn;
}
public String getEnableInsertBtn() {
return enableInsertBtn;
}
public void setEnableInsertBtn(String enableInsertBtn) {
this.enableInsertBtn = enableInsertBtn;
}
public String getIsDivVisible() {
return isDivVisible;
}
public void setIsDivVisible(String isDivVisible) {
this.isDivVisible = isDivVisible;
}
public int getNumApplicationType() {
return numApplicationType;
}
public void setNumApplicationType(int numApplicationType) {
this.numApplicationType = numApplicationType;
}
}
In order to be able to use #Autowired in a class, that class has to be managed by Spring.
of
Your ProposalWiseSelectionForm class is obviously not managed by Spring and therefor messageSource is always null.
Using #Autowired MessageSource messageSource in your other classes works, because as you mention those classes are managed by Spring (as you have mentioned they are either controllers, services etc).
I am guessing that ProposalWiseSelectionForm is a DTO used to capture values from a form. The sort of class will not be a Spring bean and therefor you can't autowire stuff into it.
I suggest you either move the logic you need out of the DTO and into the controller (or some Spring managed utility) or in the extreme case that you absolutely need #Autowired in the DTO, take a look at #Configurable here and here
Try using #Component,you might be getting this issue because of the fact the Pojo class is not being recognized.
You have to make your class a Spring bean
Add #Component annotation to your class and add these 2 lines to your appContext.xml:
<context:component-scan base-package="com.<your-company-name>" />
<context:annotation-config />
Or just add the service in your beans section in the appContext.xml if you wish not to work with Spring component-scan feature.

Categories