Modeling circular dependencies while maintaining data integrity - java

I'm designing a music information system. I have a couple of entities that are connected to each other.
Below is part of the domain code.
class Album {
private Set<Track> tracks;
private boolean published;
public Set<Track> getTracks() {
return this.tracks;
}
public boolean isPublished() {
return this.published;
}
public void publish() {
System.out.println("Album.publish() called");
this.published = true;
this.tracks.forEach(track -> track.publish());
}
}
class Track {
private boolean published;
private Album album;
public boolean isPublished() {
return this.published;
}
public Album getAlbum() {
return this.album;
}
public void publish() {
// if track is single (this.album == null), set published to true
// if track is part of an album and the album is NOT published, return;
// if track is part of an album and the album is published, set published to true
if(this.album != null && !this.album.isPublished())
return;
this.published = true;
}
}
Track is an independent entity. It can be a single track (I.e. without an Album). So the album attribute is actually needed.
One domain rule is that when an album is archived (i.e. not published), its tracks cannot be published neither and if an album is published, any of its tracks can either be published or archived.
The problem is that when an album is published (e.g. album1.publish()), its tracks' publish() method is called as well. But track1.publish() checks if the album is published based on the copy it already has (which is not published).
How can I solve the problem?

If you split domain model entities by behaviour, you can get rid of described limitations
Let's have some interfaces for such entities:
interface AlbumId{
String asString();
AlbumId Absent = () -> "NO ALBUM AT ALL";
}
interface Publication{
void publish() throws Exception;
void archive() throws Exception;
boolean published();
}
interface Track{
TrackId id();
AlbumId albumId(); //smart type (as DDD suggest), therefore, no more nulls
}
Now you may enforce rules by creating class that will get you a list of tracks you can publish:
public class TracksReadyToPublishOf implements Supplier<Map<TrackId, TrackPublication>>{
//this class may access to cache and have dosens of other optimizations
public TracksReadyToPublishOf(AlbumId id){...}
#Override public get(){...}
}
Then you can reuse your code to check your rules anywhere:
public class TrackPublication implements Publication {
private final Track track;
private final Supplier<Map<TrackId, TrackPublication>> allowedTracks;
//easy for unit testing
public SmartTrackPublication(Track track, Supplier<Map<TrackId, TrackPublication>> allowedTracks){
this.track = track;
this.allowedTracks = allowedTracks;
}
public SmartTrackPublication(Track track){
this(track, new TracksReadyToPublishOf(track.albumId());
}
#Override
public publish() throws AlbumArchivedException{
if(this.albumId != AlbumId.Absent){
if(!this.allowedTracks.get().containsKey(this.track.id())){
throw new AlbumArchivedException();
}
}
this.allowedTracks.get().get(this.id()).publish();
}
}
And for album publishing:
public class AlbumPublication implements Publication{
private final AlbumId id;
private final Producer<Map<TrackId, TrackPublication>> tracks
private AlbumWithTracks(AlbumId id, Producer<Map<TrackId, TrackPublication>> tracks){
this.id = id;
this.tracks = tracks;
}
public AlbumWithTracks(AlbumId id){
this(id, new TracksReadyToPublishOf(id))
}
...
#Override publish() throws Exception{
//code for publishing album
for(TrackPublication t : Arrays.asList(
this.tracks.get()
)){
t.publish(); //track can publish anyway if it presents in list above
}
}
}

Related

How do I update a field in a room database using a repository & viewmodel

