The Artima Developer Community
Sponsored Link

Java Answers Forum
Discrete Event Simulation ( Proper Code)

5 replies on 1 page. Most recent reply: Mar 4, 2002 4:50 PM by Avin Sinanan

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 5 replies on 1 page
Avin Sinanan

Posts: 28
Nickname: avin
Registered: Feb, 2002

Discrete Event Simulation ( Proper Code) Posted: Feb 28, 2002 1:58 AM
Reply to this message Reply
Advertisement
Hello this question definite falls under Advanced.
I had to repost the question so that it was properly formatted. So I hope its looks better.
I've created the code to to the following. Its actually 3 classes of code. Any help would be appreciated.

here what it does and hereare the problems am having with it. Thanks again for reading:

Explanation of code

This code is for Discrete Event Simulation Techniques.
The code written creates a number of classes. Mainly it has the classes MS1 , MS2 and BTS1 and BTS2,

MS1 sends signals to BTS1 and MS2 sends signals to BTS2.
MS1and BTS1 has no connection to MS2 and MTS2.

How does signals go from MS1 to BTS1? It sends the signals to the class Signals. Signals then sends the signals o the class Queue which is like a cable or line in real life. Hence a cable called queueMStoBTS which is an object of class Queue connects MS1 and BTS1.

Now the for MS2 and BTS2 the same thing happens. Except the class Signals is replaced by SignalsMS2 and Queue is replaced by class QueueMS2 and its object is queueMS2toBTS2.

Now the only connection between MS1/BTS1 and MS2/BTS2 is that when the simulation is being performed signals running from MS1 to BTS1 and from MS2 toBTS2 occurs in parallel ( at the same time).

Now the Simulation is performed for 610 time units. And every 10 time units a sample of the amount of bytes ( signals are measured in bytes ) flowing through each queue is measured and that value is put into an array which stores the value. This is done for both MS1/BTS1 and MS2.BTS2.

In the end a graph is plotted with bytes at each 10 units time VS time.

Hence am suppose to get 2 graphs at the end. One for MS1/BTS1 and MS2/BTs2.

My problem is that the simulation does not run for the full 610 time units. It stop sometimes at 3 units. And the only time the graphs can be printed is when the time unit exceeds 600 time units and since the time units never exceeds 600 the graphs are never plotted.

Could you give it a look please. I worked really hard on this one.


import java.util.Random.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import DESimGraph.*;
import MS2.*;
 
class DESim extends Simulator
{
public static void main(String[] args) 
{
new DESim().start();
}
void start()
{
events = new ListQueue();
 
/* We have to create the Mobile station, Queue and BTS */
 
 
BTS1 bts1 = new BTS1();
Queue queueMStoBTS = new Queue();
Signals sig = new Signals() ;
MS1 ms1 = new MS1();
 
BTS2 bts2 = new BTS2();
QueueMS2 queueMS2toBTS2 = new QueueMS2();
SignalsMS2 sigMS2 = new SignalsMS2();
MS2 ms2 = new MS2();
 
/*After creating them we have to connect all of them*/
 
sig.queueMStoBTS = queueMStoBTS;
queueMStoBTS.bts1 = bts1;
bts1.queueMStoBTS = queueMStoBTS;
 
sigMS2.queueMS2toBTS2 =queueMS2toBTS2 ;
queueMS2toBTS2.bts2 = bts2 ;
bts2.queueMS2toBTS2 = queueMS2toBTS2 ;
 
/*Make the mobile station start creating signals immediately */
 
sig.time = 0.0;
ms1.time = 0.0 ;
 
sigMS2.time =0.0 ;
ms2.time = 0.0;
 
 
insert(sig);
insert(ms1);
insert(sigMS2);
insert(ms2);
 
 
doAllEvents();
}
}
 
/*------------MOBILE STATION ONE------------------------------------*/
/*This class generates signals and puts it in the Signals Class.
The Signals class then puts it into the Queue.
And the Queue then transports these signals to the BTS1 class.
This code is an extension of the "Build a Discete Event Simulation
Class MS2 is a basic replica of this class.

in Ten Easy Steps.. thats why it looks familar.
*/
 
