Implement mediator design pattern in Spring REST app? - java

I am working in FHIR APIs. I have a PatientService interface and 2 implementation classes such as DSTU2PatientService, STU3PatientService.
Our client has an implemented FHIR DSTU2 API for demographics, whereas Procedure is in STU3.
My use case is, how to distinguish which service( DSTU2/STU3 ) should be called when request comes from the patient to get their health data from EHR system.
How to include mediator pattern to achieve the call dynamically? I don't want to use if condition.
application.properties
fhir.demogrphics=DSTU2
fhir.procedure=STU3
FHIRPatientService.java
public interface FHIRPatientService {
Object getDemographics(PatientDTO patient);
Object getProcedures(PatientDTO patient);
}
I have integrated the FHIR DSTU2 API DSTU2PatientService.
DSTU2PatientService.java
#Service(value = "dstu2PatientService")
public class DSTU2PatientService implements PatientService {
private static final Logger LOG = LoggerFactory.getLogger(DSTU2PatientService.class);
private FhirContext fhirContextDstu2;
#Autowired
private FHIRConfig fhirConfig;
#Autowired
private BasicAuthInterceptor authInterceptor;
public DSTU2PatientService(#Qualifier("fhirContextDstu2") FhirContext fhirContextDstu2) {
this.fhirContextDstu2 = fhirContextDstu2;
}
#Override
public Object getDemographics(PatientDTO patient) {
Bundle bundle = null;
try {
IGenericClient clientDstu2 = fhirContextDstu2.newRestfulGenericClient(fhirConfig.getFhirServerPathDstu2());
clientDstu2.registerInterceptor(authInterceptor);
bundle = clientDstu2.search()
.forResource(Patient.class)
.where(Patient.GIVEN.matches().value(patient.getGiven()))
.and(Patient.FAMILY.matches().value(patient.getFamily()))
.and(Patient.BIRTHDATE.exactly().day(patient.getBirthdate()))
.and(Patient.ADDRESS.contains().value(patient.getAddress()))
.and(Patient.GENDER.exactly().codes(patient.getGender()))
.returnBundle(Bundle.class)
.execute();
}catch(Exception e){
LOG.error("Demographics: {}", e.getMessage());
bundle = new Bundle();
}
return bundle;
}
#Override
public Object getProcedures(PatientDTO patient) {
Bundle bundle = null;
try {
IGenericClient clientDstu2 = fhirContextDstu2.newRestfulGenericClient(fhirConfig.getFhirServerPathDstu2());
clientDstu2.registerInterceptor(authInterceptor);
clientDstu2.registerInterceptor(CommonUtil.headersInterceptor(patient.getMychartId()));
bundle = clientDstu2.search()
.forResource(Procedure.class)
.where(new ReferenceClientParam("patient").hasId(patient.getSubject()))
.and(Procedure.DATE.afterOrEquals().day(patient.getStartDate()))
.and(Procedure.DATE.beforeOrEquals().day(patient.getEndDate()))
.returnBundle(Bundle.class)
.execute();
}catch(Exception e){
LOG.error("Procedures: {}", e.getMessage());
bundle = new Bundle();
}
return bundle;
}
}
I have integrated the FHIR STU3 API STU3PatientService.
STU3PatientService.java
#Service(value = "stu3PatientService")
public class STU3PatientService implements PatientService {
private static final Logger LOG = LoggerFactory.getLogger(STU3PatientService.class);
private FhirContext fhirContextStu3;
#Autowired
private FHIRConfig fhirConfig;
#Autowired
private BasicAuthInterceptor authInterceptor;
public STU3PatientService(#Qualifier("fhirContextStu3") FhirContext fhirContextStu3) {
this.fhirContextStu3 = fhirContextStu3;
}
#Override
public Object getDemographics(PatientDTO patient) {
Bundle bundle = null;
try {
IGenericClient clientStu3 = fhirContextStu3.newRestfulGenericClient(fhirConfig.getFhirServerPathStu3());
clientStu3.registerInterceptor(authInterceptor);
bundle = clientStu3.search()
.forResource(Patient.class)
.where(Patient.GIVEN.matches().value(patient.getGiven()))
.and(Patient.FAMILY.matches().value(patient.getFamily()))
.and(Patient.BIRTHDATE.exactly().day(patient.getBirthdate()))
.and(Patient.ADDRESS.contains().value(patient.getAddress()))
.and(Patient.GENDER.exactly().codes(patient.getGender()))
.returnBundle(Bundle.class)
.execute();
}catch(Exception e){
LOG.error("Demographics: {}", e.getMessage());
bundle = new Bundle();
}
return bundle;
}
#Override
public bundle getProcedures(PatientDTO patient) {
Bundle bundle = null;
try {
IGenericClient clientStu3 = fhirContextStu3.newRestfulGenericClient(fhirConfig.getFhirServerPathStu3());
clientStu3.registerInterceptor(authInterceptor);
clientStu3.registerInterceptor(CommonUtil.headersInterceptor(patient.getMychartId()));
bundle = clientStu3.search()
.forResource(Procedure.class)
.where(new ReferenceClientParam("patient").hasId(patient.getSubject()))
.and(Procedure.DATE.afterOrEquals().day(patient.getStartDate()))
.and(Procedure.DATE.beforeOrEquals().day(patient.getEndDate()))
.returnBundle(Bundle.class)
.execute();
}catch(Exception e){
LOG.error("Procedures: {}", e.getMessage());
bundle = new Bundle();
}
return bundle;
}
}
FHIRComponent.java
#Component(value = "fhirService")
public class FHIRComponent {
private static final Logger LOG = LoggerFactory.getLogger(FHIRComponent.class);
private FHIRResourceVersionConfig fhirResourceVersionConfig;
private PatientService dstu2PatientService;
private PatientService stu3PatientService;
public FHIRComponent(
#Qualifier("dstu2PatientService") FHIRPatientService dstu2PatientService,
#Qualifier("stu3PatientService") FHIRPatientService stu3PatientService,
FHIRResourceVersionConfig fhirResourceVersionConfig) {
this.dstu2PatientService = dstu2PatientService;
this.stu3PatientService = stu3PatientService;
this.fhirResourceVersionConfig = fhirResourceVersionConfig;
}
public Object getDemographics(PatientDTO patient, String resourceType) {
Object result = null;
if("DSTU2".equalsIgnoreCase(fhirResourceVersionConfig.findResource(resourceName)))
result = patientServiceDstu2.getDemographics(patient);
else
result = patientServiceStu3.getDemographics(patient);
return result;
}
public Object getConditions(PatientDTO patient) {
Object result = null;
if("DSTU2".equalsIgnoreCase(fhirResourceVersionConfig.findResource(resourceName)))
result = patientServiceDstu2.getConditions(patient);
else
result = patientServiceStu3.getConditions(patient);
return result;
}
}

