Avoid saving data in spring data rest in handleBeforeSave - spring

I am using #RepositoryRestResource for Mongo Repositories.
I want to do some pre-save check and if those checks are not meeting the requirements, I want to abandon the save operation.
I tried :
#HandleBeforeSave
public void handleBeforeSave(CallLog callLog)
throws InternalServerException {
CallLog log = callRepository.findOne(callLog.getConferenceId());
if (log != null
&& (callLog.getStatus().equals(Constants.CALL_IN_PROGRESS) || callLog
.getStatus().equals(Constants.CALL_DROPPED))) {
if (callLog.getStatus().equals(Constants.CALL_DROPPED)) {
User user = userRepository.findOne(callLog.getReceiverId());
user.setStatus(Constants.USER_STATUS_IDLE);
userRepository.save(user);
}
throw new InternalServerException(
"This call has already been received");
} else {
User user = userRepository.findOne(callLog.getReceiverId());
user.setStatus(Constants.USER_STATUS_BUSY);
userRepository.save(user);
}
}
But throwing exception, does not actually abandon the save call. Is there any other way to do it?

You can use a RestController to intercept the request.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html

Related

Spring Cache - Clear cache only when API response is success

I am using Spring Cache #CacheEvict & #Cacheable
Currently I am running a scheduler every Hr to clear cache and next time when fetchUser() is called it will fetch data from external APi and add to cache.
#Scheduled(cron = "0 0 * * * *}")
#CacheEvict(value = "some-unique-value", allEntries = true)
public void clearUserCache() {
log.info("Cache cleared");
}
#Cacheable(value = "some-unique-value", unless = "#result.isFailure()")
#Override
public Result<UserResponse> fetchUser() {
try {
UserResponse userResponse = api.fetchUserDetail();
return Result.success(userResponse);
} catch (Exception e) {
return Result.failure(INTERNAL_SERVER_ERROR);
}
}
Now what we need is to clear cache only when User API call is success. Is there a way to do that.
As now cache is cleared on schedule and suppose external API call fails. Main API will return error response. In that case I should be able to use existing cache itself.
If I got it correctly, why don't you call it as a normal method after checking the API call is correct at this method's parent?
With your code, something along the lines of
// we just leave scheduled here as you need it.
#Scheduled(cron = "0 0 * * * *}")
#CacheEvict(value = "some-unique-value", allEntries = true)
public void clearUserCache() {
log.info("Cache cleared");
}
#Cacheable(value = "some-unique-value", unless = "#result.isFailure()")
#Override
public Result<UserResponse> fetchUser() {
try {
UserResponse userResponse = api.fetchUserDetail();
return Result.success(userResponse);
} catch (Exception e) {
return Result.failure(INTERNAL_SERVER_ERROR);
}
}
public void parentMethod() {
Result<UserResponse> userResult = this.fetchUser();
if(userResult.isFailure()) {
this.clearUserCache();
}
}
This way, if any Exception is thrown it will return with a failure status and you're able to check it. So the cache will be cleared either every hour or when it didn't work.
So the next time, as it was a failure and there's no cache, it will try again.
I didn't find any direct implementation but with a work around I was able to do it.
Use Case
User API response should be updated only when next service call is triggered which make use of User API. It should not be updated by scheduler. As we need to pass on header information coming in from external system, to User API as well.
Cache must be cleared only when User API response is success.
Steps:
Added a variable in scheduler and turning it ON on Schedule time and OFF when cache is updated.
This flag is used in UserService class to check if scheduler was triggered or not.
If not, use cache. If true, trigger User API call. Check for response, if success. Trigger CacheEvict method and update Cache.
Sample Code:
SchedulerConfig
private boolean updateUserCache;
#Scheduled(cron = "${0 0 * * * *}") // runs every Hr
public void userScheduler() {
updateUserCache = true;
log.info("Scheduler triggered for User");
}
#CacheEvict(value = "USER_CACHE", allEntries = true)
public void clearUserCache() {
updateUserCache = false;
log.info("User cache cleared");
}
public boolean isUserCacheUpdateRequired() {
return updateUserCache;
}
UserService
UserResponse userResponse = null;
if (schedulerConfig.isUserCacheUpdateRequired()) {
userResponse = userCache.fetchUserDetail();
if (userResponse != null) {
// clear's cache and userResponse is stored in cache automatically when getUserDetail is called below
schedulerConfig.clearUserCache();
}
}
return userCache.getUserDetail(userResponse);
UserCache
#Cacheable(value = "USER_CACHE", key = "#root.targetClass", unless = "#result.isFailure()")
public Result<User> getUserDetail(UserResponse userResponse) {
try {
if (userResponse == null) { // handle first time trigger when cache is not available
userResponse = fetchUserDetail(); // actual API call
}
return Result.success(mapToUser(userResponse));
} catch (Exception e) {
return Result.failure("Error Response");
}
}
Note:
Result is a custom Wrapper, assume it as a object which has success or failure attributes
I had to add #Cacheable part as separate Bean because caching only works on proxy objects. If I keep getUserDetail inside UserService and call directly, its not been intercepted as proxy and cache logic is not working, API call is triggered each time.
Most important: This is not the best solution and has scope for improvement.

