I'm refactoring a view from using Binder.setBean(T) and mutable state to using pure views with Binder.readBean(T) and Binder.writeBean(T).
As part of the old view, I have several components with binders that don't bind directly to T but to its fields, and the components encapsulate and manage those fields entirely.
A simplified model:
class Foo {
String name; // get, set
}
class Bar {
int max; // get, set
int min; // get, set
}
class Baz {
Bar bar; // get only
Foo foo; // get only
}
And for the view code:
class FooEditor {
Binder<Foo> binder;
{
binder.forField(...).bind(Foo::getName, Foo::setName);
}
}
class BarEditor {
Binder<Bar> binder;
{
binder.forField(...).bind(Bar::getMin, Foo::setMin);
binder.forField(...).bind(Bar::getMax, Foo::setMax);
}
}
class BazEditor {
Binder<Baz> binder;
{
// old model:
// binder.setBean(...);
// fooEditor.getBinder().readBean(binder.getBean().getFoo());
// barEditor.getBinder().readBean(binder.getBean().getBar());
}
}
How can I achieve something like the following?
class BazEditor {
{
binder.forField(???)
.bind(b -> fooEditor.getBinder().readBean(b.getFoo()),
(b, v) -> fooEditor.getBinder().writeBean(b.getFoo()));
// repeat for Bar
}
}
I've tried using ReadOnlyHasValue, but I think due to its implementation, the "getter" always returns the same value (by instance equality), the field is never considered modified by the binder, and the setter is never called.
I've thought about refactoring the components Foo and Bar to bind directly to sub-properties given a Binder<Baz>, but I feel like there should be a better solution.
I think there there is no established best practice for this. I tend to prefer wrapping sub-form as a Field component whose value is Bean or list of Beans myself. I.e. full encapsulation of the internal logic of the sub-form. Then it is clear to use this sub-form as bound field in the Binder on the upper level (it does not need to know whether sub-form has a Binder used internally or not). You can find example of that approach (amongst some other things) in this example project
https://github.com/TatuLund/ProtoTools
Related
Currently, my notification request is like this:
public class EmailRequest{
public enum EmailType{
TYPE_1,
TYPE_2,
...
}
EmailType emailType;
String toAddress;
EmailRenderer renderer;
}
where EmailRenderer is an interface
public interface EmailRenderer{
EmailMessage render()
}
Now, each type of email has a separate implementation of the renderer interface and each implementation contains some rendering data that has to be provided by the client. This data can be different for each implementation.
Example:
public class Type1EmailRenderer implements EmailRenderer{
String param1;
String param2;
#Override
EmailMessage render(){
//rendering logic using the params
}
}
But, it seems redundant to me for the user to set the email type and renderer as well. Choosing the renderer should automatically get me the emailType. How should I restructure the request to be free of this redundancy? Also, can I use any design pattern for providing the renderers to my users?
I'll base my answer on a claim that,
putting aside programming-related questions, at the level of human logic, it looks to me strange that if I want to send an email I should know about renderers at all.
In my understanding If I have emails of different types (you've called them TYPE_1 and TYPE_2, let's give more "business" names for better clarity, like "dailyReport" or "advertisement", you'll see later why) I should just prepare a request with my data (param1, param2) and send it. I shouldn't care about renderers at all as long as the same email type assumes that the same type of renderer will be used.
So, lets say, type "advertisement" has a mandatory parameter String topic and optional parameter String targetAudience and type "dailyReport" has Integer totalUsersCount and optional String mostActiveUserName.
In this case, I propose the somewhat hybrid approach mainly based on Builder creation pattern:
public class EmailRequestBuilder {
private String toAddress;
private EmailRequestBuilder(String to) {
this.toAddress = to;
}
public static EmailRequestBuilder newEmailRequest(String to) {
return new EmailRequestBuilder(to);
}
public AdvertisementBuilder ofAdvertisementType(String topic) {
return new AdvertisementBuilder(topic, this);
}
public DailyReportBuilder ofDailyReportType(Integer totalUsersCount) {
return new DailyReportBuilder(totalUsersCount, this);
}
// all builders in the same package, hence package private build method,
// concrete email type builders will call this method, I'll show at the end
EmailRequest build(EmailType type, EmailRenderer emailRenderer) {
return new EmailRequest (to, type, emailRenderer);
}
}
public class AdvertisementBuilder {
private String topic;
private EmailRequestBuilder emailRequestBuilder;
// package private, so that only EmailRequestBuilder will be able to create it
AdvertisementBuilder(String topic, EmailRequestBuilder emailRequestBuilder) // mandatory parameters in constructor + reference to already gathered data {
this.topic = topic;
this.emailRequestBuilder = emailRequestBuilder;
}
// for optional parameters provide an explicit method that can be called
// but its not a mandatory call
public AdvertisementBuilder withTargetAudience(String audience) {
this.audience = audience;
return this;
}
public EmailRequest buildRequest() {
EmailRenderer renderer = new AdvertisementRenderer(topic, audience);
return emailRequestBuilder.build(EmailType.ADVERTISEMENT, renderer);
}
}
// A similar builder for DailyReport (I'll omit it but assume that there is a class
class DailyReportBuilder {}
Now the good part about it that now you can't go wrong as a user. A typical interaction with such a construction will be:
EmailRequest request = EmailRequestBuilder.newEmailRequest("john.smith#gmail.com")
.ofAdvertisementType("sample topic") // its a mandatory param, you have to supply, can't go wrong
.withTargetAudience("target audience") // non-mandatory call
.buildRequest();
Couple of notes:
Once you pick a type by calling ofDailyReportType/ ofAdvertisementType the user can't really supply parameters of different email type, because it gets "routed" to the builder that doesn't have methods for wrong parameters. An immediate implication of this is that an autocomplete will work in your IDE and people who will use this method will thank you about it ;)
It's easy to add new email types this way, no existing code will change.
Maybe with this approach, an enum EmailType will be redundant. I've preserved it in my solution but probably you'll drop it if it's not required.
Since I sometimes restrict the visibility (package private build methods, constructors, and so forth) - it will be __the_only__way to create the request which means that no-one will create "internal" objects only because it's possible to do so. At least a malicious programmer will think twice before breaking encapsulation :)
For example you can use "factory method".
EmailRenderer createRenderer(EmailType type) {
switch (type) {
case: TYPE_1:
return new RendererType1();
case: TYPE_2:
return new RendererType2();
...
}
}
Also, you probably can introduce cashing of this objects in order not to create them every time. Maybe some lazy initialization (you create appropriate Renderer first time when you needed and after that always return that same instance).
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!
I am building an Java App, with Eclipse RCP.
When my model classes are modified (thanks to my setter methods) I would like to send events (IEventBroker) corresponding to each differents setters, that my differents UI elements can catch. I thought about this pattern :
Model {
setValueForA() {...}
setValueForB() {...}
setValueForC() {...}
}
ServiceLayer {
setValueForA() {
model.setValueForA();
sendEventAUpdated();
}
setValueForB() {
model.setValueForB();
sendEventBUpdated();
}
setValueForC() {
model.setValueForC();
sendEventCUpdated();
}
}
Is there a way with a framework, library, annotations,... whatever who can helps me to implement less code, and to avoid this copying code? I am on 1.8 JDK
This sounds like a candidate for Observer pattern. Java language provides some basic support through Observable and Observer classes. The downside is that you will have to extend these in your corresponding classes. This frees you from the overhead of adding observer/obervable code though. Broadly, you just add notify code in your setter methods of model object. Define Observers, then tie them together from application(Service) code. Whenever a set happens, if it has notify coded, it will notify all observers associated with the model object.
Following is a rough example based on code in question :
Model extends Observable { //various observers can be notified when property changes.
setValueForA(Object value) {...
setChanged();
notifyObservers(value);
}
//Example setter above. Similar code needed in all required properties.
}
Now create observers
public class SomePropertyObserver implements Observer
{
private ObservableValue ov = null;
public SomePropertyObserver(ObservableValue ov)
{
this.ov = ov;
}
//This method is called whenever the observed object is changed.
public void update(Observable obs, Object obj)
{
//obj is the value sent from notifyObservers called from observable
}
}
Tie them together in your application code :
Model model = new Model();
SomePropertyObserver observer = new SomePropertyObserver(model);
model.addObserver(observer); // now observer will get notification whenever a property changes in model.
There are some downsides, as you have to extend Observable and hence you are very tightly coupled and restricted of further object extension.
I have a "legacy" code that I want to refactor.
The code basically does a remote call to a server and gets back a reply. Then according to the reply executes accordingly.
Example of skeleton of the code:
public Object processResponse(String responseType, Object response) {
if(responseType.equals(CLIENT_REGISTERED)) {
//code
//code ...
}
else if (responseType.equals(CLIENT_ABORTED)) {
//code
//code....
}
else if (responseType.equals(DATA_SPLIT)) {
//code
//code...
}
etc
The problem is that there are many-many if/else branches and the code inside each if is not trivial.
So it becomes hard to maintain.
I was wondering what is that best pattern for this?
One thought I had was to create a single object with method names the same as the responseType and then inside processResponse just using reflection call the method with the same name as the responseType.
This would clean up processResponse but it moves the code to a single object with many/many methods and I think reflection would cause performance issues.
Is there a nice design approach/pattern to clean this up?
Two approaches:
Strategy pattern http://www.dofactory.com/javascript/strategy-design-pattern
Create dictionary, where key is metadata (in your case metadata is responseType) and value is a function.
For example:
Put this in constructor
responses = new HashMap<string, SomeAbstraction>();
responses.Put(CLIENT_REGISTERED, new ImplementationForRegisteredClient());
responses.Put(CLIENT_ABORTED, new ImplementationForAbortedClient());
where ImplementationForRegisteredClient and ImplementationForAbortedClient implement SomeAbstraction
and call this dictionary via
responses.get(responseType).MethodOfYourAbstraction(SomeParams);
If you want to follow the principle of DI, you can inject this Dictionary in your client class.
My first cut would be to replace the if/else if structures with switch/case:
public Object processResponse(String responseType, Object response) {
switch(responseType) {
case CLIENT_REGISTERED: {
//code ...
}
case CLIENT_ABORTED: {
//code....
}
case DATA_SPLIT: {
//code...
}
From there I'd probably extract each block as a method, and from there apply the Strategy pattern. Stop at whatever point feels right.
The case you've describe seems to fit perfectly to the application of Strategy pattern. In particular, you've many variants of an algorithm, i.e. the code executed accordingly to the response of the remote server call.
Implementing the Stategy pattern means that you have to define a class hierachy, such the following:
public interface ResponseProcessor {
public void execute(Context ctx);
}
class ClientRegistered implements ResponseProcessor {
public void execute(Context ctx) {
// Actions corresponding to a client that is registered
// ...
}
}
class ClientAborted implements ResponseProcessor {
public void execute(Context ctx) {
// Actions corresponding to a client aborted
// ...
}
}
// and so on...
The Context type should contain all the information that are needed to execute each 'strategy'. Note that if different strategies share some algorithm pieces, you could also use Templeate Method pattern among them.
You need a factory to create a particular Strategy at runtime. The factory will build a strategy starting from the response received. A possibile implementation should be the one suggested by #Sattar Imamov. The factory will contain the if .. else code.
If strategy classes are not to heavy to build and they don't need any external information at build time, you can also map each strategy to an Enumeration's value.
public enum ResponseType {
CLIENT_REGISTERED(new ClientRegistered()),
CLIENT_ABORTED(new ClientAborted()),
DATA_SPLIT(new DataSplit());
// Processor associated to a response
private ResponseProcessor processor;
private ResponseType(ResponseProcessor processor) {
this.processor = processor;
}
public ResponseProcessor getProcessor() {
return this.processor;
}
}
Since it is still not 100% clear when a LDM should be used I tried a simple memory test.
I created a DataView with a DataProvider that simply creates a list of few 100 entities with some big data inside (long String):
private class HeavyDataProvider implements IDataProvider<HeavyBean> {
#Override
public void detach() {
}
#Override
public Iterator<? extends HeavyBean> iterator(int first, int count) {
List<HeavyBean> l = newArrayList();
for (int i = 0; i < this.size(); i++) {
l.add(new HeavyBean());
}
return l.iterator();
}
#Override
public IModel<HeavyBean> model(HeavyBean heavyBean) {
return new CompoundPropertyModel<HeavyBean>(heavyBean);
}
#Override
public int size() {
return 500;
}
}
Using wicket's DebugBar is see this creates a Page with a size of 5MB. In the javadoc of DataProvider it is stated that the model return in above model method is usually a detachable one so I changed this method to:
#Override
public IModel<HeavyBean> model(final HeavyBean heavyBean) {
return new LoadableDetachableModel<HeavyBean>() {
#Override
protected HeavyBean load() {
return heavyBean;
}
};
}
Naively I was expecting the pagesize to be reduced in a big way now since the heavybeans will no longer be part of the model. Actual result: 5MB. Since the model will detach the heavyBean this must mean that something else still has a hold of it (DataView? Item?).
I saw other examples where DataView and DataProvider are combined in a similar fashion but for me it is unclear what the point is since it does not seem to make any difference regarding the pageSize/memory usage.
So, am I understanding/doing something wrong (likely) or are LDM's useless in DataProviders?
Side question (sorry), in which scenario would you use an LDM?
Your implementation of LDM is just plain wrong. It is holding a direct reference to the bean itself, and just returning it. This way, the bean will be serialized along the model, making it completely pointless.
You should do something like this:
#Override
public IModel<HeavyBean> model(final HeavyBean heavyBean) {
final Integer id = heavyBean.getId();
return new LoadableDetachableModel<HeavyBean>() {
#Override
protected HeavyBean load() {
return ServiceLocator.get(HeavyDao.class).get(id);
}
};
}
If you use the wicket-ioc module, the HeavyDao reference could be injected into the enclosing page/component.
I think Wicket is really easy to use, but you must understand the basics of Java serialization, or else you may end up with a very bloated http session.
For the LDM to work, you will have to actually detach the data in the detach() method. LDMs are meant to be used with databases, where you can restore / load the data on the next request with only the knowledge of an ID. So, in detach() you would trow away all data but the ID (or watever you need to relaod the data when needed) and in the load() (is this right? can't lock up the api right now) you will restore the data.
Hope that helps.