You need to make the FHIRPatientService aware for which code it is responsible:
public interface FHIRPatientService {
String getCode();
Object getDemographics(PatientDTO patient);
Object getProcedures(PatientDTO patient);
}
Then you can refactor your component
#Component(value = "fhirService")
public class FHIRComponent {
private static final Logger LOG = LoggerFactory.getLogger(FHIRComponent.class);
private FHIRResourceVersionConfig fhirResourceVersionConfig;
private List<PatientService> patientServices;//spring will inject all services
public FHIRComponent(
List<PatientService> patientServices,
FHIRResourceVersionConfig fhirResourceVersionConfig) {
this.patientServices= patientServices;
this.fhirResourceVersionConfig = fhirResourceVersionConfig;
}
private Optional<PatientService> getService(String resourceType){
return patientServices.stream()
.filter(service => service.getCode().equalsIgnoreCase(fhirResourceVersionConfig.findResource(resourceName)))
.findAny()
}
public Object getDemographics(PatientDTO patient, String resourceType) {
return getService(resourceType)
.map(service => service.getDemographics(patient))
.orElse(null);
}
...
I hope my explenation is a bit clear...

Related

Using jsmpp for sending asynchronous messages to SMSC server

we have a message campaign where we send over 100k messages (SMS) a day. So we are a client of SMSC server. We have no influence on SMSC server code. Before some time, we had around 80-90 message per second, now frequency dropped to 15 messages per second, according to tcpdumps.
I have few information regarding this, so I will try to explain best as I can.
So we are using Spring Boot 2.7 and open source jsmpp (3.0.0) library for sending SMS messages (PDU commands) to SMSC.
While reading about protocol (page 40), I noticed that there is a way to send messages asynchronously by providing a seqence_number. The code example is here. But I am not sure if that is going to help...
The code:
#Component
public class ClientConfig {
#Autowired
private MessageReceiverListener msgListener;
#Autowired
private SessionStateListener sessionListener;
private SMPPSession session;
public String charset = "ISO-10646-UCS-2";
public long idleReceiveTimeout = 65000;
public long checkBindingTimeout = 12000;
public long timeout = 7000;
public int enquireLinkTimeout = 15000;
public String hostIp = "someIpAddress";
public int port = 5000;
public String final systemId = "someSystemId";
public String final password = "password";
public BindType bindType = BindType.BIND_TRX; //transceiver
public String systemType = null;
public String addressRange = null;
public TypeOfNumber addrTon = TypeOfNumber.UNKNOWN;
public NumberingPlanIndicator addrNpi = NumberingPlanIndicator.UNKNOWN;
protected synchronized void tryToConnectToSmsc() throws Exception {
try {
// Connect to host
BindParameter bp = new BindParameter(bindType, systemId, password, systemType, addrTon, addrNpi, addressRange);
session = new SMPPSession();
session.setEnquireLinkTimer(enquireLinkTimer);
session.connectAndBind(host, port, bp, timeout);
session.setMessageReceiverListener(msgListener);
session.addSessionStateListener(sessionListener);
}
// Main connection failed.
catch (Exception e) {
//log and re-attempt connection logic here
}
}
}
The listeners:
#Component
public class MySessionListenerImpl implements SessionStateListener {
#Override
public void onStateChange(SessionState newState, SessionState oldState, Session source) {
//TODO
}
}
#Service
public class SmsListenerImpl implements MessageReceiverListener {
#Override
public void onAcceptDeliverSm(DeliverSm deliverSm) throws ProcessRequestException {
//TODO
}
#Override
public void onAcceptAlertNotification(AlertNotification alertNotification) {}
#Override
public DataSmResult onAcceptDataSm(DataSm dataSm, Session session) throws ProcessRequestException {
return null;
}
}
Message sending service:
#Service
public class MessageSendingServiceImpl extends ClientConfig implements MessageSendingService{
private final ESMClass esmClass = new ESMClass();
private final byte protocolId = (byte) 0;
private final byte priorityFlag = (byte) 1;
private final TimeFormatter formatter = new AbsoluteTimeFormatter();
private final byte defaultMsgId = (byte) 0;
public SmsAdapterServiceImpl() {
super();
}
#PostConstruct
public synchronized void init() throws Exception {
super.tryToConnectToSmsc();
}
#Override
public String send(DomainObject obj){ //DomainObject -> contains fields: id, to, from, text, delivery, validity;
String serviceType = null;
//source
TypeOfNumber sourceTON = TypeOfNumber.NATIONAL; //there is some logic here which determines if it is INTERNATIOANL, ALPHANUMERIC etc...
NumberPlaningIndicator sourceNpi = NumberPlaningIndicator.ISDN; //constant...
String sourcePhone = obj.getFrom();
//destination
TypeOfNumber destinationTON = TypeOfNumber.NATIONAL; //there is some logic here which determines if it is INTERNATIOANL, ALPHANUMERIC etc...
NumberPlaningIndicator destinationNpi = NumberPlaningIndicator.ISDN; //constant...
String destinationPhone = obj.getTo();
String scheduledDeliveryTime = null;
if (obj.getDelivery() != null) scheduledDeliveryTime = formatter.format(obj.getDelivery());
String validityPeriodTime = null;
if (obj.getValidity() != null) validityPeriodTime = formatter.format(obj.getValidity());
Map<Short, OptionalParameter> optionalParameters = new HashMap<>();
String text = obj.getText();
if ( text.length() > 89 ) { //set text as payload instead of message text
OctetString os = new OctetString(OptionalParameter.Tag.MESSAGE_PAYLOAD.code(), text, "ISO-10646-UCS-2"); //"ISO-10646-UCS-2" - encoding
optionalParameters.put(os.tag, os);
text = "";
}
String msgId =
session.submitShortMessage( serviceType ,
sourceTON ,
sourceNpi ,
sourcePhone ,
destinationTON ,
destinationNpi ,
destinationPhone ,
esmClass ,
protocolId ,
priorityFlag ,
scheduledDeliveryTime ,
validityPeriodTime ,
new RegisteredDelivery() ,
ReplaceIfPresentFlag.DEFAULT.value() ,
new GeneralDataCoding(Alphabet.ALPHA_UCS2) ,
defaultMsgId ,
text.getBytes("ISO-10646-UCS-2") ,
optionalParameters.values().toArray(new OptionalParameter[0]));
return msgId;
}
}
Client code which invokes the service (it is actually a scheduler job):
#Autowired private MessageSendingService messageSendingService;
#Scheduled(cron)
public void execute() {
List<DomainObject> messages = repository.findMessages(pageable, config.getBatch()); //up to several thousand
start(messages);
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(getSchedulerConfiguration().getPoolSize(), new NamedThreadFactory("Factory"));
List<DomainObject> domainObjects = Collections.synchronizedList(messages);
List<List<DomainObject>> domainObjectsPartitioned = partition(domainObjects.size(), config.getPoolSize()); //pool size is 4
for (List<DomainObject> list: domainObjectsPartitioned ) {
executorService.execute(new Runnable() {
#Override
public void run() {
try {
start(list);
} catch (Exception e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}
private void start(List<DomainObject> list){
for (DomainObject> obj : list) {
String mid = messageSendingService.send(obj);
//do smtg with id...
}
}

Springboot Project use AbstractRoutingDataSource question

My project uses springboot+springDataJpa+shiro.
Because my server database uses the master and salve method, so I need to call my code to connect to the two databases, I designed to use the AbstractRoutingDataSource + aop method. Now I have a problem, I think it may be caused by shiro.
I know that the connection switching is performed by the getconnection() method of AbstractRoutingDataSource, and I cannot manually control this method. The problem now is that my getconnection() is executed at most twice in an interface request. Let me post my code and describe it:
#Order(0)
#Aspect
#Component
public class RoutingAopAspect {
#Around("#annotation(targetDataSource)")
public Object routingWithDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable {
try {
DynamicRoutingDataSourceContext.setRoutingDataSource(targetDataSource.value());
return joinPoint.proceed();
} finally {
DynamicRoutingDataSourceContext.removeRoutingDataSource();
}
}
}
public class DynamicRoutingDataSourceContext {
public static final String MASTER = "master";
public static final String SLAVE = "slave";
private static final ThreadLocal<Object> threadLocalDataSource = new ThreadLocal<>();
public static void setRoutingDataSource(Object dataSource) {
if (dataSource == null) {
throw new NullPointerException();
}
threadLocalDataSource.set(dataSource);
// System.err.println(Thread.currentThread().getName()+" set RoutingDataSource : " + dataSource);
}
public static Object getRoutingDataSource() {
Object dataSourceType = threadLocalDataSource.get();
if (dataSourceType == null) {
threadLocalDataSource.set(DynamicRoutingDataSourceContext.MASTER);
return getRoutingDataSource();
}
// System.err.println(Thread.currentThread().getName()+" get RoutingDataSource : " + dataSourceType);
return dataSourceType;
}
public static void removeRoutingDataSource() {
threadLocalDataSource.remove();
// System.err.println(Thread.currentThread().getName()+" remove RoutingDataSource");
}
}
#EnableTransactionManagement
#Configuration
public class DataSourceConfig {
#Value("${datasource.master.url}")
private String masterUrl;
#Value("${datasource.master.username}")
private String masterUsername;
#Value("${datasource.master.password}")
private String masterPassword;
#Value("${dataSource.driverClass}")
private String masterDriverClassName;
#Value("${datasource.slave.url}")
private String slaveUrl;
#Value("${datasource.slave.username}")
private String slaveUsername;
#Value("${datasource.slave.password}")
private String slavePassword;
#Value("${dataSource.driverClass}")
private String slaveDriverClassName;
#Bean(name = "masterDataSource")
public DataSource masterDataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(masterUrl);
datasource.setUsername(masterUsername);
datasource.setPassword(masterPassword);
datasource.setDriverClassName(masterDriverClassName);
return datasource;
}
#Bean(name = "slaveDataSource")
public DataSource slaveDataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(slaveUrl);
datasource.setUsername(slaveUsername);
datasource.setPassword(slavePassword);
datasource.setDriverClassName(slaveDriverClassName);
return datasource;
}
#Primary
#Bean
public DynamicRoutingDataSource dynamicDataSource(#Qualifier(value = "masterDataSource") DataSource masterDataSource,
#Qualifier(value = "slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>(2);
targetDataSources.put(DynamicRoutingDataSourceContext.MASTER, masterDataSource);
targetDataSources.put(DynamicRoutingDataSourceContext.SLAVE, slaveDataSource);
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
dynamicRoutingDataSource.setTargetDataSources(targetDataSources);
dynamicRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
dynamicRoutingDataSource.afterPropertiesSet();
return dynamicRoutingDataSource;
}
}
public class DynamicRoutingDataSourceContext {
public static final String MASTER = "master";
public static final String SLAVE = "slave";
private static final ThreadLocal<Object> threadLocalDataSource = new ThreadLocal<>();
public static void setRoutingDataSource(Object dataSource) {
if (dataSource == null) {
throw new NullPointerException();
}
threadLocalDataSource.set(dataSource);
// System.err.println(Thread.currentThread().getName()+" set RoutingDataSource : " + dataSource);
}
public static Object getRoutingDataSource() {
Object dataSourceType = threadLocalDataSource.get();
if (dataSourceType == null) {
threadLocalDataSource.set(DynamicRoutingDataSourceContext.MASTER);
return getRoutingDataSource();
}
// System.err.println(Thread.currentThread().getName()+" get RoutingDataSource : " + dataSourceType);
return dataSourceType;
}
public static void removeRoutingDataSource() {
threadLocalDataSource.remove();
// System.err.println(Thread.currentThread().getName()+" remove RoutingDataSource");
}
}
This is the relevant basic configuration of AbstractRoutingDataSource.
I defined an aspect to get the parameters of #TargetDataSource in the method. This parameter is a data source that needs to be executed currently. I think there is no problem with my configuration.
Then I will use #TargetDataSource on my service method, and I use shiro, shiro’s doGetAuthorizationInfo() method and doGetAuthenticationInfo() are executed before my service, and both methods need to call my userservice .
Then the problem now is that after calling the doGetAuthorizationInfo() and doGetAuthenticationInfo() methods, they will automatically execute the getconnection() method of AbstractRoutingDataSource to switch the data source, and then execute to my own service, it will not execute the getconnection() method. , This is what I said getconnection() is executed at most twice in an interface request.
#Slf4j
#Component
public class ShiroRealm extends AuthorizingRealm {
#Autowired
#Lazy
private UserService userService;
#Autowired
CacheUtil cacheUtil;
#Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
#Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = JwtUtil.getClaim(principals.toString(), "username");
User user = userService.getUserByUsername(username);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole(user.getRole());
return simpleAuthorizationInfo;
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) {
String token = (String) auth.getCredentials();
String username = JwtUtil.getClaim(token, "username");
if (username == null) {
throw new AuthenticationException("token invalid");
}
User user = userService.getUserByUsername(username);
if (user == null) {
throw new AuthenticationException("User didn't existed!");
}
if (JwtUtil.verify(token, username, user.getPassword(), TokenType.ACCESS_TOKEN) &&
cacheUtil.hasKey(CacheKey.ACCESS_TOKEN_KEY + token)
) {
return new SimpleAuthenticationInfo(token, token, "userRealm");
}
throw new AuthenticationException("Token expired or incorrect");
}
}
#Service
public class PageServiceImpl implements PageService {
#Autowired
PageRepository pageRepository;
#Override
#TargetDataSource("slave")
#Transactional(rollbackFor = Exception.class)
public List<Page> adminFindAll() {
List<Page> pageList = pageRepository.findAll();
if (pageList.isEmpty()) {
throw new CustomNotFoundException("page list not found");
}
return pageList;
}
}
I don’t know if my description is clear. If it is not clear, please ask questions. I hope to get your help, thanks very much!

what is the value of SESSIONID in this class?

In a project I'm working on, I see this snippet of code:
#Autowired
private ContextBuilder contextBuilder;
response = service.payment(contextBuilder.getContext(), request);
request and response are two beans which contain input and output requests.
And class Contextbuilder is like this:
private Context context;
private ContextEntry contextEntry;
private UserInfoRequestBean userInfo;
private String sessionId;
private boolean session = false;
public ContextBuilder() {
this.context = new Context();
this.contextEntry = new ContextEntry();
}
public Context getContext() {
this.contextEntry.setKey("SESSIONID");
this.contextEntry.setValue(sessionId( null));
this.context.getData().add(this.contextEntry);
return this.context;
}
public String sessionId(String sessionId) {
if (this.session) {
this.session = false;
synchronized (ContextBuilder.class) {
if (sessionId != null) {
this.sessionId = sessionId;
return null;
} else {
return this.sessionId;
}
}
} else {
return this.sessionId;
}
}
I can't get what is getContext() and especially sessionId() doing? what is it putting for SESSIONID's value? is it putting always null? if yes why?

Why is this cache not getting evicted?

AdminSOAPRunner:
#Component
public class AdminSOAPRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(AdminSOAPRunner.class);
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
#Autowired
private AdminAuth adminAuthenticator;
#Autowired
private AdminBean adminBean;
private AccountService accountService;
private void setBindingProviderByAccountService() {
WSBindingProvider bindingProvider = (WSBindingProvider) this.accountService;
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, adminBean.getAccountUrl());
LOGGER.info("Endpoint {}", adminBean.getAccountUrl());
}
private RequestInfo getRequestInfo() {
RequestInfo requestInfo = new RequestInfo();
requestInfo.setAppName(adminBean.getAppName());
requestInfo.setUserId(this.getUserId());
requestInfo.setTrace(UUID.randomUUID().toString());
return requestInfo;
}
public List<ApplyAccountResult> getAccounts(ApplyAccountRequest request) {
AccountService_Service service = null;
URL serviceWSDL = AccountService_Service.class.getResource("/Account-service/Account-service.wsdl");
service = new AccountService_Service(serviceWSDL);
SOAPHandlerResolver SOAPHandlerResolver = new SOAPHandlerResolver();
SOAPHandlerResolver.getHandlerList().add(new SOAPHandler(this.adminAuthenticator));
service.setHandlerResolver(SOAPHandlerResolver);
if (accountService == null) {
accountService = service.getAccountService();
}
setBindingProviderByAccountService();
ApplyAccountAccountResponse response = null;
LOGGER.info("Making a SOAP request.");
response = AccountService.applyAccount(request, getRequestInfo(), new Holder<ResponseInfo>());
LOGGER.info("SOAP request completed.");
return response.getApplyAccountResults();
}
SOAPHandlerResolver:
public class SOAPHandlerResolver implements HandlerResolver {
#SuppressWarnings("rawtypes")
private List<Handler> handlerList;
public SOAPHandlerResolver() {
this.handlerList = null;
}
#SuppressWarnings("rawtypes")
public List<Handler> getHandlerList() {
if (this.handlerList == null) {
this.handlerList = new ArrayList<>();
}
return this.handlerList;
}
#SuppressWarnings("rawtypes")
#Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<>();
if (this.handlerList == null || this.handlerList.isEmpty()) {
this.handlerList = new ArrayList<>();
this.handlerList.add(new SOAPHandler(null));
}
handlerChain.addAll(this.handlerList);
return handlerChain;
}
}
SOAPHandler
public class SOAPHandler implements SOAPHandler<SOAPMessageContext> {
private AdminAuth adminAuth;
private static final Logger LOGGER = LoggerFactory.getLogger(SOAPHandler.class);
public MosaicOnboardSOAPHandler(AdminAuth adminAuth) {
if (adminAuth == null) {
adminAuth = new AdminAuth();
LOGGER.info("AdminAuth found null. Creating new adminAuth instance.");
}
this.adminAuth = adminAuth;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty) {
#SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
List<String> cookie = headers.get("Cookie");
if (cookie == null) {
cookie = new ArrayList<>();
headers.put("Cookie", cookie);
}
cookie.add(this.adminAuth.getToken());
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public void close(MessageContext context) {
}
#Override
public Set<QName> getHeaders() {
return null;
}
}
AdminAuth:
#Component
public class AdminAuth {
#Autowired
private AdminBean adminBean;
private static final Logger LOG = LoggerFactory.getLogger(Admin.class);
private String token;
private void generateToken() {
try {
AdminTokenHelper adminTokenHelper = new AdminTokenHelper(adminBean.getAutheticationServerURL(), adminBean.getLicense());
token = adminTokenHelper.getToken(adminBean.getUsername(), adminBean.getPassword().toCharArray());
LOG.info("Token generation successful");
} catch (Exception ex) {
ex.printStackTrace();
LOG.error("Token generation failed");
LOG.error(ex.getMessage());
throw new RuntimeException("Token generation failed", ex);
}
}
#Cacheable(value = "tokenCache")
public String getToken() {
LOG.warn("Token not available. Generating a new token.");
generateToken();
return token;
}
}
ehcache.xml
<cache name="tokenCache" maxEntriesLocalHeap="1" eternal="false" timeToIdleSeconds="895" timeToLiveSeconds="895" memoryStoreEvictionPolicy="LRU"/>
Applcation
#EnableCaching
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class).profiles(determineEnvironmentProfile());
}
}
In AdminAuth, it uses functional user to generate token. the token generated for authentication expires in 15 minutes. So my purpose was to write cache so that all the calls from ui can use the same token regardless of actual user. So i set the time 14:55 to generate new token. Now the problem comes when it's after 15 minutes and the cache doesn't evict the old toeken so that call uses the old and expired token and it fails.
I tried different eviction policies like LRU, LFU, FiFO but nothing is working. The calls are coming from ui through tomcat container in spring boot 1.3.
Why is this not getting evicted? What am i missing? Any help is appreciated
Replace #Cacheable(value = "tokenCache") with #Cacheable("tokenCache")
From the comments:
The dependency on spring-boot-starter-cache was missing. This prevented Spring Boot from automatically configuring the CacheManager. Once this dependency was added, the cache configuration worked.
See http://docs.spring.io/spring-boot/docs/1.3.x/reference/html/boot-features-caching.html

