app s~YYY cannot access app YYY’s data

GAE (Google App Engine) allows you to use an ORM library to map your noSQL data. In my test I’ve used JPA v.1.
To expose data I’ve implemented a REST API using Jersey. In this short article I don’t want to explain how to implement the complete application but how to solve the following Error

java.lang.IllegalArgumentException: app s~<yourappname> cannot access app <yourappname>'s data
	at com.google.appengine.api.datastore.DatastoreApiHelper.translateError(DatastoreApiHelper.java:36)
	at com.google.appengine.api.datastore.DatastoreApiHelper$1.convertException(DatastoreApiHelper.java:76)
	at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:106)
	at com.google.appengine.api.datastore.FutureHelper$CumulativeAggregateFuture.get(FutureHelper.java:145)
	at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:90)
	at com.google.appengine.api.datastore.FutureHelper.getInternal(FutureHelper.java:72)
	at com.google.appengine.api.datastore.FutureHelper.quietGet(FutureHelper.java:33)
	at com.google.appengine.api.datastore.DatastoreServiceImpl$2.runInternal(DatastoreServiceImpl.java:113)
	at com.google.appengine.api.datastore.DatastoreServiceImpl$2.runInternal(DatastoreServiceImpl.java:110)
	at com.google.appengine.api.datastore.TransactionRunner.runInTransaction(TransactionRunner.java:31)
	at com.google.appengine.api.datastore.DatastoreServiceImpl.put(DatastoreServiceImpl.java:110)
<continued in next message>

This Error occurs only when you use the application on GAE and not when you debug locally.

In my experience the error is related to the Entity Key.

If you try to create a new Entity forcing the Key you have this error. Why you may incur in this? Because you are copy another Entity! So remember to clear the Entity Key in the copy constructor.

Another way to face this problem is using REST: if you are creating a new Entity and in the JSON posted you force the Key GAE log this error.

This is the example. The Entity

public interface BasicEntity<T> {
	public void createVersion();
	public void updateVersion(T old);
	public boolean isRemoved();
	public String getUUID();
}

@Entity
public class Utente implements Serializable, BasicEntity<Utente> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6565127229887272677L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@JsonIgnore
	private Key key;

	public Key getKey() {
		return key;
	}

	public void setKey(Key key) {
		this.key = key;
	}

	// server
	@Transient
	@JsonProperty("uuid")
	private String UUID;

	public String getUUID() {
		UUID = KeyFactory.keyToString(key);
		return UUID;
	}

	public void setUUID(String UUID) {
		this.UUID = UUID;
		key = KeyFactory.stringToKey(UUID);
	}

	// vecchio id
	private String id;
	// id generato dal client
	private String clientUUID;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getClientUUID() {
		return clientUUID;
	}

	public void setClientUUID(String clientUUID) {
		this.clientUUID = clientUUID;
	}

	@Basic
	private Long versione;

	// fields

	@Basic
	private String email;

	@Basic
	@JsonIgnore
	private String encryptedPwd;

	@Basic
	private String nome;

	@Basic
	private String azienda;

	@Basic
	private Boolean abilitato;

	public String getEmail() {
		return email;
	}

	public void setEmail(String eMail) {
		this.email = eMail;
	}

	public String getEncryptedPwd() {
		return encryptedPwd;
	}

	public void setEncryptedPwd(String encryptedPwd) {
		this.encryptedPwd = encryptedPwd;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getAzienda() {
		return azienda;
	}

	public void setAzienda(String azienda) {
		this.azienda = azienda;
	}

	public Boolean getAbilitato() {
		return abilitato;
	}

	public void setAbilitato(Boolean abilitato) {
		this.abilitato = abilitato;
	}

	@Override
	public void updateVersion(Utente old) {
		// TODO Auto-generated method stub

	}

	@Override
	public void createVersion() {
		// TODO Auto-generated method stub

	}

	public Long getVersione() {
		return versione;
	}

	public void setVersione(Long versione) {
		this.versione = versione;
	}

	private boolean removed;

	@Override
	public boolean isRemoved() {
		return removed;
	}

	public void setRemoved(boolean removed) {
		this.removed = removed;
	}

}

DAO

