Allow the database to auto-generate the primary key (id). On creating a residence in the remote database, echo back the new record to inform the client of the id value. We demonstrate using a Play service, a JUnit test app and the MyRent Android client.
Hint: when myrent service and test downloaded ensure you run play eclipsify in a terminal in the project root folders before importing to Eclipse.
Download these three applications.
MyRent-16 is an Android client. It has been refactored to consume an API from a database in which the primary key (id) is a Long type and is auto-generated at the server side.
This differs from previous MyRent version(s) where the id has been generated client-side.
The purpose of the lab is to assist in adapting your Twitter clone for use with MongoDB.
This is a Play app. It ships with a data.yml file. If you wish to make use of this it will be necessary to remove the comments in Bootstrap.java.
Once downloaded change into its folder and run
play run
If you wish to view the code in Eclipse then first run:
play eclipsify
Download the app and import into Eclipse, first running play eclipsify.
Import the project into Eclipse.
Clean the project.
If there are any errors it may be necessary to import JUnit library.
Test as follows:
The test should pass, indicated by a green progress bar.
In the following steps we shall identify the key changes made to the tester and the Android client to accommodate communicating with a database (where the id is auto-generated on the server).
This is the new model class:
package app.models;
import java.util.Date;
import java.util.Random;
import com.google.common.base.Objects;
public class Residence
{
public Long id;
public String geolocation;
public Long date;
public boolean rented;
public String tenant;
public double zoom;
public String photo;
public Residence()
{
date = new Date().getTime();
geolocation = "";
date = 0L;
rented = false;
zoom = 0;
photo = "";
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof Residence) {
final Residence other = (Residence) obj;
return Objects.equal(id, other.id)
&& Objects.equal(geolocation, other.geolocation)
&& Objects.equal(date, other.date)
&& Objects.equal(rented, other.rented)
&& Objects.equal(tenant, other.tenant)
&& Objects.equal(zoom, other.zoom)
&& Objects.equal(photo, other.photo);
}
return false;
}
}
Note the following:
The id is declared but no longer explicitly initialized. Previously we generated a random long value and assigned it to the id.
We still use the id field in the equals method when comparing two Residence objects.
In ResidenceTest.setup we initialize the residence id values with values obtained from the server.
/**
* Set up for test.
* Write (create) an array of residences on server.
* Server echoes back each individual residence as it is created.
* The server model generates the residence id.
* Obtain this from the reflected back residence and apply
* to ResidenceTest.residences fields.
*
* @throws Exception
*/
@Before
public void setup() throws Exception {
for (int i = 0; i < NUMBER_RESIDENCES; i += 1) {
Residence res = service.createResidence(residences[i]);
residences[i].id = res.id;
}
}
In ResidenceListFragment, before refactoring we have:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_residence:
Residence residence = new Residence();
portfolio.addResidence(residence);
Intent i = new Intent(getActivity(), ResidencePagerActivity.class);
i.putExtra(ResidenceFragment.EXTRA_RESIDENCE_ID, residence.id);
startActivityForResult(i, 0);
return true;
This method remains unchanged. We provide it here to supply context:
public void createResidence(Residence res) {
Call<Residence> call = app.residenceService.createResidence(res);
call.enqueue(this);
}
The default Residence constructor generates a residence id.
We now require to obtain this id from the server. To achieve this we do the following:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_residence:
Residence residence = new Residence();
createResidence(residence);
return true;
@Override
public void onResponse(Response<Residence> response, Retrofit retrofit) {
Residence res = response.body();
if (res != null) {
Toast.makeText(getActivity(), "Residence created successfully", Toast.LENGTH_SHORT).show();
portfolio.addResidence(res);
Intent i = new Intent(getActivity(), ResidencePagerActivity.class);
i.putExtra(ResidenceFragment.EXTRA_RESIDENCE_ID, res.id);
startActivityForResult(i, 0);
}
else {
Toast.makeText(getActivity(), "Residence null returned due to incorrectly configured client", Toast.LENGTH_SHORT).show();
}
}
This is what existed prior to refactoring:
@Override
public void onResponse(Response<Residence> response, Retrofit retrofit) {
Residence res = response.body();
if (res != null) {
Toast.makeText(getActivity(), "Residence created successfully", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getActivity(), "Residence null returned due to incorrectly configured client", Toast.LENGTH_SHORT).show();
}
}
Observe what we have done. How the block of code shown in Figure 1 has been moved from the UI to a worker thread:
Test as follows:
This is a snippet from the myrent-service-2016 ResidenceAPI. It demonstrates how an id is generated and used to initialize the Residence object being written to the database. The residence object containing this newly generated id is then echoed back to the caller.
/**
*
* @param id
* @param body
*/
public static void createResidence(JsonElement body) {
Residence residence = gson.fromJson(body.toString(), Residence.class);
Residence res = new Residence();
residence.id = res.id;
residence.save();
renderJSON(gson.toJson(residence));
}