How Can I make This Algorithm Generic? - java

I am working on an object cache of CMS objects. I need to maintain a parent/child relationship between a Product and child objects (Options and Attributes). The parent (Product) is illustrated in the first code sample.
It is easy enough to do, but I am looking for a way to make the assignment of the child to the parent, as shown in the 2nd code block, generic.
Since all CMS objects extend CMSContent, I can use ProductID. However, is there a way to make the field (e.g. ProductAttribute) generic so that I can put the algorithm in a method and call the method with a parent and child object to make the attribute assignment?
I know that an ORM framework like Hibernate is appropriate here, but that won't fit since I have a fixed database structure.
public class Product extends CMSContent {
private List<ProductAttribute> productAttributes;
private List<ProductOptions> productOptions;
// getters,setters
}
Algorithm to match them up.
// attach Product Attributes to Product
for (Product p : listP) {
Map<String, Object> parameters = new HashMap<String, Object>();
for (ProductAttribute po : listPA) {
parameters.put("pid", p.getPid());
parameters.put("ref", po.getRid());
int i = jdbcTemplate.queryForInt(sqlAttr, parameters); // select count(*), 1 if matched.
if (i == 1) {
p.getProductAttributes().add(po); // generic field?
}
}
}

Wouldn't this two Methods in Product help
public void add(ProductAttribute item){
productAttributes.add(item);
}
public void add(ProductOption item){
productOption.add(item);
}
so you should be able to just add a ProductAttribute or a ProductOption

Related

How can I create row and children related by ForeignKey with RoomDB in a clean way?

