Repast Java: scheduling agent and global behaviors in a structural way - agent-based-modeling

I am previously working with Netlogo for years and I am very much getting used to developing the agent-based model based on a set of procedures. An example of supply chain simulation model structure looks like below:
;;the main simulation loop
#ScheduledMethod(start = 1, interval = 1)
public void step() {
place-order-to-suppliers() ;;procedures involving customer agent behaviors (a number of methods)
receive-shipment-from-suppliers() ;;procedures involving both supplier and customer agents and their behaviors (methods)
receive-order-from-customers() ;;procedures involving supplier agent only
ship-order-to-customers() ;;procedures involving supplier agent only
summarize() ;;procedures involving global summary behaviors independent of any agents, as well as local summary behaviors per each type of agents (customer and supplier)
}
The above structure is very useful and intuitive to develop a simulation model. We first cut the simulation world into several key parts (procedures), within which we further develop specific methods related to associated agents and behaviors. The essential part is to establish a higher level procedure (like a package) which could be useful to integrate (pack) the different types of agents and their behaviors/interactions altogether in one place and execute the model in a desired sequential order based on these procedures.
Are there any hints/examples to implement such modular modelling strategy in Repast?
Update:
Below is a simple model I wrote which is about how boy and girl interacts in the party (the full reference can be found https://ccl.northwestern.edu/netlogo/models/Party). Below is the code for Boy Class (the girl is the same so not pasted again).
package party;
import java.util.ArrayList;
import java.util.List;
import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.parameter.Parameters;
import repast.simphony.query.PropertyGreaterThan;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.grid.Grid;
import repast.simphony.space.grid.GridPoint;
import repast.simphony.util.ContextUtils;
public class Boy {
private ContinuousSpace<Object> space;
private Grid<Object> grid;
private boolean happy;
private int id, x, y,tolerance;
private boolean over;
Boy (Grid<Object> grid, int id, int x, int y) {
this.grid = grid;
this.id = id;
this.x = x;
this.y = y;
Parameters p = RunEnvironment.getInstance().getParameters();
int get_tolerance = (Integer) p.getValue("tolerance");
this.tolerance = get_tolerance;
}
// #ScheduledMethod(start = 1, interval = 1,shuffle=true)
// public void step() {
// relocation();
// update_happiness();
// endRun();
//
// }
public void endRun( ) {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
public void update_happiness() {
over = false;
Context<Object> context = ContextUtils.getContext(this);
Parameters p = RunEnvironment.getInstance().getParameters();
int tolerance = (Integer) p.getValue("tolerance");
GridPoint pt = grid.getLocation(this);
int my_x = this.getX();
int boy_count = 0;
int girl_count = 0;
Query<Object> query = new PropertyEquals<Object>(context, "x", my_x);
for (Object o : query.query()) {
if (o instanceof Boy) {
boy_count++;
}
else {
girl_count++;
}
}
int total = boy_count + girl_count;
double ratio = (girl_count / (double)total);
// System.out.println((girl_count / (double)total));
if (ratio <= (tolerance / (double)100)) {
happy = true;
// System.out.println("yes");
}
else {
happy = false;
// System.out.println("no");
}
over = true;
// System.out.println(over);
}
public void relocation() {
if (!happy) {
List<Integer> x_list = new ArrayList<Integer>();
for (int i = 5; i <= 50; i = i + 5) {
x_list.add(i);
}
int index = RandomHelper.nextIntFromTo(0, 9);
int group_x = x_list.get(index);
while(group_x == this.getX()){
index = RandomHelper.nextIntFromTo(0, 9);
group_x = x_list.get(index);
}
int group_y = 35;
while (grid.getObjectAt(group_x,group_y) != null) {
group_y = group_y + 1;
}
this.setX(group_x);
grid.moveTo(this, group_x,group_y);
}
}
public int getTolerance() {
return tolerance;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public int getID() {
return id;
}
public boolean getHappy() {
return happy;
}
public boolean getOver() {
return over;
}
public void setTolerance(int tolerance) {
this.tolerance = tolerance;
}
}
---------------------------------------------------------------------------------
The running of above code can follow the standard Repast Annotated scheduling method. However, since I want do some integration of the different agents and their methods altogether to allow the creation of bigger procedures(methods), I managed to create a Global Scheduler Agent Class to manage this modeling strategy. Below is the code:
package party;
import java.util.ArrayList;
import java.util.List;
import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduleParameters;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.engine.schedule.Schedule;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.util.ContextUtils;
import repast.simphony.util.collections.IndexedIterable;
public class Global_Scheduler {
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void updateHappiness() {
Context<Object> context = ContextUtils.getContext(this);
IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);
for (Object b: boy_agents) {
((Boy) b).update_happiness();
}
for (Object g: girl_agents) {
((Girl) g).update_happiness();
}
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void relocate() {
Context<Object> context = ContextUtils.getContext(this);
IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);
for (Object b: boy_agents) {
((Boy) b).relocation();
}
for (Object g: girl_agents) {
((Girl) g).relocation();
}
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void summary() {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int total_count = 0;
int boy_count = 0;
int girl_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
total_count ++;
boy_count++;
}
if (o instanceof Girl) {
total_count ++;
girl_count++;
}
}
System.out.println("Total happy person: " + total_count);
System.out.println("Total happy boys: " + boy_count);
System.out.println("Total happy girls: " + girl_count);
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void endRun( ) {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
}
The above code using the global scheduler agent to run the model is working fine and the outcome should behave the same. However, I am not sure if the execution of the model really follows the sequence (i.e. update_happiness() -> relocate() -> summary() -> end_run(). I would also like to know if there are better and simpler way to achieve such modeling strategy?

The code example you provided will almost work exactly as-is in a repast model agent - you simply need to change the comment line prefix ;; to // and implement the methods place-order-to-suppliers(), etc in the agent class. The agent behavior structure in a typical ABM follows this exact structure. A general 'step' method that combines the various sub-steps according to the desired order of execution.
There are a number of behavior scheduling approaches outlined in the Repast FAQ: https://repast.github.io/docs/RepastReference/RepastReference.html#_scheduling . Scheduling via annotation as you've provided in the example will repeat the behavior on a regular interval, or at a single time step. You can also schedule dynamically in the model by directly putting an action on the Repast schedule. This type of scheduling is good for event-based behavior, like scheduling a one-time behavior that is triggered by some other event in the model. You can also schedule with #Watch annotations that trigger behaviors based on a set of conditions specified in the annotation.

You can use priorities in your #ScheduledMethod annotations, e.g.,
#ScheduledMethod(start = 1, interval = 1, shuffle=true, priority=1)
where a higher priority will run before a lower priority.

Related

dynamic programming grid problem approach solving using BFS

We have an NxM grid, grid have one element named Bob. Bob can travel diagonally blocks only. The grid has some blocked blocks on which Bob can not travel. Write a function that returns on how many possible positions Bob can move. Solve this problem using BFS and submit the executable code in any programming language. In the following image example, Bob's positioning is at 9,3, and it can visit the places where Y is marked; hence your method should return 30.
Anybody any pseudocode or approach on how to solve this using BFS
Following solution is modified version of solution given by ( https://stackoverflow.com/users/10987431/dominicm00 ) on problem ( Using BFS to find number of possible paths for an object on a grid )
Map.java:
import java.awt.*;
public class Map {
public final int width;
public final int height;
private final Cell[][] cells;
private final Move[] moves;
private Point startPoint;
public Map(int[][] mapData) {
this.width = mapData[0].length;
this.height = mapData.length;
cells = new Cell[height][width];
// define valid movements
moves = new Move[]{
new Move(1, 1),
new Move(-1, 1),
new Move(1, -1),
new Move(-1, -1)
};
generateCells(mapData);
}
public Point getStartPoint() {
return startPoint;
}
public void setStartPoint(Point p) {
if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");
startPoint.setLocation(p);
}
public Cell getStartCell() {
return getCellAtPoint(getStartPoint());
}
public Cell getCellAtPoint(Point p) {
if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");
return cells[p.y][p.x];
}
private void generateCells(int[][] mapData) {
boolean foundStart = false;
for (int i = 0; i < mapData.length; i++) {
for (int j = 0; j < mapData[i].length; j++) {
/*
0 = empty space
1 = wall
2 = starting point
*/
if (mapData[i][j] == 2) {
if (foundStart) throw new IllegalArgumentException("Cannot have more than one start position");
foundStart = true;
startPoint = new Point(j, i);
} else if (mapData[i][j] != 0 && mapData[i][j] != 1) {
throw new IllegalArgumentException("Map input data must contain only 0, 1, 2");
}
cells[i][j] = new Cell(j, i, mapData[i][j] == 1);
}
}
if (!foundStart) throw new IllegalArgumentException("No start point in map data");
// Add all cells adjacencies based on up, down, left, right movement
generateAdj();
}
private void generateAdj() {
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
for (Move move : moves) {
Point p2 = new Point(j + move.getX(), i + move.getY());
if (isValidLocation(p2)) {
cells[i][j].addAdjCell(cells[p2.y][p2.x]);
}
}
}
}
}
private boolean isValidLocation(Point p) {
if (p == null) throw new IllegalArgumentException("Point cannot be null");
return (p.x >= 0 && p.y >= 0) && (p.y < cells.length && p.x < cells[p.y].length);
}
private class Move {
private int x;
private int y;
public Move(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}}
Cell.java:
import java.util.LinkedList;
public class Cell {
public final int x;
public final int y;
public final boolean isWall;
private final LinkedList<Cell> adjCells;
public Cell(int x, int y, boolean isWall) {
if (x < 0 || y < 0) throw new IllegalArgumentException("x, y must be greater than 0");
this.x = x;
this.y = y;
this.isWall = isWall;
adjCells = new LinkedList<>();
}
public void addAdjCell(Cell c) {
if (c == null) throw new IllegalArgumentException("Cell cannot be null");
adjCells.add(c);
}
public LinkedList<Cell> getAdjCells() {
return adjCells;
}}
MapHelper.java:
class MapHelper {
public static int countReachableCells(Map map) {
if (map == null) throw new IllegalArgumentException("Arguments cannot be null");
boolean[][] visited = new boolean[map.height][map.width];
// subtract one to exclude starting point
return dfs(map.getStartCell(), visited) - 1;
}
private static int dfs(Cell currentCell, boolean[][] visited) {
visited[currentCell.y][currentCell.x] = true;
int touchedCells = 0;
for (Cell adjCell : currentCell.getAdjCells()) {
if (!adjCell.isWall && !visited[adjCell.y][adjCell.x]) {
touchedCells += dfs(adjCell, visited);
}
}
return ++touchedCells;
}}
Grid.java:
public class Grid{
public static void main(String args[]){
int[][] gridData = {
{0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,2,1,0,0,0}}; //2 is bobs position, 1 is blocked, 0 can be visited
Map grid = new Map(gridData);
MapHelper solution = new MapHelper();
System.out.println(solution.countReachableCells(grid));
}}
For original answer of similar problem visit (Using BFS to find number of possible paths for an object on a grid) for original answer.

Repast: how to count the total number of agents satisfying the specific condition

Each agent has a private boolean variable "Happy?". how to count the agents with [Happy? = True]?
Is there a direct method available in repast? Or I have iterate through all agents and count them individually?
Update:
I have tried the global scheduling method: https://repast.github.io/docs/RepastReference/RepastReference.html#schedule-global
It's not working when I put below code using the #ScheduledMethods in the ContextBuilder.
grid.moveTo(this_girl, group_x,group_y);
}
}
return context;
}
#ScheduledMethod(start = 1, interval = 1, shuffle=true)
public void step () {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
System.out.println(end_count);
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
System.out.println(end_count);
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
}
It's working if I put above code in either boy agent or girl agent actions.
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void step() {
relocation();
update_happiness();
endRun();
}
public void endRun( ) {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
System.out.println(end_count);
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
System.out.println(end_count);
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
You can use a Query for this -- see the query answer to this question:
Repast: how to get a particular agent set based on the specific conditions?
You could also use the query method in a Context where you pass it a predicate where the predicate returns true if happy.
In both of these cases, you'll need an accessor method for the private boolean happy field -- e.g.
public boolean isHappy() {
return happy;
}
Also in both cases, the queries return an iterable over all the agents where happy is true, rather than a collection where you could take the size to get the count. So, you'll have to iterate through that and increment a counter.
Update:
Your current problem is with the scheduling. You can't easily schedule a method on the ConetextBuilder as its not really part of the model, but rather used to initialize it. The easiest way to schedule what you want is to schedule it explicitly in the ContextBuilder with something like:
RunEnvironment.getInstance().getCurrentSchedule().schedule(ScheduleParameters.createRepeating(1, 1, ScheduleParameters.LAST_PRIORITY), () -> {
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
System.out.println(end_count);
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count++;
}
if (o instanceof Girl) {
end_count++;
}
}
System.out.println(end_count);
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
});
The LAST_PRIORITY should insure that all the agent behavior will have taken place before the happiness count is polled.