I created a room database following this guide from code labs It makes use of a repository to:
A Repository manages query threads and allows you to use multiple backends. In the most common example, the Repository implements the logic for deciding whether to fetch data from a network or use results cached in a local database.
I followed the guide and i'm now able to create the entity's & retrieve the data. I even went further and created another whole entity outside the scope of the guide.
However I can't find many resources that use this MVVM(?) style so am struggling as to really under stand the repository. For now I want to update a field. Just one, as if I am able to manage that the rest should be similar.
I want to update a field called dartshit and I have the dao method created for this:
#Query("UPDATE AtcUserStats SET dartsHit = :amount WHERE userName = :userName")
void UpdateHitAmount(int amount, String userName);
I have one repository which I assumed I use for all entities:
public class UsersRepository {
private UsersDao mUsersDao;
private AtcDao mAtcDao;
private LiveData<List<Users>> mAllUsers;
private LiveData<List<AtcUserStats>> mAllAtc;
private AtcUserStats mAtcUser;
UsersRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
mUsersDao = db.usersDao();
mAtcDao = db.atcDao();
mAllUsers = mUsersDao.fetchAllUsers();
mAllAtc = mAtcDao.getAllAtcStats();
}
LiveData<List<Users>> getAllUsers() {
return mAllUsers;
}
LiveData<List<AtcUserStats>> getAllAtcStats() {
return mAllAtc;
}
LiveData<AtcUserStats> getAtcUser(String username) {
return mAtcDao.findByName(username);
}
public void insert (Users user) {
new insertAsyncTask(mUsersDao).execute(user);
}
public void insertAtc (AtcUserStats atc) {
new insertAsyncAtcTask(mAtcDao).execute(atc);
}
private static class insertAsyncTask extends AsyncTask<Users, Void, Void> {
private UsersDao mAsyncTaskDao;
insertAsyncTask(UsersDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Void doInBackground(final Users... params) {
mAsyncTaskDao.insertNewUser(params[0]);
return null;
}
}
private static class insertAsyncAtcTask extends AsyncTask<AtcUserStats, Void, Void> {
private AtcDao mAsyncTaskDao;
insertAsyncAtcTask(AtcDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Void doInBackground(final AtcUserStats... params) {
mAsyncTaskDao.insertNewAtcUser(params[0]);
return null;
}
}
}
My question is how do I create a AsyncTask for the update query I am trying to run in this repository?
Here is what I have so far by broadly copying the insert repository methods:
private class updateHitAsyncTask {
private AtcDao mAsyncTaskDao;
public updateHitAsyncTask(AtcDao mAtcDao) {
mAsyncTaskDao = mAtcDao;
}
protected Void doInBackground(int amount, String name) {
mAsyncTaskDao.UpdateHitAmount(amount, name);
return null;
}
}
Which is incorrect is that I'm getting a llegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. error. But i thought this AsyncTask is suppose to take care of this?
Here is my update method in my view model, which is reporting 0 errors:
void updateHitAmount (int amount, String name) {
mRepository.updateAtcHits(amount, name);
}
and here is the UI code where im actually trying to tie all these together, I suspect there must be a better way that using onChanged for simply updating a field but again I am struggling to come across any advice on google with the repository approach:
private void callOnChanged() {
mAtcViewModel = ViewModelProviders.of(this).get(AtcViewModel.class);
mAtcViewModel.getAllUsers().observe(this, new Observer<List<AtcUserStats>>() {
#Override
public void onChanged(#Nullable final List<AtcUserStats> atc) {
// Update the cached copy of the users in the adapter.
for (int i = 0; i < atc.size(); i++) {
if (atc.get(i).getUserName().equals(mUser)) {
mAtcViewModel.updateHitAmount(55, mUser);
//atc.get(i).setDartsHit(55);
Log.d("id", String.valueOf(userSelected.getId()));
}
}
}
});
How can I update fields using this approach on the background thread?
Figured it out due to this answer here. It was mostly because of my lack of understanding of AsyncTask. Essentially I needed to create an object and pass the data that way and then execute in the background:
private static class MyTaskParams {
int amount;
String name;
MyTaskParams(int amount, String name) {
this.amount = amount;
this.name = name;
}
}
public void updateAtcHits (int amount, String name) {
MyTaskParams params = new MyTaskParams(amount,name);
new updateHitAsyncTask(mAtcDao).execute(params);
}
private class updateHitAsyncTask extends AsyncTask<MyTaskParams,Void,Void>{
private AtcDao mAsyncTaskDao;
public updateHitAsyncTask(AtcDao mAtcDao) {
mAsyncTaskDao = mAtcDao;
}
#Override
protected Void doInBackground(MyTaskParams... myTaskParams) {
int amount =myTaskParams[0].amount;
String name = myTaskParams[0].name;
mAsyncTaskDao.UpdateHitAmount(amount, name);
return null;
}
}

How to use Observable pattern with Firebase on Android

I am trying to implement a room booking system with an Observable design pattern using Firebase. I am pretty new to Observable pattern, but I have created the general files as such:
Subject.java
public interface Subject {
void Attach(Observer o);
void Detach(Observer o);
void refreshAccess();
}
Observer.java
public interface Observer {
void update(String newAuthorKey);
}
Booking.java
public class Booking implements Subject {
private String authorKey; //authorKey for the booking
private ArrayList<Observer> observers; //users registered for the room
public Booking(){
observers = new ArrayList<Observer>();
}
public void Attach(Observer o){
observers.add(o);
}
public void Detach(Observer o){
observers.remove(o);
}
public void refreshAccess(){
}
public void refreshAccess(String newAuthorKey){
this.authorKey = newAuthorKey;
this.NotifyObservers();
}
private void NotifyObservers(){
for (Observer o:observers)
o.update(this.authorKey);
}
}
User.java
public class User implements Observer {
private String authorKey;
private Subject subject;
public User(Subject subject){
this.subject = subject;
//register itself to the subject
this.subject.Attach(this);
}
#Override
public void update(String newAuthorKey){
//get update from subject
this.authorKey = newAuthorKey;
//do something according to the update
}
}
Essentially, the idea is that when a room is booked, a new Booking object gets initialised, and the user who books it (and any of the other user he chooses to share this booking with) gets added as users into this booking. How can I update this information into Firebase (I have set it up already in my application), and how can I get a list of all the Bookings that each user subscribed to? I have a fragment on my android app that handles all the event listeners, etc, but I have no idea how to link it up to these classes with Firebase at the moment.
Much appreciated! :)
The pattern Observable works with one or more Observer attached to one ore more Observable. Try this:
public class Booking extends Observable {
private String authorKey; //authorKey for the booking
// private ArrayList<Observer> observers; //users registered for the room (no need because Observable holds a list of Observer already)
public Booking(String authorKey){
this.authorKey = authorKey;
}
public void refreshAccess(){
nofityObservers(null);
}
public void refreshAccess(String newAuthorKey){
String oldAuthorKey = this.authorKey;
this.authorKey = newAuthorKey;
nofityObservers(oldAuthorKey);
}
#Override
public void notifyObservers(Object arg) {
setChanged();
super.notifyObservers(arg);
}
}
public class User implements java.util.Observer {
private ArrayList<String> authorKeys; // to get all bookings a user has
public User(){
}
public void addBooking(Booking b) {
b.addObserver(this);
}
#Override
public void update(Observable o, Object arg) {
if (!(o instanceof Booking ))
return;
Booking b = (Booking) o;
if(arg != null)
authorKeys.remove(arg);
authorKeys.add(b.getAuthorKey());
}
}
And somewhere in your system:
User u1 = new User();
User u2 = new User();
Booking b = new Booking(authorKey1);
b.addObserver(u1);
b.addObserver(u2);
b.refreshAccess(); // u1 and u2 get notified
b.deleteObserver(u2); // you might want to override this to notify user remove booking info
b.refreshAccess(authorKey2); // u1 get notified

Getter is not associated to any field - Realm

I am new to using Realm library and was trying to implement it in my android application. Just got stuck at a point where I am trying to section my listview based on the view type of a particular element in my json response.
I have tried to implement the sections with recycler view but the problem is I have 2 view types and addition of headers for those view types was causing an issue. Since Realm doesn't have the support of RecyclerAdapter, I created an implementation that will use a custom adapter that supports the RecyclerView.
So, I though I will use a ListView and try to use a simple interface for each of the Object type to determine the type and then insert the Headers based on the position of the group.
For some reason Realm is not allowing me to implement an interface in a class which extends RealmObject.
This is how that class looks like :
import com.google.gson.annotations.SerializedName;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
import io.realm.annotations.PrimaryKey;
public class TestClass extends RealmObject implements Subjects {
#PrimaryKey
#SerializedName("subjectID")
private String subjectID;
private String subjectDate;
#SerializedName("subjectDescription")
private String subjectDescription;
public String getSubjectID() {
return subjectID;
}
public void setSubjectID(String subjectID) {
this.subjectID = subjectID;
}
public String getSubjectDate() {
return subjectDate;
}
public void setSubjectDate(String subjectDate) {
this.subjectDate = subjectDate;
}
public String getSubjectDescription() {
return subjectDescription;
}
public void setSubjectDescription(String subjectDescription) {
this.subjectDescription = subjectDescription;
}
#Override
public boolean isSubjectA() {
return true;
}
#Override
public boolean isFoo() {
return false;
}
#Override
public boolean isBar() {
return false;
}
}
And this is the Compilation Error log :
Error:(76, 20) error: Getter isSubject is not associated to any field.
Note: Creating DefaultRealmModule
Warning:File for type 'io.realm.DefaultRealmModule' created in the last round will not be subject to annotation processing.
Warning:File for type 'io.realm.DefaultRealmModuleMediator' created in the last round will not be subject to annotation processing.
2 warnings
I have no idea why is complaining about this issue but its not compiling the project.
I read a few discussion about the issue here : link .. Apparently, there's an open discussion about this issue but any other help will be really appreciated.. Thank you
You have an typo in your field's name, also it shouldn't have prefix, so it would be "subject", and getter must be isSubject()
#Ignore
private boolean subject = false;
public boolean isSubject() {
return subject;
}
.

RequestFactoryEditorDriver doesn't save full graph even though "with()" is called. Is circular reference an issue?

Could you guys please help me find where I made a mistake ?
I switched from SimpleBeanEditorDriver to RequestFactoryEditorDriver and my code no longer saves full graph even though with() method is called. But it correctly loads full graph in the constructor.
Could it be caused by circular reference between OrganizationProxy and PersonProxy ? I don't know what else to think :( It worked with SimpleBeanEditorDriver though.
Below is my client code. Let me know if you want me to add sources of proxies to this question (or you can see them here).
public class NewOrderView extends Composite
{
interface Binder extends UiBinder<Widget, NewOrderView> {}
private static Binder uiBinder = GWT.create(Binder.class);
interface Driver extends RequestFactoryEditorDriver<OrganizationProxy, OrganizationEditor> {}
Driver driver = GWT.create(Driver.class);
#UiField
Button save;
#UiField
OrganizationEditor orgEditor;
AdminRequestFactory requestFactory;
AdminRequestFactory.OrderRequestContext requestContext;
OrganizationProxy organization;
public NewOrderView()
{
initWidget(uiBinder.createAndBindUi(this));
requestFactory = createFactory();
requestContext = requestFactory.contextOrder();
driver.initialize(requestFactory, orgEditor);
String[] paths = driver.getPaths();
createFactory().contextOrder().findOrganizationById(1).with(paths).fire(new Receiver<OrganizationProxy>()
{
#Override
public void onSuccess(OrganizationProxy response)
{
if (response == null)
{
organization = requestContext.create(OrganizationProxy.class);
organization.setContactPerson(requestContext.create(PersonProxy.class));
} else
organization = requestContext.edit(response);
driver.edit(organization, requestContext);
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
private static AdminRequestFactory createFactory()
{
AdminRequestFactory factory = GWT.create(AdminRequestFactory.class);
factory.initialize(new SimpleEventBus());
return factory;
}
#UiHandler("save")
void buttonClick(ClickEvent e)
{
e.stopPropagation();
save.setEnabled(false);
try
{
AdminRequestFactory.OrderRequestContext ctx = (AdminRequestFactory.OrderRequestContext) driver.flush();
if (!driver.hasErrors())
{
// Link to each other
PersonProxy contactPerson = organization.getContactPerson();
contactPerson.setOrganization(organization);
String[] paths = driver.getPaths();
ctx.saveOrganization(organization).with(paths).fire(new Receiver<Void>()
{
#Override
public void onSuccess(Void arg0)
{
createConfirmationDialogBox("Saved!").center();
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
} finally
{
save.setEnabled(true);
}
}
}
with() is only used for retrieval of information, so your with() use with a void return type is useless (but harmless).
Whether a full graph is persisted is entirely up to your server-side code, which is intimately bound to your persistence API (JPA, JDO, etc.)
First, check that the Organization object you receive in your save() method on the server-side is correctly populated. If it's not the case, check your Locators (and/or static findXxx methods) ; otherwise, check your save() method's code.
Judging from the code above, I can't see a reason why it wouldn't work.
It took me some time to realize that the problem was the composite id of Person entity.
Below is the code snippet of PojoLocator that is used by my proxy entities.
public class PojoLocator extends Locator<DatastoreObject, Long>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, Long id)
{
}
#Override
public Long getId(DatastoreObject domainObject)
{
}
}
In order to fetch child entity from DataStore you need to have id of a parent class. In order to achieve that I switched "ID class" for Locator<> to String which represents textual form of Objectify's Key<> class.
Here is how to looks now:
public class PojoLocator extends Locator<DatastoreObject, String>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, String id)
{
Key<DatastoreObject> key = Key.create(id);
return ofy.load(key);
}
#Override
public String getId(DatastoreObject domainObject)
{
if (domainObject.getId() != null)
{
Key<DatastoreObject> key = ofy.fact().getKey(domainObject);
return key.getString();
} else
return null;
}
}
Please note that your implementation may slightly differ because I'm using Objectify4.

Designing a service interface to allow both synchronous and asynchronous implementations

Not sure how to describe this for sure, but I think I've boiled down what I want to do in the title. To elaborate, I'm looking for a design pattern that would let me have a implementation of a service that would in one situation return the result of a call synchronously but in another case return details on how to complete the call asynchronously (say a job ID).
Maybe just by defining the problem like that it's clear that what I'm trying to do breaks the idea of designing an interface contract. Could be headed in the wrong direction entirely.
What I was thinking of was possibly something like this:
public class Data {
private int id;
/* getter/setter */
}
public class QueuedData extends Data {
private int jobId;
/* getter/setter */
}
public interface MyService {
public Data fetchData(int id);
}
public class SyncedMyService implements MyService {
private SyncDao syncDao;
public Data fetchData(int id) {
return syncDao.getData(id);
}
}
public class QueuedMyService implements MyService {
private JobQueue queue;
public QueuedData fetchData(int id) {
int jobId = queue.startGetData(id);
QueuedData queuedData = createQueuedDate(jobId);
return queuedData;
}
}
Is this a sensible way to go about this task? Thanks for any advice. (there's probably a design-pattern book I should be reading)
This is very similar to the Future pattern used in the java.util.concurrent package. A Future represents a result that will be available in the future after the computation is completed in a separate thread. If the computation is already complete before the result is required, the computed value is returned. Else the call to get the result blocks till the computation is over.
So I think this pattern is the right way to go about having both synchronous and asynchronous services.
This is how you can implement the solution using Future:
public class Data {
private int id;
private final String name;
Data(String name) { this.name = name; }
public String getName() { return name; }
}
public class FutureData extends Data {
private int id;
private final Future<String> nameFuture;
FutureData(Future<String> nameFuture) { this.nameFuture = nameFuture; }
#Override public String getName() { return nameFuture.get(); }
}
public interface MyService {
public Data fetchData(int id);
}
public class SyncMyService implements MyService {
private SyncDao syncDao;
public Data fetchData(int id) {
return syncDao.getData(id);
}
}
public class AsyncMyService implements MyService {
private static final ExecutorService executor =
Executors.newFixedThreadPool(10);
public FutureData fetchData(final int id) {
Future<String> future = executor.submit(new Callable<String>() {
public String call() {
String name;
//some long computation that computes the name using the id given
return name;
}
});
FutureData futureData = new FutureData(future);
return futureData;
}
}
For Quartz just replace the ExecutorService with the JobQueue and use Quartz's equivalent of Future.
This is a fine use of Inheritance. Your SynchedMyService and QueuedMyService are following the contract/rules designated by MyService.
Also by having the fetchData() method return a type Data, you are allowing yourself the ability to build on top of the Data object and return more complex objects (like QueuedData)
If you don't want to have the logic of which of the classes to instantiate each time. Look at the Factory design pattern to assist you as you continue to grow your application

Categories

Resources