public abstract class BasicDAO<T extends BasicEntity<T>> {

	private EntityManager em;

	protected abstract String getClassName();

	protected abstract Class<?> getClassType();

	public BasicDAO() {
		startTransaction();
	}

	public void startTransaction() {
		setEm(EMF.get().createEntityManager());
	}

	public void endTransaction() {
		getEm().close();
	}

	public EntityManager getEm() {
		return em;
	}

	public void setEm(EntityManager em) {
		this.em = em;
	}

	@SuppressWarnings("unchecked")
	protected T get(String id) {
		return (T) getEm().find(getClassType(), id);
	}

	protected T insert(T myObject) {
		myObject.createVersion();
		getEm().persist(myObject);
		getEm().refresh(myObject); 
		return myObject;
	}

	protected T update(T myObject, String uuid) {
		if (myObject.getUUID() != null && myObject.getUUID().equalsIgnoreCase(uuid)) {
			T old = get(uuid);
			if (old != null) {
				myObject.updateVersion(old);
				getEm().persist(myObject);
				getEm().refresh(myObject); 
			}
			return myObject;
		}
		return null;
	}

	protected boolean delete(String id) {
		boolean ok = false;
		Object myObject = get(id);
		if (myObject != null) {
			getEm().remove(myObject);
			ok = true;
		}
		return ok;
	}

	protected abstract T reattach(T myObject);

	@SuppressWarnings("unchecked")
	protected List<T> gets() {
		return (List<T>) getEm().createQuery("Select from " + getClassName())
				.getResultList();
	}

}

public class UtenteDAO extends BasicDAO<Utente> {

	public Utente getUtente(String id) {
		return get(id);
	}

	public void insertUtente(Utente utente) {
		insert(utente);
	}
	
	public void updateUtente(Utente utente, String id) {
		updateUtente(utente, id);
	}

	public List<Utente> getUtenti() {
		return gets();
	}

	@Override
	protected String getClassName() {
		return "Utente";
	}

	@Override
	protected Class<?> getClassType() {
		return Utente.class;
	}

	@Override
	protected Utente reattach(Utente myObject) {
		// TODO Auto-generated method stub
		return null;
	}

}

Jersey REST mapping

@Produces(MediaType.APPLICATION_JSON)
@Path("/utenti")
public class UtenteResource {
	
	@GET
	@Path("/")
	public List<Utente> getUtentu() {
		UtenteDAO dao = new UtenteDAO();
		return dao.getUtenti();
	}

	@GET
	@Path("/{id}")
	public Utente getPraticaById(@PathParam("id") String id) {
		UtenteDAO dao = new UtenteDAO();
		return dao.getUtente(id);
	}
	
	
	@POST
	@Path("/{id}")
	@Consumes(MediaType.APPLICATION_JSON)
	public void updateUtente(@Context HttpServletRequest Req, Utente utente, @PathParam("id") String id) {
		UtenteDAO dao = new UtenteDAO();
		dao.updateUtente(utente, id);
	}
	
	@POST
	@Path("/new")
	@Consumes(MediaType.APPLICATION_JSON)
	public void insertUtente(@Context HttpServletRequest Req, Utente utente) {
		UtenteDAO dao = new UtenteDAO();
		dao.insertUtente(utente);
	}

}

The JSON posted that give you the error
curl -H “Content-Type: application/json” -X POST –data @jsontest/new_user.json http://localhost:8888/rest/utenti/new

{
	"uuid": "agxpbGVnYWxlY2xvdWRyGwsSB1ByYXRpY2EYlAIMCxIGVXRlbnRlGJYCDA",
	"id": null,
	"clientUUID": null,
	"versione": null,
	"email": "giulio.roggero@gmail.com",
	"encryptedPwd": "adskasdhkasjhjakshd832329y",
	"nome": "Giulio Roggero",
	"azienda": "Isola Software",
	"abilitato": true
}

remove uuid and you can create a new user

{
	"id": null,
	"clientUUID": null,
	"versione": null,
	"email": "giulio.roggero@gmail.com",
	"encryptedPwd": "adskasdhkasjhjakshd832329y",
	"nome": "Giulio Roggero",
	"azienda": "Isola Software",
	"abilitato": true
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s