ASP.NET/SQL Function not storing all values in a loop - asp.net

So I'm creating a monopoly game, and I've got two functions which read/write information about the game to/from a database so it can be retrieved between postbacks. I also have a start game function which initialises everything to 0 and then calls the writeToDatabase(). createArrays() just creates a list of players/squares, squares have been removed as they'not relevant.
The problem I'm having is I believe it is only storing some of the values within the loop. When the start game function is called it correctly sets the players positions to 0, and their money to 1500, however for some reason when reading from the database again the 4th players details immediately go back to what they were during the previous session.
private void readFromDatabase()
{
createArrays();
for (int i = 0; i < players.Count(); i++)
{
players[i].SetID(Convert.ToInt32(players_table.GetRow(i)["ID"]));
players[i].SetPosition(Convert.ToInt32(players_table.GetRow(i)["position"]));
players[i].SetMoney(Convert.ToInt32(players_table.GetRow(i)["money"]));
players[i].SetInJail(Convert.ToBoolean(players_table.GetRow(i)["isInJail"]));
players[i].SetIsBankrupt(Convert.ToBoolean(players_table.GetRow(i)["isBankrupt"]));
}
currentPlayerID = Convert.ToInt32(gameinfo_table.GetRow(0)["CurrentPlayerID"]);
currentSquareID = Convert.ToInt32(gameinfo_table.GetRow(0)["CurrentSquareID"]);
freeParkingAmount = Convert.ToInt32(gameinfo_table.GetRow(0)["FreeParkingAmount"]);
currentPlayer = players[currentPlayerID];
CurrentSquare = squares[currentSquareID];
}
private void writeToDatabase()
{
CurrentSquare = squares[currentSquareID];
for (int i = 0; i < players.Count(); i++)
{
SQLDatabase.DatabaseRow prow = players_table.GetRow(players[i].GetID());
prow["ID"] = players[i].GetID().ToString();
prow["position"] = players[i].GetPosition().ToString();
prow["money"] = players[i].GetMoney().ToString();
prow["isInJail"] = players[i].IsInJail().ToString();
prow["isBankrupt"] = players[i].IsBankrupt().ToString();
players_table.Update(prow);
}
SQLDatabase.DatabaseRow girow = gameinfo_table.GetRow(0);
girow["CurrentPlayerID"] = currentPlayerID.ToString();
girow["CurrentSquareID"] = CurrentSquare.GetID().ToString();
girow["FreeParkingAmount"] = freeParkingAmount.ToString();
gameinfo_table.Update(girow);
}
private void startGame()
{
createArrays();
currentPlayerID = 0;
currentPlayer = players[0];
CurrentSquare = squares[0];
writeToDatabase();
}
private void createArrays()
{
for (int i = 0; i < 4; i++)
{
Player player = new Player(i);
players.Add(player);
}
}
I really can't work out why this is happening, as when it creates the player array it loops through 4 times, therefore creating 4 brand new players, and immediately overwriting the details in the database. It just seems odd it works perfectly fine for the first 3 players but the 4ths details don't seem to change. Any help would be greatly appreciated, I'm sure it something simple but I have spent hours on this and haven't got anywhere.

Related

Connect All Siblings in Binary Tree Using Pointers

