Are there any techiques to collect a number of gwt-rpc service callback results?
I have a dialog window used to create new or edit existing object. These objects have a number of references to other object. So when user creating or editing an object he may pick one in the ListBox.
public class School {
private String name;
private String address;
}
public class Car {
private String model;
private String type;
}
public class Person {
private String firstName;
private String lastName;
private School school;
private Car firstCar;
}
When the dialog window appears on the screen it should request all available values for all referencing fields. These values are requested with AsyncCallback's via gwt-rpc, so I can handle it one-by-one.
service.getAllSchools(new AsyncCallback<List<School>>() {
#Override
public void onSuccess(List<School> result) {
fillSchoolListBox(result);
}
#Override
public void onFailure(Throwable caught) {
Window.alert("ups...");
}
});
...
service.getAllSchools(new AsyncCallback<List<Car>>() {
#Override
public void onSuccess(List<Car> result) {
fillCarListBox(result);
}
#Override
public void onFailure(Throwable caught) {
Window.alert("ups...");
}
});
How to get all result in one place?
Thanks.
The best solution would be Command Patter as igorbel said, but if you are beginner you can design for example Bean Container that only contains beans that must be transported at one request.
For example:
public class BeanContainer{
private ArrayList<School> schools = new ArrayList<School>();
private ArrayList<Car> cars = new ArrayList<Car>;
private ArrayList<Person> people = ArrayList<Person>();
public void addSchool(School school){
this.schools.add(school);
}
public void addSchoolCollection(ArrayList<School> schools){
this.schools.add(schools);
}
public ArrayList<School> getSchoolCollection(){
return schools;
}
...
}
Why don't you create a new service method that returns all the data as a result?
The implementation of such a method could simply call all of the other methods. You will have to encapsulate all the required data and return it as a single result. One example how you could handle this:
In the service implementation:
#Override
public Data getAllData(){
List<Cars> cars = this.getAllCars();
List<School> schools = this.getAllSchools();
return new Data(cars, schools);
}
And you can then use the method like this:
service.getAllData(new AsyncCallback<Data data>() {
#Override
public void onSuccess(Data data) {
fillCarListBox(data.getCars());
fillSchoolListBox(data.getSchools());
}
#Override
public void onFailure(Throwable caught) {
Window.alert("Pogreska...");
}
});
With this kind of approach you minimize the number of service calls on your client side. This not only creates a more readable code, but also usually speeds up the client side of your app. You should always try to minimize the number of service calls, ideally to a single one.
Concerning the more general question of collecting a number of asynchronous callbacks, a good approach is to use the Command Pattern. Gwt Remote Action is a library that provides an implementation of the mentioned pattern for doing RPC calls:
http://code.google.com/p/gwt-remote-action/
Related
I have class three classes. Pref, ClassA, and ClassB.
public class Pref{
public static ArrayList<Pref> prefList;
public static Observable<ArrayList<Pref>> observable;
public static void loadData(){
prefList = getFromDb();
observable = Observable.just(prefList);
}
}
Application runs the ClassA First.
public ClassA{
public ClassA(){
initObserver();
setObserver();
}
public void initObserver(){
Pref.loadData();
}
public void setObserver(){
Observer<ArrayList<Pref>> obs = new Observer() {
#Override
public void onSubscribe(Disposable dspsbl) {
System.out.println("Subscribed");
}
#Override
public void onNext(ArrayList<Pref>> t) {
System.out.println("Loading Preference.");
//Need to do some other works here.
}
#Override
public void onError(Throwable thrwbl) {
}
#Override
public void onComplete() {
}
};
Pref.observable.subscribe(obs);
}
}
Now I want to change the list from ClassB.
public class ClassB{
private void changeList(){
Pref.prefList = loadDataFromSomeSource();
}
}
When I run ClassA, the System.out works fine. But when I change the list from ClassB nothing happens. My question is, is the right way to work with Rxjava. Is it for Rxjava built? If I am wrong how can I achieve this functionality? How can I write several ClassA like classes so that When the ClassB::changeList() runs, I can listen it in ClassA?
By setting Pref.prefList = loadDataFromSomeSource();, you assign a new list instance to Pref.prefList. This will not update Pref.observable in any way, because this still refers to the old Pref.prefList instance.
I also think that you can not use an Observable to publish events through it. As far as I understand your situation, you need an ObservableSource (see http://reactivex.io/RxJava/javadoc/io/reactivex/ObservableSource.html). For example, it is implemented by PublishSubject. You could use it like this:
PublishSubject<String> source = PublishSubject.create();
source.subscribe(System.out::println);
source.onNext("test 1");
source.onNext("test 2");
source.onNext("test 3");
Or, in your case: in class Pref, you can use public static PublishSubject<ArrayList<Pref>> source = PublishSubject.create();. When loading the data, you can publish the new data using onNext, like this in ClassB: Pref.source.onNext(loadDataFromSomeSource())
Designing a new application, I have two sets of domain objects. One set mirrors the other and domain objects basically are paired up with similar attributes. When a domain object in the set A is created, updated, or deleted, a corresponding domain object in the set B will also be created, updated, or deleted. To reduce any coupling, I would like to separate those operations between a pair of domain objects. What will be a good mechanism to achieve this approach? I am thinking of using a messaging system. Will it work well for this case? I use Spring for this project.
Yes, using application events is a common solution for decreasing coupling between objects.
Actually spring already has builtin mechanism for that.
You might come up with something like:
#SpringBootApplication
public class So44490189Application {
public static void main(String[] args) {
SpringApplication.run(So44490189Application.class, args);
}
public static class UserCreatedEvent {
private final String email;
public UserCreatedEvent(String email) {
this.email = email;
}
}
#Service
public static class UserService {
#EventListener
public void handleUserCreatedEvent(UserCreatedEvent userCreatedEvent) {
System.out.println("Creating user " + userCreatedEvent.email);
}
}
#Service
public static class MemberService {
#EventListener
public void handleUserCreatedEvent(UserCreatedEvent userCreatedEvent) {
System.out.println("Creating member " + userCreatedEvent.email);
}
}
#Service
public static class OperationService {
private final ApplicationEventPublisher eventPublisher;
#Autowired
public OperationService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void createUser(String email) {
eventPublisher.publishEvent(new UserCreatedEvent(email));
}
}
#RestController
public static class OperationController {
private final OperationService operationService;
#Autowired
public OperationController(OperationService operationService) {
this.operationService = operationService;
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public void createUser(String email) {
operationService.createUser(email);
}
}
}
Usage
curl -XPOST 'localhost:8080?email=admin#localhost.localdomain'
Output
Creating member admin#localhost.localdomain
Creating user admin#localhost.localdomain
In this case creation user and members are mirrored.
One possible problem is transaction support and there is a couple of ways to deal with that. Spring has tools for it as well.
Recently I came across a problem which I was asked to design using appropriate design patterns. The proble statement is:
Implement a remote control of TV.
Any remote control we use, either at home/hotel or at a friend’s place,
we just pick up the TV remote control and start pressing Up and Down
or Forward and Back keys to change the channels.
Choose a suitable design pattern for implementation of this problem.
I am not able to figure out how to design this ask. This is what I came up with:
Place is an abstract class.
Home extends Place
Hotel extends Place
FriendPlace extends Place
TVRemote is a class
Place has a TVRemote
Keys is an interface
Keys has a method press()
UpKey, DownKey, ForwardKey, BackKey are classes implementing Keys
TVRemote has Keys
There could be more Keys in TVRemote
This is what I could think of but unable to incorporate a Design Pattern here. Any guidance?
A simplistic approach will be to create an interface
interface RemoteControl
{
public void up();
public vois down();
public void forward();
public void back();
}
and then create specific classes that will implement that interface for specific devices
e.g.
public class HomeRemote implements RemoteControl {
public void up(){
..
}
public vois down(){
..
}
public void forward(){
..
}
public void back(){
..
}
}
However
After our discussion - and after searching a little bit more, i am inclined to think now that Bridge pattern is what is asked for here.
Check this out - http://www.programcreek.com/2011/10/java-design-pattern-bridge/
There abstract class for remote control is used with basic implementation of (up,down,forward,back)
Then each specific TVRemote extends the abstract class to add more/and device specific functionality.
Also note that TVs are using common interface where (goUp(),goDown(),goForward(),goBack() and possibly on(),off()) functions are described.
Some observations:
different remote controls may have different number of buttons
different buttons execute different actions
remote control should be oblivious of the details how the action is executed
one should be able to reprogram remote control either by assigning different actions to buttons or by supporting different devices
The most straightforward pattern to use with this situation is Command. One could create specific Command implementations and then assign Commands to buttons:
public interface Command {
void Execute();
}
public class Button {
private readonly Command command;
public Button(Command command) {
this.command = command;
}
public void Press() {
this.command.Execute();
}
}
public class Remote {
public Button ButtonPlaceholder1 { get; set; }
public Button ButtonPlaceholder2 { get; set; }
public Button ButtonPlaceholder3 { get; set; }
public Button ButtonPlaceholder4 { get; set; }
}
So, what would be the benefit of having Button class? Well, let's say you want to introduce a slider button, which can be moved Up and Down. In this case, you will configure it with two Commands:
public class SliderButton {
public SliderButton(Command up, Command down) {
this.commandUp = up;
this.commandDown = down;
}
public void Up() {
this.commandUp.Execute();
}
public void Down() {
this.commandDown.Execute();
}
}
And interesting follow-up question on this interview would be, "How to implement a button that would cancel the action made by pressing previous button? (e.g. I was watching ESPN channel, but there was a break in between a match, so I switched to MTV, but I want to check once in a while whether break has ended, and if not, go back to MTV)
You should use command pattern here. Usually it has Invoker, Client, Command and Receiver. Here are the classes you may require.
Command
public interface ICommand {
void execute();
}
Invoker
public class RemoteControl {
Map<Key, ICommand> commandsByKey;
public RemoteControl() {
commandsByKey = new HashMap<>();
}
public void setCommand(Key key, ICommand command) {
commandsByKey.put(key, command);
}
public void press(Key key) throws Exception {
ICommand command = commandsByKey.get(key);
if(command == null)
throw new Exception("Invalid Key");
command.execute();
}
}
Receiver
public class TV {
private String brand;
public TV(String brand) {
this.brand = brand;
}
#Override
public String toString() {
return brand + " TV";
}
}
Client
public abstract class Place {
private TV tv;
private RemoteControl remoteControl;
public Place(TV tv) {
this.tv = tv;
this.remoteControl = new RemoteControl();
remoteControl.setCommand(Key.UP, new UpCommand(this.tv));
remoteControl.setCommand(Key.FORWARD, new ForwardCommand(this.tv));
remoteControl.setCommand(Key.DOWN, new DownCommand(this.tv));
remoteControl.setCommand(Key.BACK, new BackCommand(this.tv));
}
public TV getTv() {
return tv;
}
public RemoteControl getRemoteControl() {
return remoteControl;
}
}
public class Home extends Place {
public Home() {
super(new TV("Sony"));
}
}
public class Hotel extends Place {
public Hotel() {
super(new TV("LG"));
}
}
Concrete Commands
public class UpCommand implements ICommand {
private TV tv;
public UpCommand(TV tv) {
this.tv = tv;
}
#Override
public void execute() {
System.out.println("Up Command - " + tv);
}
}
public class DownCommand implements ICommand {
private TV tv;
public DownCommand(TV tv) {
this.tv = tv;
}
#Override
public void execute() {
System.out.println("Down Command - " + tv);
}
}
public class ForwardCommand implements ICommand {
private TV tv;
public ForwardCommand(TV tv) {
this.tv = tv;
}
#Override
public void execute() {
System.out.println("Forward Command - " + tv);
}
}
public class BackCommand implements ICommand {
private TV tv;
public BackCommand(TV tv) {
this.tv = tv;
}
#Override
public void execute() {
System.out.println("Back Command - " + tv);
}
}
Keys
public enum Key {
UP, DOWN, FORWARD, BACK
}
TEST
public class RemoteTest {
public static void main(String[] args) throws Exception {
Place home = new Home();
home.getRemoteControl().press(Key.UP);
home.getRemoteControl().press(Key.DOWN);
home.getRemoteControl().press(Key.BACK);
Hotel hotel = new Hotel();
hotel.getRemoteControl().press(Key.UP);
}
}
If you add any additional keys to the remote you don't need to touch any of the existing command or invoker. You just need to add it in the client. This adheres to Open Close principle. If you have different remote for each place then make it as constructor argument, so you no need to change any other classes.
I am using the MaterialDrawer library to create a simple drawer for my app, some of the instances of classes in the library need a string passed into them when called. An example is the IProfile class:
IProfile profile = new ProfileDrawerItem().withName("John Doe");
where the withName() method takes in a string.
I have created a class MyObservable.java (extends Observable) class that I intend using to get data to be used in my MainActivity which has the MaterialDrawer library implemented. In this class, I have a method implementData() which has my listener for what I need from my firebase database.
This is what it looks like:
public class MyObservable extends Observable {
// Attach our firebase reference...
Firebase userRef = new Firebase("https://myApp.firebaseio.com/users");
AuthData authData;
public String username = "";
public String email = "";
public void changeUsername(String username) {
this.username = username;
setChanged();
notifyObservers(username);
}
public void implementData(){
// Get the authentication data of our user from the reference.
authData = userRef.getAuth();
// This is the listener I have to get the data from.
userRef.child(authData.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
UserSchema user = snapshot.getValue(UserSchema.class);
// This guy needs to be used in the MainActivity appDrawer() method
String userName = user.getName();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}
class MyObserver implements Observer {
public void update(Observable observable, Object data) {
// For now I just print it out to System.out
System.out.println("Username:" + data);
}
}
Then I notify my observers of the username change with the changeUsername() method:
public void changeUsername(String username) {
this.username = username;
setChanged();
notifyObservers(username);
}
In the MyObservable class, I have a MyObserver class that implements Observer with the update() method called whenever an observer has been updated. In the update() method for now, I just print out the username of the user to ensure something is actually happening.
This is where I need the data from the observer (In the MainActivity):
public class MainActivity extends AppCompatActivity {
...
public void appDrawer(){
IProfile profile = new ProfileDrawerItem()
// I need the user's data here
.withName("Test")
.withEmail("test#test.com")
.withIcon(R.drawable.avatar2);
}
...
}
I have spent hours trying to 'react' to the events happening in the listener by trying to retrieve data to be used in my MainActivity but I'm not sure I'm using the Observable/Observer pattern properly, also since this is an Asynchronous event by Firebase to get data, using an Observer has been the best way to do this.
The appDrawer() method is called in my Activity's onCreate() .
How do I retrieve data from the Listener with an Observer, so I can use it elsewhere?
I can't tell by your design what's really going on. Naming a class Listener then making it Observable seems counter-intuitive. A listener listens or observes. Nonetheless, it sounds like you have another class in the Listener that's an Observer so I'm a little lost but you seem unsure if you've implemented the pattern correctly. That I can clear up with an example.
public class MyObserver implements Observer {
#Override
public void update(Observable o, Object arg) {
System.out.println(arg + " " + ((MyObservable)o).name);
}
}
public class MyObservable extends Observable {
public String name = "Observable";
public void changeMe(String word) {
setChanged();
notifyObservers(word);
}
}
public class Test {
public static void main(String[] args) {
MyObservable myObservable = new MyObservable();
myObservable.addObserver(new MyObserver());
myObservable.changeMe("Hello");
}
}
The update method gives you the object you're observing as well as the arguments (the data you want shared with the observer) you passed into notifyObservers(). If you've done it like this then you should get the behavior you expect.
As you can see data can be sent to the observers that is outside or inside the observable. When you run it the output is...
Hello Observable
I have a GUI that has 2 JTextFields- EmailLoginField and jPasswordField1. Ill just discuss the EmailLoginField and just duplicate what is recommended on jPasswordField1 too.
So heres some GUI code:
package p;
imports ...
public class EmailLoginGUI extends javax.swing.JFrame {
public EmailLoginGUI() {
initComponents();
}
private void initComponents() {
...
EmailLoginField = new javax.swing.JTextField();
}
...
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
EmailMainGUI open = new EmailMainGUI();
open.setVisible(true);
This next code snippet is what I have tried to do to get the text from the JTextField EmailLoginField in EmailLoginGUI.java
public String getEmailLoginField(){
return EmailLoginField.getText();
}
public String getjPasswordField(){
return jPasswordField1.getText();
}
Here is the next part (not assuming the code immediately above is correct). This next code is an entirely different public class, which same package of course. Here is what I have tried it should look at the EmailLoginGUI class and get the JTextField content, eventually storing it as a String.
PLEASE NOTE: the final strings that contain the JTextField content MUST NOT be inside the SendEmail(EmailLoginGUI c1, EmailLoginGUI c2){. They should be just outside of it just inside public class SendEmail { this is so that they can be used by other code later.
package p;
imports ...
public class SendEmail {
JTextField userTF;
JPasswordField passPF;
SendEmail(EmailLoginGUI c1, EmailLoginGUI c2){
userTF.setText(c1.getEmailLoginField());
passPF.setText(c2.getjPasswordField());
}
public String user(){
return userTF.getText();
}
public String pass() {
return passPF.getText();
}
...
SendEmail(...) {
Properties props = new Properties();
...
Session session = Session.getInstance(props, new javax.mail.Authenticator()
{
protected javax.mail.PasswordAuthentication getPasswordAuthentication()
{
return new javax.mail.PasswordAuthentication(user(), pass()); //This is where the final strings need to go.
}
});
Hopefully what I am trying to do is clear:
Get the content from JTextField created in EmailLoginGUI.java. Get this into SendEmail.java. Its final type should be String and is 'just on the inside' of the public class SendEmail. I have had everything from NullPointerException to Cannot find symbol for hours! Think I've been attempting it for so long that I could benefit from some fresh eyes!
Help would be greatly appreciated.
In SendEmail class create Constructor which has an argument of user input
SendEmail(String userInput) {
//Your Code
}
In EmailLoginGUI create
String userInput = EmailLoginField.getText().toString();
SendEmail sendemail = new SendEmail(userInput);
This method works I have used it. Hope it helps.
I realised both the security risk and how a dialogue would be easier, however I don't have time to go back to change it really. I have already coded the listener too so that's not a problem. But yes that's what I want to do! Where am I going wrong?
Then you need to implement some kind of Observer Pattern.
Start by defining the expected operations that the login view might generate, for example, it's reasonable to expect that the user can either accept or cancel the view
public interface EmailLoginListener {
public void emailLoginWasAccepted(EmailLoginGUI gui);
public void emailLoginWasCanceled(EmailLoginGUI gui);
}
Update the view to provide support for the listener
public class EmailLoginGUI extends javax.swing.JFrame {
private List<EmailLoginListener> listeners;
public EmailLoginGUI() {
initComponents();
listeners = new ArrayList<>(25);
}
//...
public void addEmailLoginListener(EmailLoginListener listener) {
listeners.add(listener);
}
public void removeEmailLoginListener(EmailLoginListener listener) {
listeners.add(listener);
}
protected void fireLoginWasAccepted() {
for (EmailLoginListener listener : listeners) {
listener.emailLoginWasAccepted(this);
}
}
protected void fireLoginWasCanceled() {
for (EmailLoginListener listener : listeners) {
listener.emailLoginWasCanceled(this);
}
}
}
In your action handlers for your buttons on the EmailLoginGUI view, trigger the required event...
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
fireLoginWasAccepted();
}
Remember, you should also do this for the cancel operation if you have one.
Now, when you create an instance of EmailLoginGUI, make sure you also register a EmailLoginListener with it
EmailLoginGUI loginView = new EmailLoginGUI();
loginView.addEmailLoginListener(new EmailLoginListener() {
#Override
public void emailLoginWasAccepted(EmailLoginGUI gui) {
gui.dispose();
String email = gui.getEmailLoginField();
String password = gui.getjPasswordField();
EmailMainGUI open = new EmailMainGUI();
open.setCredentials(email, password);
//...
open.setVisible(true);
}
#Override
public void emailLoginWasCanceled(EmailLoginGUI gui) {
// Exit the program?
gui.dispose();
}
});
//...
loginView.setVisible(true);
This will require you to either change the constructor of EmailMainGUI to accept the email and password or a method to pass that information to the class (as I've demonstrated above)
Finally change SendEmail to accept String values instead of your gui components
public class SendEmail {
String email;
String password;
SendEmail(String email, String password) {
this.email = email;
this.password = password;
}
public String user() {
return email;
}
public String pass() {
return password;
}
}