Using scanner to read phrases

Hey StackOverflow Community,
So, I have this line of information from a txt file that I need to parse.
Here is an example lines:
-> date & time AC Power Insolation Temperature Wind Speed
-> mm/dd/yyyy hh:mm.ss kw W/m^2 deg F mph
Using a scanner.nextLine() gives me a String with a whole line in it, and then I pass this off into StringTokenizer, which then separates them into individual Strings using whitespace as a separator.
so for the first line it would break up into:
date
&
time
AC
Power
Insolation
etc...
I need things like "date & time" together, and "AC Power" together. Is there anyway I can specify this using a method already defined in StringTokenizer or Scanner? Or would I have to develop my own algorithm to do this?
Would you guys suggest I use some other form of parsing lines instead of Scanner? Or, is Scanner sufficient enough for my needs?
ejay
oh, this one was tricky, maybe you could build up some Trie structure with your tokens, i was bored and wrote a little class which solves your problem. Warning: it's a bit hacky, but was fun to implement.
The Trie class:
class Trie extends HashMap<String, Trie> {
private static final long serialVersionUID = 1L;
boolean end = false;
public void addToken(String strings) {
addToken(strings.split("\\s+"), 0);
}
private void addToken(String[] strings, int begin) {
if (begin == strings.length) {
end = true;
return;
}
String key = strings[begin];
Trie t = get(key);
if (t == null) {
t = new Trie();
put(key, t);
}
t.addToken(strings, begin + 1);
}
public List<String> tokenize(String data) {
String[] split = data.split("\\s+");
List<String> tokens = new ArrayList<String>();
int pos = 0;
while (pos < split.length) {
int tokenLength = getToken(split, pos, 0);
tokens.add(glue(split, pos, tokenLength));
pos += tokenLength;
}
return tokens;
}
public String glue(String[] parts, int pos, int length) {
StringBuilder sb = new StringBuilder();
sb.append(parts[pos]);
for (int i = pos + 1; i < pos + length; i++) {
sb.append(" ");
sb.append(parts[i]);
}
return sb.toString();
}
private int getToken(String[] tokens, int begin, int length) {
if (end) {
return length;
}
if (begin == tokens.length) {
return 1;
}
String key = tokens[begin];
Trie t = get(key);
if (t != null) {
return t.getToken(tokens, begin + 1, length + 1);
}
return 1;
}
}
and how to use it:
Trie t = new Trie();
t.addToken("AC Power");
t.addToken("date & time");
t.addToken("date & foo");
t.addToken("Speed & fun");
String data = "date & time AC Power Insolation Temperature Wind Speed";
List<String> tokens = t.tokenize(data);
for (String s : tokens) {
System.out.println(s);
}