invalid_grant of OAuthAuthorizationServerProvider

I'm working on writing fully customized ASP.NET Identity for my WebAPi.
I have rewritten my own derived OAuthAuthorizationServerProvider in this way:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Check User availability ...
//ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
// if i couldn't found user in my DataBase ...
//if (user == null)
//{
//context.SetError("invalid_grant", "The user name or password is incorrect.");
// return;
//}
context.Validated();
}
}
GrantResourceOwnerCredentials just returns an invalid_grant error for each calls. i want to handle it but, i don't know how.
ValidateClientAuthentication is where you would do your authentication checks and this is where you throw errors if anything doesn't match.
move your code there and do the checks before you call context.Validated(). You only call the Validate method once you make sure everything is validated correctly.
here is an example of such an implementation I did a while back:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
//first try to get the client details from the Authorization Basic header
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
//no details in the Authorization Header so try to find matching post values
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("client_not_authorized", "invalid client details");
return Task.FromResult<object>(null);
}
var dataLayer = new RepoManager(new DataLayerDapper()).DataLayer;
var audienceDto = dataLayer.GetAudience(clientId);
if (audienceDto == null || !clientSecret.Equals(audienceDto.Secret))
{
context.SetError("unauthorized_client", "unauthorized client");
return Task.FromResult<object>(null);
}
context.Validated();
return Task.FromResult<object>(null);
}
Notice how the checks happen in order and certain errors are raised with some appropriate errors.
This code takes a client id and client secret from an authorization header but you can easily drop all that and replace it with your own checks and database calls.
The important part is that this is where you deal with stuff like this and this is where you set the errors so your clients know what's going on.
GrantResourceOwnerCredentials this is where you get once the call is properly authenticated, at which point you can start creating tokens, adding claims and creating the authentication ticket. This method does not get hit if the previous one fails to authenticate the request.
Here is a working example:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim("clientID", context.ClientId));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"audience", context.ClientId
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
return Task.FromResult<object>(null);
}
Now, if you get an invalid grant error that usually happens because you either didn't set up the grant_type in your initial call or you set up the wrong value.
in my case I had to setup this:
"grant_type", "password"

getCurrentUser not going null even i logged out using Parse sdk