This question is somehow related to my last question, because it is the same project but now I am trying to go one more step forward.
So, in my previous question I only had one table; this time I have two tables: the new second table is supposed to contain related attributes for the rows of the first table, in a OneToMany relationship. So, I store a ForeignKey in the second table that would store the Row ID of the first table's related row (obviously).
The problem is this: the intention is creating both registers (parent and child) at the same time, using the same form, and ParentTable uses AUTO_INCREMENT for his PrimaryKey (AKA ID).
Due to how RoomDb works, I do the creation using a POJO: but after insertion, this POJO won't give me the auto-generated ID as far as I know... so, the only workaround I am able to imagine is, when submitting the form, first make the INSERT for the parent, then using one of the form's fields that created the parent to make some kind of "SELECT * FROM parent_table WHERE field1 LIKE :field1", retrieving the ID, and then use that ID to create the child table's POJO and perform the next INSERT operation. However I feel something's not right about this approach, the last time I implemented something similar this way I ended up with a lot of Custom Listeners and a callback hell (I still have nightmares about that).
About the Custom Listeners thing, it is the solution I ended up choosing for a different problem for a different project (more details about it in this old question). Taking a look to that old question might help adding some context about how misguided I am in MVVM's architecture. However, please notice the current question has nothing to do with WebServices, because the Database is purely local in the phone's app, no external sources.
However, I am wondering: isn't this overkill (I mean the INSERT parent -> SELECT parentID -> INSERT child thing)? Is it inevitable having to do it this way, or there is rather a more clean way to do so?
The "create method" in my Repository class looks like this:
public void insertParent(Parent parent) {
new InsertParentAsyncTask(parent_dao).execute(parent);
}
private static class InsertParentAsyncTask extends AsyncTask<Parent, Void, Void> {
private final ParentDao parent_dao;
private InsertParentAsyncTask(ParentDao parent_dao) {
this.parent_dao = parent_dao;
}
#Override
protected Void doInBackground(Parent... parents) {
parent_dao.insert(parents[0]);
return null;
}
}
Trying to follow Mario's answer, I changed this method in my parent's DAO:
// OLD
#Insert
void insert(Parent parent);
// NEW (yes, I use short type for parent's ID)
#Insert
short insert(Parent parent);
EDIT2:
Now, I am trying to make changes to my Repository's insert AsyncTask, like this:
private static class InsertParentAsyncTask extends AsyncTask<Parent, Void, Short> {
private final ParentDao parent_dao;
private InsertParentAsyncTask(ParentDao parent_dao) {
this.parent_dao = parent_dao;
}
#Override
protected Short doInBackground(Parent... parents) {
short parent_id;
parent_id = parent_dao.insert(parents[0]);
return parent_id;
}
#Override
protected void onPostExecute(Short hanzi_id) {
// TODO ??? What now?
}
}
LONG STORY SHORT
It worked for me this way down here, but this ain't clean code (obviously):
// TODO I am aware that AsyncTask is deprecated
// My Repository class uses this
public void insertParentAndChildren(Parent parent, String[] children_list) {
new InsertParentAndChildrenAsyncTask(parent_dao, children_list).execute(parent);
}
private static class InsertParentAndChildrenAsyncTask extends AsyncTask<Parent, Void, Short> {
private final ParentDao parent_dao;
private String[] children_list;
private InsertParentAndChildrenAsyncTask(ParentDao parent_dao, String[] children_list) {
this.parent_dao = parent_dao;
this.children_list = children_list;
}
#Override
protected Short doInBackground(Parent... parents) {
short parent_id;
Long row_id = parent_dao.insert(parents[0]);
parent_id = parent_dao.getIdForRowId(row_id);
return parent_id;
}
#Override
protected void onPostExecute(Short parent_id) {
// Second "create method" for children
for (int n = 0; n < children_list.length; n++) {
Child child = new Child();
child.setParentId( parent_id );
child.setMeaning( children_list[n] );
// My Repository has this method as well
insertChildStaticMethod(child);
}
}
}
You are on the right track. A clean way would be to wrap it in a function like this:
fun saveParent(parent: Parent): Int {
val rowId = parentDao.insert(parent) // Returns Long rowId
val parentId = parentDao.getIdForRowId(rowId) // SELECT id FROM table_parent WHERE rowid = :rowId
return parentId
}
This function could be part of a repository class to make it even more clean.
Your functions in DAO can return the rowId and Parent.ID like this:
#Insert
fun insert(parent: Parent): Long
#Query("SELECT ID FROM table_parent WHERE rowid = :rowId")
fun getIdForRowId(rowId: Long): short
If you want to get basic functionality working first, you can call the Room database functions on the main thread when you build your database with allowMainThreadQueries():
MyApp.database = Room.databaseBuilder(this, AppDatabase::class.java, "MyDatabase").allowMainThreadQueries().build()
Like this, you can postpone background processing to later. If you have specific questions about that subject, it is better to ask a separate question.
I think you could try SELECT last_insert_rowid() as a query on room (you write it just like that no need to reference any table). This statement returns the rowid of the last insertion into your database. By default rowId is what most sql DBs use as primary keys when you define them as auto incremental integers. so I guess you would define the following method in your DAO
#Query("SELECT last_insert_rowid()")
public abstract int getLastId()
#Insert
void insert(Parent parent)
then you can use it together with your insert statement in a transaction. like so
#Transaction
public int insertAndGetPrimaryKey(Parent parent){
insert(parent);
return getLastId();
}
it is important to use transaction as else the id delivered could be the wrong one if in your app multiple threads could potentially modify the tables at the same time.
btw I would not use short for a primary key. not only is it short XD (only 32k capacity) but the satndard is really to use Integer (4 bn capacity). if these were the 80's id be all for it (those are 2 entire bytes that you are saving after all XD) but now a days memory is cheap and abundant and as i said integer is what DBs work with by default.

Design pattern for API with type identifier that determines what downstream services to call