class MS1 extends Event
{
private Vector msSignals = new Vector();
 
String handoff = "120";
String locationUpdate = "1250";
String callSetup = "3000";
String callEnd = "350" ;
 
public MS1()
{
msSignals.addElement(handoff);
msSignals.addElement(locationUpdate);
msSignals.addElement(callSetup);
msSignals.addElement(callEnd);
}
 
void execute(AbstractSimulator simulator) 
{ 
 
time += Random.exponential(1.0);
 
if (time <= 610.0) 
{
int number =(int)(Math.random()*3);
String size = (String) msSignals.elementAt(number); 
Signals.method1(size);
simulator.insert(this);
}
 
}
}
 
 
 
 
 
 
/*--------------MS1 signals are put here---------------------*/
 
class Signals extends Event
{
Queue queueMStoBTS ;
 
static int i =0;
static private java.util.Vector inputSignals = new java.util.Vector();
 
public Signals()
{
}
 
void execute(AbstractSimulator simulator) 
{
 
 
queueMStoBTS.insert(simulator ,Signals.method());
time += Random.exponential(1.0);
if (time <= 610.0) 
{
simulator.insert(this);
}
 
}
 
 
static public void method1(String input)
{
inputSignals.addElement(input);
}
 
static public String method()
{
String signal = (String) inputSignals.firstElement();
inputSignals.removeElementAt(0);
return signal ;
}
}
 
 
 
/*------------------------------------------------*/
 
class Queue 
{
BTS1 bts1 ;
static int totalBytes = 0;
static double timeNow =0 ;
static double timeBelow =0;
 
/* A vector is cerated to hold siganals */
static private java.util.Vector signals = new java.util.Vector();
 
void insert( AbstractSimulator simulator ,String signal)
{
if(bts1.isAvaiable())
{
 
 
//int bytes = Integer.valueOf(signal).intValue();
int bytes = Integer.parseInt(signal);
 
totalBytes = totalBytes + bytes ;
 
timeNow = ((Simulator)simulator).now();
 
 
if(timeNow <= (timeBelow + 10))
{
 
System.out.println("Total Bytes" + totalBytes);
 
}
if(timeNow > (timeBelow + 10))
{
//Send total byes and time now tp 2 matrices
 
 
int timeNowInt = (int)(timeNow);
 
DynamicArray.arrayMethod1(totalBytes);
DynamicArray.arrayMethod(timeNowInt);
 
totalBytes = 0; 
timeBelow = timeBelow + 10 ;
 
 
 
 
}
 
if(timeNow > 600)
{
 
DynamicArray.print();
 
}
bts1.insert(simulator , signal); 
 
}
else
{
signals.addElement(signal);
}
}
 
int size() 
{
return signals.size();
}
 
String remove() 
{
String signal = (String) signals.firstElement();
signals.removeElementAt(0);
return signal;
}
 
}
 
 
/*-----------------------------------------------------------------*/
 
cla ss BTS1 extends Event
{
private String signalNumberServe ;
Queue queueMStoBTS ;
 
void execute(AbstractSimulator simulator) 
{
System.out.println("Finished processing bytes " + signalNumberServe + " at time " + time);
signalNumberServe = null ;
if( queueMStoBTS.size()> 0)
{
String signalNumber = queueMStoBTS.remove();
insert((Simulator) simulator, signalNumber);
}
}
 
boolean isAvaiable()
{
return (signalNumberServe == null);
}
 
void insert(AbstractSimulator simulator ,String signal)
{
signalNumberServe = signal ;
double serviceTime = Random.exponential(0);
time = ((Simulator)simulator).now() + serviceTime;
simulator.insert(this);
}
}
 
 
 
 
 
/*---------------------Global---------------------------*/
class Global
{
static public int totalSize =0 ;
static public int totalSizeMS2 =0 ;
 
}
 
 
/*---------------------MATRIX---------------------------*/
 