Problem: https://www.educative.io/m/connect-all-siblings
I'm attempting to connect all sibling nodes by creating a dummy node and set it's next to the node that we're currently visiting by using a next pointer, but after executing the code:
public static void populate_sibling_pointers(BinaryTreeNode root) {
if(root == null) return;
Queue<BinaryTreeNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
int size = q.size();
BinaryTreeNode dummy = new BinaryTreeNode(0);
for(int i = 0; i < size; i++){
BinaryTreeNode cur = q.poll();
dummy.next = cur;
dummy = dummy.next;
if(cur.left!=null){
q.offer(cur.left);
}
if(cur.right!=null){
q.offer(cur.right);
}
}
}
}
I still failed to pass some test but I'm not sure what I did wrong here.
Any help is appreciated!
Two issues:
You should create a new dummy node only once. By creating a new one at every iteration of the while loop, you break the chain of next references. So the creation of that node should happen before the while loop.
The last node in the next chain should have its next set to null.
Here is the corrected code:
class connectSiblings{
public static void populate_sibling_pointers(BinaryTreeNode root) {
if(root == null) return;
Queue<BinaryTreeNode> q = new LinkedList<>();
q.offer(root);
BinaryTreeNode dummy = new BinaryTreeNode(0);
while(!q.isEmpty()){
int size = q.size();
for(int i = 0; i < size; i++){
BinaryTreeNode cur = q.poll();
dummy.next = cur;
dummy = dummy.next;
if(cur.left!=null){
q.offer(cur.left);
}
if(cur.right!=null){
q.offer(cur.right);
}
}
}
dummy.next = null;
}
}
You can further optimise this code by replacing the use of the LinkedList with the actual linked list you are building with the next references: when a layer of the tree has been correctly wired with next references, you can iterate that section of that linked list to find and wire the nodes of the next layer, which then can serve as linked list for the next layer, ...etc.

observableList doesn't show rows in a loop for?

I have a problem where I am hanging out several days to display the lines in an observablelist in a loop! Yet the code function very well in console! Any help would be welcome.
private void showActivitiesDriver() throws IOException {
Path path = Paths.get("Download/Cards/F__100000015956101711071539.C1B");
byte[] data = Files.readAllBytes(path);
dataFileCard = new FileBlockTGD(data);
w = new WrapperActivityChangeInfo(dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i), dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i).getActivityChangeInfo().get(j));
for (i = 0; i < dataFileCard.getDriver_activity_data().getActivityDailyRecords().size(); i++) {
w.setTheDateTime(dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i).getActivityRecordDate().toString());
System.out.println(w.getTheDateTime());
dateActivitiesColumn.setCellValueFactory(cellData -> new SimpleStringProperty(
cellData.getValue().getTheDateTime()));
/*
dateActivitiesColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(
DateUtil.parseDateToString(cellData.getValue().getActivityRecordDate())));
*/
for (j = 0; j < dataFileCard.getDriver_activity_data().getActivityDailyRecords().get(i).
getActivityChangeInfo().size(); j++) {
driverActivitiesColumn.setCellValueFactory(cellData -> new SimpleStringProperty(
cellData.getValue().getTheActivity()));
WrapperActivityChangeInfoList = FXCollections.observableArrayList();
WrapperActivityChangeInfoList.add(new WrapperActivityChangeInfo(dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i), dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i).getActivityChangeInfo().get(j)));
System.out.println(WrapperActivityChangeInfoList);
}
}
// Set data to tableview
activitiesDriverTableView.setItems(WrapperActivityChangeInfoList);
//System.out.println(WrapperActivityChangeInfoList.toString());
}
}
I expect to see all the lines, but just one, yet the code works nice in console.
You create a new ObservableList (initially empty) in every iteration of the inner loop. This way after the add invocation you've got a list containing a single list. One of those lists is assigned to the TableView in the end. Should see a sequence of dates followed by a number of WrapperActivityChangeInfo.toString results surrounded by [] in the output indicating that you're printing multiple lists.
Furthermore there is no point in assigning a cellValueFactory in every iteration of the loop.
You need to move the list creation outside of the loops.:
...
WrapperActivityChangeInfoList = FXCollections.observableArrayList();
driverActivitiesColumn.setCellValueFactory(cellData -> new SimpleStringProperty(
cellData.getValue().getTheActivity()));
for (i = 0; i < dataFileCard.getDriver_activity_data().getActivityDailyRecords().size(); i++) {
...
for (j = 0; j < dataFileCard.getDriver_activity_data().getActivityDailyRecords().get(i).
getActivityChangeInfo().size(); j++) {
WrapperActivityChangeInfoList.add(new WrapperActivityChangeInfo(dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i), dataFileCard.getDriver_activity_data()
.getActivityDailyRecords().get(i).getActivityChangeInfo().get(j)));
System.out.println(WrapperActivityChangeInfoList);
}
}
activitiesDriverTableView.setItems(WrapperActivityChangeInfoList);