How to manage session with Parse SDK?
I have used SharedPrefences to locally store the session user info, and checked on the start whether move the user to Home Screen or Login screen. Is this the right process or there is an option to maintain session automatically without using SharedPrefecences.
Just use SharedPrefences according to your Login and SignUp Activity besides you can also use Parse Session Management..
I don't know the solution to the first problem as even I failed to get it working. One of the workaround is to store the user information in shared preferences temporarily when he/she logs in and clear them when user logs out of the app.
private void setUserPreferences(String username){
SharedPreferences sharedPreferences=getSharedPreferences("DEFAULT_SP", Context.MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("username", username);
editor.commit();
}
private String getUserPreferences(){
SharedPreferences sharedPreferences=getSharedPreferences("DEFAULT_SP", Context.MODE_PRIVATE);
return sharedPreferences.getString("username", null);
}
private void clearUserPreferences(){
SharedPreferences sharedPreferences=getSharedPreferences("DEFAULT_SP", Context.MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.clear();
editor.commit();
}
Now you can call these functions when you log into the app and log out of the app. Not a viable solution but its all what I've got for the time being.
Also, you cannot login using email-id in parse, you will need username for that. So what you can do is to find the username associated with that email and then log into parse using that username.
private String mUsername=null;
private void getParseUsername(String email){
ParseQuery<ParseObject> query = ParseQuery.getQuery("User");
query.whereEqualTo("email", email);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> parseList, ParseException e) {
if (e == null) {
//assuming you don't have same email id's in the parse database
//, I don't think that's even allowed.
mUsername = parseList.get(0).getString("");
} else {
Log.d("parseList", "Error: " + e.getMessage());
}
}
});
}
For retrieving user info, you can simply type this code:
ParseUser.getCurrentUser().getUsername()
For your fourth question, if I understand it correctly, you don't want user to register with a mobile number which is already registered.
private boolean mDuplicatePhoneNo=false;
private void isPhoneNumberDuplicate(String phoneNo)
ParseQuery<ParseObject> query = ParseQuery.getQuery("User");
//Here phone_no is the field name in which you have stored your phone numbers
//Make sure they are in string format.
query.whereEqualTo("phone_no", phone);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> parseList, ParseException e) {
if (e == null) {
if(phoneNo.equals(parseList.get(0).getString("phone_no"))){
mDuplicatePhoneNo=true;
}
} else {
Log.d("parseList", "Error: " + e.getMessage());
}
}
});
Also make sure to visit https://parse.com/docs/android/guide#getting-started
for a better guide.

Get User custom fields without SOQL (like $User in formulas)?