class DynamicArray
{
static private int i ;
static private int l;
static private int data[] = new int[1];
static private int data1[] = new int[1];
static private int newdata[];
static private int newdata1[];
static private int k=0;
static private int q=0;
static private int newSize;
static private int newSize1;
 
public DynamicArray(){}
 
static void arrayMethod(int j)
{
i = j ;
if(k==data.length)
{
newSize = data.length +1;
int[] newData = new int[newSize];
 
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
data[k] = i;
}
else
{
data[k]=i;
 
}
 
k++;
 
}
 
 
static void arrayMethod1(int m)
{
l = m ;
if(q==data1.length)
{
newSize1 = data1.length+1;
Global.totalSize = newSize1 ;
int[] newData1 = new int[newSize1];
System.arraycopy(data1, 0, newData1, 0, data1.length);
data1 = newData1;
data1[q] = l;
}
else
{
data1[q]=l;
System.out.println("Nope ");
}
 
q++;
 
}
 
 
 
static void print()
{
System.out.println("here ");
 
int ee = data.length ; 
int ff = data1.length ;
 
System.out.println("" + ee );
System.out.println("" + ff );
 
for(int ll =0 ; ll < ee ; ll++)
{
System.out.println("" + data[ll]);
}
 
for(int hh =0 ; hh < ff ; hh++)
{
System.out.println("" + data1[hh]);
}
 
 
DESimGraph graph = new DESimGraph(data , data1) ;
 
}
}
 
 
 


import java.util.Random.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import DESimGraph.*;
 
class MS2 extends Event
{
 
String size1 = "1000" ;
 
void execute(AbstractSimulator simulator) 
{
 
time += Random.exponential(1.0);
 
if (time <= 610.0) 
{
SignalsMS2.method1(size1);
simulator.insert(this);
}
 
}
}
 
 
 
 
/*--------------MS2 signals are put here---------------------*/
 
class SignalsMS2 extends Event
{
QueueMS2 queueMS2toBTS2 ;
 
static int i =0;
static private java.util.Vector inputSignalsMS2 = new java.util.Vector();
 
public SignalsMS2()
{
}
 
void execute(AbstractSimulator simulator) 
{
 
 
queueMS2toBTS2.insert(simulator ,SignalsMS2.method());
time += Random.exponential(1.0);
if (time <= 610.0) 
{
simulator.insert(this);
}
 
}
 
 
static public void method1(String input)
{
inputSignalsMS2.addElement(input);
}
 
static public String method()
{
String signal = (String) inputSignalsMS2.firstElement();
inputSignalsMS2.removeElementAt(0);
return signal ;
}
}
 
 
 
/*------------------------------------------------*/
 
class QueueMS2 
{
BTS2 bts2 ;
static private int totalBytes = 0;
static private double timeNow =0 ;
static private double timeBelow =0;
 
/* A vector is cerated to hold siganals */
private java.util.Vector signalsMS2 = new java.util.Vector();
 
void insert( AbstractSimulator simulator ,String signal)
{
if(bts2.isAvaiable())
{
 
 
//int bytes = Integer.valueOf(signal).intValue();
int bytes = Integer.parseInt(signal);
 
totalBytes = totalBytes + bytes ;
 
timeNow = ((Simulator)simulator).now();
 
 
if(timeNow <= (timeBelow + 10))
{
 
System.out.println("Total Bytes" + totalBytes);
 
}
if(timeNow > (timeBelow + 10))
{
//Send total byes and time now tp 2 matrices
 
 
int timeNowInt = (int)(timeNow);
 
DynamicArray2.arrayMethod1(totalBytes);
DynamicArray2.arrayMethod(timeNowInt);
 
totalBytes = 0; 
timeBelow = timeBelow + 10 ;
 
 
 
 
}
 
if(timeNow > 600)
{
 
DynamicArray2.print();
 
}
bts2.insert(simulator , signal); 
 
}
else
{
signalsMS2.addElement(signal);
}
}
 
int size() 
{
return signalsMS2.size();
}
 
String remove() 
{
String signal = (String) signalsMS2.firstElement();
signalsMS2.removeElementAt(0);
return signal;
}
 
}
 
 
/*-----------------------------------------------------------------*/
 
