I am somewhat new to android development and okhttp/Retrofit
Please check my first post for the reason why I need to try and get a retry mechanism working
My First post
I need some help implementing the .clone() for Retrofit in my service so that it can try to call my URL again if it fails the first time.
my urlcontroller.java
public class UrlController{
public static boolean loading = false;
private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.MINUTES)
.writeTimeout(60, TimeUnit.MINUTES)
.readTimeout(60, TimeUnit.MINUTES)
.callTimeout(60, TimeUnit.MINUTES)
.build();
public static String IP_ADDRESS = "https://e***edd****.com/";//Enter You Ip_Address here here
public static String Purchase_code = "********************";
public static String Custom_Security = "***************";//Enter the Custom Security code here
// Please don't change the below code without proper knowledge
private static final OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static String Base_URL = IP_ADDRESS + "json/appr/v1/";
private static final Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(Base_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password, Context context) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createService(serviceClass, authToken, context);
} else {
return createService(serviceClass);
}
}
public static <S> S createServiceNoTimeout(Class<S> serviceClass, String authToken, Context context) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor = new AuthenticationInterceptor(authToken, context);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
httpClient.connectTimeout(0, TimeUnit.MINUTES);
httpClient.readTimeout(0, TimeUnit.SECONDS);
httpClient.writeTimeout(0, TimeUnit.SECONDS);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
public static <S> S createServiceNoTimeoutUP(
Class<S> serviceClass, String username, String password, Context context) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createServiceNoTimeout(serviceClass, authToken, context);
}
return createService(serviceClass);
}
public static <S> S createService(
Class<S> serviceClass, final String authToken, Context context) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor =
new AuthenticationInterceptor(authToken, context);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
public static Map<String, String> AddHeaders(Context context) {
Map<String, String> map = new HashMap<>();
*THIS INFO WAS REMOVED FOR SECURITY PURPOSES
return map;
}
public static Map<String, String> UploadImageAddHeaders(Context context) {
Map<String, String> map = new HashMap<>();
*THIS INFO WAS REMOVED FOR SECURITY PURPOSES
return map;
}
}
My splashScreen.java
I Removed some lines of code which basically just gets the data the was returned from the call to my webpage which then gets implemented in my app it is basic data like names, color-codes and user login/signup data
public void api_getSettings() {
RestService restService = UrlController.createService(RestService.class);
try{
Call<ResponseBody> myCall = restService.getSettings(UrlController.AddHeaders(this));
myCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> responseObj) {
try {
System.out.println("try2");
if (responseObj.isSuccessful()) {
Log.d("info settings Responce", "" + responseObj.toString());
JSONObject response = new JSONObject(responseObj.body().string());
if (response.getBoolean("success")) {
jsonObjectSetting = response.getJSONObject("data");
//some stuff have been hidden for security reasons
} else {
Toast.makeText(activity, response.get("test message").toString(), Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
} catch (
ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
Related
How to return value from enqueue function to LoadinBackground()
listnews is returning as null
public class NewsAppLoader extends AsyncTaskLoader<ArrayList> {
private static final String USGS_REQUEST_URL =
"https://newsapi.org/v2/everything?q=tesla&from=2021-04-18&sortBy=publishedAt&apiKey=47ebcd70505c4649b04dd050c8bbe307";
private static final String BASE_URL =
"https://newsapi.org/v2/";
private static final String LOG_TAG = "check";
final String API_KEY = "47ebcd70505c4649b04dd050c8bbe307";
public NewsAppLoader(Context context) {
super(context);
//this.apiClient = apiClient;
}
NewsAppAdapter newsAdapter;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
APIInterface api = retrofit.create(APIInterface.class);
Call<ResponseModel> call = api.getLatestNews("Tesla", API_KEY);
// #Nullable
#SuppressLint("LongLogTag")
#Override
public ArrayList<News> loadInBackground() {
ArrayList<News> listNews = new ArrayList<News>();
call.enqueue(new Callback<ResponseModel>() {
#Override
public void onResponse(Call<ResponseModel> call, Response<ResponseModel> response) {
if (response.body().getStatus().equals("ok")) {
List<Article> articleList = response.body().getArticles();
if (articleList.size() > 0) {
String title = articleList.get(0).getTitle();
String desc = articleList.get(0).getDescription();
String author = articleList.get(0).getAuthor();
String imgURL = articleList.get(0).getUrlToImage();
listNews.add(new News(title, null, desc, author));
// return new ArrayList<News>(listNews);
//getNewsList(listNews);
}
}
//return articleList;
}
#Override
public void onFailure(Call<ResponseModel> call, Throwable t) {
Log.e("out", t.toString());
}
});
return listNews;
}
// listNews = callRetrofit(call);
//return listNews;
public ArrayList<News> getNewsList(ArrayList<News> news) {
return news;
}
}
please suggest any method to return value from OnResponse to LoadinBackground() . So that I can load that values in List View adapter .
You can use call.execute to get response synchronously. But AsyncTask is not mandatory at all, you can use your current code without AsyncTask. Actually, Retrofit executes HTTP requests in background when you use call.enqueue, so you can easily use it without AsyncTask
I am developing an android app (java), I am using Firebase, for each registered user I have a token of the device, how can I send a notification to a specific user using his token ?
For sending a notification to users the only thing required is that user's token. You can send notification using FCM.
Here, I'm sharing my FCM class which can be used for this purpose. It is using Okhttp3 requests, so make sure you add its dependency.
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
After adding this dependency, all you have to do is to use this FCM class.
FCMMessages.java
public class FCMMessages {
private Context context;
public void sendMessageSingle(Context context, final String recipient, final String title, final String body, final Map<String, String> dataMap)
{
this.context = context;
Map<String, Object> notificationMap = new HashMap<>();
notificationMap.put("body", body);
notificationMap.put("title", title);
Map<String, Object> rootMap = new HashMap<>();
rootMap.put("notification", notificationMap);
rootMap.put("to", recipient);
if (dataMap != null)
rootMap.put("data", dataMap);
new SendFCM().setFcm(rootMap).execute();
}
public void sendMessageMulti(Context context, final JSONArray recipients, final String title, final String body, final Map<String, String> dataMap) {
this.context = context;
Map<String, Object> notificationMap = new HashMap<>();
notificationMap.put("body", body);
notificationMap.put("title", title);
Map<String, Object> rootMap = new HashMap<>();
rootMap.put("notification", notificationMap);
rootMap.put("registration_ids", recipients);
if (dataMap != null)
rootMap.put("data", dataMap);
new SendFCM().setFcm(rootMap).execute();
}
#SuppressLint("StaticFieldLeak")
class SendFCM extends AsyncTask<String, String, String> {
private String FCM_MESSAGE_URL = "https://fcm.googleapis.com/fcm/send";
private Map<String, Object> fcm;
SendFCM setFcm(Map<String, Object> fcm) {
this.fcm = fcm;
return this;
}
#Override
protected String doInBackground(String... strings) {
try {
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSON, new JSONObject(fcm).toString());
Request request = new Request.Builder()
.url(FCM_MESSAGE_URL)
.post(body)
.addHeader("Authorization","key=" + StaticConfig.myMessagingAuth)
.build();
Response response = new OkHttpClient().newCall(request).execute();
return response.body().string();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject resultJson = new JSONObject(result);
int success, failure;
success = resultJson.getInt("success");
failure = resultJson.getInt("failure");
//Toast.makeText(context, "Sent: " + success + "/" + (success + failure), Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
// Toast.makeText(context, "Message Failed, Unknown error occurred.", Toast.LENGTH_LONG).show();
}
}
}
}
Make sure you get the messagingAuth from your firebase project settings. To get the messagingAuth token, follow these steps:
Open Firebase Project > Project Settings > Cloud Messaging > Server key
Copy the value of server key and paste it as messagingAuth in your android project.
To send a notification to single user token use sendMessageSingle method. It would be like
String user_token = "wiubd92uhe91dik-q";
String notification_title = "This is notification title";
String notification_des = "This is notification description";
new FCMMessages().sendMessageSingle(MainActivity.this, user_token, notification_title, notification_des, null);
To send a notification to multiple user tokens use sendMessageMulti method. It would be like
ArrayList<String> user_tokens = new ArrayList<>();
user_tokens.add(token_1);
user_tokens.add(token_2);
user_tokens.add(token_3);
String notification_title = "This is notification title";
String notification_des = "This is notification description";
new FCMMessages().sendMessageMulti(MainActivity.this, new JSONArray(user_tokens), notification_title, notification_des, null);
Use this YouTube link here EDMT Dev has implemented the following in his Eat it new series. And kindly mark this as the correct answer if this helps you.
Add the below dependency
`implementation 'io.reactivex.rxjava2:rxandroid:2.1.1`'
Now Create these classes :
Token Model This Model is used to retrieve token data( Token , Phone ). I have also a variable for the phone because I made this class according to my datastructure . Kindly modify the code according to your need
public class TokenModel {
private String phone,token;
public TokenModel() {
}
public TokenModel(String phone, String token) {
this.phone = phone;
this.token = token;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}}
FCM Send Data Model
public class FCMSendData {
private String to;
private Map<String,String> data;
public FCMSendData(String to, Map<String, String> data) {
this.to = to;
this.data = data;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public Map<String, String> getData() {
return data;
}
public void setData(Map<String, String> data) {
this.data = data;
}}
Create FCM Result Model
class FCMResult {
private String message_id;
public FCMResult() {
}
public String getMessage_id() {
return message_id;
}
public void setMessage_id(String message_id) {
this.message_id = message_id;
}}
Create RetrofitFCMClient
public class RetrofitFCMClient {
private static Retrofit instance;
public static Retrofit getInstance()
{
if(instance==null)
{
instance = new Retrofit.Builder().baseUrl("https://fcm.googleapis.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return instance;
}
return instance;
}}
Now we need to implement an interface
//Authorization key is server key of Cloud Messaging
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:key=**YOUR_AUTHORIZATION KEY HERE**"
})
#POST("fcm/send")
Observable<FCMResponse> sendNotification(#Body FCMSendData body);}
Now We are ready to use the firebase messaging just need to put data and use our retrofit to push it
TokenModel tokenModel = dataSnapshot.getValue(TokenModel.class);
//("FCM",tokenModel.getToken());
Map<String, String> notiData = new
HashMap<>();
notiData.put(Common.NOTI_TITLE, "YOUR NOTIFICATION TITLE");
notiData.put(Common.NOTI_CONTENT,"YOUR_NOTFICATION CONTENT );
FCMSendData sendData = new FCMSendData(tokenModel.getToken(),
notiData);
compositeDisposable
.add(ifcmService.sendNotification(sendData)
.subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<FCMResponse>() {
#Override
public void accept(FCMResponse
fcmResponse)
throws Exception {
if (fcmResponse.getSuccess()
== 1) {
Toast.makeText(getContext(),
"Success", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getContext(), "Failed
to Notify", Toast.LENGTH_LONG).show();
}
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable
throwable) throws Exception {
Toast.makeText(getContext(),
throwable.getMessage(), Toast.LENGTH_LONG).show();
}
}));
Use this YouTube link here EDMT Dev has implemented the following in his Eat it new series
I am using AWS Rekognition to build an application and I have realized that every time i make a request to the service a connection to aws keep being reestablished which is slowing down performance. Is there any way to make one single connection that persists throughout the session? My code can be seen below:
private static final AmazonRekognition rekognitionClient = RekognitionUtil.setupRekognitionClient();
private static AWSCredentialsProvider setupCredentials(String accessKey, String secretKey) {
AWSCredentialsProvider provider = new AWSCredentialsProvider() {
#Override
public AWSCredentials getCredentials() {
return new AWSCredentials() {
#Override
public String getAWSAccessKeyId() {
LOG.info("Access key: " + ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_ACCESS_KEY,accessKey));
return ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_ACCESS_KEY,accessKey);
}
#Override
public String getAWSSecretKey() {
LOG.info("Secret key: " + ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_SECRET_KEY,secretKey));
return ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_SECRET_KEY,secretKey);
}
};
}
#Override
public void refresh() {
}
};
return provider;
}
private static AmazonRekognition setupRekognitionClient() {
AWSCredentialsProvider provider = setupCredentials("xxxx", "xxxx");
return AmazonRekognitionClientBuilder.standard().withCredentials(provider).withRegion(ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_REGION,"xxx")).build();
}
private static AWSCredentialsProvider setupCredentials(String accessKey, String secretKey) {
AWSCredentialsProvider provider = new AWSCredentialsProvider() {
#Override
public AWSCredentials getCredentials() {
return new AWSCredentials() {
#Override
public String getAWSAccessKeyId() {
LOG.info("Access key: " + ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_ACCESS_KEY,accessKey));
return ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_ACCESS_KEY,accessKey);
}
#Override
public String getAWSSecretKey() {
LOG.info("Secret key: " + ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_SECRET_KEY,secretKey));
return ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_SECRET_KEY,secretKey);
}
};
}
#Override
public void refresh() {
}
};
return provider;
}
private static AmazonRekognition setupRekognitionClient() {
AWSCredentialsProvider provider = setupCredentials("xxxx", "xxx");
return AmazonRekognitionClientBuilder.standard().withCredentials(provider).withRegion(ConfigUtil.getString(ConfigConstants.CONFIG_REKOGNITION_REGION,"xxx")).build();
}
public static String searchCollectionByFace(String collectionId, ByteBuffer sourceByteBuffer) throws Exception {
LOG.info("Searching face collection by face...");
String faceId = "";
try {
ObjectMapper objectMapper = new ObjectMapper();
// Get an image object from S3 bucket.
Image image = new Image().withBytes(sourceByteBuffer);
// Search collection for faces similar to the largest face in the image.
SearchFacesByImageRequest searchFacesByImageRequest = new SearchFacesByImageRequest().withCollectionId(collectionId).withImage(image).withFaceMatchThreshold(70F).withMaxFaces(2);
SearchFacesByImageResult searchFacesByImageResult = rekognitionClient.searchFacesByImage(searchFacesByImageRequest);
List<FaceMatch> faceImageMatches = searchFacesByImageResult.getFaceMatches();
for (FaceMatch face : faceImageMatches) {
LOG.info(face.getFace().getFaceId());
if(face.getFace().getConfidence() > SIMILARITY_LIMIT){
faceId = face.getFace().getFaceId();
}
}
return faceId;
} catch (Exception ex) {
LOG.error("Error has occurred searching for face", ex);
throw new Exception();
}
}
You can try to fine tune:
Max connections
Max connection idle time
in the client configuration you pass to the client.
#Configuration
public class CustomRemoteTokenService implements ResourceServerTokenServices {
private static final Logger logger = LoggerFactory.getLogger(CustomRemoteTokenService.class);
#Resource
Environment environment;
private RestOperations restTemplate;
private String checkTokenEndpointUrl;
private String clientId;
private String clientSecret;
private String tokenName = "token";
private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
#Autowired
public CustomRemoteTokenService() {
restTemplate = new RestTemplate();
((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
#Override
// Ignore 400
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getRawStatusCode() != 400
&& response.getRawStatusCode() != 403 /* && response.getRawStatusCode() != 401 */) {
super.handleError(response);
}
}
});
}
public void setRestTemplate(RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
public void setCheckTokenEndpointUrl(String checkTokenEndpointUrl) {
this.checkTokenEndpointUrl = checkTokenEndpointUrl;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public void setAccessTokenConverter(AccessTokenConverter accessTokenConverter) {
this.tokenConverter = accessTokenConverter;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
#Override
public OAuth2Authentication loadAuthentication(String accessToken)
throws AuthenticationException, InvalidTokenException, GenericException {
/*
* This code needs to be more dynamic. Every time an API is added we have to add
* its entry in the if check for now. Should be changed later.
*/
HttpServletRequest request = Context.getCurrentInstance().getRequest();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add(tokenName, accessToken);
formData.add("api", environment.getProperty("resource.api"));
/* formData.add("api", "5b64018880999103244f1fdd");*/
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", getAuthorizationHeader(clientId, clientSecret));
Map<String, Object> map = null;
try {
map = postForMap(checkTokenEndpointUrl, formData, headers);
} catch (ResourceAccessException e) {
logger.error("Socket Exception occured at " + System.currentTimeMillis() + "for client_id : " + clientId);
GenericException ge = new GenericException(
"Could not validate your access token. If this occurs too often please contact MapmyIndia support at apisupport#mapmyindia.com");
ge.setHttpErrorCode(504);
ge.setOauthError("Access Token validation failed");
throw ge;
}
if (map.containsKey("error")) {
logger.error("check_token returned error: " + map.get("error") + " for client id : " + clientId);
String temp = map.get("error").toString();
GenericException ge = new GenericException(map.get("error_description").toString());
ge.setHttpErrorCode(Integer.parseInt(map.get("responsecode").toString()));
ge.setOauthError(temp);
switch (temp) {
case "invalid_token":
throw new InvalidTokenException(accessToken);
default:
throw ge;
}
}
Assert.state(map.containsKey("client_id"), "Client id must be present in response from auth server");
return tokenConverter.extractAuthentication(map);
}
#Override
public OAuth2AccessToken readAccessToken(String accessToken) {
throw new UnsupportedOperationException("Not supported: read access token");
}
private String getAuthorizationHeader(String clientId, String clientSecret) {
String creds = String.format("%s:%s", clientId, clientSecret);
try {
return "Basic " + new String(Base64.encode(creds.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Could not convert String");
}
}
private Map<String, Object> postForMap(String path, MultiValueMap<String, String> formData, HttpHeaders headers)
throws RestClientException {
if (headers.getContentType() == null) {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}
#SuppressWarnings("rawtypes")
Map map = restTemplate.exchange(path, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();
#SuppressWarnings("unchecked")
Map<String, Object> result = map;
return result;
}
}
I autowired Environment and getting null when I do environment.getProperty("resource.api");
It is always returning null but in another classes I autowire Environment and successfully retrieve the value from properties.
You have to take this steps :
1.Register a Properties
You need to register you properties file by #PropertySource("classpath:foo.properties") as :
#Configuration
#PropertySource("classpath:foo.properties")
public class CustomRemoteTokenService implements ResourceServerTokenServices {
//...
}
2.Injecting Properties
To obtain the value of a property with the Environment API:
#Autowired
private Environment env;
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