How to sort the choices in a Wicket dropdown according to the current user locale?

I have the following issue:
a drop down with a list of elements
each of these elements has a fixed key, which is used by the IChoiceRenderer implementation to look up the localized version of the key (it's a standard, utility renderer implemented in a different package)
the list of localized keys is in a properties file, linked to the panel which instantiates the dropdown.
Is there an elegant/reusable solution to have the dropdown display its elements sorted alphabetically ?
In the end, I think using the render is probably the best approach. To make it reusable and efficient, I isolated this in a Behavior.
Here's the code:
import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.html.form.AbstractChoice;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static java.util.Arrays.sort;
/**
* This {#link Behavior} can only be used on {#link AbstractChoice} subclasses. It will sort the choices
* according to their "natural display order" (i.e. the natural order of the display values of the choices).
* This assumes that the display value implements {#link Comparable}. If this is not the case, you should
* provide a comparator for the display value. An instance of this class <em>cannot be shared</em> between components.
* Because the rendering can be costly, the sort-computation is done only once, by default,
* unless you set to <code>false</code> the <code>sortOnlyOnce</code> argument in the constructor.
*
* #author donckels (created on 2012-06-07)
*/
#SuppressWarnings({"unchecked"})
public class OrderedChoiceBehavior extends Behavior {
// ----- instance fields -----
private Comparator displayValueComparator;
private boolean sortOnlyOnce = true;
private boolean sorted;
// ----- constructors -----
public OrderedChoiceBehavior() {
}
public OrderedChoiceBehavior(boolean sortOnlyOnce) {
this.sortOnlyOnce = sortOnlyOnce;
}
public OrderedChoiceBehavior(boolean sortOnlyOnce, Comparator displayValueComparator) {
this.sortOnlyOnce = sortOnlyOnce;
this.displayValueComparator = displayValueComparator;
}
// ----- public methods -----
#Override
public void beforeRender(Component component) {
if (this.sorted && this.sortOnlyOnce) { return;}
AbstractChoice owner = (AbstractChoice) component;
IChoiceRenderer choiceRenderer = owner.getChoiceRenderer();
List choices = owner.getChoices();
// Temporary data structure: store the actual rendered value with its initial index
Object[][] displayValuesWithIndex = new Object[choices.size()][2];
for (int i = 0, valuesSize = choices.size(); i < valuesSize; i++) {
Object value = choices.get(i);
displayValuesWithIndex[i][0] = choiceRenderer.getDisplayValue(value);
displayValuesWithIndex[i][1] = i;
}
sort(displayValuesWithIndex, new DisplayValueWithIndexComparator());
List valuesCopy = new ArrayList(choices);
for (int i = 0, length = displayValuesWithIndex.length; i < length; i++) {
Object[] displayValueWithIndex = displayValuesWithIndex[i];
int originalIndex = (Integer) displayValueWithIndex[1];
choices.set(i, valuesCopy.get(originalIndex));
}
this.sorted = true;
}
public Comparator getDisplayValueComparator() {
return this.displayValueComparator;
}
// ----- inner classes -----
private class DisplayValueWithIndexComparator implements Comparator<Object[]> {
// ----- Comparator -----
public int compare(Object[] left, Object[] right) {
Object leftDisplayValue = left[0];
Object rightDisplayValue = right[0];
if (null == leftDisplayValue) { return -1;}
if (null == rightDisplayValue) { return 1;}
if (null == getDisplayValueComparator()) {
return ((Comparable) leftDisplayValue).compareTo(rightDisplayValue);
} else {
return getDisplayValueComparator().compare(leftDisplayValue, rightDisplayValue);
}
}
}
}
Use this extension of DropDownChoice using Java's Collator (basically locale sensitive sorting - take national characters and national sorting rules into account)
Code tested with Wicket 6 and Java 5+:
import java.text.Collator;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import org.apache.wicket.Session;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.model.IModel;
import com.google.common.collect.Ordering;
/**
* DropDownChoice which sort its choices (or in HTML's terminology select's options) according it's localized value
* and using current locale based Collator so it's sorted how it should be in particular language (ie. including national characters,
* using right order).
*
* #author Michal Bernhard michal#bernhard.cz 2013
*
* #param <T>
*/
public class OrderedDropDownChoice<T> extends DropDownChoice<T> {
public OrderedDropDownChoice(String id, IModel<? extends List<? extends T>> choices, IChoiceRenderer<? super T> renderer) {
super(id, choices, renderer);
}
public OrderedDropDownChoice(String id, IModel<? extends List<? extends T>> choices) {
super(id, choices);
}
public OrderedDropDownChoice(String id) {
super(id);
}
public OrderedDropDownChoice(
String id,
IModel<T> model,
IModel<? extends List<? extends T>> choices,
IChoiceRenderer<? super T> renderer) {
super(id, model, choices, renderer);
}
#Override
public List<? extends T> getChoices() {
List<? extends T> unsortedChoices = super.getChoices();
List<? extends T> sortedChoices = Ordering.from(displayValueAlphabeticComparator()).sortedCopy(unsortedChoices);
return sortedChoices;
}
private Collator localeBasedTertiaryCollator() {
Locale currentLocale = Session.get().getLocale();
Collator collator = Collator.getInstance(currentLocale);
collator.setStrength(Collator.TERTIARY);
return collator;
}
private Comparator<T> displayValueAlphabeticComparator() {
final IChoiceRenderer<? super T> renderer = getChoiceRenderer();
return new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
Object o1DisplayValue = renderer.getDisplayValue(o1);
Object o2DisplayValue = renderer.getDisplayValue(o2);
return localeBasedTertiaryCollator().compare(o1DisplayValue, o2DisplayValue);
}
};
}
}
Copied from https://gist.github.com/michalbcz/7236242
If you want a Wicket-based solution you can try to sort the list with something like that:
public class ChoiceRendererComparator<T> implements Comparator<T> {
private final IChoiceRenderer<T> renderer;
public ChoiceRendererComparator(IChoiceRenderer<T> renderer) {
this.renderer = renderer;
}
#SuppressWarnings("unchecked")
public int compare(T o1, T o2) {
return ((Comparable<Object>) renderer.getDisplayValue(o1)).compareTo(renderer.getDisplayValue(o2));
}
}
Usage:
List<Entity> list = ...
IChoiceRenderer<Entity> renderer = ...
Collections.sort(list, new ChoiceRendererComparator<Entity>(renderer));
DropDownChoice<Entity> dropdown = new DropDownChoice<Entity>("dropdown", list, renderer);
The solution we use at my company is Javascript based, we set a special css class on the dropdowns we want to be sorted, and a little jQuery trick does the sort.
Facing the same problem, I moved part of the localisation data from my XMLs to the database, implemented a matching Resolver and was able to use the localized Strings for sorting.
The table design and hibernate configuration was kind of tricky and is described here: Hibernate #ElementCollection - Better solution needed.
The ResourceLoader is along these lines:
public class DataBaseStringResourceLoader extends ComponentStringResourceLoader {
private static final transient Logger logger = Logger
.getLogger(DataBaseStringResourceLoader.class);
#Inject
private ISomeDAO someDao;
#Inject
private IOtherDao otherDao;
#Inject
private IThisDAO thisDao;
#Inject
private IThatDAO thatDao;
#Override
public String loadStringResource(Class<?> clazz, String key, Locale locale,
String style, String variation) {
String resource = loadFromDB(key, new Locale(locale.getLanguage()));
if (resource == null) {
resource = super.loadStringResource(clazz, key, locale, style, variation);
}
return resource;
}
private String loadFromDB(String key, Locale locale) {
String resource = null;
if (locale.getLanguage() != Locale.GERMAN.getLanguage()
&& locale.getLanguage() != Locale.ENGLISH.getLanguage()) {
locale = Locale.ENGLISH;
}
if (key.startsWith("some") || key.startsWith("other")
|| key.startsWith("this") || key.startsWith("that")) {
Integer id = Integer.valueOf(key.substring(key.indexOf(".") + 1));
ILocalizedObject master;
if (key.startsWith("some")) {
master = someDao.findById(id);
} else if (key.startsWith("other")) {
master = otherDao.findById(id);
} else if (key.startsWith("this") ){
master = thisDao.findById(id);
} else {
master = thatDao.findById(id);
}
if (master != null && master.getNames().get(locale) != null) {
resource = master.getNames().get(locale).getName();
} else if (master == null) {
logger.debug("For key " + key + " there is no master.");
}
}
return resource;
}
[...]
}