cla ss BTS2 extends Event
{
private String signalNumberServe ;
QueueMS2 queueMS2toBTS2 ;
 
void execute(AbstractSimulator simulator) 
{
System.out.println("Finished processing bytes " + signalNumberServe + " at time " + time);
signalNumberServe = null ;
if( queueMS2toBTS2.size()> 0)
{
String signalNumber = queueMS2toBTS2.remove();
insert((Simulator) simulator, signalNumber);
}
}
 
boolean isAvaiable()
{
return (signalNumberServe == null);
}
 
void insert(AbstractSimulator simulator ,String signal)
{
signalNumberServe = signal ;
double serviceTime = Random.exponential(0);
time = ((Simulator)simulator).now() + serviceTime;
simulator.insert(this);
}
}
 
 
 
 
 
 
 
/*---------------------MATRIX---------------------------*/
 
class DynamicArray2
{
static private int i ;
static private int l;
static private int data[] = new int[1];
static private int data1[] = new int[1];
static private int newdata[];
static private int newdata1[];
static private int k=0;
static private int q=0;
static private int newSize;
static private int newSize1;
 
public DynamicArray2(){}
 
static void arrayMethod(int j)
{
i = j ;
if(k==data.length)
{
newSize = data.length +1;
int[] newData = new int[newSize];
 
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
data[k] = i;
}
else
{
data[k]=i;
 
}
 
k++;
 
}
 
 
static void arrayMethod1(int m)
{
l = m ;
if(q==data1.length)
{
newSize1 = data1.length+1;
Global.totalSizeMS2 = newSize1 ;
int[] newData1 = new int[newSize1];
System.arraycopy(data1, 0, newData1, 0, data1.length);
data1 = newData1;
data1[q] = l;
}
else
{
data1[q]=l;
System.out.println("Nope ");
}
 
q++;
 
}
 
 
 
static void print()
{
System.out.println("here ");
 
int ee = data.length ; 
int ff = data1.length ;
 
System.out.println("" + ee );
System.out.println("" + ff );
 
for(int ll =0 ; ll < ee ; ll++)
{
System.out.println("" + data[ll]);
}
 
for(int hh =0 ; hh < ff ; hh++)
{
System.out.println("" + data1[hh]);
}
 
 
DESimGraph graphMS2toBTS2 = new DESimGraph(data , data1) ;
 
}
}
 




import java.util.Random.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
 
/*---------------------DESim ADD GRAPH-------------------*/
/*This class takes the values stored in the Dynamic Arrays 
makes a point to point graph out of them.
*/
 
 
class DESimGraph
{
private int[] data ;
private int[] data1;
 
public DESimGraph(int[] dataEx , int[] data1Ex)
{
data = dataEx ;
data1 = data1Ex;
 
 
Plot plot = new Plot(data , data1); 
 
plot.setLayout(null);
JFrame frame = new JFrame();
frame.setBackground(Color.white);
 
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.getContentPane().add(plot);
plot.updateUI();
frame.setSize(800,800);
frame.setVisible(true); 
System.out.println("Now");
try {
Thread.sleep(500000);
} catch (Exception e) {}
}
}
 
