1

I'm developing a GAE/J app using JDO to manage the Datastore. It offers a number of Endpoints to interact with the data and so on. I'm also developing a Javascript client for those endpoints.

Situation:

First I have an endpoint method Token getSessionToken(User usr), which generates a session token, assigns it to the user and stores both user and session token in the Datastore.

Then I have another endpoint method Info getInfo(Token token) which receives a session token, checks if that session token corresponds to an user and if so, returns some info.

Problem

From my Javascript client, I call the first method and everything is fine. Then I call the second method with the previously retreved session token, and I receive an error saying that the session token doesn't correspond to any user...

I've checked and I realised that this error happens just because the new session token has not been persisted yet!

Question

My current solution is to make the Javascript client call the second method once, and if it receives an error, wait a while and call again... is there a better solution?


EDIT:

This is the code invloved in the first method call to get an idea about why it takes so long...

Endpoint:

@ApiMethod(
    name = "getSessionToken",
    path = "get_session_token",
    httpMethod = HttpMethod.GET
)
public SessionToken getSessionToken (@Named("email") String email, @Named("password") String password) 
        throws InternalServerErrorException {       
    SessionToken sessionToken = new UsersController().getSessionToken(email, password);
    return sessionToken;
}

Control:

public SessionToken getSessionToken(String email, String password) throws InternalServerErrorException {        
    SessionToken sessionToken = null;
    
    PersistenceManager pm = PMF.get().getPersistenceManager();      
    Transaction txn = DatastoreServiceFactory.getDatastoreService().beginTransaction();
    try {
        DAO dao = new DAO(pm);
        
        User user = dao.getUserByLogin(email, password);
        
        dao.deleteSessionToken(user.getSessionToken());
        sessionToken = SessionTokenManager.generateToken(user.getEmail(), user.getPassword());
        user.setSessionToken(sessionToken);
        
        user = dao.insertUser(user);    
    
        txn.commit();   
    
    } catch (Exception e) {
        throw new InternalServerErrorException();
    } finally {
        if (txn.isActive()) {
            txn.rollback();
        }
        pm.close();
    }       
    return sessionToken;
}

DAO:

public User getUserByLogin(String email, String password) throws InternalServerErrorException {
    User user = null;
    Query query = null;
    try {
        query = this.pm.newQuery(User.class);
        query.setFilter("email == emailParam && password == passwordParam");
        query.declareParameters("String emailParam, String passwordParam");     
        List<User> results = (List<User>) query.execute(email, password);
        user = results.get(0);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.getUserByLogin()");
    } finally {
        query.closeAll();
    }
    return user;
}

/////

public void deleteSessionToken(SessionToken sessionToken) throws InternalServerErrorException {
    try {
        this.pm.deletePersistent(sessionToken);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.deleteSessionToken()");
    }
}

/////

public User insertUser(User user) throws InternalServerErrorException {     
    try {
        this.pm.makePersistent(user);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.insertUser()", e);
    }                
    return user;
}

Model:

@PersistenceCapable
public class User { 
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;    
    @Persistent
    private String name;
    @Persistent
    private String email;
    @Persistent
    private String password;    
    @Persistent
    private Folder rootFolder;  
    @Persistent
    private SessionToken sessionToken;  
    @Persistent(defaultFetchGroup = "true")
    private AccountContainer accountContainer;
    //getters & setters
}

/////

@PersistenceCapable
public class SessionToken {         
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;
    @Persistent
    private String token;
    @Persistent
    private Long created;
    @Persistent
    private String sha1;
    //getters & setters
}
4

1 回答 1

0

也许以下之一是可能的并且适合您的需求

  • 你可以将这两个调用组合成一个“getSessionTokenAndInfo”调用吗?您将令牌和信息一起返回的位置。根据您的代码的工作方式,令牌和用户对象可能已经可用并且不需要加载?

  • 使用某种形式的缓存,以便第一个端点在 memcache 中留下一些东西,这样就不需要在第二次调用中尝试从数据存储中检索它(至少在大多数情况下,memcache 对于这种情况应该足够可靠)。

于 2013-05-08T13:42:21.523 回答