Generate view from a dynamic model - java

I have a model which can be modified at run time. Here's an example :
public class JavaMethod
{
private String name;
private List<Parameter> parameters;
private boolean isConstructor; // this is an example
}
The parameters can have different type (integer, boolean, string, float...) and different valid values. For example, an integer parameter named age could only hold positive integers.
The problem is that I would like to generate a view with Swing to configure that JavaMethodobject, but I am not sure of the proper way to do it.
For example, the age parameter which is a positive integer would be linked to a class extending JTextField that prevent entering negative any letters. Another integer parameter named numberOfFingers which can range from 8 to 12 would be linked to a class extending JComboBox that allows selection of an option in that range.
I could do this with polymorphism by giving the task of generating the appropriate Swing component to the Parameter object, but then my model would know about how the view is generated.
What is the proper way of generating a view for a model like this?
All I can think of (without the model involved in the generation of the view) is a kind of giant switch in the controller that picks the good component by reading the Parameter's details.
Thanks

For that you are needed to create Customized PlainDocument . For example for JTextField containing only age value you should create AgeDocument class which would look something like this :
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
class AgeDocument extends PlainDocument
{
#Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
{
/**Write your logic here**/
if (str == null)
{
return;
}
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length; i++)
{
if (!Character.isDigit(arr[i]))//Checking for Non Numeric.
{
return;
}
if (Character.getNumericValue(arr[i])==0 )
{
try
{
int val = Integer.parseInt(getText(0,offs));
if (val == 0)
{
super.insertString(offs,"", a);//Don't allow to put 0 as age.
return;
}
}
catch (Exception ex){return;}
}
}
super.insertString(offs, new String(str), a);
}
}
And whenever you want to set this AgeDocument property to a JTextField object you simply write JTextFieldOBject.setDocument(new AgeDocument ())
Likewise , you can create many model independently. And can use them anywhere in your code.

The best way to solve this problem is to use the Visitor Pattern.
For example :
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class Main
{
public static class JavaMethod implements Iterable<Parameter>
{
private List<Parameter> parameters;
public JavaMethod()
{
this.parameters = new ArrayList<>();
// This is an example
this.parameters.add(new IntegerParameter());
this.parameters.add(new StringParameter());
}
#Override
public Iterator<Parameter> iterator()
{
return this.parameters.iterator();
}
}
public static interface Parameter
{
public void accept(ParameterVisitor visitor);
}
public static class IntegerParameter implements Parameter
{
public int value = 10;
#Override
public void accept(final ParameterVisitor visitor)
{
visitor.visit(this);
}
}
public static class StringParameter implements Parameter
{
public String value = "Hello";
#Override
public void accept(final ParameterVisitor visitor)
{
visitor.visit(this);
}
}
public static interface ParameterVisitor
{
void visit(StringParameter stringParameter);
void visit(IntegerParameter integerParameter);
}
public static class ParameterSwingVisitor implements ParameterVisitor
{
private final JComponent container;
public ParameterSwingVisitor(final JComponent container)
{
this.container = container;
}
#Override
public void visit(final StringParameter stringParameter)
{
this.container.add(new JTextField(stringParameter.value));
}
#Override
public void visit(final IntegerParameter integerParameter)
{
// This could be a custom component to pick numbers
this.container.add(new JLabel(String
.valueOf(integerParameter.value)));
}
}
public static void main(final String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
JPanel myPanel = new JPanel(); // view
JavaMethod myMethod = new JavaMethod(); // model
final ParameterVisitor visitor = new ParameterSwingVisitor(
myPanel);
for (final Parameter picked : myMethod)
{
picked.accept(visitor); // This will add the appropriate
// swing
// component
}
JFrame myFrame = new JFrame("Visitor pattern");
myFrame.setContentPane(myPanel);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
myFrame.setSize(500, 500);
}
});
}
}
More information about this pattern here.

Related

ConcurrentSkipListMap firstKey() throws NoSuchElementException even though it contains data