I have an endpoint, let's call it "GetPersonInfo". GetPersonInfo is given a few parameters but one of them is "PersonType". Based on this PersonType, multiple downstream services are called. Some of these services could be shared between PersonType's but that is not a guarantee.
For example GetPersonInfo(...) #1:
PersonType = "Adult"
When GetPersonInfo is called for Adult, the API endpoint would need to make two downstream calls and populate the payload model with results:
"GetPersonName()" and "GetFavoriteAlcoholicBeverage()"
For example GetPersonInfo(...) #2:
PersonType = "Child"
When GetPersonInfo is called for Child, the api endpoint would need to make two downstream calls and populate the payload model with results:
"GetPersonName()" and "GetFavoriteToy()"
For example GetPersonInfo(...) #3:
PersonType = "NamelessPerson"
When GetPersonInfo is called for NamelessPerson, the api endpoint would need to make one downstream call:
"GetPersonIdNumber()"
Each of these calls would be populating the same model PersonInfo but all of the fields are nullable in case the downstream call wasn't required for that person type.
Is there a pattern where I can achieve this without duplicating the common downstream calls in every single logic implementation for getting the person info by PersonType.
Below is the initial call
public PersonInfo getPersonInfo(int id, PersonType personType) {
// logic here based on personType to call necessary downstreams and populate person info model
}
Well, the poor man's approach would be an if-cascade. :-)
But thinking in design patterns, this looks clearly like a strategy pattern. Each of your downstreams would define a stragegy, and each PersonType would trigger one or more strategies. We will talk about this many-to-many relationship later on.
Let's start with a strategy interface...
public interface PersonStrategy {
void enrichPerson(String id, PersonInfo result);
}
... and let's have some downstreams implemented as strategies:
public class DefaultStrategy implements PersonStrategy {
#Override
public void enrichPerson(String id, PersonInfo result) {
// fetch basic person data ...
}
}
public class FavoriteToyStrategy implements PersonStrategy {
#Override
public void enrichPerson(String id, PersonInfo result) {
// fetch toys ...
}
}
public class FavoriteAlcoholicBeverageStrategy implements PersonStrategy {
#Override
public void enrichPerson(String id, PersonInfo result) {
// fetch beverages ...
}
}
Once this is provided, your initial method would look like this:
private final Map<PersonType, List<PersonStrategy>> strategies = new LinkedHashMap<>();
public PersonInfo getPersonInfo(String id, PersonType type) {
final PersonInfo result = new PersonInfo();
strategies.get(type).forEach(strategy -> strategy.enrichPerson(id, result));
return result;
}
As you see, I implemented the many-to-many dependency in a multi-value map with the type as key. It's not yet populated, I think you can imagine how it works.
Other possibilities:
have a factory that returns the strategies belonging to a specific
type.
have each strategy decide if it reacts to a given type or
provide a list of types that it belongs to.
As you see: not a single if statement is needed here.

How to name a composite class like this?

Our team are using Spring Boot 2 with sql2o as db library. In the paste in our services, for trivial methods, we simply call the repository and returns the model. For example, if I have a Supplier table, I had in the service
#Override
public List<Supplier> findAll() {
return supplierRepository.findAll();
}
Now, since in our controllers we need 99% in the cases other objects correlated to the model, I would create a composite class that holds the model and other models. For example:
#Override
public List<UnknownName> findAll() {
List<Supplier> suppliers = supplierRepository.findAll();
List<UnknownName> res = new ArrayList<>();
UnknownName unknownName;
LegalOffice legalOffice;
if (suppliers != null) {
for (Supplier supplier in suppliers) {
unknownName = new UnknownName();
unknownName.setSupplier(supplier);
legalOffice = legalOfficeService.findByIdlegaloffice(supplier.getLegalofficeid);
unknownName.setLegalOffice(legalOffice);
res.add(unknownName);
}
}
return res;
}
What should the name of class UnknownName?
PS: I simplified the code for better redability, but I use a generic enrich() function that I call for all the find methods, so I don't have to dupe the code.
I would recommend SupplierDto or SupplierLegalOfficeDto. DTO stands for Data Transfer Objects and it's commonly used for enriched models (more here).
Also you shouldn't check suppliers for null as repository always returns a non-null list.
In the end, I adopted the suffix Aggregator, following the Domain-driven design wording.

ISIS: Moving from deprecated #Action(invokeOn=...) to #Action(associateWith=...)