how to find the size of object stored (in bytes or kb,mb) on persistence store in blackberry

I am trying to find the size of the object that I store on persistence store . I have programatically found out the size of object as shown in code but I can not find out the size of this object when it is stored on persistence store.
Does data get compressed automatically when it is comitted to store.
I m using Memory.getFlashStats().getFree(); to get the free size of persistence store before and after commitnig the object to store and the difference between the two values should be equal to the size of object that i have calculated.
please see the code
package Bean;
import java.util.Enumeration;
import java.util.Vector;
import net.rim.device.api.system.Memory;
import net.rim.device.api.system.MemoryStats;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.container.MainScreen;
import bean.UserCredentials;
public class MyStoreScreen extends MainScreen implements FieldChangeListener
{
private int nObjectSize;
static final long PERSISTENT_STORE_DEMO_ID = 0x42c16456ab0b5eabL;
private static PersistentObject oPersistenStore;
private int nFreePersistenceInStarting=Memory.getPersistentStats().getFree();
private int nFreePersistenceAtEnd;
ButtonField oCalculateMemButton ;
private MenuItem saveItem = new MenuItem("Save ", 110, 10)
{
public void run()
{
Dialog.alert("initially free memory ----------------------"+nFreePersistenceInStarting);
oPersistenStore = PersistentStore.getPersistentObject(PERSISTENT_STORE_DEMO_ID);
Vector storeVector = (Vector)oPersistenStore.getContents();
Vector userinfo ;
int size = (storeVector == null) ? 0 : storeVector.size();
if(size == 0)
{
userinfo = new Vector();
}
else
{
userinfo = storeVector;
}
UserCredentials oUserCredentials = new UserCredentials("akanksha","chandra",1,3434.3434,343545646);
for(int i =0;i<=100;i++)
{
userinfo.addElement(oUserCredentials);
}
nObjectSize= fnCalculateSizeOfObject(userinfo);
Dialog.alert("size of object is "+ nObjectSize);
synchronized(oPersistenStore)
{
oPersistenStore.setContents(userinfo);
oPersistenStore.commit();
}
}
};
private MenuItem getItem = new MenuItem( "Get item", 110, 11 )
{
public void run()
{
oPersistenStore = PersistentStore.getPersistentObject(PERSISTENT_STORE_DEMO_ID);
synchronized(oPersistenStore)
{
Vector arrCredential = (Vector)oPersistenStore.getContents();
if(arrCredential != null)
{
String dataContents = "";
int nSize = (arrCredential == null) ? 0 : arrCredential.size();
if(nSize != 0)
{
for (int i = 0; i < nSize; i++)
{
UserCredentials oUserCredentials = (UserCredentials)arrCredential.elementAt(i);
dataContents+="\n size of vector is "+nSize+ " username : "+oUserCredentials.getStrUsername()+"\n password : "+oUserCredentials.getStrPassword();
dataContents += "\n\nUser sal : "+oUserCredentials.getdSalary();
dataContents += "\n amount : "+oUserCredentials.getlAmount();
dataContents += "\n s no "+oUserCredentials.getnSerialNo();
}
Dialog.alert(dataContents);
}
else
{
Dialog.alert("Zero Elements ");
}
}
else
{
Dialog.alert("No contents ");
}
}
}
};
private MenuItem resetStoreItem = new MenuItem( "Delete Store", 110, 11 )
{
public void run()
{
int choice = Dialog.ask(Dialog.D_OK_CANCEL, "Do you want to delete ?");
if(choice == Dialog.D_OK)
{
// oPersistenStore = PersistentStore.getPersistentObject(PERSISTENT_STORE_DEMO_ID);
PersistentStore.destroyPersistentObject(PERSISTENT_STORE_DEMO_ID);
}
else
{
}
}
};
private MenuItem CalculateTotalFlashUsed = new MenuItem("calculate used flash size ", 0, 7)
{
public void run()
{
Dialog.alert("used size of Persistence Store is "+fnUsedPersistenceSize());
};
};
public MyStoreScreen()
{
oCalculateMemButton = new ButtonField("calculate free flash memory in starting", ButtonField.CONSUME_CLICK);
oCalculateMemButton.setChangeListener(this);
this.add(oCalculateMemButton);
this.addMenuItem(saveItem);
this.addMenuItem(getItem);
this.addMenuItem(resetStoreItem);
this.addMenuItem(CalculateTotalFlashUsed);
oPersistenStore = PersistentStore.getPersistentObject(PERSISTENT_STORE_DEMO_ID);
}
public void fieldChanged(Field field, int context)
{
if(field ==oCalculateMemButton)
{
// nFreeFlashInStarting =Memory.getFlashTotal();
// nFreeFlashInStarting =Memory.getFlashStats().getFree();
// nFreeFlashAtEnd =Memory.getFlashStats().getFree();
// String message = "total flash is Memory.getFlashStats().getAllocated(); "+nFreeFlashInStarting+" Memory.getFlashTotal() is : "+Memory.getFlashTotal();
String message = "total free flash memory in starting is :"+ nFreePersistenceInStarting;
Dialog.alert(message);
}
}
private int fnCalculateSizeOfObject(Vector userInfo )
{
int nSize = 0;
Enumeration oEnumeration = userInfo.elements();
while(oEnumeration.hasMoreElements())
{
UserCredentials oUserCredentials = (UserCredentials) oEnumeration.nextElement();
String UserName = oUserCredentials.getStrUsername();
String password = oUserCredentials.getStrPassword();
int nSerialNo = oUserCredentials.getnSerialNo();
double dSalary = oUserCredentials.getdSalary();
long lAmount = oUserCredentials.getlAmount();
nSize+= 4+8+8+fnCalculateSizeOfString(UserName)+fnCalculateSizeOfString(password);
}
return nSize;
}
private int fnCalculateSizeOfString(String strInputString)
{
//convert String to char array
char[] characterArray = strInputString.toCharArray();
int nlength = characterArray.length;
return nlength;
}
public int fnUsedPersistenceSize()
{
nFreePersistenceAtEnd = Memory.getPersistentStats().getFree();
int nUsedPersistenceMemory = nFreePersistenceInStarting -nFreePersistenceAtEnd;
return nUsedPersistenceMemory;
}
}
Memory.getFlashStats().getFree() is not that accurate, you can see it when measuring storage of the same object several times - values may be different every time.
The best way to measure object size is to calculate its fields size (what you actually doing).

Resources