I wrote a small application that receives data from a web socket, which I store in static ConcurrentSkipListMap.
The application initially creates a new thread where it runs infinitely while loop calling ConcurrentSkipListMap.firstKey(). After a while, this call throws a NoSuchElementException, even though the ConcurrentSkipListMap contains data.
break point in catch block
Example of my application:
I have cacher class that contains websocket implementation and NavigableMap init:
package solvethat.net.triobot.Example;
import com.binance.api.client.BinanceApiCallback;
import com.binance.api.client.BinanceApiClientFactory;
import com.binance.api.client.domain.event.DepthEvent;
import com.binance.api.client.domain.market.OrderBook;
import com.binance.api.client.domain.market.OrderBookEntry;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class AskCacher {
private long updateId;
private final BinanceApiClientFactory factory;
public AskCacher() {
factory = BinanceApiClientFactory.newInstance();
initAsks();
runWebsocket();
}
/**
* Init data getting order book snapshot
*/
private void initAsks() {
try {
OrderBook orderBook = factory.newRestClient().getOrderBook("btcusdt".toUpperCase(), 10);
updateId = orderBook.getLastUpdateId();
NavigableMap<Double, Double> asks = new ConcurrentSkipListMap<>(Comparator.naturalOrder());
for (OrderBookEntry ask : orderBook.getAsks()) {
asks.put(Double.parseDouble(ask.getPrice()), Double.parseDouble(ask.getQty()));
}
StaticData.ask = asks;
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
private void runWebsocket() {
factory.newWebSocketClient().onDepthEvent("btcusdt", new BinanceApiCallback<>() {
/**
* Set ask price and call analysis method
*/
#Override
public void onResponse(DepthEvent depthEvent) {
if (depthEvent.getFinalUpdateId() > updateId) {
updateId = depthEvent.getFinalUpdateId();
updateOrderBook(depthEvent.getAsks());
}
}
/**
* Just print err message
*/
#Override
public void onFailure(final Throwable cause) {
System.err.println(cause.getMessage());
}
});
}
/**
* Updates an order book (asks) with a delta received from the server.
* Whenever the qty specified is ZERO, it means the price should was removed from the order book.
*/
private void updateOrderBook(List<OrderBookEntry> orderBookDeltas) {
for (OrderBookEntry orderBookDelta : orderBookDeltas) {
Double price = Double.parseDouble(orderBookDelta.getPrice());
BigDecimal qty = new BigDecimal(orderBookDelta.getQty());
if (qty.compareTo(BigDecimal.ZERO) == 0) {
// qty=0 means remove this level
StaticData.ask.remove(price);
} else {
StaticData.ask.put(price, Double.parseDouble(orderBookDelta.getQty()));
}
}
// Print best ask to see if cacher is alive
System.out.println("btc-usdt best ask: " + StaticData.ask.firstKey());
// Edit map length
if (StaticData.ask.size() > 10) {
StaticData.ask.tailMap((Double) StaticData.ask.keySet().toArray()[10], true).clear();
}
}}
Then infinite loop:
package solvethat.net.triobot.Example;
public class InfiniteLoop {
public void loopProcess() {
Analyzer analyzer = new Analyzer();
while (true) {
analyzer.analyze(StaticData.ask.firstEntry());
}
}}
And analyzer class:
package solvethat.net.triobot.Example;
import java.util.Map;
public class Analyzer {
public void analyze(Map.Entry<Double, Double> entry) {
StaticData.AnalyzeObject analyzeObject = new StaticData.AnalyzeObject();
analyzeObject.setBestAsk(entry.getKey());
if (analyzeObject.getBestAsk() > 50000) {
System.out.println("It is a good price!!");
}
}
}
Static data model:
package solvethat.net.triobot.Example;
import java.util.NavigableMap;
public class StaticData {
public static NavigableMap<Double, Double> ask;
public static class AnalyzeObject {
double bestAsk;
public double getBestAsk() {
return bestAsk;
}
public void setBestAsk(double bestAsk) {
this.bestAsk = bestAsk;
}
}
}
Main class for example run:
package solvethat.net.triobot.Example;
public class Main {
public static void main(String[] arguments) {
new AskCacher();
new Thread(new InfiniteLoop()::loopProcess).start();
}
}
The example only shows how the application is composed, but I was not able to use it to raise an error but I opened my repo as public:
https://github.com/Sick-E/TrioBot
Can anyone please help me?
Thank you.
Tomas
You can replace your code with something like that (no exception handling is required)
Optional.ofNullable(trio.getThirdPair().getBids().firstEntry())
.map(Map.Entry::getKey)
.ifPresent(trio.getTrioAnalysis()::setBidThird);

Designing resource access: Final enums vs static members of extendable classes

I am trying to design a framework for loading resources. So I have two options
Approach 1
Underlying structure: An interface with a simple abstract class implementation and more specific extends.
Access: static final members of class initialized to the class.
Approach 2
Underlying structure: A specific enum from the get go, implementing all interface methods: no leveraging partial implementations of abstract classes.
Access: as enum entries
While approach 1 is a lot more flexible and reusable, I like the way enums provide a clean usable list, ready to use as opposed to static finals with scope for Class.instance.instance.instance. ...
Is there a standard way to do this? Is there a better way to do this?
Though not strictly needed here's the code
Approach 1
Interface LoadableResource<T>
import java.util.ArrayDeque;
import java.util.Queue;
public interface LoadableResource<T> {
Queue<Exception> exceptionQueue=new ArrayDeque<>();
boolean load();//Load the resource and return status
boolean isLoaded() ;
T getResource();
void onLoadFail();
void onLoadSuccess();
void onException(Exception ex);
Queue<Exception> getExcpetions();
}
Abstract SimpleLoadableResource<T>
import java.util.Queue;
public abstract class SimpleLoadableResource<T> implements LoadableResource<T> {
private boolean FLAG_LOADED = false;
private T resource;
#Override
public boolean isLoaded() {
return FLAG_LOADED;
}
#Override
public T getResource() {
return resource;
}
#Override
public void onLoadFail() {}
#Override
public void onLoadSuccess() {}
#Override
public void onException(Exception ex) {exceptionQueue.add(ex); }
#Override
public Queue<Exception> getExcpetions() { return exceptionQueue; }
protected void setLoaded(boolean FLAG_LOADED) {
this.FLAG_LOADED = FLAG_LOADED;
}
public abstract T loader() throws Exception;
#Override
public boolean load() {
try {
resource=loader();
} catch (Exception e) { onException(e); }
if (isLoaded())
onLoadSuccess();
else
onLoadFail();
return isLoaded();
}
}
Specific SimpleLoadableImage
import javax.imageio.ImageIO;
import java.awt.*;
public class SimpleLoadableImage extends SimpleLoadableResource<Image>{
public static final SimpleLoadableImage LOGO1=new SimpleLoadableImage("1.jpg");
public static final SimpleLoadableImage LOGO2=new SimpleLoadableImage("2.jpg");
private final String path;
public SimpleLoadableImage(String path) {
this.path = path;
super.load();
}
#Override
public Image loader() throws Exception {
var res=ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(path));
setLoaded(true);
return res;
}
}
Approach 2
import javax.imageio.ImageIO;
import java.awt.*;
import java.util.ArrayDeque;
import java.util.Queue;
public enum SimpleLoadableImage_Enum {
LOGO1("1.jpg"),
LOGO("2.jpg");
private final String path;
Queue<Exception> exceptionQueue=new ArrayDeque<>();
private boolean FLAG_LOADED = false;
private Image resource;
private SimpleLoadableImage_Enum(String path){
this.path=path;
try {
resource=ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(path));
FLAG_LOADED=true;
} catch (Exception e) {
exceptionQueue.add(e);
}
}
public boolean isLoaded() { return FLAG_LOADED; }
public Image getResource() { return resource; }
public Queue<Exception> getExcpetions() { return exceptionQueue; }
}

