├── README.md
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-ldpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── menu
│ └── activity_group_messenger.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
├── values
│ ├── strings.xml
│ └── styles.xml
└── layout
│ └── activity_group_messenger.xml
├── .settings
└── org.eclipse.jdt.core.prefs
├── gen
└── edu
│ └── buffalo
│ └── cse
│ └── cse486586
│ └── groupmessenger
│ ├── BuildConfig.java
│ └── R.java
├── .classpath
├── project.properties
├── proguard-project.txt
├── src
└── edu
│ └── buffalo
│ └── cse
│ └── cse486586
│ └── groupmessenger
│ ├── MessageBody.java
│ ├── GroupMessengerProvider.java
│ ├── OnPTestClickListener.java
│ └── GroupMessengerActivity.java
├── .project
└── AndroidManifest.xml
/README.md:
--------------------------------------------------------------------------------
1 | GroupMessenger
2 | ==============
3 |
4 | Group Messenger for Android
5 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/router/GroupMessenger/master/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/gen/edu/buffalo/cse/cse486586/groupmessenger/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /** Automatically generated file. DO NOT MODIFY */
2 | package edu.buffalo.cse.cse486586.groupmessenger;
3 |
4 | public final class BuildConfig {
5 | public final static boolean DEBUG = true;
6 | }
--------------------------------------------------------------------------------
/res/menu/activity_group_messenger.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | GroupMessenger
5 | Settings
6 | Send
7 | PTest
8 | Test1
9 | Test2
10 | Type to compose
11 |
12 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/src/edu/buffalo/cse/cse486586/groupmessenger/MessageBody.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.cse486586.groupmessenger;
2 |
3 | import java.io.Serializable;
4 | import java.util.Arrays;
5 |
6 | public class MessageBody implements Serializable{
7 |
8 | public int sequenceNumber;
9 | public String message;
10 | public int sender;
11 | public String messageId; // concat of AVDNumber and timestamp
12 | public int[] vectorClock;
13 | public String messageType; //"reg" or "order"
14 |
15 | public MessageBody(String mId,String type,String body,int sender,int[] vClock)
16 | {
17 | // TODO Auto-generated constructor stub
18 | this.messageId=mId;
19 | this.message=body;
20 | this.messageType=type;
21 | this.sender=sender;
22 | this.vectorClock=Arrays.copyOf(vClock, vClock.length);
23 | this.sequenceNumber=-1;
24 |
25 | }
26 |
27 | public void setSequencenumber(int n)
28 | {
29 | sequenceNumber=n;
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | GroupMessenger
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/res/layout/activity_group_messenger.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
35 |
36 |
48 |
49 |
--------------------------------------------------------------------------------
/gen/edu/buffalo/cse/cse486586/groupmessenger/R.java:
--------------------------------------------------------------------------------
1 | /* AUTO-GENERATED FILE. DO NOT MODIFY.
2 | *
3 | * This class was automatically generated by the
4 | * aapt tool from the resource data it found. It
5 | * should not be modified by hand.
6 | */
7 |
8 | package edu.buffalo.cse.cse486586.groupmessenger;
9 |
10 | public final class R {
11 | public static final class attr {
12 | }
13 | public static final class drawable {
14 | public static final int ic_launcher=0x7f020000;
15 | }
16 | public static final class id {
17 | public static final int button1=0x7f070001;
18 | public static final int button4=0x7f070002;
19 | public static final int editText1=0x7f070000;
20 | public static final int menu_settings=0x7f070004;
21 | public static final int textView1=0x7f070003;
22 | }
23 | public static final class layout {
24 | public static final int activity_group_messenger=0x7f030000;
25 | }
26 | public static final class menu {
27 | public static final int activity_group_messenger=0x7f060000;
28 | }
29 | public static final class string {
30 | public static final int app_name=0x7f040000;
31 | public static final int button_ptest=0x7f040003;
32 | public static final int button_send=0x7f040002;
33 | public static final int button_test1=0x7f040004;
34 | public static final int button_test2=0x7f040005;
35 | public static final int edittext_hint=0x7f040006;
36 | public static final int menu_settings=0x7f040001;
37 | }
38 | public static final class style {
39 | /**
40 | Base application theme, dependent on API level. This theme is replaced
41 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
42 |
43 |
44 | Theme customizations available in newer API levels can go in
45 | res/values-vXX/styles.xml, while customizations related to
46 | backward-compatibility can go here.
47 |
48 |
49 | Base application theme for API 11+. This theme completely replaces
50 | AppBaseTheme from res/values/styles.xml on API 11+ devices.
51 |
52 | API 11 theme customizations can go here.
53 |
54 | Base application theme for API 14+. This theme completely replaces
55 | AppBaseTheme from BOTH res/values/styles.xml and
56 | res/values-v11/styles.xml on API 14+ devices.
57 |
58 | API 14 theme customizations can go here.
59 | */
60 | public static final int AppBaseTheme=0x7f050000;
61 | /** Application theme.
62 | All customizations that are NOT specific to a particular API-level can go here.
63 | */
64 | public static final int AppTheme=0x7f050001;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/edu/buffalo/cse/cse486586/groupmessenger/GroupMessengerProvider.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.cse486586.groupmessenger;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedReader;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.InputStreamReader;
11 |
12 | import android.content.ContentProvider;
13 | import android.content.ContentValues;
14 | import android.content.Context;
15 | import android.database.Cursor;
16 | import android.database.MatrixCursor;
17 | import android.net.Uri;
18 | import android.util.Log;
19 |
20 | /**
21 | * GroupMessengerProvider is a key-value table. Once again, please note that we do not implement
22 | * full support for SQL as a usual ContentProvider does. We re-purpose ContentProvider's interface
23 | * to use it as a key-value table.
24 | *
25 | * Please read:
26 | *
27 | * http://developer.android.com/guide/topics/providers/content-providers.html
28 | * http://developer.android.com/reference/android/content/ContentProvider.html
29 | *
30 | * before you start to get yourself familiarized with ContentProvider.
31 | *
32 | * There are two methods you need to implement---insert() and query(). Others are optional and
33 | * will not be tested.
34 | *
35 | * @author stevko
36 | *
37 | */
38 | public class GroupMessengerProvider extends ContentProvider {
39 |
40 | @Override
41 | public int delete(Uri uri, String selection, String[] selectionArgs) {
42 | // You do not need to implement this.
43 | return 0;
44 | }
45 |
46 | @Override
47 | public String getType(Uri uri) {
48 | // You do not need to implement this.
49 | return null;
50 | }
51 |
52 | @Override
53 | public Uri insert(Uri uri, ContentValues values) {
54 | /*
55 | * TODO: You need to implement this method. Note that values will have two columns (a key
56 | * column and a value column) and one row that contains the actual (key, value) pair to be
57 | * inserted.
58 | *
59 | * For actual storage, you can use any option. If you know how to use SQL, then you can use
60 | * SQLite. But this is not a requirement. You can use other storage options, such as the
61 | * internal storage option that I used in PA1. If you want to use that option, please
62 | * take a look at the code for PA1.
63 | */
64 | Log.v("insert", values.toString());
65 | String filename=values.getAsString("key");
66 | String value=values.getAsString("value");
67 |
68 | try {
69 | File f=new File(this.getContext().getFilesDir().getAbsoluteFile(),filename);
70 | if(!f.exists())
71 | f.createNewFile();
72 | FileOutputStream outputStream = new FileOutputStream(f);//openFileOutput(filename, Context.MODE_PRIVATE);
73 | outputStream.write(value.getBytes());
74 | outputStream.close();
75 | } catch (Exception e) {
76 | Log.e(GroupMessengerActivity.class.getSimpleName(), "File write failed");
77 | }
78 | return uri;
79 | }
80 |
81 | @Override
82 | public boolean onCreate() {
83 | // If you need to perform any one-time initialization task, please do it here.
84 | return false;
85 | }
86 |
87 | @Override
88 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
89 | String sortOrder) {
90 | /*
91 | * TODO: You need to implement this method. Note that you need to return a Cursor object
92 | * with the right format. If the formatting is not correct, then it is not going to work.
93 | *
94 | * If you use SQLite, whatever is returned from SQLite is a Cursor object. However, you
95 | * still need to be careful because the formatting might still be incorrect.
96 | *
97 | * If you use a file storage option, then it is your job to build a Cursor * object. I
98 | * recommend building a MatrixCursor described at:
99 | * http://developer.android.com/reference/android/database/MatrixCursor.html
100 | */
101 | Log.v("query", selection);
102 |
103 | try {
104 | File f=new File(this.getContext().getFilesDir().getAbsoluteFile(),selection);
105 | FileInputStream inputStream=new FileInputStream(f);
106 |
107 | BufferedReader buf= new BufferedReader(new InputStreamReader(new BufferedInputStream(inputStream)));
108 | String value="",line="";
109 | while((line=buf.readLine())!=null)
110 | value+=line;
111 |
112 | buf.close();
113 | inputStream.close();
114 | String[] cols={"key","value"};
115 | String[] row={selection,value};
116 | MatrixCursor result=new MatrixCursor(cols);
117 | result.addRow(row);
118 | return result;
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | } catch (Exception e) {
128 | Log.e(GroupMessengerActivity.class.getSimpleName(), "Unable to read file.");
129 | }
130 |
131 | return null;
132 | }
133 |
134 | @Override
135 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
136 | // You do not need to implement this.
137 | return 0;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/edu/buffalo/cse/cse486586/groupmessenger/OnPTestClickListener.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.cse486586.groupmessenger;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.ContentValues;
5 | import android.database.Cursor;
6 | import android.net.Uri;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.View.OnClickListener;
10 | import android.widget.TextView;
11 |
12 | /**
13 | * OnPTestClickListener demonstrates how to access a ContentProvider. First, please read
14 | *
15 | * http://developer.android.com/guide/topics/providers/content-providers.html
16 | * http://developer.android.com/reference/android/content/ContentProvider.html
17 | *
18 | * before you start. Please note that our use of a ContentProvider is a bit different from the
19 | * standard way of using it as described in the PA2 spec. The bottom line is that our
20 | * ContentProvider does not have full support for SQL. It is just a key-value table, like a hash
21 | * table. It just needs to be able to insert (key, value) pairs, store them, and return them when
22 | * queried.
23 | *
24 | * A ContentProvider has a unique URI that other apps use to access it. ContentResolver is
25 | * the class to use when accessing a ContentProvider.
26 | *
27 | * @author stevko
28 | *
29 | */
30 | public class OnPTestClickListener implements OnClickListener {
31 |
32 | private static final String TAG = OnPTestClickListener.class.getName();
33 | private static final int TEST_CNT = 50;
34 | private static final String KEY_FIELD = "key";
35 | private static final String VALUE_FIELD = "value";
36 |
37 | private final TextView mTextView;
38 | private final ContentResolver mContentResolver;
39 | private final Uri mUri;
40 | private final ContentValues[] mContentValues;
41 |
42 | public OnPTestClickListener(TextView _tv, ContentResolver _cr) {
43 | mTextView = _tv;
44 | mContentResolver = _cr;
45 | mUri = buildUri("content", "edu.buffalo.cse.cse486586.groupmessenger.provider");
46 | mContentValues = initTestValues();
47 | }
48 |
49 | /**
50 | * buildUri() demonstrates how to build a URI for a ContentProvider.
51 | *
52 | * @param scheme
53 | * @param authority
54 | * @return the URI
55 | */
56 | private Uri buildUri(String scheme, String authority) {
57 | Uri.Builder uriBuilder = new Uri.Builder();
58 | uriBuilder.authority(authority);
59 | uriBuilder.scheme(scheme);
60 | return uriBuilder.build();
61 | }
62 |
63 | private ContentValues[] initTestValues() {
64 | ContentValues[] cv = new ContentValues[TEST_CNT];
65 | for (int i = 0; i < TEST_CNT; i++) {
66 | cv[i] = new ContentValues();
67 | cv[i].put(KEY_FIELD, "key" + Integer.toString(i));
68 | cv[i].put(VALUE_FIELD, "val" + Integer.toString(i));
69 | }
70 |
71 | return cv;
72 | }
73 |
74 | @Override
75 | public void onClick(View v) {
76 | if (testInsert()) {
77 | mTextView.append("Insert success\n");
78 | } else {
79 | mTextView.append("Insert fail\n");
80 | return;
81 | }
82 |
83 | if (testQuery()) {
84 | mTextView.append("Query success\n");
85 | } else {
86 | mTextView.append("Query fail\n");
87 | }
88 | }
89 |
90 | /**
91 | * testInsert() uses ContentResolver.insert() to insert values into your ContentProvider.
92 | *
93 | * @return true if the insertions were successful. Otherwise, false.
94 | */
95 | private boolean testInsert() {
96 | try {
97 | for (int i = 0; i < TEST_CNT; i++) {
98 | mContentResolver.insert(mUri, mContentValues[i]);
99 | }
100 | } catch (Exception e) {
101 | Log.e(TAG, e.toString());
102 | return false;
103 | }
104 |
105 | return true;
106 | }
107 |
108 | /**
109 | * testQuery() uses ContentResolver.query() to retrieves values from your ContentProvider.
110 | * It simply queries one key at a time and verifies whether it matches any (key, value) pair
111 | * previously inserted by testInsert().
112 | *
113 | * Please pay extra attention to the Cursor object you return from your ContentProvider.
114 | * It should have two columns; the first column (KEY_FIELD) is for keys
115 | * and the second column (VALUE_FIELD) is values. In addition, it should include exactly
116 | * one row that contains a key and a value.
117 | *
118 | * @return
119 | */
120 | private boolean testQuery() {
121 | try {
122 | for (int i = 0; i < TEST_CNT; i++) {
123 | String key = (String) mContentValues[i].get(KEY_FIELD);
124 | String val = (String) mContentValues[i].get(VALUE_FIELD);
125 |
126 | Cursor resultCursor = mContentResolver.query(mUri, null, key, null, null);
127 | if (resultCursor == null) {
128 | Log.e(TAG, "Result null");
129 | throw new Exception();
130 | }
131 |
132 | int keyIndex = resultCursor.getColumnIndex(KEY_FIELD);
133 | int valueIndex = resultCursor.getColumnIndex(VALUE_FIELD);
134 | if (keyIndex == -1 || valueIndex == -1) {
135 | Log.e(TAG, "Wrong columns");
136 | resultCursor.close();
137 | throw new Exception();
138 | }
139 |
140 | resultCursor.moveToFirst();
141 |
142 | if (!(resultCursor.isFirst() && resultCursor.isLast())) {
143 | Log.e(TAG, "Wrong number of rows");
144 | resultCursor.close();
145 | throw new Exception();
146 | }
147 |
148 | String returnKey = resultCursor.getString(keyIndex);
149 | String returnValue = resultCursor.getString(valueIndex);
150 | if (!(returnKey.equals(key) && returnValue.equals(val))) {
151 | Log.e(TAG, "(key, value) pairs don't match\n");
152 | resultCursor.close();
153 | throw new Exception();
154 | }
155 |
156 | resultCursor.close();
157 | }
158 | } catch (Exception e) {
159 | return false;
160 | }
161 |
162 | return true;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/edu/buffalo/cse/cse486586/groupmessenger/GroupMessengerActivity.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.cse486586.groupmessenger;
2 |
3 | import java.io.DataInputStream;
4 | import java.io.DataOutputStream;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 | import java.io.ObjectInputStream;
8 | import java.io.ObjectOutputStream;
9 | import java.net.InetAddress;
10 | import java.net.ServerSocket;
11 | import java.net.Socket;
12 | import java.net.URI;
13 | import java.net.UnknownHostException;
14 | import java.util.ArrayList;
15 | import java.util.Arrays;
16 | import java.util.Comparator;
17 | import java.util.Hashtable;
18 | import java.util.Iterator;
19 | import java.util.PriorityQueue;
20 | import java.util.Vector;
21 | import java.util.concurrent.Executors;
22 |
23 | import android.net.Uri;
24 | import android.os.AsyncTask;
25 | import android.os.Bundle;
26 | import android.app.Activity;
27 | import android.content.ContentValues;
28 | import android.content.Context;
29 | import android.telephony.TelephonyManager;
30 | import android.text.method.ScrollingMovementMethod;
31 | import android.util.Log;
32 | import android.view.Menu;
33 | import android.view.View;
34 | import android.widget.Button;
35 | import android.widget.EditText;
36 | import android.widget.TextView;
37 | import android.view.View.OnClickListener;
38 |
39 |
40 | /**
41 | * GroupMessengerActivity is the main Activity for the assignment.
42 | *
43 | * @author stevko
44 | *
45 | */
46 |
47 | /* Logic for the code :
48 | *
49 | * AVD0 is the sequencer.
50 | * The sequencer implements causal ordering.
51 | * All the others implement total ordering (thanks to the sequencer)
52 | *
53 | * --- Subhranil
54 | *
55 | * */
56 | public class GroupMessengerActivity extends Activity {
57 |
58 |
59 | private String myPortStr;
60 | public int AVDNumber;
61 | // static final String REMOTE_PORT0 = "11108";
62 | // static final String REMOTE_PORT1 = "11112";
63 | public final int SERVER_PORT = 10000;
64 | public final String[] ports={"11108","11112","11116","11120","11124"};
65 | private PriorityQueue deliverQueue;
66 | private Hashtable waitingQ;
67 | private Vector sequencerWaitingQ;
68 | public int[] vClock={0,0,0,0,0};
69 | private int[] vClockForSequencer={0,0,0,0,0};
70 | private int localSqNumber; // for each process
71 | private int globalSqNumber; // for the sequencer
72 | public int numberOfNodes=5;
73 | public String TAG = GroupMessengerActivity.class.getSimpleName();
74 |
75 |
76 | @Override
77 | protected void onCreate(Bundle savedInstanceState) {
78 | super.onCreate(savedInstanceState);
79 | setContentView(R.layout.activity_group_messenger);
80 |
81 | TextView tv = (TextView) findViewById(R.id.textView1);
82 | tv.setMovementMethod(new ScrollingMovementMethod());
83 |
84 |
85 |
86 | init();
87 |
88 | //setup the sever
89 | try {
90 | ServerSocket serverSocket = new ServerSocket(GroupMessengerActivity.this.SERVER_PORT);
91 | new ServerTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, serverSocket);
92 | } catch (IOException e) {
93 | Log.d(TAG, "Can't create a ServerSocket");
94 | return;
95 | }
96 |
97 | findViewById(R.id.button1).setOnClickListener(
98 | new OnPTestClickListener(tv, getContentResolver()));
99 |
100 |
101 |
102 | Button sendButton=(Button)findViewById(R.id.button4);
103 | sendButton.setOnClickListener(new OnClickListener() {
104 |
105 | @Override
106 | public void onClick(View arg0) {
107 | // TODO Auto-generated method stub // write sending code here
108 | String message=((EditText)findViewById(R.id.editText1)).getText().toString();
109 | ((EditText)findViewById(R.id.editText1)).setText("");
110 | GroupMessengerActivity g=GroupMessengerActivity.this;
111 | String id=String.valueOf(g.AVDNumber)+String.valueOf(System.currentTimeMillis() / 1000L);
112 | g.vClock[g.AVDNumber]++;
113 | MessageBody m=new MessageBody(id, "reg", message, g.AVDNumber,g.vClock );
114 | new ClientThread(m,g.ports).start();
115 | // new ClientTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, message, "");
116 | }
117 | });
118 |
119 | }
120 |
121 |
122 | /***
123 | * ServerTask is an AsyncTask that should handle incoming messages. It is created by
124 | * ServerTask.executeOnExecutor() call in SimpleMessengerActivity.
125 | *
126 | * Please make sure you understand how AsyncTask works by reading
127 | * http://developer.android.com/reference/android/os/AsyncTask.html
128 | *
129 | * @author stevko
130 | *
131 | */
132 | private class ServerTask extends AsyncTask {
133 |
134 | @Override
135 | protected Void doInBackground(ServerSocket... sockets) {
136 | ServerSocket serverSocket = sockets[0];
137 | try
138 | {
139 | while(true) {
140 | Socket serverSock=serverSocket.accept();
141 | ObjectInputStream oStream=new ObjectInputStream(serverSock.getInputStream());
142 | MessageBody m=(MessageBody)oStream.readObject();
143 |
144 | Executors.newSingleThreadExecutor().execute(new MessageHandler(m));
145 |
146 | // final String textReceived=m.message;//.readLine();
147 | // runOnUiThread(new Runnable() {
148 | //
149 | // @Override
150 | // public void run() {
151 | // // TODO Auto-generated method stub
152 | // onProgressUpdate(textReceived);
153 | // }
154 | // });
155 |
156 | oStream.close();
157 | serverSock.close();
158 | }
159 | }
160 | catch(Exception e)
161 | {
162 | Log.d(TAG, e.getStackTrace().toString());
163 | //System.out.println(e);
164 | }
165 | return null;
166 | }
167 |
168 |
169 | }
170 |
171 | public void onProgressUpdate(String...strings) {
172 | /*
173 | * The following code displays what is received in doInBackground().
174 | */
175 | String strReceived = strings[0].trim();
176 | TextView remoteTextView = (TextView) findViewById(R.id.textView1);
177 | remoteTextView.append(strReceived + "\t\n");
178 | TextView localTextView = (TextView) findViewById(R.id.textView1);
179 | localTextView.append("\n");
180 |
181 | /*
182 | * The following code creates a file in the AVD's internal storage and stores a file.
183 | *
184 | * For more information on file I/O on Android, please take a look at
185 | * http://developer.android.com/training/basics/data-storage/files.html
186 | */
187 |
188 | // String filename = "SimpleMessengerOutput";
189 | // String string = strReceived + "\n";
190 | // FileOutputStream outputStream;
191 | //
192 | // try {
193 | // outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
194 | // outputStream.write(string.getBytes());
195 | // outputStream.close();
196 | // } catch (Exception e) {
197 | // Log.e(TAG, "File write failed");
198 | // }
199 | return;
200 | }
201 |
202 |
203 |
204 | /***
205 | * ClientTask is an AsyncTask that should send a string over the network.
206 | * It is created by ClientTask.executeOnExecutor() call whenever OnKeyListener.onKey() detects
207 | * an enter key press event.
208 | *
209 | * @author stevko
210 | *
211 | */
212 |
213 | public class ClientThread extends Thread
214 | {
215 | private MessageBody mssg;
216 | private String[] ports;
217 | public ClientThread(MessageBody m,String ports[])
218 | {
219 | mssg=m;
220 | this.ports=ports;
221 | }
222 | public void run()
223 | {
224 |
225 | try {
226 | // String remotePort = REMOTE_PORT0;
227 | // if (msgs[1].equals(REMOTE_PORT0))
228 | // remotePort = REMOTE_PORT1;
229 |
230 | for(int i=0;i {
257 | //
258 | // @Override
259 | // protected Void doInBackground(String... msgs) {}
260 | // }
261 |
262 | @Override
263 | public boolean onCreateOptionsMenu(Menu menu) {
264 | // Inflate the menu; this adds items to the action bar if it is present.
265 | getMenuInflater().inflate(R.menu.activity_group_messenger, menu);
266 | return true;
267 | }
268 |
269 |
270 | // Rest of the code is new and added by Subhranil
271 |
272 | public void init()
273 | {
274 | getAVDDetails();
275 | Comparator comp=new MyComparator();
276 | deliverQueue=new PriorityQueue(50, comp);
277 | waitingQ=new Hashtable();
278 | sequencerWaitingQ=new Vector();
279 | localSqNumber=0;
280 | globalSqNumber=0;
281 | TAG=TAG+String.valueOf(AVDNumber);
282 |
283 | }
284 |
285 |
286 | public void getAVDDetails()
287 | {
288 | TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
289 | String portStr = tel.getLine1Number().substring(tel.getLine1Number().length() - 4);
290 | myPortStr = String.valueOf((Integer.parseInt(portStr) * 2));
291 | AVDNumber=Arrays.asList(ports).indexOf(myPortStr);
292 | }
293 |
294 | public class MessageHandler implements Runnable
295 | {
296 | private MessageBody message;
297 | public MessageHandler(MessageBody m)
298 | {
299 | message=m;
300 | }
301 |
302 | public void run()
303 | {
304 | handleIncomingMessage(message);
305 | }
306 |
307 | //probably the most important function .
308 | public void handleIncomingMessage(MessageBody message)
309 | {
310 | // if(true)
311 | // {
312 | // System.out.println("Going out:"+AVDNumber);
313 | // return;
314 | // }
315 |
316 | //Log.d(TAG, "Handling"+message.message+"at avd index:"+String.valueOf(AVDNumber));
317 | if(message.messageType.equals("order")) // message from sequencer
318 | {
319 | MessageBody m=waitingQ.get(message.messageId);
320 | //Log.d(TAG, "No message found with id:"+message.messageId);
321 | if(m!=null)
322 | { m.setSequencenumber(message.sequenceNumber);
323 | deliverQueue.add(m);
324 | }
325 | }
326 | else //regular message
327 | {
328 | waitingQ.put(message.messageId, message);
329 | if(AVDNumber!=4) // non sqequncer
330 | {
331 | for(int i=0;i 0) {
352 | Iterator it = sequencerWaitingQ.iterator();
353 | while (it.hasNext())
354 | {
355 | MessageBody mess=it.next();
356 | if (mess.vectorClock[mess.sender]==(vClockForSequencer[mess.sender]+1))
357 | {
358 | vClockForSequencer[mess.sender]+=1;
359 | MessageBody m=new MessageBody(mess.messageId, "order", "" , AVDNumber, vClockForSequencer);
360 | m.setSequencenumber(globalSqNumber++);
361 | new ClientThread(m,ports).start();
362 | it.remove();
363 | } // end of if 254
364 | } //end of while 246
365 | } // end of if 244
366 |
367 | }
368 | catch (Exception e) {
369 | // TODO: handle exception
370 | Log.e(TAG, e.getMessage());
371 | }
372 | }
373 |
374 | }
375 |
376 |
377 |
378 | //Implementation of the total ordering
379 |
380 | while (deliverQueue.size() != 0) {
381 | MessageBody front = deliverQueue.peek();
382 | if(front.sequenceNumber==localSqNumber && waitingQ.containsKey(front.messageId))
383 | {
384 |
385 | localSqNumber++;
386 | final String messageStr=front.message;
387 | waitingQ.remove(front.messageId);
388 | deliverQueue.poll();
389 |
390 | ContentValues keyValueToInsert = new ContentValues();
391 | // inserting <”key-to-insert”, “value-to-insert”>
392 | keyValueToInsert.put("key", String.valueOf(front.sequenceNumber));
393 | keyValueToInsert.put("value", messageStr);
394 | Uri providerUri= Uri.parse("content://edu.buffalo.cse.cse486586.groupmessenger.provider");
395 |
396 |
397 | Uri newUri = getContentResolver().insert(
398 | providerUri, // assume we already created a Uri object with our provider URI
399 | keyValueToInsert
400 | );
401 |
402 | runOnUiThread(new Runnable() {
403 |
404 | @Override
405 | public void run() {
406 | // TODO Auto-generated method stub
407 | onProgressUpdate(messageStr);
408 | }
409 | });
410 | //onProgressUpdate(messageStr);
411 | }
412 | else
413 | break;
414 |
415 | }
416 |
417 | }
418 |
419 | }
420 |
421 | public class MyComparator implements Comparator
422 | {
423 | public int compare(MessageBody a,MessageBody b)
424 | {
425 | return (a.sequenceNumber-b.sequenceNumber);
426 | }
427 | }
428 |
429 | }
430 |
431 |
432 |
433 |
--------------------------------------------------------------------------------