I have some custom fields on my User object that I want to access with APEX code in my VisualForce trigger. When I access it from a Formula field I get to use a nifty $User reference like this:
$User.my_prop__c
From APEX I have to query the User object by UserId like this:
[select my_prop__c from User where id = :UserInfo.getUserId()].my_prop__c;
Is there something baked into APEX already that would let me get at the user properties without the SOQL query? If not, does anyone know of a utility class for lazy loading and caching user properties so the overhead is minimal.
I would use something similar to the following code sample. It uses a singleton pattern to statically store the information in memory for the duration of your transaction. It's similar to the lazy loading that twamley proposed but I feel this is a much simpler approach.
Usage 1: UserUtil.CurrentUser.Email;
Usage 2: User someUser = UserUtil.getUser(someUserId);
This will allow you to access the same information on the current user or other users in the system. Notice the queryUsers method just returns a query result. This makes it easy to add and remove fields from your query as it is isolated in its own method keeping things simple.
Note: that this code pulls in all users when used. Most orgs do not have multiple hundreds of users so heap size shouldn't be a concern. But if it is you can just modify the queryUsers() method to only return active users or filter down based on other criteria.
public class UserUtil {
//Protected Members
private static final UserUtil instance = new UserUtil();
private Map<Id, User> mapUsers;
//Properties
public static User CurrentUser {
get { return getUser(UserInfo.getUserId()); }
}
//Constructor
private UserUtil() {
mapUsers = new Map<Id, User>(queryUsers());
}
//Public Methods
public static User getUser(Id userId) {
if (instance.mapUsers.containsKey(userId)) {
return instance.mapUsers.get(userId);
}
else {
throw new InvalidUserIdException('Unable to locate user id: ' + userId);
}
}
//Private Methods
private List<User> queryUsers() {
return [SELECT
Id
, Name
, UserName
, Email
, Alias
FROM
User];
}
//Internal Classes
public class InvalidUserIdException extends Exception {}
}
I wrote my own utility class. I'm still interested in better techniques though.
This utility class lazy loads when the first property is accessed. Update_Closed_Won_Opportunities__c and Set_Opportunities_to_Closed_Won__c are my custom fields on the User object (visible only to System Administrators so people can't upgrade their permissions).
public with sharing class MyUserInfo {
private Id userId;
private User myUser; // Hold onto the user object once we've loaded it
// Default constructor uses the active user id
public MyUserInfo() {
userId = UserInfo.getUserId();
}
// Secondary constructor accepts a user id as a parameter
public MyUserInfo(Id someOtherUserId) {
userId = someOtherUserId;
}
// Only called one time when we first need it so grab all of the custom fields now
private void LazyLoadUser() {
System.AssertNotEquals(null, userId);
myUser = [
SELECT Update_Closed_Won_Opportunities__c, Set_Opportunities_To_Closed_Won__c
FROM User
WHERE id = :userId
];
System.AssertNotEquals(null, myUser, 'Unable to load user with id ' + userId); // could return defaults instead
}
// Getters (be sure to include each field in the SOQL of LazyLoadUser)
public boolean UpdateClosedWonOpportunities { get {
if (myUser == null) LazyLoadUser();
return myUser.Update_Closed_Won_Opportunities__c;
} }
public boolean SetOpportunitiesToClosedWon { get {
if (myUser == null) LazyLoadUser();
return myUser.Set_Opportunities_To_Closed_Won__c;
} }
}
Here is my trigger utilizing that class. The first line myUserInfo = new MyUserInfo(); doesn't run any SOQL. That won't happen until the first custom get property is used. Subsequent calls don't need SOQL.
trigger LockClosedOpportunity on Opportunity (before update) {
MyUserInfo myUserInfo = new MyUserInfo();
for (Opportunity o : trigger.old)
{
if (!myUserInfo.UpdateClosedWonOpportunities && o.StageName == 'Closed Won')
trigger.newMap.get(o.Id).addError('You do not have permission to change an Opportunity after it has been set to Closed Won.');
}
for (Opportunity o : trigger.new)
{
if ( !myUserInfo.SetOpportunitiesToClosedWon && o.StageName == 'Closed Won' && trigger.oldMap.get(o.Id).StageName != 'Closed Won' )
o.addError('You do not have permission to set an Opportunity to Closed Won.');
}
}
It reads similar to $User in formulas and I don't have to worry about tacking on multiple SOQL calls when one (or zero) suffices.

Play Framework: Image Display question

ref:
http://www.lunatech-research.com/playframework-file-upload-blob
I'm uneasy about one point in this example
#{list items:models.User.findAll(), as:'user'}
<img src="#{userPhoto(user.id)}">
#{/list}
At this point I'm already holding the user object (including the image blob). Yet the userPhoto() method makes another dip into the backend to get the Image user.photo
public static void userPhoto(long id) {
final User user = User.findById(id);
notFoundIfNull(user);
response.setContentTypeIfNotSet(user.photo.type());
renderBinary(user.photo.get());
}
Any way to avoid this unnecessary findById call?
You're not actually holding the user object any more though, because the userPhoto action is invoked in a separate request that's sent when the browser tries to load the image from the URL generated by #{userPhoto(user.id)}.
Of course, you could use the cache to store data from each user's photo Blob, which would reduce the likelihood that you had to go to the database on the image request. It's more trouble than it's worth in this case though since you're just doing a simple primary key lookup for the user object, and that should be relatively inexpensive. Plus Blobs aren't serializable, so you have to pull out each piece of information separately.
Still, if you were to try that it might look something like this:
// The action that renders your list of images
public static void index() {
List<User> users = User.findAll();
for (User user : users) {
cachePhoto(user.photo);
}
render(users);
}
// The action that returns the image data to display
public static void userPhoto(long id) {
InputStream photoStream;
String path = Cache.get("image_path_user_" + id);
String type = Cache.get("image_type_user_" + id);
// Was the data we needed in the cache?
if (path == null || type == null) {
// No, we'll have to go to the database anyway
User user = User.findById(id);
notFoundIfNull(user);
cachePhoto(user.photo);
photoStream = user.photo.get();
type = user.photo.type();
} else {
// Yes, just generate the stream directly
try {
photoStream = new FileInputStream(new File(path));
} catch (Exception ex) {
throw new UnexpectedException(ex);
}
}
response.setContentTypeIfNotSet(type);
renderBinary(photoStream);
}
// Convenience method for caching the photo information
private static void cachePhoto(Blob photo) {
if (photo == null) {
return;
}
Cache.set("image_path_user_" + user.id,
photo.getFile.getAbsolutePath());
Cache.set("image_type_user_" + user.id,
photo.getType());
}
Then you'd still have to worry about appropriately populating/invalidating the cache in your add, update, and delete actions too. Otherwise your cache would be polluted with stale data.

Resources