CircularFifoQueue doesn't work inside the method, what to use instead?

I need to write the method which let to store always last 10 (the newset) elements and only 10.I have tried to use CircularFifoBuffer.It works perfectly usee like this:
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import org.apache.commons.collections4.queue.CircularFifoQueue;
public class Main {
public static void main(String[] args) {
Queue<Integer> fifo = new CircularFifoQueue<Integer>(3);
fifo.add(11);
fifo.add(22);
fifo.add(33);
fifo.add(44);
fifo.add(55);
System.out.println(fifo); // [33, 44, 55]
But it doesn;t work when used inside the method:
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import org.apache.commons.collections4.queue.CircularFifoQueue;
public class TV {
public int channelNumber = 11;
public int getChannelNumber() {
return channelNumber;
}
public void addToChannelsHistory(int channnelNumber) {
Queue<Integer> fifo = new CircularFifoQueue<Integer>(3);
fifo.add(channnelNumber);
System.out.print(fifo);
}
}
Could you help what to use instead?
You have to use the notion of attribute, a member of your class which is a data, not a method:
public class TV {
private final Queue<Integer> fifo = new CircularFifoQueue<Integer>(3);
public Queue<Integer> getChannelNumbers() {
return fifo;
}
public Integer getChannelNumber() {
return fifo.isEmpty() ? null : fifo.peek();
}
public void addToChannelsHistory(int channnelNumber) {
fifo.add(channnelNumber);
}
public String toString() {
return fifo.toString();
}
public static void main( String[] args ) {
TV tv = new TV();
tv.addToChannelsHistory(11);
tv.addToChannelsHistory(22);
tv.addToChannelsHistory(33);
tv.addToChannelsHistory(44);
tv.addToChannelsHistory(55);
System.out.print( tv );
}
}
Forgive me if I've misunderstood, but as far as I can tell by copying this locally, this works. However, in a Java program, the main method is the entry point into the program. If you aren't instantiating your TV class in the main method, the addToChannelHistory method will never get run. For instance, this works for me:
public class TV {
public int channelNumber = 11;
public int getChannelNumber() {
return channelNumber;
}
public void addToChannelsHistory(int channnelNumber) {
Queue<Integer> fifo = new CircularFifoQueue<Integer>(3);
fifo.add(channnelNumber);
System.out.print(fifo);
}
public static void main(String[] args) {
TV tv = new TV();
tv.addToChannelsHistory(11);
tv.addToChannelsHistory(22);
tv.addToChannelsHistory(33);
tv.addToChannelsHistory(44);
tv.addToChannelsHistory(55);
}
}
Running that program should print out 33 to the console.

Data Structures Containing Polymorphic Method References

The line
associations.put("test1",B::setBeta);
below does not compile. I'm not clear why it won't work since B extends A. Is there a way to make this work? I'm trying to build a map of method references from an inheritance family.
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public enum Test {
ENUM0() {
#Override
public void init() {
associations.put("test0",A::setAlpha);
}
},
ENUM1() {
#Override
public void init() {
associations.put("test1",B::setBeta);
}
};
public abstract void init();
Map<String, BiConsumer<? extends A, String>> associations = new HashMap<>();
}
class A {
public String getAlpha() {
return alpha;
}
public void setAlpha(String alpha) {
this.alpha = alpha;
}
String alpha;
}
class B extends A {
public String getBeta() {
return beta;
}
public void setBeta(String beta) {
this.beta = beta;
}
String beta;
}
This seems like a curious case of type inference, explicitly tagging the expression resolves the compilation errors:
associations.put("test1", (BiConsumer<B, String>) B::setBeta);

How would I dynamically select a certain Object depending on user input then use other Methods to alter that particular Object?

Hi I'm currently writing a Virtual Pet style app, I have created a Class for the base of the pets called Pet.class
package com.grim.droidchi;
public class Pet {
public static int Health = 100;
public static int Happiness = 10;
public static int Level = 1;
public static int Hunger = 0;
public static int Exp = 0;
public static String Name;
public static Boolean isAlive = true;
public static Boolean isSick = false;
public Pet(int startHealth, int startLevel, int startHunger) {
}
}
And a 'Dog' class which extends the base pet class
package com.grim.droidchi;
public class Dog extends Pet {
public Dog(int startHealth, int startLevel, int startHunger) {
super(startHealth, startLevel, startHunger);
}
}
every 30 minutes An AlarmManager triggers my Gameloop.class
package com.grim.droidchi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.util.Log;
import android.widget.TextView;
public class Gameloop extends BroadcastReceiver {
MediaPlayer mp = null;
private static final String TAG = "VPET";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Loop running");
if (Pet.isAlive == true) {
Pet.Hunger = Pet.Hunger + 1;
Pet.Exp = Pet.Exp + 2;
Pet.Happiness = Pet.Happiness - 1;
mp = MediaPlayer.create(context, R.raw.beep);
mp.start();
petLevel();
petStatus();
randomEncounters();
} else {
}
}
private void petLevel() {
}
private void randomEncounters() {
if (Math.random() < 0.20) {
Pet.isSick = true;
}
}
private void petStatus() {
if (Pet.Hunger > 7) {
Pet.isAlive = false;
}
}
}
How do I get what's done in the Gameloop to be dependent on which particular pet the user decides to pick? (Assuming I create more pet types. )
P.S Also as a siden ote to this question, What is the best way to implement keeping the UI always up-to-date from the Gameloop class?
Any help will be appreciated. I am still learning about Java and Android sometimes its hard to find a specific/question answer even a midst of all good learning materials.
Thank you.
For type of pet:
if (pet instanceof Dog)
To update the UI, define an Interface. See my answer here:
Accessing R from a BroadcastReceiver
It's for a different scenario but easily adapted.
[EDIT]
instanceof is often a sign of a poor design.
Try this:
public void feed(Pet pet, int foodAmount){
pet.feed(foodAmount);
}
public class Pet{
}
public class Dog extends Pet{
public void feed(int foodAmount){
// feed like a dog
}
}
public class Cat extends Pet{
public void feed(int foodAmount){
// feed like a cat
}
}
Then just use pet.feed(10);

Categories

Resources