class Plot extends JPanel
{
int[] x ; 
int[] y ; 
int size = Global.totalSize ;
int[] xx = new int[size];
int[] yy = new int[size];
String xlabel, ylabel, title;
int xdim, ydim, yzero, xzero, xdraw, ydraw;
double xtic, ytic, xpoint, ypoint;
double xmax, xmin, ymax, ymin; 
static double x1max ;
static double x1min ;
 
 
 
public Plot(int[] dataEx , int[] data1Ex)
{
System.out.println("Yep ");
 
x = dataEx ;
y = data1Ex ;
 
 
 
xdim = 600;
ydim = 600;
xtic = 100;
ytic = 5000;
xlabel = ("Time");
ylabel = ("Bytes");
 
title = ylabel + " versus " + xlabel;
 
xmax = x[0];
xmin = x[0];
ymax = y[0];
ymin = y[0];
x1min= x[0];
x1max= x[0];
 
for (int i=0; i < size; i++){
if (x > xmax) {
xmax = x;
}
if (x < xmin) {
xmin = x;
 
}
if (y > ymax) {
ymax = y;
x1max = x;
}
if (y < ymin) {
ymin = y;
x1min = x;
}
 
}
 
 
//xx and yy are the scaled x and y used for plotting
 
for (int i=0; i < size; i++){
xx = (int) (50 + (((x-xmin)/(xmax-xmin)) * (xdim-100)));
yy = (int) ((ydim - 50) - (((y-ymin)/(ymax-ymin)) * (ydim-100)));
}
 
//Find Zero point on y-axis required for drawing the axes
 
if ((ymax*ymin) < 0){
yzero = (int) ((ydim - 50) - (((0-ymin)/(ymax-ymin)) * (ydim-100)));
}
else{
yzero = (int) ((ydim - 50) - ((0/(ymax-ymin)) * (ydim-100)));
}
 
//Find zero point on x-axis required for drawing the axes
 
if ((xmax*xmin) < 0) {
xzero = (int) (50 + (((0-xmin)/(xmax-xmin)) * (xdim-100)));
}
else{
xzero = (int) (50 + ((0/(xmax-xmin)) * (xdim-100)));
}
 
//Now ready to plot the results
 
repaint(); 
 
 
 
 
}
 
 
public void paint(Graphics g){ 
 
Font f1 = new Font("TimesRoman", Font.PLAIN, 10);
g.setFont(f1);
 
//First draw the axes
 
//y-axis
 
g.drawLine(xzero, 50, xzero, ydim-50);
g.drawLine(xzero, 50, (xzero - 5), 55);
g.drawLine(xzero, 50, (xzero + 5), 55);
 
//x-axis
 
g.drawLine(50, yzero, xdim-50, yzero);
g.drawLine((xdim-50), yzero, (xdim-55), (yzero + 5));
g.drawLine((xdim-50), yzero, (xdim-55), (yzero - 5));
 
 
//Initialise the labelling taking into account the xtic and ytic values
 
//x-axis labels
 
if (xmin <= 0){
xpoint = xmin - (xmin%xtic);
}else{
xpoint = xmin - (xmin%xtic) + xtic;
}
 
do{
xdraw = (int) (50 + (((xpoint-xmin)/(xmax-xmin))*(xdim-100)));
g.drawString(xpoint + "", xdraw, (yzero+10));
xpoint = xpoint + xtic;
}while (xpoint <= xmax);
 
if (ymin <= 0){
ypoint = ymin - (ymin%ytic);
}else{
ypoint = ymin - (ymin%ytic) + ytic;
}
 
do{
ydraw = (int) ((ydim - 50) - (((ypoint - ymin)/(ymax-ymin))*(ydim-100)));
g.drawString(ypoint + "", (xzero - 20), ydraw);
ypoint = ypoint + ytic;
 
}while (ypoint <= ymax);
 
//Titles and labels
 
Font f2 = new Font("TimesRoman", Font.BOLD, 14);
g.setFont(f2);
 
g.drawString(xlabel, (xdim - 100), (yzero + 25));
g.drawString(ylabel, (xzero - 25), 40);
g.drawString(title, (xdim/2 - 75), 20);
 
//Finding Maximum and Minimun values for the curve
 
 
 
 
 
// Draw Lines
 
g.drawString("Maximum point" + "("+ x1max + "," + ymax + ")", (xdim/2 + 250), 170);
g.drawString("Minimum point" + "("+ x1min + "," + ymin + ")", (xdim/2 + 250), 200);
 
for (int j = 0; j < size-1; j++)
{
 
g.drawLine(xx[j], yy[j], xx[j+1], yy[j+1]); 
} 
 
 
}
 
 
 
} 


interface Comparable {
boolean lessThan(Comparable y);
}
 
abstract class AbstractEvent implements Comparable {
abstract void execute(AbstractSimulator simulator);
}
 
abstract class OrderedSet {
abstract void insert(Comparable x);
abstract Comparable removeFirst();
abstract int size();
}
 
class AbstractSimulator {
OrderedSet events;
void insert(AbstractEvent e) {
events.insert(e);
}
AbstractEvent cancel(AbstractEvent e) {
throw new java.lang.RuntimeException("Method not implemented");
}
}
 
 
abstract class Event extends AbstractEvent {
double time;
public boolean lessThan(Comparable y) {
Event e = (Event) y; // Will throw an exception if y is not an Event
return this.time < e.time;
}
}
 