I am working on a project using ISIS 1.16.2. I have a superclass, called ConfigurationItem, which has some common properties (name, createdTimestamp etc.).
For example it has a delete action method, annotated with #Action(invokeOn = InvokeOn.OBJECT_AND_COLLECTION, ...), which I need to be callable from entitys detail view as well as from collection views with selection boxes.
Example:
public class ConfigurationItem {
#Action(
invokeOn = InvokeOn.OBJECT_AND_COLLECTION,
semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
domainEvent = DeletedDomainEvent.class)
public Object delete() {
repositoryService.remove(this);
return null;
}
// ...
}
public class ConfigurationItems {
#Action(semantics = SemanticsOf.SAFE)
public List<T> listAll() {
return repositoryService.allInstances(<item-subclass>.class);
}
// ...
}
This works pretty well but the "invokeOn" annotation is now deprecated. The JavaDoc says that one should switch to #Action(associateWith="...") but I don't know how to transfer the semantics of 'InvokeOn' since I have no collection field for reference.
Instead I only have the collection of objects returned by the database retrieve action.
My question is: How do I transfer the deprecated #Action(invokeOn=...) semantics to the new #Action(associateWith="...") concept for collection return values with no backed property field?
Thanks in advance!
Good question, this obviously isn't explained well enough in the Apache Isis documentation.
The #Action(invokeOn=InvokeOn.OBJECT_AND_COLLECTION) has always been a bit of a kludge, because it involves invoking an action against a standalone collection (which is to say, the list of object returned from a previous query). We don't like this because there is no "single" object to invoke the action on.
When we implemented that feature, the support for view models was nowhere near as comprehensive as it now is. So, our recommendation now is, rather than returning a bare standalone collection, instead wrap it in a view model which holds the collection.
The view model then gives us a single target to invoke some behaviour on; the idea being that it is the responsibility of the view model to iterate over all selected items and invoke an action on them.
With your code, we can introduce SomeConfigItems as the view model:
#XmlRootElement("configItems")
public class SomeConfigItems {
#lombok.Getter #lombok.Setter
private List<ConfigurationItem> items = new ArrayList<>();
#Action(
associateWith = "items", // associates with the items collection
semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
domainEvent = DeletedDomainEvent.class)
public SomeConfigItems delete(List<ConfigurationItem> items) {
for(ConfigurationItem item: items) {
repositoryService.remove(item);
}
return this;
}
// optionally, select all items for deletion by default
public List<ConfigurationItem> default0Delete() { return getItems(); }
// I don't *think* that a choices method is required, but if present then
// is the potential list of items for the argument
//public List<ConfigurationItem> choices0Delete() { return getItems(); }
}
and then change the ConfigurationItems action to return this view model:
public class ConfigurationItems {
#Action(semantics = SemanticsOf.SAFE)
public SelectedItems listAll() {
List<T> items = repositoryService.allInstances(<item-subclass>.class);
return new SelectedItems(items);
}
}
Now that you have a view model to represent the output, you'll probably find other things you can do with it.
Hope that makes sense!

Can Hibernate automatically manage the order of child collections?

Given a Parent class which has many Children, can Hibernate automatically manage the order of said children? From reading documentation and searching, it seems that the #OrderColumn annotation may enable this, but I've not found any examples of how to do it. The closest thing I've found is JPA 2.0 #OrderColumn annotation in Hibernate 3.5, which looks a bit discouraging, given that it looks just like what I want to do.
Here is a rough sketch of what I'm trying to do, minus the annotations, since I'm not sure what they would be:
class Parent {
// I probably need some sort of #OrderColumn annotation here, right?
private List<Child> children = new ArrayList<Child>;
}
class Child {
private Parent parent;
private int order;
}
class SomeBusinessLogic {
public static void createFamily() {
Parent dad = new Parent("Tom");
List<Children> children = dad.getChildren();
children.add(new Child("Alice");
children.add(new Child("Bob");
children.add(new Child("Carl");
session.save(dad);
}
public static void addChild(Parent parent) { // assuming Tom is passed in
List<Children> children = parent.getChildren();
children.add(1, new Child("Zelda");
session.save(parent);
// now, the order should be: Alice, Zelda, Bob, Carl
}
}
If someone can give me enough details to make this toy example work (or tell me that it will not work), I would be most appreciative.
In order to store children in its order you should map it with #IndexedColumn annotation it will create indexed column on your child objects table.

Categories