ConcurrentModificationException when reinserting a node JavaFX [duplicate]

We all know you can't do the following because of ConcurrentModificationException:
for (Object i : l) {
if (condition(i)) {
l.remove(i);
}
}
But this apparently works sometimes, but not always. Here's some specific code:
public static void main(String[] args) {
Collection<Integer> l = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
l.add(4);
l.add(5);
l.add(6);
}
for (int i : l) {
if (i == 5) {
l.remove(i);
}
}
System.out.println(l);
}
This, of course, results in:
Exception in thread "main" java.util.ConcurrentModificationException
Even though multiple threads aren't doing it. Anyway.
What's the best solution to this problem? How can I remove an item from the collection in a loop without throwing this exception?
I'm also using an arbitrary Collection here, not necessarily an ArrayList, so you can't rely on get.
Iterator.remove() is safe, you can use it like this:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Note that Iterator.remove() is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Source: docs.oracle > The Collection Interface
And similarly, if you have a ListIterator and want to add items, you can use ListIterator#add, for the same reason you can use Iterator#remove — it's designed to allow it.
In your case you tried to remove from a list, but the same restriction applies if trying to put into a Map while iterating its content.
This works:
Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
if (iter.next() == 5) {
iter.remove();
}
}
I assumed that since a foreach loop is syntactic sugar for iterating, using an iterator wouldn't help... but it gives you this .remove() functionality.
With Java 8 you can use the new removeIf method. Applied to your example:
Collection<Integer> coll = new ArrayList<>();
//populate
coll.removeIf(i -> i == 5);
Since the question has been already answered i.e. the best way is to use the remove method of the iterator object, I would go into the specifics of the place where the error "java.util.ConcurrentModificationException" is thrown.
Every collection class has a private class which implements the Iterator interface and provides methods like next(), remove() and hasNext().
The code for next looks something like this...
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
Here the method checkForComodification is implemented as
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
So, as you can see, if you explicitly try to remove an element from the collection. It results in modCount getting different from expectedModCount, resulting in the exception ConcurrentModificationException.
You can either use the iterator directly like you mentioned, or else keep a second collection and add each item you want to remove to the new collection, then removeAll at the end. This allows you to keep using the type-safety of the for-each loop at the cost of increased memory use and cpu time (shouldn't be a huge problem unless you have really, really big lists or a really old computer)
public static void main(String[] args)
{
Collection<Integer> l = new ArrayList<Integer>();
Collection<Integer> itemsToRemove = new ArrayList<>();
for (int i=0; i < 10; i++) {
l.add(Integer.of(4));
l.add(Integer.of(5));
l.add(Integer.of(6));
}
for (Integer i : l)
{
if (i.intValue() == 5) {
itemsToRemove.add(i);
}
}
l.removeAll(itemsToRemove);
System.out.println(l);
}
In such cases a common trick is (was?) to go backwards:
for(int i = l.size() - 1; i >= 0; i --) {
if (l.get(i) == 5) {
l.remove(i);
}
}
That said, I'm more than happy that you have better ways in Java 8, e.g. removeIf or filter on streams.
Same answer as Claudius with a for loop:
for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
Object object = it.next();
if (test) {
it.remove();
}
}
With Eclipse Collections, the method removeIf defined on MutableCollection will work:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
With Java 8 Lambda syntax this can be written as follows:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
The call to Predicates.cast() is necessary here because a default removeIf method was added on the java.util.Collection interface in Java 8.
Note: I am a committer for Eclipse Collections.
Make a copy of existing list and iterate over new copy.
for (String str : new ArrayList<String>(listOfStr))
{
listOfStr.remove(/* object reference or index */);
}
People are asserting one can't remove from a Collection being iterated by a foreach loop. I just wanted to point out that is technically incorrect and describe exactly (I know the OP's question is so advanced as to obviate knowing this) the code behind that assumption:
for (TouchableObj obj : untouchedSet) { // <--- This is where ConcurrentModificationException strikes
if (obj.isTouched()) {
untouchedSet.remove(obj);
touchedSt.add(obj);
break; // this is key to avoiding returning to the foreach
}
}
It isn't that you can't remove from the iterated Colletion rather that you can't then continue iteration once you do. Hence the break in the code above.
Apologies if this answer is a somewhat specialist use-case and more suited to the original thread I arrived here from, that one is marked as a duplicate (despite this thread appearing more nuanced) of this and locked.
With a traditional for loop
ArrayList<String> myArray = new ArrayList<>();
for (int i = 0; i < myArray.size(); ) {
String text = myArray.get(i);
if (someCondition(text))
myArray.remove(i);
else
i++;
}
ConcurrentHashMap or ConcurrentLinkedQueue or ConcurrentSkipListMap may be another option, because they will never throw any ConcurrentModificationException, even if you remove or add item.
Another way is to use a copy of your arrayList just for iteration:
List<Object> l = ...
List<Object> iterationList = ImmutableList.copyOf(l);
for (Object curr : iterationList) {
if (condition(curr)) {
l.remove(curr);
}
}
A ListIterator allows you to add or remove items in the list. Suppose you have a list of Car objects:
List<Car> cars = ArrayList<>();
// add cars here...
for (ListIterator<Car> carIterator = cars.listIterator(); carIterator.hasNext(); )
{
if (<some-condition>)
{
carIterator().remove()
}
else if (<some-other-condition>)
{
carIterator().add(aNewCar);
}
}
Now, You can remove with the following code
l.removeIf(current -> current == 5);
I know this question is too old to be about Java 8, but for those using Java 8 you can easily use removeIf():
Collection<Integer> l = new ArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
l.removeIf(i -> i.intValue() == 5);
Java Concurrent Modification Exception
Single thread
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
list.remove(it.next()); //throws ConcurrentModificationException
}
}
Solution: iterator remove() method
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
it.remove()
}
}
Multi thread
copy/convert and iterate over another one collection. For small collections
synchronize[About]
thread safe collection[About]
I have a suggestion for the problem above. No need of secondary list or any extra time. Please find an example which would do the same stuff but in a different way.
//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
Object r = list.get(index);
if( state ) {
list.remove(index);
index = 0;
continue;
}
index += 1;
}
This would avoid the Concurrency Exception.
for (Integer i : l)
{
if (i.intValue() == 5){
itemsToRemove.add(i);
break;
}
}
The catch is the after removing the element from the list if you skip the internal iterator.next() call. it still works! Though I dont propose to write code like this it helps to understand the concept behind it :-)
Cheers!
Example of thread safe collection modification:
public class Example {
private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());
public void removeFromQueue() {
synchronized (queue) {
Iterator<String> iterator = queue.iterator();
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
}
}
I know this question assumes just a Collection, and not more specifically any List. But for those reading this question who are indeed working with a List reference, you can avoid ConcurrentModificationException with a while-loop (while modifying within it) instead if you want to avoid Iterator (either if you want to avoid it in general, or avoid it specifically to achieve a looping order different from start-to-end stopping at each element [which I believe is the only order Iterator itself can do]):
*Update: See comments below that clarify the analogous is also achievable with the traditional-for-loop.
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 1;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i++);
} else {
i += 2;
}
}
No ConcurrentModificationException from that code.
There we see looping not start at the beginning, and not stop at every element (which I believe Iterator itself can't do).
FWIW we also see get being called on list, which could not be done if its reference was just Collection (instead of the more specific List-type of Collection) - List interface includes get, but Collection interface does not. If not for that difference, then the list reference could instead be a Collection [and therefore technically this Answer would then be a direct Answer, instead of a tangential Answer].
FWIWW same code still works after modified to start at beginning at stop at every element (just like Iterator order):
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 0;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i);
} else {
++i;
}
}
One solution could be to rotate the list and remove the first element to avoid the ConcurrentModificationException or IndexOutOfBoundsException
int n = list.size();
for(int j=0;j<n;j++){
//you can also put a condition before remove
list.remove(0);
Collections.rotate(list, 1);
}
Collections.rotate(list, -1);
Try this one (removes all elements in the list that equal i):
for (Object i : l) {
if (condition(i)) {
l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
}
}
You can use a while loop.
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
if(entry.getKey().equals("test")) {
iterator.remove();
}
}
I ended up with this ConcurrentModificationException, while iterating the list using stream().map() method. However the for(:) did not throw the exception while iterating and modifying the the list.
Here is code snippet , if its of help to anyone:
here I'm iterating on a ArrayList<BuildEntity> , and modifying it using the list.remove(obj)
for(BuildEntity build : uniqueBuildEntities){
if(build!=null){
if(isBuildCrashedWithErrors(build)){
log.info("The following build crashed with errors , will not be persisted -> \n{}"
,build.getBuildUrl());
uniqueBuildEntities.remove(build);
if (uniqueBuildEntities.isEmpty()) return EMPTY_LIST;
}
}
}
if(uniqueBuildEntities.size()>0) {
dbEntries.addAll(uniqueBuildEntities);
}
If using HashMap, in newer versions of Java (8+) you can select each of 3 options:
public class UserProfileEntity {
private String Code;
private String mobileNumber;
private LocalDateTime inputDT;
// getters and setters here
}
HashMap<String, UserProfileEntity> upMap = new HashMap<>();
// remove by value
upMap.values().removeIf(value -> !value.getCode().contains("0005"));
// remove by key
upMap.keySet().removeIf(key -> key.contentEquals("testUser"));
// remove by entry / key + value
upMap.entrySet().removeIf(entry -> (entry.getKey().endsWith("admin") || entry.getValue().getInputDT().isBefore(LocalDateTime.now().minusMinutes(3)));
The best way (recommended) is use of java.util.concurrent package. By
using this package you can easily avoid this exception. Refer
Modified Code:
public static void main(String[] args) {
Collection<Integer> l = new CopyOnWriteArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
for (Integer i : l) {
if (i.intValue() == 5) {
l.remove(i);
}
}
System.out.println(l);
}
Iterators are not always helpful when another thread also modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for removal):
for (i in myList.size-1 downTo 0) {
myList.getOrNull(i)?.also {
if (it == 5)
myList.remove(it)
}
}
In case ArrayList:remove(int index)- if(index is last element's position) it avoids without System.arraycopy() and takes not time for this.
arraycopy time increases if(index decreases), by the way elements of list also decreases!
the best effective remove way is- removing its elements in descending order:
while(list.size()>0)list.remove(list.size()-1);//takes O(1)
while(list.size()>0)list.remove(0);//takes O(factorial(n))
//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
Integer integer = rdm.nextInt();
ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion
// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++)
if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion
// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--)
if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion
// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
for index loop: 1090 msec
for desc index: 519 msec---the best
for iterator: 1043 msec
you can also use Recursion
Recursion in java is a process in which a method calls itself continuously. A method in java that calls itself is called recursive method.

Depth first search orders

In depth first search, whenever a node is visited, we have to again take one of its adjacent nodes and the perform this process for this adjacent node. Depending on this , there may be multiple Depth first search orders. So , is there any way to count the total different DFS orders in a graph without applying the algorithm and manually calculating? Please give me the solution as soon as possible..
you can do it by counting the nodes at each level and keep multiplying every time going to the next level.
LinkedList<Node> connections = startNode.connections;
long totalOrders = 1L;
while(!connections.isEmpty()){
LinkedList<Node> newConnections = new LinkedList<>();
List<Integer> conSizes = new LinkedList()<>;
for (Node connection : connections) {
if(!connection.visited){
connection.visited = true;
newConnections.addAll(connection.connections);
totalOrders = totalOrders * factorial(connection.connections.size());
}
}
totalOrders = totalOrders * factorial(connections.size());
connections = newConnections;
}
System.out.println(totalOrders)
public static long factorial(int n) {
long fact = 1; // this will be the result
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}

Presentation of data from Mondrian OLAP engine + Olap4j

I'm doing a little bit of planning of an application that uses Mondrian OLAP engine with Olap4j and should present/display data to user. I understand all the back-end stuff, but I'm not sure how should I display the data in the view layer.
For example olap4j has a formatter that prints the SELECT nicely into the console.
How is the data that I get from olap4j displayed in view layer ? I just went through the olap4j API, and there doesn't seem to be anything for getting the result in a form that can be somehow further processed and displayed. Is this process part of the Pentaho solution ? So that otherwise it is really not easy to present data just from Mondrian OLAP engine and olap4j ?
EDIT: I'm used to traditionally get some data from a database into my DTO and display it in view layer. But how do I create DTOs for such a complicated result set ?
You can create your own view layer it's just a little bit tricky.
OlapStatement.executeOlapQuery() returns a CellSet, you will have to work with that. Also read the specifications, it's a good source of information.
Here is an example, that creates List<List<MyCell>> (not the best representation but it's easy to undarstand how it works). This creates a table similar to http://www.olap4j.org/api/index.html?org/olap4j/Position.html (without the "Gender" and "Product" labels).
private final static int COLUMNS = 0; //see Cellset javadoc
private final static int ROWS= 1; //see Cellset javadoc
/**
* Outer list: rows, inner list: elements in a row
*/
private List<List<MyCell>> getListFromCellSet(CellSet cellSet) {
List<List<MyCell>> toReturn= new ArrayList<List<MyCell>>();
//Column header
//See http://www.olap4j.org/api/index.html?org/olap4j/Position.html on how Position works, it helps a lot
//Every position will be a column in the header
for (Position pos : cellSet.getAxes().get(COLUMNS).getPositions()) {
for (int i = 0; i < pos.getMembers().size(); i++) {
if (toReturn.size() <= i) {
toReturn.add(i, new ArrayList<MyCell>());
}
Member m = pos.getMembers().get(i);
MyCell myCell = new MyCell(m); //use m.getCaption() for display
toReturn.get(i).add(myCell );
}
}
//Put empty elements to the beginning of the list, so there will be place for the rows header
if (cellSet.getAxes().get(ROWS).getPositions().size() > 0) {
for (int count=0; count < cellSet.getAxes().get(1).getPositions().get(0).getMembers().size(); count++) {
for (int i = 0; i < toReturn.size(); i++) {
toReturn.get(i).add(0, new MyCell());
}
}
}
//Content + row header
for(int i = 0; i < cellSet.getAxes().get(ROWS).getPositionCount(); i++) {
List<MyCell> row = new ArrayList<MyCell>();
//Header
for (org.olap4j.metadata.Member m : cellSet.getAxes().get(ROWS).getPositions().get(i).getMembers()) {
row.add(new MyCell(m));
}
//Content
for (int j = 0; j < cellSet.getAxes().get(COLUMNS).getPositionCount(); j++) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(j); //coordinte
list.add(i); //coordinte
row.add(new MyCell(cellSet.getCell(list))); //use cell.getFormattedValue() for display
}
toReturn.add(row);
}
return toReturn;
}
Create the MyCell class with these constructors:
public class MyCell {
...
public MyCell(){...}
public MyCell(Member m){...}
public MyCell(Cell c){...}
}
Don't forget to display the filters, use Cellset.getFilterAxis() for that.
You can also check the Rectangular formatter on SourceForge, but it's a bit longer.

Resources