Error in application android to fetch data in the database postgreSQL by WebServices with Ksoap2

First made a WebService Using axis2, which has a connection class with the database, and the class with pedidosDAO with CRUD. Using SoupUI can perform the call of methods. So far so good, I created an android app to consume these services, however this giving error when showing the data of the bank in a ListView, when I run appears (unfortunately XsaladaTeste has stopped), I had already done before and had worked but now I have been going on since time I'm not getting my logcat this buggy and not showing this log. What am I doing wrong?
PedidosXsaladaBusca.java
package com.example.xsaladateste;
public class PedidosXsaladaBusca {
private int id_pedidos;
private String informacao_adicionais;
private int mesa;
private String nome_sobrenome_cliente;
private String nome_xsalada;
private double total_a_pagar;
PedidosXsaladaBusca() {
}
PedidosXsaladaBusca(int id_pedidos, String informacao_adicionais, int mesa, String nome_sobrenome_cliente,
String nome_xsalada, double total_a_pagar) {
this.id_pedidos = id_pedidos;
this.informacao_adicionais = informacao_adicionais;
this.mesa = mesa;
this.nome_sobrenome_cliente = nome_sobrenome_cliente;
this.nome_xsalada = nome_xsalada;
this.total_a_pagar = total_a_pagar;
}
public int getId_pedidos() {
return id_pedidos;
}
public void setId_pedidos(int id_pedidos) {
this.id_pedidos = id_pedidos;
}
public String getNome_sobrenome_cliente() {
return nome_sobrenome_cliente;
}
public void setNome_sobrenome_cliente(String nome_sobrenome_cliente) {
this.nome_sobrenome_cliente = nome_sobrenome_cliente;
}
public int getMesa() {
return mesa;
}
public void setMesa(int mesa) {
this.mesa = mesa;
}
public String getInformacao_adicionais() {
return informacao_adicionais;
}
public void setInformacao_adicionais(String informacao_adicionais) {
this.informacao_adicionais = informacao_adicionais;
}
public double getTotal_a_pagar() {
return total_a_pagar;
}
public void setTotal_a_pagar(double total_a_pagar) {
this.total_a_pagar = total_a_pagar;
}
public String getNome_xsalada() {
return nome_xsalada;
}
public void setNome_xsalada(String nome_xsalada) {
this.nome_xsalada = nome_xsalada;
}
#Override
public String toString() {
return "PedidosXsaladaBusca [id_pedidos=" + id_pedidos + ", informacao_adicionais=" + informacao_adicionais
+ ", mesa=" + mesa + ", nome_sobrenome_cliente=" + nome_sobrenome_cliente + ", nome_xsalada="
+ nome_xsalada + ", total_a_pagar=" + total_a_pagar + "]";
}
}
PedidosDAO.java
public class PedidosDAO {
// Setando Caminhos
private static final String URL = "http://192.168.0.1:8080/BancoParaXsalada/services/PedidosDAO?wsdl";
private static final String nameSpace = "http://xsalada.com.br";
// referencias ao metodos no SoapUI XML file
private static final String BUSCAR = "buscarTodos";
// metodo inserir no banco pelo android usando biblioteca Ksoap2
public ArrayList<PedidosXsaladaBusca> buscarTodos() {
ArrayList<PedidosXsaladaBusca> lista = new ArrayList<PedidosXsaladaBusca>();
SoapObject buscarTodos = new SoapObject(nameSpace, BUSCAR);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(buscarTodos);
envelope.implicitTypes = true;
HttpTransportSE http = new HttpTransportSE(URL);
try {
http.call("urn:" + BUSCAR, envelope);
Vector<SoapObject> resposta = (Vector<SoapObject>) envelope.getResponse();
for (SoapObject soapObject : resposta) {
PedidosXsaladaBusca user = new PedidosXsaladaBusca();
user.setId_pedidos(Integer.parseInt(soapObject.getProperty("id_pedidos").toString()));
user.setInformacao_adicionais(soapObject.getProperty("informacao_adicionais").toString());
user.setMesa(Integer.parseInt(soapObject.getProperty("mesa").toString()));
user.setNome_sobrenome_cliente(soapObject.getProperty("nome_sobrenome_cliente").toString());
user.setNome_xsalada(soapObject.getProperty("nome_xsalada").toString());
user.setTotal_a_pagar(Double.parseDouble(soapObject.getProperty("total_a_pagar").toString()));
lista.add(user);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return lista;
}
}
MainActivity.java
public class MainActivity extends Activity {
public ListView listaUsuario = (ListView) findViewById(R.id.listaPedidos);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
PedidosDAO dao = new PedidosDAO();
ArrayList<PedidosXsaladaBusca> lista = dao.buscarTodos();
ArrayAdapter<PedidosXsaladaBusca> adpUser = new ArrayAdapter<PedidosXsaladaBusca>(this,
android.R.layout.simple_list_item_1, lista);
listaUsuario.setAdapter(adpUser);
}
Resolved, it was not code error I realized he was giving the following error: [timestamp - DDMs] Can not bind to site 8600 is debugger
then researched and solve. below is the link I found to resolve the error:
Eclipse DDMS error "Can't bind to local 8600 for debugger"

Categories