class Simulator extends AbstractSimulator {
double time;
double now() {
return time;
}
void doAllEvents() {
Event e;
while ( (e= (Event) events.removeFirst()) != null) {
time = e.time;
e.execute(this);
}
}
}
 
 
class ListQueue extends OrderedSet {
java.util.Vector elements = new java.util.Vector();
void insert(Comparable x) {
int i = 0;
while (i < elements.size() && ((Comparable) elements.elementAt(i)).lessThan(x)) {
i++;
}
elements.insertElementAt(x,i);
}
Comparable removeFirst() {
if (elements.size() ==0) return null;
Comparable x = (Comparable) elements.firstElement();
elements.removeElementAt(0);
return x;
}
Object remove(Object x) {
for (int i = 0; i < elements.size(); i++) {
if (elements.elementAt(i).equals(x)) {
Object y = elements.elementAt(i);
elements.removeElementAt(i);
return y;
}
}
return null;
}
public int size() {
return elements.size();
}
} 
 


Avin Sinanan

Posts: 28
Nickname: avin
Registered: Feb, 2002

Re: Discrete Event Simulation ( Proper Code) Posted: Mar 3, 2002 11:21 PM
Reply to this message Reply
How do you edit a posting?

Bill Venners

Posts: 2284
Nickname: bv
Registered: Jan, 2002

Re: Discrete Event Simulation ( Proper Code) Posted: Mar 4, 2002 12:18 AM
Reply to this message Reply
Well, just as the writer writes, and having writ, moves on, the poster posts, and have posted, moves on. The poster can preview, and having previewed, can edit. But once the poster has punched the post message button, the posters post is preserved for posterity.

The reason I don't offer a way to edit a posting is because I figured people might go back and change their posts, or delete them, and then the replies wouldn't make sense. So my recommendation is just to use the preview function to check things out before you post, then take a deep breath and post your message. If you later realize you want to make a correction, then just post a reply to your original message.

Charles Bell

Posts: 519
Nickname: charles
Registered: Feb, 2002

Re: Discrete Event Simulation ( Proper Code) Posted: Mar 4, 2002 2:27 PM
Reply to this message Reply
I was looking through your code yesterday. There are several problems with a Random method.

You use a method Random.exponential(1.0) and Random.exponential(0.0)
These methods do not exist in the API that I can find.
I susbstituted:
Random random = new Random();
double number = random.nextDouble();
in the appropriate places.
But I can't tell if that is what is required.

The code has &gt; in several places which probably should be >

In the method:
void doAllEvents() {Event e;while ( (e= (Event) events.removeFirst()) != null) {time = e.time;e.execute(this);

events.removeFirst() removes all the elements and is not programmed properly to return null when there are no more elements.

You have to fix these before proceeding.
I can only guess what the fix is.

The lines:

if(timeNow &gt; 600){DynamicArray.print();}

control when the plots are going to occur.
You would have to modify the code here to ensure a plot every run.

Avin Sinanan

Posts: 28
Nickname: avin
Registered: Feb, 2002

Re: Discrete Event Simulation ( Proper Code) Posted: Mar 4, 2002 4:25 PM
Reply to this message Reply
Hey Charles Bell.. thanks for the help. I'll look through it now and make the changes. THanks.. is it ok if I keep you updated?

yours respectufully Avin Sinanan

Avin Sinanan

Posts: 28
Nickname: avin
Registered: Feb, 2002

Re: Discrete Event Simulation ( Proper Code) Posted: Mar 4, 2002 4:50 PM
Reply to this message Reply
Hey charles you have any other ideas cause I don't think thats the problem.. I did make the changes and well it still doesn't work.

You see when its just one MS and one BTS the program works fine. But the minute I try to get two MS and two BTS to work in parallel it doesn't work.

any ideas ?

Flat View: This topic has 5 replies on 1 page
Topic: Please Kishori Help Previous Topic   Next Topic Topic: Java Swings(JTable)

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use