Tweaked phone app for testbed experiment; tweaked testbed files
authorrtrimana <rtrimana@uci.edu>
Sat, 12 May 2018 05:00:19 +0000 (22:00 -0700)
committerrtrimana <rtrimana@uci.edu>
Sat, 12 May 2018 05:00:19 +0000 (22:00 -0700)
103 files changed:
version2/src/C/Makefile
version2/src/Control-2bulbs/.gitignore [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/compiler.xml [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/copyright/profiles_settings.xml [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/gradle.xml [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/misc.xml [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/modules.xml [new file with mode: 0644]
version2/src/Control-2bulbs/.idea/runConfigurations.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/.gitignore [new file with mode: 0644]
version2/src/Control-2bulbs/app/build.gradle [new file with mode: 0644]
version2/src/Control-2bulbs/app/libs/core-1.56.0.0.jar [new file with mode: 0644]
version2/src/Control-2bulbs/app/proguard-rules.pro [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/androidTest/java/com/example/ali/control/ApplicationTest.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/AndroidManifest.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/com/example/ali/control/MainActivity.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Abort.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/ArbitrationRound.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/CloudComm.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Commit.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/CommitPart.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Entry.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/IoTString.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/KeyValue.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/LastMessage.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Liveness.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/LocalComm.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/NewKey.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Pair.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/PendingTransaction.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/RejectedMessage.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/ServerException.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Slot.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotBuffer.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotIndexer.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Table.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/TableStatus.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/ThreeTuple.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/TimingSingleton.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/Transaction.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionPart.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionStatus.java [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/layout/activity_main.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/layout/content_main.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/menu/menu_main.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/mipmap-hdpi/ic_launcher.png [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/mipmap-mdpi/ic_launcher.png [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/mipmap-xhdpi/ic_launcher.png [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values-v21/styles.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values-w820dp/dimens.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values/colors.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values/dimens.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values/strings.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/main/res/values/styles.xml [new file with mode: 0644]
version2/src/Control-2bulbs/app/src/test/java/com/example/ali/control/ExampleUnitTest.java [new file with mode: 0644]
version2/src/Control-2bulbs/build.gradle [new file with mode: 0644]
version2/src/Control-2bulbs/gradle.properties [new file with mode: 0644]
version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.jar [new file with mode: 0644]
version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.properties [new file with mode: 0644]
version2/src/Control-2bulbs/gradlew [new file with mode: 0644]
version2/src/Control-2bulbs/gradlew.bat [new file with mode: 0644]
version2/src/Control-2bulbs/java_pid6346.hprof [new file with mode: 0644]
version2/src/Control-2bulbs/settings.gradle [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/BulbColor.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/BulbSwitch.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateGroup.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostFirmware.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostInfo.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateInfo.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateLocation.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateService.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateVersion.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiFirmware.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiInfo.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/Filler.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/Filler2.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/IoTAddress.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/IoTDeviceAddress.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/IoTHTTP.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/IoTSet.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/IoTUDP.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/LifxHeader.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/LifxLightBulb.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/LightBulb.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/LightState.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/LightsController.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/README.txt [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/Sensor.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/Setup.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/Wemo.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/WemoController.java [new file with mode: 0644]
version2/src/java/light_fan_embed_benchmark_2bulbs/build.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/run1.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/run2.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/run3.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller2.bash [new file with mode: 0755]
version2/src/java/light_fan_embed_benchmark_2bulbs/runSetup.bash [new file with mode: 0755]
version2/src/others/Magnetic-Sensor/Makefile
version2/src/others/ino/IR-Sensor/IR-Sensor_Fidelius-Cloud.ino
version2/src/others/ino/Magnetic-Sensor/Magnetic-Sensor_Fidelius-Cloud.ino
version2/src/others/ino/Temp-Sensor/Temp-Sensor_Fidelius-Cloud.ino

index ba09b7a11bb58eb866585ddd16349bed0ef71231..020db0a515c3ac705da33276636776006f978701 100644 (file)
@@ -55,6 +55,9 @@ flash12:
 flash13:
        particle flash IoT-13 photon_firmware*.bin
 
+flash14:
+       particle flash IoT-14 photon_firmware*.bin
+
 PHONY += clean
 clean:
        rm -f *.bin
diff --git a/version2/src/Control-2bulbs/.gitignore b/version2/src/Control-2bulbs/.gitignore
new file mode 100644 (file)
index 0000000..c6cbe56
--- /dev/null
@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
diff --git a/version2/src/Control-2bulbs/.idea/compiler.xml b/version2/src/Control-2bulbs/.idea/compiler.xml
new file mode 100644 (file)
index 0000000..96cc43e
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+      <entry name="!?*.aj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/.idea/copyright/profiles_settings.xml b/version2/src/Control-2bulbs/.idea/copyright/profiles_settings.xml
new file mode 100644 (file)
index 0000000..e7bedf3
--- /dev/null
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+  <settings default="" />
+</component>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/.idea/gradle.xml b/version2/src/Control-2bulbs/.idea/gradle.xml
new file mode 100644 (file)
index 0000000..7ac24c7
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/.idea/misc.xml b/version2/src/Control-2bulbs/.idea/misc.xml
new file mode 100644 (file)
index 0000000..ba7052b
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="NullableNotNullManager">
+    <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
+    <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
+    <option name="myNullables">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+        </list>
+      </value>
+    </option>
+    <option name="myNotNulls">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+        </list>
+      </value>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/.idea/modules.xml b/version2/src/Control-2bulbs/.idea/modules.xml
new file mode 100644 (file)
index 0000000..893470c
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/Control.iml" filepath="$PROJECT_DIR$/Control.iml" />
+      <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/.idea/runConfigurations.xml b/version2/src/Control-2bulbs/.idea/runConfigurations.xml
new file mode 100644 (file)
index 0000000..7f68460
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/.gitignore b/version2/src/Control-2bulbs/app/.gitignore
new file mode 100644 (file)
index 0000000..796b96d
--- /dev/null
@@ -0,0 +1 @@
+/build
diff --git a/version2/src/Control-2bulbs/app/build.gradle b/version2/src/Control-2bulbs/app/build.gradle
new file mode 100644 (file)
index 0000000..aa12c7f
--- /dev/null
@@ -0,0 +1,47 @@
+apply plugin: 'com.android.application'
+
+android {
+
+    dexOptions {
+        preDexLibraries = false
+    }
+
+
+    compileSdkVersion 27
+    buildToolsVersion "27.0.3"
+
+    defaultConfig {
+        applicationId "com.example.ali.control"
+        minSdkVersion 15
+        targetSdkVersion 23
+        versionCode 1
+        versionName "1.0"
+        //jackOptions {
+        //    enabled true
+        //}
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    //compileOptions {
+        //sourceCompatibility JavaVersion.VERSION_1_8
+        //targetCompatibility JavaVersion.VERSION_1_8
+    //}
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    testCompile 'junit:junit:4.12'
+    compile 'com.android.support:appcompat-v7:23.3.0'
+    compile 'com.android.support:design:23.3.0'
+//    compile files('libs/bcpg-jdk15on-1.56.0.0.jar')
+//    compile files('libs/bcpkix-jdk15on-1.56.0.0.jar')
+//    compile files('libs/bctls-jdk15on-1.56.0.0.jar')
+//    compile files('libs/core-1.56.0.0.jar')
+//    compile files('libs/pg-1.54.0.0.jar')
+//    compile files('libs/pkix-1.54.0.0.jar')
+//    compile files('libs/prov-1.56.0.0.jar')
+}
diff --git a/version2/src/Control-2bulbs/app/libs/core-1.56.0.0.jar b/version2/src/Control-2bulbs/app/libs/core-1.56.0.0.jar
new file mode 100644 (file)
index 0000000..025783c
Binary files /dev/null and b/version2/src/Control-2bulbs/app/libs/core-1.56.0.0.jar differ
diff --git a/version2/src/Control-2bulbs/app/proguard-rules.pro b/version2/src/Control-2bulbs/app/proguard-rules.pro
new file mode 100644 (file)
index 0000000..817c313
--- /dev/null
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/Ali/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/version2/src/Control-2bulbs/app/src/androidTest/java/com/example/ali/control/ApplicationTest.java b/version2/src/Control-2bulbs/app/src/androidTest/java/com/example/ali/control/ApplicationTest.java
new file mode 100644 (file)
index 0000000..bfa3cce
--- /dev/null
@@ -0,0 +1,13 @@
+package com.example.ali.control;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
+ */
+public class ApplicationTest extends ApplicationTestCase<Application> {
+    public ApplicationTest() {
+        super(Application.class);
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/AndroidManifest.xml b/version2/src/Control-2bulbs/app/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..59e8cdd
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.ali.control">
+
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
+</manifest>
diff --git a/version2/src/Control-2bulbs/app/src/main/java/com/example/ali/control/MainActivity.java b/version2/src/Control-2bulbs/app/src/main/java/com/example/ali/control/MainActivity.java
new file mode 100644 (file)
index 0000000..9a0fd49
--- /dev/null
@@ -0,0 +1,190 @@
+package com.example.ali.control;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.os.StrictMode;
+
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import iotcloud.*;
+import java.io.*;
+import java.util.concurrent.*;
+import android.os.Handler;
+
+/**
+ * This is a simple alarm controller for Android phone based on the code from Ali Younis
+ * @author Rahmadi Trimananda <rtrimana@uci.edu>
+ * @version 1.0
+ */
+public class MainActivity extends AppCompatActivity implements View.OnClickListener {
+
+    Button alarmButton;
+    TextView alarmStatus;
+
+    Table t1 = null;
+    Semaphore mutex = new Semaphore(1);
+
+    boolean alarmOn = false;
+
+    private Handler handler = new Handler();
+    private static final String CLOUD_SERVER = "http://dc-6.calit2.uci.edu/test.iotcloud/";
+    private static final String PASSWORD = "reallysecret";
+    private static final int LOCAL_MACHINE_ID = 400;
+    private static final int LISTENING_PORT = -1;
+
+    private Runnable runnable = new Runnable() {
+        @Override
+        public void run() {
+
+            //String strAlarm = "alarm";
+            //IoTString iotAlarm = new IoTString(strAlarm);
+            String strBulb = "bulb";
+            IoTString iotBulb = new IoTString(strBulb);
+
+            // Insert custom code here
+            try {
+                Log.e("Ali:::::", "loop............");
+                mutex.acquire();
+                //t1 = new Table(CLOUD_SERVER, PASSWORD, LOCAL_MACHINE_ID, LISTENING_PORT, MainActivity.this);
+                //t1.rebuild();
+                t1.update();
+                IoTString testValStatus = t1.getCommitted(iotBulb);
+                t1.update();
+
+                int intStatus = 0;
+                if(testValStatus != null) {
+                    String strStatus = testValStatus.toString();
+                    intStatus = Integer.parseInt(strStatus);
+                }
+
+                if (intStatus == 0) {
+                    alarmStatus.setText("OFF");
+                    alarmButton.setText("ON");
+                    alarmStatus.setTextColor(Color.BLUE);
+                    //alarmSwitch.setChecked(false);
+                    alarmOn = false;
+                    Log.d("RAHMADI::::", "Set text to OFF and BLUE with alarm value: " + testValStatus);
+                }
+                else {// value 1
+                    alarmStatus.setText("ON");
+                    alarmButton.setText("OFF");
+                    alarmStatus.setTextColor(Color.RED);
+                    //alarmSwitch.setChecked(true);
+                    alarmOn = true;
+                    Log.d("RAHMADI::::", "Set text to ON and RED with alarm value: " + testValStatus);
+                }
+                mutex.release();
+
+            } catch (Exception e) {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                e.printStackTrace(pw);
+                Log.e("ALI::::", sw.toString());
+            }
+
+
+            // Repeat every 2 seconds
+            handler.postDelayed(runnable, 1000);
+        }
+    };
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+
+        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
+        StrictMode.setThreadPolicy(policy);
+
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+
+        try {
+            Log.e("Ali::::", "Here1");
+            t1 = new Table(CLOUD_SERVER, PASSWORD, LOCAL_MACHINE_ID, LISTENING_PORT, MainActivity.this);
+            Log.e("Ali::::", "Here2");
+            //t1.initTable();
+            t1.rebuild(); // update
+            t1.addLocalCommunication(260, "192.168.1.192", 6000);
+            Log.e("Ali::::", "Here3");
+
+        } catch (Exception e) {
+
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            e.printStackTrace(pw);
+            Log.e("ALI::::", sw.toString());
+
+        }
+        // TextViews
+        alarmStatus = (TextView) findViewById(R.id.alarmStatus);
+        alarmStatus.setText("OFF");
+        alarmStatus.setTextColor(Color.BLUE);
+        alarmButton = (Button) findViewById(R.id.alarmButton);
+        alarmButton.setOnClickListener(this);
+
+        //handler.post(runnable);
+    }
+
+    public void onClick(View v) {
+
+        if (v == alarmButton) {
+            String strBulb = "bulb";
+            IoTString iotBulb = new IoTString(strBulb);
+            String strStatusOn = "on";
+            IoTString iotStatusOn = new IoTString(strStatusOn);
+            String strStatusOff = "off";
+            IoTString iotStatusOff = new IoTString(strStatusOff);
+
+            Log.d("RAHMADI:::::", "Button pressed!");
+
+            try {
+                mutex.acquire();
+                if (!alarmOn) {
+
+                    try {
+                        t1.update();
+                        t1.startTransaction();
+                        t1.addKV(iotBulb, iotStatusOn);
+                        t1.commitTransaction();
+                        alarmOn = true;
+                        alarmButton.setText("ON");
+                    } catch (Exception e) {
+                        StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw);
+                        e.printStackTrace(pw);
+                        Log.e("ALI::::", sw.toString());
+                    }
+
+                } else {
+
+                    try {
+                        t1.update();
+                        t1.startTransaction();
+                        t1.addKV(iotBulb, iotStatusOff);
+                        t1.commitTransaction();
+                        alarmOn = false;
+                        alarmButton.setText("OFF");
+                    } catch (Exception e) {
+                        StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw);
+                        e.printStackTrace(pw);
+                        Log.e("ALI::::", sw.toString());
+                    }
+                }
+                mutex.release();
+
+            } catch (Exception e) {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                e.printStackTrace(pw);
+                Log.e("ALI::::", sw.toString());
+            }
+        }
+    }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Abort.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Abort.java
new file mode 100644 (file)
index 0000000..7cafe43
--- /dev/null
@@ -0,0 +1,118 @@
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+import java.lang.Long;
+
+/**
+ * This Entry records the abort sent by a given machine.
+ * @author Ali Younis <ayounis@uci.edu>
+ * @version 1.0
+ */
+
+
+class Abort extends Entry {
+       private long transactionClientLocalSequenceNumber = -1;
+       private long transactionSequenceNumber = -1;
+       private long sequenceNumber = -1;
+       private long transactionMachineId = -1;
+       private long transactionArbitrator = -1;
+       private long arbitratorLocalSequenceNumber = -1;
+
+       private Pair<Long, Long> abortId = null;
+
+
+       public Abort(Slot slot, long _transactionClientLocalSequenceNumber, long _transactionSequenceNumber ,  long _transactionMachineId, long _transactionArbitrator, long _arbitratorLocalSequenceNumber) {
+               super(slot);
+               transactionClientLocalSequenceNumber = _transactionClientLocalSequenceNumber;
+               transactionSequenceNumber = _transactionSequenceNumber;
+               transactionMachineId = _transactionMachineId;
+               transactionArbitrator = _transactionArbitrator;
+               arbitratorLocalSequenceNumber = _arbitratorLocalSequenceNumber;
+               abortId = new Pair<Long, Long>(transactionMachineId, transactionClientLocalSequenceNumber);
+       }
+
+       public Abort(Slot slot, long _transactionClientLocalSequenceNumber, long _transactionSequenceNumber, long _sequenceNumber ,  long _transactionMachineId, long _transactionArbitrator, long _arbitratorLocalSequenceNumber) {
+               super(slot);
+               transactionClientLocalSequenceNumber = _transactionClientLocalSequenceNumber;
+               transactionSequenceNumber = _transactionSequenceNumber;
+               sequenceNumber = _sequenceNumber;
+               transactionMachineId = _transactionMachineId;
+               transactionArbitrator = _transactionArbitrator;
+               arbitratorLocalSequenceNumber = _arbitratorLocalSequenceNumber;
+
+               abortId = new Pair<Long, Long>(transactionMachineId, transactionClientLocalSequenceNumber);
+       }
+
+       public Pair<Long, Long> getAbortId() {
+               return abortId;
+       }
+
+       public long getTransactionMachineId() {
+               return transactionMachineId;
+       }
+
+       public long getTransactionSequenceNumber() {
+               return transactionSequenceNumber;
+       }
+
+       public long getTransactionClientLocalSequenceNumber() {
+               return transactionClientLocalSequenceNumber;
+       }
+
+       public long getArbitratorLocalSequenceNumber() {
+               return arbitratorLocalSequenceNumber;
+       }
+
+
+       public void setSlot(Slot s) {
+               parentslot = s;
+       }
+
+       public long getSequenceNumber() {
+               return sequenceNumber;
+       }
+
+       public void setSequenceNumber(long _sequenceNumber) {
+               sequenceNumber = _sequenceNumber;
+       }
+
+
+       public long getTransactionArbitrator() {
+               return transactionArbitrator;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               long transactionClientLocalSequenceNumber = bb.getLong();
+               long transactionSequenceNumber = bb.getLong();
+               long sequenceNumber = bb.getLong();
+               long transactionMachineId = bb.getLong();
+               long transactionArbitrator = bb.getLong();
+               long arbitratorLocalSequenceNumber = bb.getLong();
+
+               return new Abort(slot, transactionClientLocalSequenceNumber, transactionSequenceNumber, sequenceNumber, transactionMachineId, transactionArbitrator, arbitratorLocalSequenceNumber);
+       }
+
+       public void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeAbort);
+               bb.putLong(transactionClientLocalSequenceNumber);
+               bb.putLong(transactionSequenceNumber);
+               bb.putLong(sequenceNumber);
+               bb.putLong(transactionMachineId);
+               bb.putLong(transactionArbitrator);
+               bb.putLong(arbitratorLocalSequenceNumber);
+       }
+
+       public int getSize() {
+               //return (6 * Long.BYTES) + Byte.BYTES;
+               return (6 * Long.SIZE/8) + Byte.SIZE/8;
+       }
+
+       public byte getType() {
+               return Entry.TypeAbort;
+       }
+
+       public Entry getCopy(Slot s) {
+               return new Abort(s, transactionClientLocalSequenceNumber, transactionSequenceNumber, sequenceNumber, transactionMachineId, transactionArbitrator, arbitratorLocalSequenceNumber);
+       }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ArbitrationRound.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ArbitrationRound.java
new file mode 100644 (file)
index 0000000..0f7d8c8
--- /dev/null
@@ -0,0 +1,110 @@
+package iotcloud;
+
+import java.util.Set;
+import java.util.HashSet;
+
+import java.util.List;
+import java.util.ArrayList;
+
+
+class ArbitrationRound {
+
+    public static final int MAX_PARTS = 10;
+
+    Set<Abort> abortsBefore = null;
+    List<Entry> parts = null;
+    Commit commit = null;
+    int currentSize = 0;
+    boolean didSendPart = false;
+    boolean didGenerateParts = false;
+
+    public ArbitrationRound(Commit _commit, Set<Abort> _abortsBefore) {
+
+        parts = new ArrayList<Entry>();
+
+        commit = _commit;
+        abortsBefore = _abortsBefore;
+
+
+        if (commit != null) {
+            commit.createCommitParts();
+            currentSize += commit.getNumberOfParts();
+        }
+
+        currentSize += abortsBefore.size();
+    }
+
+    public void generateParts() {
+        if (didGenerateParts) {
+            return;
+        }
+        parts = new ArrayList<Entry>(abortsBefore);
+        if (commit != null) {
+            parts.addAll(commit.getParts().values());
+        }
+    }
+
+
+    public List<Entry> getParts() {
+        return parts;
+    }
+
+    public void removeParts(List<Entry> removeParts) {
+        parts.removeAll(removeParts);
+        didSendPart = true;
+    }
+
+    public boolean isDoneSending() {
+        if ((commit == null) && abortsBefore.isEmpty()) {
+            return true;
+        }
+
+        return parts.isEmpty();
+    }
+
+    public Commit getCommit() {
+        return commit;
+    }
+
+    public void setCommit(Commit _commit) {
+        if (commit != null) {
+            currentSize -= commit.getNumberOfParts();
+        }
+        commit = _commit;
+
+        if (commit != null) {
+            currentSize += commit.getNumberOfParts();
+        }
+    }
+
+    public void addAbort(Abort abort) {
+        abortsBefore.add(abort);
+        currentSize++;
+    }
+
+    public void addAborts(Set<Abort> aborts) {
+        abortsBefore.addAll(aborts);
+        currentSize += aborts.size();
+    }
+
+
+    public Set<Abort> getAborts() {
+        return abortsBefore;
+    }
+
+    public int getAbortsCount() {
+        return abortsBefore.size();
+    }
+
+    public int getCurrentSize() {
+        return currentSize;
+    }
+
+    public boolean isFull() {
+        return currentSize >= MAX_PARTS;
+    }
+
+    public boolean didSendPart() {
+        return didSendPart;
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/CloudComm.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/CloudComm.java
new file mode 100644 (file)
index 0000000..0ecaf77
--- /dev/null
@@ -0,0 +1,911 @@
+package iotcloud;
+
+import java.io.*;
+import java.net.*;
+import java.util.Arrays;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.security.SecureRandom;
+import android.util.*;
+import java.nio.charset.StandardCharsets;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import android.content.*;
+import java.nio.ByteBuffer;
+
+
+/**
+ * This class provides a communication API to the webserver.  It also
+ * validates the HMACs on the slots and handles encryption.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+class CloudComm {
+       private static final int SALT_SIZE = 8;
+       private static final int TIMEOUT_MILLIS = 2000; // 100
+       public static final int IV_SIZE = 16;
+
+       /** Sets the size for the HMAC. */
+       static final int HMAC_SIZE = 32;
+
+       private String baseurl;
+       private SecretKeySpec key;
+       private Mac mac;
+       private String password;
+       private SecureRandom random;
+       private byte salt[];
+       private Table table;
+       private int listeningPort = -1;
+       private Thread localServerThread = null;
+       private boolean doEnd = false;
+
+       private TimingSingleton timer = null;
+
+       private Context context;
+
+
+
+
+       /**
+        * Empty Constructor needed for child class.
+        */
+       CloudComm() {
+               timer = TimingSingleton.getInstance();
+       }
+
+       private void deleteFile(Context context) {
+               File fd = context.getFileStreamPath("config.txt");
+               fd.delete();
+       }
+
+
+       private void writeToFile(byte[] data,Context context) {
+               try {
+//                     OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("config.txt", Context.MODE_PRIVATE));
+//                     outputStreamWriter.write(data);
+//                     outputStreamWriter.close();
+
+                       FileOutputStream outputStreamWriter = context.openFileOutput("config.txt", Context.MODE_PRIVATE);
+                       outputStreamWriter.write(data);
+                       outputStreamWriter.close();
+
+               }
+               catch (IOException e) {
+                       Log.e("Exception", "File write failed: " + e.toString());
+               }
+       }
+
+       private byte[] readFromFile(Context context) throws FileNotFoundException {
+
+               byte[] ret1 = null;
+
+               try {
+                       InputStream inputStream = context.openFileInput("config.txt");
+
+                       if ( inputStream != null ) {
+
+
+                               ret1 = new byte[inputStream.available()];
+                               for(int i = 0; i < ret1.length;i++)
+                               {
+                                       ret1[i] = (byte)inputStream.read();
+                               }
+
+
+
+
+//                             InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+//                             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+//                             String receiveString = "";
+//                             StringBuilder stringBuilder = new StringBuilder();
+
+//                             while ( (receiveString = bufferedReader.readLine()) != null ) {
+//                                     stringBuilder.append(receiveString);
+//                             }
+
+                               inputStream.close();
+//                             ret = stringBuilder.toString();
+                       }
+               }
+               catch (FileNotFoundException e) {
+                       Log.e("login activity", "File not found: " + e.toString());
+
+                       throw e;
+               } catch (IOException e) {
+                       Log.e("login activity", "Can not read file: " + e.toString());
+               }
+
+               return ret1;
+       }
+
+
+
+       /**
+        * Constructor for actual use. Takes in the url and password.
+        */
+       CloudComm(Table _table,  String _baseurl, String _password, int _listeningPort, Context _context) {
+               timer = TimingSingleton.getInstance();
+               this.table = _table;
+               this.baseurl = _baseurl;
+               this.password = _password;
+               this.random = new SecureRandom();
+               this.listeningPort = _listeningPort;
+               this.context = _context;
+
+
+               if (this.listeningPort > 0) {
+                       localServerThread = new Thread(new Runnable() {
+                               public void run() {
+                                       localServerWorkerFunction();
+                               }
+                       });
+                       localServerThread.start();
+               }
+       }
+
+       /**
+        * Generates Key from password.
+        */
+       private SecretKeySpec initKey() {
+               try {
+
+                       Log.e("Ali:::::", "KEY KEY KEY......");
+
+
+
+                       boolean doCrypt = false;
+
+                       byte[] keySaved = null;
+
+                       try {
+//                             String file = readFromFile(context);
+                               byte[] dat = readFromFile(context);//file.getBytes();
+
+                               boolean saltMatch = true;
+                               for(int i = 0; i < salt.length; i++)
+                               {
+
+                                       Log.e("ALIasdasdaS:", " " + ((int) salt[i] & 255) + " " + ((int) dat[i] & 255));
+
+                                       if(dat[i] != salt[i])
+                                       {
+                                               saltMatch = false;
+//                                             break;
+                                       }
+                               }
+
+                               if(saltMatch )
+                               {
+                                       keySaved = new byte[dat.length - salt.length];
+                                       for(int i = salt.length; i < dat.length;i++)
+                                       {
+                                               keySaved[i-salt.length] = dat[i];
+                                       }
+                               }
+                               else
+                               {
+                                       doCrypt = true;
+                                       Log.e("Ali:::::", "Salt No Match......");
+
+                               }
+
+
+
+
+
+                       }
+                       catch (Exception e)
+                       {
+                               doCrypt = true;
+                       }
+
+
+
+                       if(doCrypt) {
+                               Log.e("Ali:::::", "Doing Crypt......");
+                               PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
+                               generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password.toCharArray()), salt, 65536);
+                               KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(128);
+
+
+//                     PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(),
+//                                                         salt,
+//                                                         65536,
+//                                                         128);
+//                     SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(keyspec);
+//                     SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
+
+
+//                     return new SecretKeySpec(tmpkey.getEncoded(), "AES");
+
+
+                               byte[] keyDat = key.getKey();
+                               byte[] saveDat = new byte[salt.length + keyDat.length];
+
+                               for (int i = 0 ; i < salt.length;i++)
+                               {
+                                       saveDat[i] = salt[i];
+                               }
+
+                               for (int i = 0 ; i < keyDat.length;i++)
+                               {
+                                       saveDat[i + salt.length] = keyDat[i];
+                               }
+
+
+                               deleteFile(context);
+                               writeToFile(saveDat, context);
+
+                               return new SecretKeySpec(key.getKey(), "AES");
+                       }
+                       else{
+
+                               Log.e("Ali:::::", "Using Saved......");
+
+                               return new SecretKeySpec(keySaved, "AES");
+                       }
+
+
+               } catch (Exception e) {
+                       StringWriter sw = new StringWriter();
+                       PrintWriter pw = new PrintWriter(sw);
+                       e.printStackTrace(pw);
+                        // stack trace as a string
+
+
+                       throw new Error("Failed generating key.   "  + sw.toString());
+               }
+       }
+
+       /**
+        * Inits all the security stuff
+        */
+       public void initSecurity() throws ServerException {
+               // try to get the salt and if one does not exist set one
+               if (!getSalt()) {
+                       //Set the salt
+                       setSalt();
+               }
+
+               initCrypt();
+       }
+
+       /**
+        * Inits the HMAC generator.
+        */
+       /**
+        * Inits the HMAC generator.
+        */
+       private void initCrypt() {
+
+               if (password == null) {
+                       return;
+               }
+
+               try {
+                       key = initKey();
+                       password = null; // drop password
+                       mac = Mac.getInstance("HmacSHA256");
+                       mac.init(key);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed To Initialize Ciphers");
+               }
+       }
+
+
+       /*
+        * Builds the URL for the given request.
+        */
+       private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException {
+               String reqstring = isput ? "req=putslot" : "req=getslot";
+               String urlstr = baseurl + "?" + reqstring + "&seq=" + sequencenumber;
+               if (maxentries != 0)
+                       urlstr += "&max=" + maxentries;
+               return new URL(urlstr);
+       }
+
+       private void setSalt() throws ServerException {
+
+               if (salt != null) {
+                       // Salt already sent to server so dont set it again
+                       return;
+               }
+
+               try {
+                       byte[] saltTmp = new byte[SALT_SIZE];
+                       random.nextBytes(saltTmp);
+
+                       URL url = new URL(baseurl + "?req=setsalt");
+                       
+                       timer.startTime();
+                       URLConnection con = url.openConnection();
+                       HttpURLConnection http = (HttpURLConnection) con;
+
+                       http.setRequestMethod("POST");
+                       http.setFixedLengthStreamingMode(saltTmp.length);
+                       http.setDoOutput(true);
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+
+                       
+                       http.connect();
+
+                       OutputStream os = http.getOutputStream();
+                       os.write(saltTmp);
+                       os.flush();
+                       
+                       int responsecode = http.getResponseCode();
+                       if (responsecode != HttpURLConnection.HTTP_OK) {
+                               // TODO: Remove this print
+                               System.out.println(responsecode);
+                               throw new Error("Invalid response");
+                       }
+
+                       timer.endTime();
+
+                       salt = saltTmp;
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       timer.endTime();
+                       throw new ServerException("Failed setting salt", ServerException.TypeConnectTimeout);
+               }
+       }
+
+       private boolean getSalt() throws ServerException {
+               URL url = null;
+               URLConnection con = null;
+               HttpURLConnection http = null;
+
+               try {
+                       url = new URL(baseurl + "?req=getsalt");
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       throw new Error("getSlot failed");
+               }
+               try {
+
+                       timer.startTime();
+                       con = url.openConnection();
+                       http = (HttpURLConnection) con;
+                       http.setRequestMethod("POST");
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+                       http.setReadTimeout(TIMEOUT_MILLIS);
+
+                       
+                       http.connect();
+                       timer.endTime();
+
+
+               } catch (SocketTimeoutException e) {
+                       timer.endTime();
+                       throw new ServerException("getSalt failed", ServerException.TypeConnectTimeout);
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       throw new Error("getSlot failed  " + e.toString());
+               }
+
+               try {
+
+                       timer.startTime();
+
+                       int responsecode = http.getResponseCode();
+                       if (responsecode != HttpURLConnection.HTTP_OK) {
+                               // TODO: Remove this print
+                               // System.out.println(responsecode);
+                               throw new Error("Invalid response");
+                       }
+
+//                     Log.e("Aaaaa", "Code " + responsecode);
+
+
+                       InputStream is = http.getInputStream();
+//
+//
+//                     BufferedReader rd= new BufferedReader(new InputStreamReader(is));
+//                     int line;
+//                     StringBuilder sb= new StringBuilder();
+//                     while ((line = rd.read())!= -1)
+//                     {
+//                             sb.append((char)line);
+//                             Log.e("Aaaaa", "line " + line);
+//
+//                     }
+//
+//
+//                     int sdfsdfds = (int)sb.toString().charAt(0);
+//                     Log.e("Aaaaa", "length " + (int)sb.toString().charAt(0));
+//                     Log.e("Aaaaa", "Res " + sb.toString().length());
+
+
+//                     is = new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8));
+
+
+//                     if (is.available() > 0) {
+//                     if (sb.toString().length() > 0) {
+                       if(true)
+                       {
+                               try {
+                                       DataInputStream dis = new DataInputStream(is);
+                                       int salt_length = dis.readInt();
+                                       byte[] tmp = new byte[salt_length];
+//                             byte [] tmp = new byte[8];
+                                       dis.readFully(tmp);
+                                       salt = tmp;
+
+                                       for (int i = 0; i < 8; i++) {
+                                               Log.e("ALIasdasdaS:", "asd " + ((int) salt[i] & 255));
+                                       }
+
+
+                                       timer.endTime();
+
+                                       return true;
+                               }
+                               catch (Exception e)
+                               {
+                                       timer.endTime();
+
+                                       Log.e("Aaaaa", "Salt No Data");
+
+                                       return false;
+                               }
+                       }
+                       else {
+
+
+                               return false;
+                       }
+               } catch (SocketTimeoutException e) {
+                       timer.endTime();
+
+                       throw new ServerException("getSalt failed", ServerException.TypeInputTimeout);
+               } catch (Exception e) {
+
+                       throw new Error("getSlot failed + " + e);
+               }
+       }
+
+
+       private byte[] createIV(long machineId, long localSequenceNumber) {
+               ByteBuffer buffer = ByteBuffer.allocate(IV_SIZE);
+               buffer.putLong(machineId);
+               long localSequenceNumberShifted = localSequenceNumber << 16;
+               buffer.putLong(localSequenceNumberShifted);
+               return buffer.array();
+
+       }
+
+       private byte[] encryptSlotAndPrependIV(byte[] rawData, byte[] ivBytes) {
+               try {
+                       ivBytes = new byte[IV_SIZE];
+                       IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+                       //Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
+                       // We no longer need PKCS5Padding for CTR mode
+                       // There was a bug that the crypto library for Android that adds 16 more bytes into
+                       // the existing 2048 bytes after HMAC is calculated so that this causes HMAC mismatch
+                       // on the Java side that is expecting exactly 2048 bytes of padding.
+                       Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+                       cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+
+                       byte[] encryptedBytes = cipher.doFinal(rawData);
+                       byte[] bytes = new byte[encryptedBytes.length + IV_SIZE];
+                       System.arraycopy(ivBytes, 0, bytes, 0, ivBytes.length);
+                       System.arraycopy(encryptedBytes, 0, bytes, IV_SIZE, encryptedBytes.length);
+
+                       return bytes;
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed To Encrypt");
+               }
+       }
+
+
+       private byte[] stripIVAndDecryptSlot(byte[] rawData) {
+               try {
+                       byte[] ivBytes = new byte[IV_SIZE];
+                       byte[] encryptedBytes = new byte[rawData.length - IV_SIZE];
+                       System.arraycopy(rawData, 0, ivBytes, 0, IV_SIZE);
+                       System.arraycopy(rawData, IV_SIZE, encryptedBytes, 0 , encryptedBytes.length);
+
+                       IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+
+                       //Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
+                       // We no longer need PKCS5Padding for CTR mode
+                       // There was a bug that the crypto library for Android that adds 16 more bytes into
+                       // the existing 2048 bytes after HMAC is calculated so that this causes HMAC mismatch
+                       // on the Java side that is expecting exactly 2048 bytes of padding.
+                       Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+                       cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
+
+                       return cipher.doFinal(encryptedBytes);
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed To Decrypt");
+               }
+       }
+
+       /*
+        * API for putting a slot into the queue.  Returns null on success.
+        * On failure, the server will send slots with newer sequence
+        * numbers.
+        */
+       public Slot[] putSlot(Slot slot, int max) throws ServerException {
+               URL url = null;
+               URLConnection con = null;
+               HttpURLConnection http = null;
+
+               try {
+                       if (salt == null) {
+                               if (!getSalt()) {
+                                       throw new ServerException("putSlot failed", ServerException.TypeSalt);
+                               }
+                               initCrypt();
+                       }
+                       long sequencenumber = slot.getSequenceNumber();
+                       byte[] slotBytes = slot.encode(mac);
+                       // slotBytes = encryptCipher.doFinal(slotBytes);
+
+                       // byte[] iVBytes = slot.getSlotCryptIV();
+
+                       // byte[] bytes = new byte[slotBytes.length + IV_SIZE];
+                       // System.arraycopy(iVBytes, 0, bytes, 0, iVBytes.length);
+                       // System.arraycopy(slotBytes, 0, bytes, IV_SIZE, slotBytes.length);
+
+
+                       byte[] bytes = encryptSlotAndPrependIV(slotBytes, slot.getSlotCryptIV());
+
+
+
+                       url = buildRequest(true, sequencenumber, max);
+
+                       timer.startTime();
+                       con = url.openConnection();
+                       http = (HttpURLConnection) con;
+
+                       http.setRequestMethod("POST");
+                       http.setFixedLengthStreamingMode(bytes.length);
+                       http.setDoOutput(true);
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+                       http.setReadTimeout(TIMEOUT_MILLIS);
+                       http.connect();
+
+                       OutputStream os = http.getOutputStream();
+                       os.write(bytes);
+                       os.flush();
+
+                       timer.endTime();
+
+
+                       // System.out.println("Bytes Sent: " + bytes.length);
+               } catch (ServerException e) {
+                       timer.endTime();
+
+                       throw e;
+               } catch (SocketTimeoutException e) {
+                       timer.endTime();
+
+                       throw new ServerException("putSlot failed", ServerException.TypeConnectTimeout);
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       throw new Error("putSlot failed");
+               }
+
+
+
+               try {
+                       timer.startTime();
+                       InputStream is = http.getInputStream();
+                       DataInputStream dis = new DataInputStream(is);
+                       byte[] resptype = new byte[7];
+                       dis.readFully(resptype);
+                       timer.endTime();
+
+                       if (Arrays.equals(resptype, "getslot".getBytes()))
+                       {       
+                               return processSlots(dis);
+                       }
+                       else if (Arrays.equals(resptype, "putslot".getBytes()))
+                       {
+                               return null;
+                       }
+                       else
+                               throw new Error("Bad response to putslot");
+
+               } catch (SocketTimeoutException e) {
+                               timer.endTime();
+                       throw new ServerException("putSlot failed", ServerException.TypeInputTimeout);
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       throw new Error("putSlot failed");
+               }
+       }
+
+       /**
+        * Request the server to send all slots with the given
+        * sequencenumber or newer.
+        */
+       public Slot[] getSlots(long sequencenumber) throws ServerException {
+               URL url = null;
+               URLConnection con = null;
+               HttpURLConnection http = null;
+
+               try {
+                       if (salt == null) {
+                               if (!getSalt()) {
+                                       throw new ServerException("getSlots failed", ServerException.TypeSalt);
+                               }
+                               initCrypt();
+                       }
+
+                       url = buildRequest(false, sequencenumber, 0);
+                       timer.startTime();
+                       con = url.openConnection();
+                       http = (HttpURLConnection) con;
+                       http.setRequestMethod("POST");
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+                       http.setReadTimeout(TIMEOUT_MILLIS);
+
+                       
+
+                       http.connect();
+                       timer.endTime();
+
+               } catch (SocketTimeoutException e) {
+                       timer.endTime();
+
+                       throw new ServerException("getSlots failed", ServerException.TypeConnectTimeout);
+               } catch (ServerException e) {
+                       timer.endTime();
+
+                       throw e;
+               } catch (IOException e) {
+                       // e.printStackTrace();
+                       throw new Error("getSlots failed   " + e.toString());
+               }
+
+               try {
+                       
+                       timer.startTime();
+                       InputStream is = http.getInputStream(); 
+                       DataInputStream dis = new DataInputStream(is);
+                       byte[] resptype = new byte[7];
+                       
+                       dis.readFully(resptype);
+                       timer.endTime();
+
+                       if (!Arrays.equals(resptype, "getslot".getBytes()))
+                               throw new Error("Bad Response: " + new String(resptype));
+
+                       return processSlots(dis);
+               } catch (SocketTimeoutException e) {
+                       timer.endTime();
+
+                       throw new ServerException("getSlots failed", ServerException.TypeInputTimeout);
+               } catch (Exception e) {
+                       // e.printStackTrace();
+                       StringWriter sw = new StringWriter();
+                       PrintWriter pw = new PrintWriter(sw);
+                       e.printStackTrace(pw);
+                       throw new Error("getSlots failed   " + sw.toString());
+               }
+       }
+
+       /**
+        * Method that actually handles building Slot objects from the
+        * server response.  Shared by both putSlot and getSlots.
+        */
+       private Slot[] processSlots(DataInputStream dis) throws Exception {
+               int numberofslots = dis.readInt();
+               int[] sizesofslots = new int[numberofslots];
+
+               Slot[] slots = new Slot[numberofslots];
+               for (int i = 0; i < numberofslots; i++)
+                       sizesofslots[i] = dis.readInt();
+
+               for (int i = 0; i < numberofslots; i++) {
+
+                       byte[] rawData = new byte[sizesofslots[i]];
+                       dis.readFully(rawData);
+
+
+                       // byte[] data = new byte[rawData.length - IV_SIZE];
+                       // System.arraycopy(rawData, IV_SIZE, data, 0, data.length);
+
+
+                       byte[] data = stripIVAndDecryptSlot(rawData);
+
+                       slots[i] = Slot.decode(table, data, mac);
+
+                       Log.e("Ali::::", "Slot Process");
+               }
+               dis.close();
+               return slots;
+       }
+
+       public byte[] sendLocalData(byte[] sendData, long localSequenceNumber, String host, int port) {
+
+               if (salt == null) {
+                       return null;
+               }
+               try {
+
+                       System.out.println("Passing Locally");
+
+                       mac.update(sendData);
+                       byte[] genmac = mac.doFinal();
+                       byte[] totalData = new byte[sendData.length + genmac.length];
+                       System.arraycopy(sendData, 0, totalData, 0, sendData.length);
+                       System.arraycopy(genmac, 0, totalData, sendData.length, genmac.length);
+
+                       // Encrypt the data for sending
+                       // byte[] encryptedData = encryptCipher.doFinal(totalData);
+//                     byte[] encryptedData = encryptCipher.doFinal(totalData);
+
+                       byte[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber());
+                       byte[] encryptedData = encryptSlotAndPrependIV(totalData, iv);
+
+
+
+                       // Open a TCP socket connection to a local device
+                       Socket socket = new Socket(host, port);
+                       socket.setReuseAddress(true);
+                       DataOutputStream output = new DataOutputStream(socket.getOutputStream());
+                       DataInputStream input = new DataInputStream(socket.getInputStream());
+
+
+                       timer.startTime();
+                       // Send data to output (length of data, the data)
+                       output.writeInt(encryptedData.length);
+                       output.write(encryptedData, 0, encryptedData.length);
+                       output.flush();
+
+                       int lengthOfReturnData = input.readInt();
+                       byte[] returnData = new byte[lengthOfReturnData];
+                       input.readFully(returnData);
+
+                       timer.endTime();
+
+//                     returnData = decryptCipher.doFinal(returnData);
+                       returnData = stripIVAndDecryptSlot(returnData);
+
+                       // We are done with this socket
+                       socket.close();
+
+                       mac.update(returnData, 0, returnData.length - HMAC_SIZE);
+                       byte[] realmac = mac.doFinal();
+                       byte[] recmac = new byte[HMAC_SIZE];
+                       System.arraycopy(returnData, returnData.length - realmac.length, recmac, 0, realmac.length);
+
+                       if (!Arrays.equals(recmac, realmac))
+                               throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
+
+                       byte[] returnData2 = new byte[lengthOfReturnData - recmac.length];
+                       System.arraycopy(returnData, 0, returnData2, 0, returnData2.length);
+
+                       return returnData2;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       // throw new Error("Local comms failure...");
+
+               }
+
+               return null;
+       }
+
+       private void localServerWorkerFunction() {
+
+               ServerSocket inputSocket = null;
+
+               try {
+                       // Local server socket
+                       inputSocket = new ServerSocket(listeningPort);
+                       inputSocket.setReuseAddress(true);
+                       inputSocket.setSoTimeout(TIMEOUT_MILLIS);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Local server setup failure...");
+               }
+
+               while (!doEnd) {
+
+                       try {
+                               // Accept incoming socket
+                               Socket socket = inputSocket.accept();
+
+                               DataInputStream input = new DataInputStream(socket.getInputStream());
+                               DataOutputStream output = new DataOutputStream(socket.getOutputStream());
+
+                               // Get the encrypted data from the server
+                               int dataSize = input.readInt();
+                               byte[] readData = new byte[dataSize];
+                               input.readFully(readData);
+
+                               timer.endTime();
+
+                               // Decrypt the data
+//                             readData = decryptCipher.doFinal(readData);
+                               readData = stripIVAndDecryptSlot(readData);
+
+
+                               mac.update(readData, 0, readData.length - HMAC_SIZE);
+                               byte[] genmac = mac.doFinal();
+                               byte[] recmac = new byte[HMAC_SIZE];
+                               System.arraycopy(readData, readData.length - recmac.length, recmac, 0, recmac.length);
+
+                               if (!Arrays.equals(recmac, genmac))
+                                       throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
+
+                               byte[] returnData = new byte[readData.length - recmac.length];
+                               System.arraycopy(readData, 0, returnData, 0, returnData.length);
+
+                               // Process the data
+                               // byte[] sendData = table.acceptDataFromLocal(readData);
+                               byte[] sendData = table.acceptDataFromLocal(returnData);
+
+                               mac.update(sendData);
+                               byte[] realmac = mac.doFinal();
+                               byte[] totalData = new byte[sendData.length + realmac.length];
+                               System.arraycopy(sendData, 0, totalData, 0, sendData.length);
+                               System.arraycopy(realmac, 0, totalData, sendData.length, realmac.length);
+
+                               // Encrypt the data for sending
+//                             byte[] encryptedData = encryptCipher.doFinal(totalData);
+                               byte[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber());
+                               byte[] encryptedData = encryptSlotAndPrependIV(totalData, iv);
+
+
+                               timer.startTime();
+                               // Send data to output (length of data, the data)
+                               output.writeInt(encryptedData.length);
+                               output.write(encryptedData, 0, encryptedData.length);
+                               output.flush();
+
+                               // close the socket
+                               socket.close();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                               // throw new Error("Local comms failure...");
+
+                       }
+               }
+
+               if (inputSocket != null) {
+                       try {
+                               inputSocket.close();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                               throw new Error("Local server close failure...");
+                       }
+               }
+       }
+
+       public void close() {
+               doEnd = true;
+
+               if (localServerThread != null) {
+                       try {
+                               localServerThread.join();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                               throw new Error("Local Server thread join issue...");
+                       }
+               }
+
+               // System.out.println("Done Closing Cloud Comm");
+       }
+
+       protected void finalize() throws Throwable {
+               try {
+                       close();        // close open files
+               } finally {
+                       super.finalize();
+               }
+       }
+
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Commit.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Commit.java
new file mode 100644 (file)
index 0000000..17edc12
--- /dev/null
@@ -0,0 +1,286 @@
+package iotcloud;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.nio.ByteBuffer;
+
+class Commit {
+
+    private Map<Integer, CommitPart> parts = null;
+    private Set<Integer> missingParts = null;
+    private boolean isComplete = false;
+    private boolean hasLastPart = false;
+    private Set<KeyValue> keyValueUpdateSet = null;
+    private boolean isDead = false;
+    private long sequenceNumber = -1;
+    private long machineId = -1;
+    private long transactionSequenceNumber = -1;
+
+    private Set<IoTString> liveKeys = null;
+
+    public Commit() {
+        parts = new HashMap<Integer, CommitPart>();
+        keyValueUpdateSet = new HashSet<KeyValue>();
+
+        liveKeys = new HashSet<IoTString>();
+    }
+
+    public Commit(long _sequenceNumber, long _machineId, long _transactionSequenceNumber) {
+        parts = new HashMap<Integer, CommitPart>();
+        keyValueUpdateSet = new HashSet<KeyValue>();
+
+        liveKeys = new HashSet<IoTString>();
+
+        sequenceNumber = _sequenceNumber;
+        machineId = _machineId;
+        transactionSequenceNumber = _transactionSequenceNumber;
+        isComplete = true;
+    }
+
+
+    public void addPartDecode(CommitPart newPart) {
+
+        if (isDead) {
+            // If dead then just kill this part and move on
+            newPart.setDead();
+            return;
+        }
+
+        CommitPart previoslySeenPart = parts.put(newPart.getPartNumber(), newPart);
+
+        if (previoslySeenPart != null) {
+            // Set dead the old one since the new one is a rescued version of this part
+            previoslySeenPart.setDead();
+        } else if (newPart.isLastPart()) {
+            missingParts = new HashSet<Integer>();
+            hasLastPart = true;
+
+            for (int i = 0; i < newPart.getPartNumber(); i++) {
+                if (parts.get(i) == null) {
+                    missingParts.add(i);
+                }
+            }
+        }
+
+        if (!isComplete && hasLastPart) {
+
+            // We have seen this part so remove it from the set of missing parts
+            missingParts.remove(newPart.getPartNumber());
+
+            // Check if all the parts have been seen
+            if (missingParts.size() == 0) {
+
+                // We have all the parts
+                isComplete = true;
+
+                // Decode all the parts and create the key value guard and update sets
+                decodeCommitData();
+
+                // Get the sequence number and arbitrator of this transaction
+                sequenceNumber = parts.get(0).getSequenceNumber();
+                machineId = parts.get(0).getMachineId();
+                transactionSequenceNumber = parts.get(0).getTransactionSequenceNumber();
+            }
+        }
+    }
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    public long getTransactionSequenceNumber() {
+        return transactionSequenceNumber;
+    }
+
+    public Map<Integer, CommitPart> getParts() {
+        return parts;
+    }
+
+    public void addKV(KeyValue kv) {
+        keyValueUpdateSet.add(kv);
+        liveKeys.add(kv.getKey());
+    }
+
+    public void invalidateKey(IoTString key) {
+        liveKeys.remove(key);
+
+        if (liveKeys.size() == 0) {
+            setDead();
+        }
+    }
+
+    public Set<KeyValue> getKeyValueUpdateSet() {
+        return keyValueUpdateSet;
+    }
+
+    public int getNumberOfParts() {
+        return parts.size();
+    }
+
+    public long getMachineId() {
+        return machineId;
+    }
+
+    public boolean isComplete() {
+        return isComplete;
+    }
+
+    public boolean isLive() {
+        return !isDead;
+    }
+
+    public void setDead() {
+        if (isDead) {
+            // Already dead
+            return;
+        }
+
+        // Set dead
+        isDead = true;
+
+        // Make all the parts of this transaction dead
+        for (Integer partNumber : parts.keySet()) {
+            CommitPart part = parts.get(partNumber);
+            part.setDead();
+        }
+    }
+
+    public CommitPart getPart(int index) {
+        return parts.get(index);
+    }
+
+    public void createCommitParts() {
+
+        parts.clear();
+
+        // Convert to bytes
+        byte[] byteData = convertDataToBytes();
+
+
+        int commitPartCount = 0;
+        int currentPosition = 0;
+        int remaining = byteData.length;
+
+        while (remaining > 0) {
+
+            Boolean isLastPart = false;
+            // determine how much to copy
+            int copySize = CommitPart.MAX_NON_HEADER_SIZE;
+            if (remaining <= CommitPart.MAX_NON_HEADER_SIZE) {
+                copySize = remaining;
+                isLastPart = true; // last bit of data so last part
+            }
+
+            // Copy to a smaller version
+            byte[] partData = new byte[copySize];
+            System.arraycopy(byteData, currentPosition, partData, 0, copySize);
+
+            CommitPart part = new CommitPart(null, machineId, sequenceNumber, transactionSequenceNumber, commitPartCount, partData, isLastPart);
+            parts.put(part.getPartNumber(), part);
+
+            // Update position, count and remaining
+            currentPosition += copySize;
+            commitPartCount++;
+            remaining -= copySize;
+        }
+    }
+
+    private void decodeCommitData() {
+
+        // Calculate the size of the data section
+        int dataSize = 0;
+        for (int i = 0; i < parts.keySet().size(); i++) {
+            CommitPart tp = parts.get(i);
+            dataSize += tp.getDataSize();
+        }
+
+        byte[] combinedData = new byte[dataSize];
+        int currentPosition = 0;
+
+        // Stitch all the data sections together
+        for (int i = 0; i < parts.keySet().size(); i++) {
+            CommitPart tp = parts.get(i);
+            System.arraycopy(tp.getData(), 0, combinedData, currentPosition, tp.getDataSize());
+            currentPosition += tp.getDataSize();
+        }
+
+        // Decoder Object
+        ByteBuffer bbDecode = ByteBuffer.wrap(combinedData);
+
+        // Decode how many key value pairs need to be decoded
+        int numberOfKVUpdates = bbDecode.getInt();
+
+        // Decode all the updates key values
+        for (int i = 0; i < numberOfKVUpdates; i++) {
+            KeyValue kv = (KeyValue)KeyValue.decode(bbDecode);
+            keyValueUpdateSet.add(kv);
+            liveKeys.add(kv.getKey());
+        }
+    }
+
+    private byte[] convertDataToBytes() {
+
+        // Calculate the size of the data
+        //int sizeOfData = Integer.BYTES; // Number of Update KV's
+        int sizeOfData = Integer.SIZE/8; // Number of Update KV's
+        for (KeyValue kv : keyValueUpdateSet) {
+            sizeOfData += kv.getSize();
+        }
+
+        // Data handlers and storage
+        byte[] dataArray = new byte[sizeOfData];
+        ByteBuffer bbEncode = ByteBuffer.wrap(dataArray);
+
+        // Encode the size of the updates and guard sets
+        bbEncode.putInt(keyValueUpdateSet.size());
+
+        // Encode all the updates
+        for (KeyValue kv : keyValueUpdateSet) {
+            kv.encode(bbEncode);
+        }
+
+        return bbEncode.array();
+    }
+
+    private void setKVsMap(Map<IoTString, KeyValue> newKVs) {
+        keyValueUpdateSet.clear();
+        liveKeys.clear();
+
+        keyValueUpdateSet.addAll(newKVs.values());
+        liveKeys.addAll(newKVs.keySet());
+
+    }
+
+
+    public static Commit merge(Commit newer, Commit older, long newSequenceNumber) {
+
+        if (older == null) {
+            return newer;
+        } else if (newer == null) {
+            return older;
+        }
+
+        Map<IoTString, KeyValue> kvSet = new HashMap<IoTString, KeyValue>();
+        for (KeyValue kv : older.getKeyValueUpdateSet()) {
+            kvSet.put(kv.getKey(), kv);
+        }
+
+        for (KeyValue kv : newer.getKeyValueUpdateSet()) {
+            kvSet.put(kv.getKey(), kv);
+        }
+
+        long transactionSequenceNumber = newer.getTransactionSequenceNumber();
+
+        if (transactionSequenceNumber == -1) {
+            transactionSequenceNumber = older.getTransactionSequenceNumber();
+        }
+
+        Commit newCommit = new Commit(newSequenceNumber, newer.getMachineId(), transactionSequenceNumber);
+
+        newCommit.setKVsMap(kvSet);
+
+        return newCommit;
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/CommitPart.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/CommitPart.java
new file mode 100644 (file)
index 0000000..f465416
--- /dev/null
@@ -0,0 +1,126 @@
+
+
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+class CommitPart extends Entry{
+
+    // Max size of the part excluding the fixed size header
+    public static final int MAX_NON_HEADER_SIZE = 512;
+
+
+    // Sequence number of the transaction this commit is for, -1 if not a cloud transaction
+    private long machineId = -1; // Machine Id of the device that made the commit
+    private long sequenceNumber = -1; // commit sequence number for this arbitrator
+    private long transactionSequenceNumber = -1;
+    private int partNumber = -1; // Parts position in the
+    private Boolean isLastPart = false;
+    private byte[] data = null;
+
+    private Pair<Long, Integer> partId = null;
+    private Pair<Long, Long> commitId = null;
+
+
+    public CommitPart(Slot s, long _machineId, long _sequenceNumber, long _transactionSequenceNumber, int _partNumber, byte[] _data, Boolean _isLastPart) {
+        super(s);
+        machineId = _machineId;
+        sequenceNumber = _sequenceNumber;
+        transactionSequenceNumber = _transactionSequenceNumber;
+        partNumber = _partNumber;
+        isLastPart = _isLastPart;
+        data = _data;
+
+        partId = new Pair<Long, Integer>(sequenceNumber, partNumber);
+        commitId = new Pair<Long, Long>(machineId, sequenceNumber);
+    }
+
+    public int getSize() {
+        if (data == null) {
+            //return (3 * Long.BYTES) + (2 * Integer.BYTES) + (2 * Byte.BYTES);
+            return (3 * Long.SIZE/8) + (2 * Integer.SIZE/8) + (2 * Byte.SIZE/8);
+        }
+        //return (3 * Long.BYTES) + (2 * Integer.BYTES) + (2 * Byte.BYTES) + data.length;
+        return (3 * Long.SIZE/8) + (2 * Integer.SIZE/8) + (2 * Byte.SIZE/8) + data.length;
+    }
+
+    public void setSlot(Slot s) {
+        parentslot = s;
+    }
+
+    public int getPartNumber() {
+        return partNumber;
+    }
+
+    public int getDataSize() {
+        return data.length;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public Pair<Long, Integer> getPartId() {
+        return partId;
+    }
+
+    public Pair<Long, Long> getCommitId() {
+        return commitId;
+    }
+
+    public Boolean isLastPart() {
+        return isLastPart;
+    }
+
+    public long getMachineId() {
+        return machineId;
+    }
+
+    public long getTransactionSequenceNumber() {
+        return transactionSequenceNumber;
+    }
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    static Entry decode(Slot s, ByteBuffer bb) {
+        long machineId = bb.getLong();
+        long sequenceNumber = bb.getLong();
+        long transactionSequenceNumber = bb.getLong();
+        int partNumber = bb.getInt();
+        int dataSize = bb.getInt();
+        Boolean isLastPart = bb.get() == 1;
+
+        // Get the data
+        byte[] data = new byte[dataSize];
+        bb.get(data);
+
+        return new CommitPart(s, machineId, sequenceNumber, transactionSequenceNumber, partNumber, data, isLastPart);
+    }
+
+    public void encode(ByteBuffer bb) {
+        bb.put(Entry.TypeCommitPart);
+        bb.putLong(machineId);
+        bb.putLong(sequenceNumber);
+        bb.putLong(transactionSequenceNumber);
+        bb.putInt(partNumber);
+        bb.putInt(data.length);
+
+        if (isLastPart) {
+            bb.put((byte)1);
+        } else {
+            bb.put((byte)0);
+        }
+
+        bb.put(data);
+    }
+
+    public byte getType() {
+        return Entry.TypeCommitPart;
+    }
+
+    public Entry getCopy(Slot s) {
+        return new CommitPart(s, machineId, sequenceNumber, transactionSequenceNumber, partNumber, data, isLastPart);
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Entry.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Entry.java
new file mode 100644 (file)
index 0000000..dd9e75b
--- /dev/null
@@ -0,0 +1,116 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * Generic class that wraps all the different types of information
+ * that can be stored in a Slot.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+abstract class Entry implements Liveness {
+
+       static final byte TypeCommitPart = 1;
+       static final byte TypeAbort = 2;
+       static final byte TypeTransactionPart = 3;
+       static final byte TypeNewKey = 4;
+       static final byte TypeLastMessage = 5;
+       static final byte TypeRejectedMessage = 6;
+       static final byte TypeTableStatus = 7;
+
+
+
+       /* Records whether the information is still live or has been
+                superceded by a newer update.  */
+
+       private boolean islive = true;
+       protected Slot parentslot;
+
+       public Entry(Slot _parentslot) {
+               parentslot = _parentslot;
+       }
+
+       /**
+        * Static method for decoding byte array into Entry objects.  First
+        * byte tells the type of entry.
+        */
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               byte type = bb.get();
+               switch (type) {
+
+               case TypeCommitPart:
+                       return CommitPart.decode(slot, bb);
+
+               case TypeAbort:
+                       return Abort.decode(slot, bb);
+
+               case TypeTransactionPart:
+                       return TransactionPart.decode(slot, bb);
+
+               case TypeNewKey:
+                       return NewKey.decode(slot, bb);
+
+               case TypeLastMessage:
+                       return LastMessage.decode(slot, bb);
+
+               case TypeRejectedMessage:
+                       return RejectedMessage.decode(slot, bb);
+
+               case TypeTableStatus:
+                       return TableStatus.decode(slot, bb);
+
+               default:
+                       throw new Error("Unrecognized Entry Type: " + type);
+               }
+       }
+
+       /**
+        * Returns true if the Entry object is still live.
+        */
+       public boolean isLive() {
+               return islive;
+       }
+
+
+       /**
+        * Flags the entry object as dead.  Also decrements the live count
+        * of the parent slot.
+        */
+       public void setDead() {
+
+               if (!islive ) {
+                       return; // already dead
+               }
+
+               islive = false;
+
+               if (parentslot != null) {
+                       parentslot.decrementLiveCount();
+               }
+       }
+
+
+       /**
+        * Serializes the Entry object into the byte buffer.
+        */
+       abstract void encode(ByteBuffer bb);
+
+
+       /**
+        * Returns the size in bytes the entry object will take in the byte
+        * array.
+        */
+       abstract int getSize();
+
+
+       /**
+        * Returns a byte encoding the type of the entry object.
+        */
+       abstract byte getType();
+
+
+       /**
+        * Returns a copy of the Entry that can be added to a different slot.
+        */
+       abstract Entry getCopy(Slot s);
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/IoTString.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/IoTString.java
new file mode 100644 (file)
index 0000000..83a3fa1
--- /dev/null
@@ -0,0 +1,105 @@
+package iotcloud;
+
+import java.util.Arrays;
+
+/**
+ * IoTString is wraps the underlying byte string.  We don't use the
+ * standard String class as we have bytes and not chars.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+final public class IoTString {
+       byte[] array;
+       int hashcode;
+
+       private IoTString() {
+       }
+
+       /**
+        * Builds an IoTString object around the byte array.  This
+        * constructor makes a copy, so the caller is free to modify the byte array.
+        */
+
+       public IoTString(byte[] _array) {
+               array=(byte[]) _array.clone();
+               hashcode=Arrays.hashCode(array);
+       }
+
+       /**
+        * Converts the String object to a byte representation and stores it
+        * into the IoTString object.
+        */
+
+       public IoTString(String str) {
+               array=str.getBytes();
+               hashcode=Arrays.hashCode(array);
+       }
+
+        /**
+        * Internal methods to build an IoTString using the byte[] passed
+        * in.  Caller is responsible for ensuring the byte[] is never
+        * modified.
+        */
+
+       static IoTString shallow(byte[] _array) {
+               IoTString i=new IoTString();
+               i.array = _array;
+               i.hashcode = Arrays.hashCode(_array);
+               return i;
+       }
+
+       /**
+        * Internal method to grab a reference to our byte array.  Caller
+        * must not modify it.
+        */
+
+       byte[] internalBytes() {
+               return array;
+       }
+
+       /**
+        * Returns the hashCode as computed by Arrays.hashcode(byte[]).
+        */
+
+       public int hashCode() {
+               return hashcode;
+       }
+
+       /**
+        * Returns a String representation of the IoTString.
+        */
+
+       public String toString() {
+               return new String(array);
+       }
+
+       /**
+        * Returns a copy of the underlying byte string.
+        */
+
+       public byte[] getBytes() {
+               return (byte[]) array.clone();
+       }
+
+       /**
+        * Returns true if two byte strings have the same content.
+        */
+
+       public boolean equals(Object o) {
+               if (o instanceof IoTString) {
+                       IoTString i=(IoTString)o;
+                       return Arrays.equals(array, i.array);
+               }
+               return false;
+       }
+
+       /**
+        * Returns the length in bytes of the IoTString.
+        */
+
+       public int length() {
+               return array.length;
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/KeyValue.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/KeyValue.java
new file mode 100644 (file)
index 0000000..f6d34d9
--- /dev/null
@@ -0,0 +1,78 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * KeyValue entry for Slot.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+class KeyValue { /*extends Entry */
+       private IoTString key;
+       private IoTString value;
+
+       public KeyValue(IoTString _key, IoTString _value) {
+               key = _key;
+               value = _value;
+       }
+
+       public IoTString getKey() {
+               return key;
+       }
+
+       public IoTString getValue() {
+               return value;
+       }
+
+       static KeyValue decode(ByteBuffer bb) {
+               int keylength = bb.getInt();
+               int valuelength = bb.getInt();
+               byte[] key = new byte[keylength];
+               bb.get(key);
+
+               if (valuelength != 0) {
+                       byte[] value = new byte[valuelength];
+                       bb.get(value);
+                       return new KeyValue(IoTString.shallow(key), IoTString.shallow(value));
+               }
+
+               return new KeyValue(IoTString.shallow(key), null);
+       }
+
+       public void encode(ByteBuffer bb) {
+               bb.putInt(key.length());
+
+               if (value != null) {
+                       bb.putInt(value.length());
+               } else {
+                       bb.putInt(0);
+               }
+
+               bb.put(key.internalBytes());
+
+               if (value != null) {
+                       bb.put(value.internalBytes());
+               }
+       }
+
+       public int getSize() {
+               if (value != null) {
+                       //return 2 * Integer.BYTES + key.length() + value.length();
+                       return 2 * Integer.SIZE/8 + key.length() + value.length();
+               }
+
+               //return 2 * Integer.BYTES + key.length();
+               return 2 * Integer.SIZE/8 + key.length();
+       }
+
+       public String toString() {
+               if (value == null) {
+                       return "null";
+               }
+               return value.toString();
+       }
+
+       public KeyValue getCopy() {
+               return new KeyValue(key, value);
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/LastMessage.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/LastMessage.java
new file mode 100644 (file)
index 0000000..d9482e1
--- /dev/null
@@ -0,0 +1,56 @@
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This Entry records the last message sent by a given machine.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+class LastMessage extends Entry {
+       private long machineid;
+       private long seqnum;
+
+       public LastMessage(Slot slot, long _machineid, long _seqnum) {
+               super(slot);
+               machineid=_machineid;
+               seqnum=_seqnum;
+       }
+
+       public long getMachineID() {
+               return machineid;
+       }
+
+       public long getSequenceNumber() {
+               return seqnum;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               long machineid=bb.getLong();
+               long seqnum=bb.getLong();
+               return new LastMessage(slot, machineid, seqnum);
+       }
+
+       public void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeLastMessage);
+               bb.putLong(machineid);
+               bb.putLong(seqnum);
+       }
+
+       public int getSize() {
+               //return 2*Long.BYTES+Byte.BYTES;
+               return 2*Long.SIZE/8+Byte.SIZE/8;
+       }
+
+       public byte getType() {
+               return Entry.TypeLastMessage;
+       }
+
+       public Entry getCopy(Slot s) {
+               return new LastMessage(s, machineid, seqnum);
+       }
+}
+
+
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Liveness.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Liveness.java
new file mode 100644 (file)
index 0000000..2c840e4
--- /dev/null
@@ -0,0 +1,11 @@
+package iotcloud;
+
+/**
+ * Interface common to both classes that record information about the
+ * last message sent by a machine.  (Either a Slot or a LastMessage.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+interface Liveness {
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/LocalComm.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/LocalComm.java
new file mode 100644 (file)
index 0000000..c2eb11b
--- /dev/null
@@ -0,0 +1,25 @@
+package iotcloud;
+
+class LocalComm {
+    private Table t1;
+    private Table t2;
+
+    public LocalComm(Table _t1, Table _t2) {
+        t1 = _t1;
+        t2 = _t2;
+    }
+
+    public byte[] sendDataToLocalDevice(Long deviceId, byte[] data) throws InterruptedException{
+        System.out.println("Passing Locally");
+
+        if (deviceId == t1.getMachineId()) {
+            // return t1.localCommInput(data);
+        } else if (deviceId == t2.getMachineId()) {
+            // return t2.localCommInput(data);
+        } else {
+            throw new Error("Cannot send to " + deviceId + " using this local comm");
+        }
+
+        return new byte[0];
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/NewKey.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/NewKey.java
new file mode 100644 (file)
index 0000000..e4d6996
--- /dev/null
@@ -0,0 +1,62 @@
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This Entry records the abort sent by a given machine.
+ * @author Ali Younis <ayounis@uci.edu>
+ * @version 1.0
+ */
+
+
+class NewKey extends Entry {
+       private IoTString key;
+       private long machineid;
+
+       public NewKey(Slot slot, IoTString _key, long _machineid) {
+               super(slot);
+               key = _key;
+               machineid = _machineid;
+       }
+
+       public long getMachineID() {
+               return machineid;
+       }
+
+       public IoTString getKey() {
+               return key;
+       }
+
+       public void setSlot(Slot s) {
+               parentslot = s;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               int keylength = bb.getInt();
+               byte[] key = new byte[keylength];
+               bb.get(key);
+               long machineid = bb.getLong();
+
+               return new NewKey(slot, IoTString.shallow(key), machineid);
+       }
+
+       public void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeNewKey);
+               bb.putInt(key.length());
+               bb.put(key.internalBytes());
+               bb.putLong(machineid);
+       }
+
+       public int getSize() {
+               //return Long.BYTES + Byte.BYTES + Integer.BYTES + key.length();
+               return Long.SIZE/8 + Byte.SIZE/8 + Integer.SIZE/8 + key.length();
+       }
+
+       public byte getType() {
+               return Entry.TypeNewKey;
+       }
+
+       public Entry getCopy(Slot s) {
+               return new NewKey(s, key, machineid);
+       }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Pair.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Pair.java
new file mode 100644 (file)
index 0000000..6352fc1
--- /dev/null
@@ -0,0 +1,43 @@
+package iotcloud;
+
+class Pair<A, B> {
+       private A a;
+       private B b;
+       int hashCode = -1;
+
+       Pair(A a, B b) {
+               this.a = a;
+               this.b = b;
+
+               hashCode = 23;
+               hashCode = hashCode * 31 + a.hashCode();
+               hashCode = hashCode * 31 + b.hashCode();
+       }
+
+       A getFirst() {
+               return a;
+       }
+
+       B getSecond() {
+               return b;
+       }
+
+
+       public int hashCode() {
+               return hashCode;
+       }
+
+       public boolean equals(Object o) {
+               if (o instanceof Pair) {
+                       Pair i = (Pair)o;
+                       if (a.equals(i.getFirst()) && b.equals(i.getSecond())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       public String toString() {
+               return "<" + a + "," + b + ">";
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/PendingTransaction.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/PendingTransaction.java
new file mode 100644 (file)
index 0000000..592aae1
--- /dev/null
@@ -0,0 +1,217 @@
+package iotcloud;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashSet;
+
+import java.nio.ByteBuffer;
+
+
+class PendingTransaction {
+
+    private Set<KeyValue> keyValueUpdateSet = null;
+    private Set<KeyValue> keyValueGuardSet = null;
+    private long arbitrator = -1;
+    private long clientLocalSequenceNumber = -1;
+    private long machineId = -1;
+
+    private int currentDataSize = 0;
+
+    public PendingTransaction(long _machineId) {
+        machineId = _machineId;
+        keyValueUpdateSet = new HashSet<KeyValue>();
+        keyValueGuardSet = new HashSet<KeyValue>();
+    }
+
+    /**
+     * Add a new key value to the updates
+     *
+     */
+    public void addKV(KeyValue newKV) {
+
+        KeyValue rmKV = null;
+
+        // Make sure there are no duplicates
+        for (KeyValue kv : keyValueUpdateSet) {
+            if (kv.getKey().equals(newKV.getKey())) {
+
+                // Remove key if we are adding a newer version of the same key
+                rmKV = kv;
+                break;
+            }
+        }
+
+        // Remove key if we are adding a newer version of the same key
+        if (rmKV != null) {
+            keyValueUpdateSet.remove(rmKV);
+            currentDataSize -= rmKV.getSize();
+        }
+
+        // Add the key to the hash set
+        keyValueUpdateSet.add(newKV);
+        currentDataSize += newKV.getSize();
+    }
+
+    /**
+     * Add a new key value to the guard set
+     *
+     */
+    public void addKVGuard(KeyValue newKV) {
+        // Add the key to the hash set
+        keyValueGuardSet.add(newKV);
+        currentDataSize += newKV.getSize();
+    }
+
+    /**
+     * Checks if the arbitrator is the same
+     */
+    public boolean checkArbitrator(long arb) {
+        if (arbitrator == -1) {
+            arbitrator = arb;
+            return true;
+        }
+
+        return arb == arbitrator;
+    }
+
+    /**
+     * Get the transaction arbitrator
+     */
+    public long getArbitrator() {
+        return arbitrator;
+    }
+
+    /**
+     * Get the key value update set
+     */
+    public Set<KeyValue> getKVUpdates() {
+        return keyValueUpdateSet;
+    }
+
+    /**
+     * Get the key value update set
+     */
+    public Set<KeyValue> getKVGuard() {
+        return keyValueGuardSet;
+    }
+
+    public void setClientLocalSequenceNumber(long _clientLocalSequenceNumber) {
+        clientLocalSequenceNumber = _clientLocalSequenceNumber;
+    }
+
+    public long getClientLocalSequenceNumber() {
+        return clientLocalSequenceNumber;
+    }
+
+    public long getMachineId() {
+        return machineId;
+    }
+
+    public boolean evaluateGuard(Map<IoTString, KeyValue> keyValTableCommitted, Map<IoTString, KeyValue> keyValTableSpeculative, Map<IoTString, KeyValue> keyValTablePendingTransSpeculative) {
+        for (KeyValue kvGuard : keyValueGuardSet) {
+
+            // First check if the key is in the speculative table, this is the value of the latest assumption
+            KeyValue kv = keyValTablePendingTransSpeculative.get(kvGuard.getKey());
+
+
+            if (kv == null) {
+                // if it is not in the pending trans table then check the speculative table and use that
+                // value as our latest assumption
+                kv = keyValTableSpeculative.get(kvGuard.getKey());
+            }
+
+
+            if (kv == null) {
+                // if it is not in the speculative table then check the committed table and use that
+                // value as our latest assumption
+                kv = keyValTableCommitted.get(kvGuard.getKey());
+            }
+
+            if (kvGuard.getValue() != null) {
+                if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
+                    return false;
+                }
+            } else {
+                if (kv != null) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public Transaction createTransaction() {
+
+        Transaction newTransaction = new Transaction();
+        int transactionPartCount = 0;
+
+        // Convert all the data into a byte array so we can start partitioning
+        byte[] byteData = convertDataToBytes();
+
+        int currentPosition = 0;
+        int remaining = byteData.length;
+
+        while (remaining > 0) {
+
+            Boolean isLastPart = false;
+            // determine how much to copy
+            int copySize = TransactionPart.MAX_NON_HEADER_SIZE;
+            if (remaining <= TransactionPart.MAX_NON_HEADER_SIZE) {
+                copySize = remaining;
+                isLastPart = true; // last bit of data so last part
+            }
+
+            // Copy to a smaller version
+            byte[] partData = new byte[copySize];
+            System.arraycopy(byteData, currentPosition, partData, 0, copySize);
+
+            TransactionPart part = new TransactionPart(null, machineId, arbitrator, clientLocalSequenceNumber, transactionPartCount, partData, isLastPart);
+            newTransaction.addPartEncode(part);
+
+            // Update position, count and remaining
+            currentPosition += copySize;
+            transactionPartCount++;
+            remaining -= copySize;
+        }
+
+        // Add the Guard Conditions
+        for (KeyValue kv : keyValueGuardSet) {
+            newTransaction.addGuardKV(kv);
+        }
+
+        //  Add the updates
+        for (KeyValue kv : keyValueUpdateSet) {
+            newTransaction.addUpdateKV(kv);
+        }
+
+        return newTransaction;
+    }
+
+    private byte[] convertDataToBytes() {
+
+        // Calculate the size of the data
+        //int sizeOfData = 2 * Integer.BYTES; // Number of Update KV's and Guard KV's
+        int sizeOfData = 2 * Integer.SIZE/8; // Number of Update KV's and Guard KV's
+        sizeOfData += currentDataSize;
+
+        // Data handlers and storage
+        byte[] dataArray = new byte[sizeOfData];
+        ByteBuffer bbEncode = ByteBuffer.wrap(dataArray);
+
+        // Encode the size of the updates and guard sets
+        bbEncode.putInt(keyValueGuardSet.size());
+        bbEncode.putInt(keyValueUpdateSet.size());
+
+        // Encode all the guard conditions
+        for (KeyValue kv : keyValueGuardSet) {
+            kv.encode(bbEncode);
+        }
+
+        // Encode all the updates
+        for (KeyValue kv : keyValueUpdateSet) {
+            kv.encode(bbEncode);
+        }
+
+        return bbEncode.array();
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/RejectedMessage.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/RejectedMessage.java
new file mode 100644 (file)
index 0000000..4154791
--- /dev/null
@@ -0,0 +1,101 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+
+/**
+ * Entry for tracking messages that the server rejected.  We have to
+ * make sure that all clients know that this message was rejected to
+ * prevent the server from reusing these messages in an attack.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+
+class RejectedMessage extends Entry {
+       /* Sequence number */
+       private long sequencenum;
+       
+
+       /* Machine identifier */
+       private long machineid;
+       /* Oldest sequence number in range */
+       private long oldseqnum;
+       /* Newest sequence number in range */
+       private long newseqnum;
+       /* Is the machine identifier of the relevant slots equal to (or not
+        * equal to) the specified machine identifier. */
+       private boolean equalto;
+       /* Set of machines that have not received notification. */
+       private HashSet<Long> watchset;
+
+       RejectedMessage(Slot slot, long _sequencenum, long _machineid, long _oldseqnum, long _newseqnum, boolean _equalto) {
+               super(slot);
+               sequencenum = _sequencenum;
+               machineid=_machineid;
+               oldseqnum=_oldseqnum;
+               newseqnum=_newseqnum;
+               equalto=_equalto;
+       }
+
+       long getOldSeqNum() {
+               return oldseqnum;
+       }
+
+       long getNewSeqNum() {
+               return newseqnum;
+       }
+
+       boolean getEqual() {
+               return equalto;
+       }
+
+       long getMachineID() {
+               return machineid;
+       }
+
+
+       long getSequenceNumber() {
+               return sequencenum;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               long sequencenum=bb.getLong();
+               long machineid=bb.getLong();
+               long oldseqnum=bb.getLong();
+               long newseqnum=bb.getLong();
+               byte equalto=bb.get();
+               return new RejectedMessage(slot,sequencenum, machineid, oldseqnum, newseqnum, equalto==1);
+       }
+
+       void setWatchSet(HashSet<Long> _watchset) {
+               watchset=_watchset;
+       }
+
+       void removeWatcher(long machineid) {
+               if (watchset.remove(machineid))
+                       if (watchset.isEmpty())
+                               setDead();
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeRejectedMessage);
+               bb.putLong(sequencenum);
+               bb.putLong(machineid);
+               bb.putLong(oldseqnum);
+               bb.putLong(newseqnum);
+               bb.put(equalto?(byte)1:(byte)0);
+       }
+
+       int getSize() {
+               //return 4*Long.BYTES + 2*Byte.BYTES;
+               return 4*Long.SIZE/8 + 2*Byte.SIZE/8;
+       }
+
+       byte getType() {
+               return Entry.TypeRejectedMessage;
+       }
+       
+       Entry getCopy(Slot s) {
+               return new RejectedMessage(s,sequencenum, machineid, oldseqnum, newseqnum, equalto);
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ServerException.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ServerException.java
new file mode 100644 (file)
index 0000000..1705c70
--- /dev/null
@@ -0,0 +1,19 @@
+package iotcloud;
+
+public class ServerException extends Exception {
+
+    public static final byte TypeConnectTimeout = 1;
+    public static final byte TypeInputTimeout = 2;
+    public static final byte TypeIncorrectResponseCode = 3;
+    public static final byte TypeSalt = 4;
+    private byte type = -1;
+
+    public ServerException(String message, byte _type) {
+        super(message);
+        type = _type;
+    }
+
+    public byte getType() {
+        return type;
+    }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Slot.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Slot.java
new file mode 100644 (file)
index 0000000..740de9c
--- /dev/null
@@ -0,0 +1,234 @@
+package iotcloud;
+import java.util.Vector;
+import java.nio.ByteBuffer;
+import javax.crypto.Mac;
+import java.util.Arrays;
+
+/**
+ * Data structuring for holding Slot information.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class Slot implements Liveness {
+       /** Sets the slot size. */
+       static final int SLOT_SIZE = 2048;
+       /** Sets the size for the HMAC. */
+       static final int HMAC_SIZE = 32;
+
+       /** Sequence number of the slot. */
+       private long seqnum;
+       /** HMAC of previous slot. */
+       private byte[] prevhmac;
+       /** HMAC of this slot. */
+       private byte[] hmac;
+       /** Machine that sent this slot. */
+       private long machineid;
+       /** Vector of entries in this slot. */
+       private Vector<Entry> entries;
+       /** Pieces of information that are live. */
+       private int livecount;
+       /** Flag that indicates whether this slot is still live for
+        * recording the machine that sent it. */
+       private boolean seqnumlive;
+       /** Number of bytes of free space. */
+       private int freespace;
+       /** Reference to Table */
+       private Table table;
+
+       private long localSequenceNumber;
+
+       Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac, long _localSequenceNumber) {
+               seqnum = _seqnum;
+               machineid = _machineid;
+               prevhmac = _prevhmac;
+               hmac = _hmac;
+               entries = new Vector<Entry>();
+               livecount = 1;
+               seqnumlive = true;
+               freespace = SLOT_SIZE - getBaseSize();
+               table = _table;
+               localSequenceNumber = _localSequenceNumber;
+       }
+
+       Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, long _localSequenceNumber) {
+               this(_table, _seqnum, _machineid, _prevhmac, null, _localSequenceNumber);
+       }
+
+       Slot(Table _table, long _seqnum, long _machineid, long _localSequenceNumber) {
+               this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null, _localSequenceNumber);
+       }
+
+       byte[] getHMAC() {
+               return hmac;
+       }
+
+       byte[] getPrevHMAC() {
+               return prevhmac;
+       }
+
+       Entry addEntry(Entry e) {
+               e = e.getCopy(this);
+               entries.add(e);
+               livecount++;
+               freespace -= e.getSize();
+               return e;
+       }
+
+       void removeEntry(Entry e) {
+               entries.remove(e);
+               livecount--;
+               freespace += e.getSize();
+       }
+
+       private void addShallowEntry(Entry e) {
+               entries.add(e);
+               livecount++;
+               freespace -= e.getSize();
+       }
+
+       /**
+        * Returns true if the slot has free space to hold the entry without
+        * using its reserved space. */
+
+       boolean hasSpace(Entry e) {
+               int newfreespace = freespace - e.getSize();
+               return newfreespace >= 0;
+       }
+
+       Vector<Entry> getEntries() {
+               return entries;
+       }
+
+       static Slot decode(Table table, byte[] array, Mac mac) {
+               mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
+               byte[] realmac = mac.doFinal();
+
+               ByteBuffer bb = ByteBuffer.wrap(array);
+               byte[] hmac = new byte[HMAC_SIZE];
+               byte[] prevhmac = new byte[HMAC_SIZE];
+               bb.get(hmac);
+               bb.get(prevhmac);
+               if (!Arrays.equals(realmac, hmac))
+                       throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
+
+               long seqnum = bb.getLong();
+               long machineid = bb.getLong();
+               int numentries = bb.getInt();
+               Slot slot = new Slot(table, seqnum, machineid, prevhmac, hmac, -1);
+
+               for (int i = 0; i < numentries; i++) {
+                       slot.addShallowEntry(Entry.decode(slot, bb));
+               }
+
+               return slot;
+       }
+
+       byte[] encode(Mac mac) {
+               byte[] array = new byte[SLOT_SIZE];
+               ByteBuffer bb = ByteBuffer.wrap(array);
+               /* Leave space for the slot HMAC.  */
+               bb.position(HMAC_SIZE);
+               bb.put(prevhmac);
+               bb.putLong(seqnum);
+               bb.putLong(machineid);
+               bb.putInt(entries.size());
+               for (Entry entry : entries) {
+                       entry.encode(bb);
+               }
+               /* Compute our HMAC */
+               mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
+               byte[] realmac = mac.doFinal();
+               hmac = realmac;
+               bb.position(0);
+               bb.put(realmac);
+               return array;
+       }
+
+       /**
+        * Returns the empty size of a Slot. Includes 2 HMACs, the machine
+        * identifier, the sequence number, and the number of entries.
+        */
+       int getBaseSize() {
+               //return 2 * HMAC_SIZE + 2 * Long.BYTES + Integer.BYTES;
+               return 2 * HMAC_SIZE + 2 * Long.SIZE/8 + Integer.SIZE/8;
+       }
+
+       /**
+        * Returns the live set of entries for this Slot.  Generates a fake
+        * LastMessage entry to represent the information stored by the slot
+        * itself.
+        */
+
+       Vector<Entry> getLiveEntries(boolean resize) {
+               Vector<Entry> liveEntries = new Vector<Entry>();
+               for (Entry entry : entries) {
+                       if (entry.isLive()) {
+                               if (!resize || entry.getType() != Entry.TypeTableStatus)
+                                       liveEntries.add(entry);
+                       }
+               }
+
+               if (seqnumlive && !resize)
+                       liveEntries.add(new LastMessage(this, machineid, seqnum));
+
+               return liveEntries;
+       }
+
+       /**
+        * Returns the sequence number of the slot.
+        */
+
+       long getSequenceNumber() {
+               return seqnum;
+       }
+
+       /**
+        * Returns the machine that sent this slot.
+        */
+
+       long getMachineID() {
+               return machineid;
+       }
+
+       /**
+        * Records that a newer slot records the fact that this slot was
+        * sent by the relevant machine.
+        */
+
+       void setDead() {
+               seqnumlive = false;
+               decrementLiveCount();
+       }
+
+       /**
+        * Update the count of live entries.
+        */
+
+       void decrementLiveCount() {
+               livecount--;
+               if (livecount == 0) {
+                       table.decrementLiveCount();
+               }
+       }
+
+       /**
+        * Returns whether the slot stores any live information.
+        */
+
+       boolean isLive() {
+               return livecount > 0;
+       }
+
+       public byte[] getSlotCryptIV() {
+               ByteBuffer buffer = ByteBuffer.allocate(CloudComm.IV_SIZE);
+               buffer.putLong(machineid);
+               long localSequenceNumberShift = localSequenceNumber << 16;
+               buffer.putLong(localSequenceNumberShift);
+               return buffer.array();
+       }
+
+       public String toString() {
+               return "<" + getSequenceNumber() + ">";
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotBuffer.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotBuffer.java
new file mode 100644 (file)
index 0000000..10faf1c
--- /dev/null
@@ -0,0 +1,122 @@
+package iotcloud;
+
+/**
+ * Circular buffer that holds the live set of slots.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class SlotBuffer {
+       static final int DEFAULT_SIZE = 2;
+
+       private Slot[] array;
+       private int head;
+       private int tail;
+       public long oldestseqn;
+
+       SlotBuffer() {
+               array = new Slot[DEFAULT_SIZE + 1];
+               head = tail = 0;
+               oldestseqn = 0;
+       }
+
+       int size() {
+               if (head >= tail)
+                       return head - tail;
+               return (array.length + head) - tail;
+       }
+
+       int capacity() {
+               return array.length - 1;
+       }
+
+       void resize(int newsize) {
+               if (newsize == (array.length - 1))
+                       return;
+
+               Slot[] newarray = new Slot[newsize + 1];
+               int currsize = size();
+               int index = tail;
+               for (int i = 0; i < currsize; i++) {
+                       newarray[i] = array[index];
+                       if ((++index) == array.length)
+                               index = 0;
+               }
+               array = newarray;
+               tail = 0;
+               head = currsize;
+       }
+
+       private void incrementHead() {
+               head++;
+               if (head >= array.length)
+                       head = 0;
+       }
+
+       private void incrementTail() {
+               tail++;
+               if (tail >= array.length)
+                       tail = 0;
+       }
+
+       void putSlot(Slot s) {
+
+               long checkNum = (getNewestSeqNum() + 1);
+
+               if (checkNum != s.getSequenceNumber()) {
+                       // We have a gap so expunge all our slots
+                       oldestseqn = s.getSequenceNumber();
+                       tail = 0;
+                       head = 1;
+                       array[0] = s;
+                       return;
+               }
+
+               array[head] = s;
+               incrementHead();
+
+               if (oldestseqn == 0) {
+                       oldestseqn = s.getSequenceNumber();
+               }
+
+               if (head == tail) {
+                       incrementTail();
+                       oldestseqn++;
+               }
+       }
+
+       Slot getSlot(long seqnum) {
+               int diff = (int) (seqnum - oldestseqn);
+               int index = diff + tail;
+
+               if (index < 0) {
+                       // Really old message so we dont have it anymore
+                       return null;
+               }
+
+               if (index >= array.length) {
+                       if (head >= tail) {
+                               return null;
+                       }
+                       index -= array.length;
+               }
+
+               if (index >= array.length) {
+
+                       return null;
+               }
+               if (head >= tail && index >= head) {
+                       return null;
+               }
+
+               return array[index];
+       }
+
+       long getOldestSeqNum() {
+               return oldestseqn;
+       }
+
+       long getNewestSeqNum() {
+               return oldestseqn + size() - 1;
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotIndexer.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/SlotIndexer.java
new file mode 100644 (file)
index 0000000..cecdf2d
--- /dev/null
@@ -0,0 +1,31 @@
+package iotcloud;
+
+/**
+ * Slot indexer allows slots in both the slot buffer and the new
+ * server response to looked up in a consistent fashion.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class SlotIndexer {
+       private Slot[] updates;
+       private SlotBuffer buffer;
+       private long firstslotseqnum;
+
+       SlotIndexer(Slot[] _updates, SlotBuffer _buffer) {
+               buffer = _buffer;
+               updates = _updates;
+               firstslotseqnum = updates[0].getSequenceNumber();
+       }
+
+       Slot getSlot(long seqnum) {
+               if (seqnum >= firstslotseqnum) {
+                       int offset = (int) (seqnum - firstslotseqnum);
+                       if (offset >= updates.length)
+                               throw new Error("Invalid Slot Sequence Number Reference");
+                       else
+                               return updates[offset];
+               } else
+                       return buffer.getSlot(seqnum);
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Table.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Table.java
new file mode 100644 (file)
index 0000000..b97be74
--- /dev/null
@@ -0,0 +1,2755 @@
+package iotcloud;
+
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.nio.ByteBuffer;
+import android.content.*;
+
+import com.example.ali.control.MainActivity;
+
+/**
+ * IoTTable data structure.  Provides client interface.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+final public class Table {
+
+       /* Constants */
+       static final int FREE_SLOTS = 10; // Number of slots that should be kept free
+       static final int SKIP_THRESHOLD = 10;
+       static final double RESIZE_MULTIPLE = 1.2;
+       static final double RESIZE_THRESHOLD = 0.75;
+       static final int REJECTED_THRESHOLD = 5;
+
+       /* Helper Objects */
+       private SlotBuffer buffer = null;
+       private CloudComm cloud = null;
+       private Random random = null;
+       private TableStatus liveTableStatus = null;
+       private PendingTransaction pendingTransactionBuilder = null; // Pending Transaction used in building a Pending Transaction
+       private Transaction lastPendingTransactionSpeculatedOn = null; // Last transaction that was speculated on from the pending transaction
+       private Transaction firstPendingTransaction = null; // first transaction in the pending transaction list
+
+       /* Variables */
+       private int numberOfSlots = 0;  // Number of slots stored in buffer
+       private int bufferResizeThreshold = 0; // Threshold on the number of live slots before a resize is needed
+       private long liveSlotCount = 0; // Number of currently live slots
+       private long oldestLiveSlotSequenceNumver = 0;  // Smallest sequence number of the slot with a live entry
+       private long localMachineId = 0; // Machine ID of this client device
+       private long sequenceNumber = 0; // Largest sequence number a client has received
+       private long localSequenceNumber = 0;
+
+       // private int smallestTableStatusSeen = -1; // Smallest Table Status that was seen in the latest slots sent from the server
+       // private int largestTableStatusSeen = -1; // Largest Table Status that was seen in the latest slots sent from the server
+       private long localTransactionSequenceNumber = 0; // Local sequence number counter for transactions
+       private long lastTransactionSequenceNumberSpeculatedOn = -1; // the last transaction that was speculated on
+       private long oldestTransactionSequenceNumberSpeculatedOn = -1; // the oldest transaction that was speculated on
+       private long localArbitrationSequenceNumber = 0;
+       private boolean hadPartialSendToServer = false;
+       private boolean attemptedToSendToServer = false;
+       private long expectedsize;
+       private boolean didFindTableStatus = false;
+       private long currMaxSize = 0;
+
+       private Slot lastSlotAttemptedToSend = null;
+       private boolean lastIsNewKey = false;
+       private int lastNewSize = 0;
+       private Map<Transaction, List<Integer>> lastTransactionPartsSent = null;
+       private List<Entry> lastPendingSendArbitrationEntriesToDelete = null;
+       private NewKey lastNewKey = null;
+
+
+       /* Data Structures  */
+       private Map<IoTString, KeyValue> committedKeyValueTable = null; // Table of committed key value pairs
+       private Map<IoTString, KeyValue> speculatedKeyValueTable = null; // Table of speculated key value pairs, if there is a speculative value
+       private Map<IoTString, KeyValue> pendingTransactionSpeculatedKeyValueTable = null; // Table of speculated key value pairs, if there is a speculative value from the pending transactions
+       private Map<IoTString, NewKey> liveNewKeyTable = null; // Table of live new keys
+       private HashMap<Long, Pair<Long, Liveness>> lastMessageTable = null; // Last message sent by a client machine id -> (Seq Num, Slot or LastMessage);
+       private HashMap<Long, HashSet<RejectedMessage>> rejectedMessageWatchListTable = null; // Table of machine Ids and the set of rejected messages they have not seen yet
+       private Map<IoTString, Long> arbitratorTable = null; // Table of keys and their arbitrators
+       private Map<Pair<Long, Long>, Abort> liveAbortTable = null; // Table live abort messages
+       private Map<Long, Map<Pair<Long, Integer>, TransactionPart>> newTransactionParts = null; // transaction parts that are seen in this latest round of slots from the server
+       private Map<Long, Map<Pair<Long, Integer>, CommitPart>> newCommitParts = null; // commit parts that are seen in this latest round of slots from the server
+       private Map<Long, Long> lastArbitratedTransactionNumberByArbitratorTable = null; // Last transaction sequence number that an arbitrator arbitrated on
+       private Map<Long, Transaction> liveTransactionBySequenceNumberTable = null; // live transaction grouped by the sequence number
+       private Map<Pair<Long, Long>, Transaction> liveTransactionByTransactionIdTable = null; // live transaction grouped by the transaction ID
+       private Map<Long, Map<Long, Commit>> liveCommitsTable = null;
+       private Map<IoTString, Commit> liveCommitsByKeyTable = null;
+       private Map<Long, Long> lastCommitSeenSequenceNumberByArbitratorTable = null;
+       private Vector<Long> rejectedSlotList = null; // List of rejected slots that have yet to be sent to the server
+       private List<Transaction> pendingTransactionQueue = null;
+       private List<ArbitrationRound> pendingSendArbitrationRounds = null;
+       private List<Entry> pendingSendArbitrationEntriesToDelete = null;
+       private Map<Transaction, List<Integer>> transactionPartsSent = null;
+       private Map<Long, TransactionStatus> outstandingTransactionStatus = null;
+       private Map<Long, Abort> liveAbortsGeneratedByLocal = null;
+       private Set<Pair<Long, Long>> offlineTransactionsCommittedAndAtServer = null;
+       private Map<Long, Pair<String, Integer>> localCommunicationTable = null;
+       private Map<Long, Long> lastTransactionSeenFromMachineFromServer = null;
+       private Map<Long, Long> lastArbitrationDataLocalSequenceNumberSeenFromArbitrator = null;
+
+
+       public Table(String baseurl, String password, long _localMachineId, int listeningPort, Context context) {
+               localMachineId = _localMachineId;
+               cloud = new CloudComm(this, baseurl, password, listeningPort, context);
+
+               init();
+       }
+
+       public Table(CloudComm _cloud, long _localMachineId) {
+               localMachineId = _localMachineId;
+               cloud = _cloud;
+
+               init();
+       }
+
+    /**
+        * Init all the stuff needed for for table usage
+        */
+       private void init() {
+
+               // Init helper objects
+               random = new Random();
+               buffer = new SlotBuffer();
+
+               // Set Variables
+               oldestLiveSlotSequenceNumver = 1;
+
+               // init data structs
+               committedKeyValueTable = new HashMap<IoTString, KeyValue>();
+               speculatedKeyValueTable = new HashMap<IoTString, KeyValue>();
+               pendingTransactionSpeculatedKeyValueTable = new HashMap<IoTString, KeyValue>();
+               liveNewKeyTable = new HashMap<IoTString, NewKey>();
+               lastMessageTable = new HashMap<Long, Pair<Long, Liveness>>();
+               rejectedMessageWatchListTable = new HashMap<Long, HashSet<RejectedMessage>>();
+               arbitratorTable = new HashMap<IoTString, Long>();
+               liveAbortTable = new HashMap<Pair<Long, Long>, Abort>();
+               newTransactionParts = new HashMap<Long, Map<Pair<Long, Integer>, TransactionPart>>();
+               newCommitParts = new HashMap<Long, Map<Pair<Long, Integer>, CommitPart>>();
+               lastArbitratedTransactionNumberByArbitratorTable = new HashMap<Long, Long>();
+               liveTransactionBySequenceNumberTable = new HashMap<Long, Transaction>();
+               liveTransactionByTransactionIdTable = new HashMap<Pair<Long, Long>, Transaction>();
+               liveCommitsTable = new HashMap<Long, Map<Long, Commit>>();
+               liveCommitsByKeyTable = new HashMap<IoTString, Commit>();
+               lastCommitSeenSequenceNumberByArbitratorTable = new HashMap<Long, Long>();
+               rejectedSlotList = new Vector<Long>();
+               pendingTransactionQueue = new ArrayList<Transaction>();
+               pendingSendArbitrationEntriesToDelete = new ArrayList<Entry>();
+               transactionPartsSent = new HashMap<Transaction, List<Integer>>();
+               outstandingTransactionStatus = new HashMap<Long, TransactionStatus>();
+               liveAbortsGeneratedByLocal = new HashMap<Long, Abort>();
+               offlineTransactionsCommittedAndAtServer = new HashSet<Pair<Long, Long>>();
+               localCommunicationTable = new HashMap<Long, Pair<String, Integer>>();
+               lastTransactionSeenFromMachineFromServer = new HashMap<Long, Long>();
+               pendingSendArbitrationRounds = new ArrayList<ArbitrationRound>();
+               lastArbitrationDataLocalSequenceNumberSeenFromArbitrator = new HashMap<Long, Long>();
+
+
+               // Other init stuff
+               numberOfSlots = buffer.capacity();
+               setResizeThreshold();
+       }
+
+       // TODO: delete method
+       public synchronized void printSlots() {
+               long o = buffer.getOldestSeqNum();
+               long n = buffer.getNewestSeqNum();
+
+               int[] types = new int[10];
+
+               int num = 0;
+
+               int livec = 0;
+               int deadc = 0;
+
+               int casdasd = 0;
+
+               int liveslo = 0;
+
+               for (long i = o; i < (n + 1); i++) {
+                       Slot s = buffer.getSlot(i);
+
+
+                       if (s.isLive()) {
+                               liveslo++;
+                       }
+
+                       Vector<Entry> entries = s.getEntries();
+
+                       for (Entry e : entries) {
+                               if (e.isLive()) {
+                                       int type = e.getType();
+
+
+                                       if (type == 6) {
+                                               RejectedMessage rej = (RejectedMessage)e;
+                                               casdasd++;
+
+                                               System.out.println(rej.getMachineID());
+                                       }
+
+
+                                       types[type] = types[type] + 1;
+                                       num++;
+                                       livec++;
+                               } else {
+                                       deadc++;
+                               }
+                       }
+               }
+
+               for (int i = 0; i < 10; i++) {
+                       System.out.println(i + "    " + types[i]);
+               }
+               System.out.println("Live count:   " + livec);
+               System.out.println("Live Slot count:   " + liveslo);
+
+               System.out.println("Dead count:   " + deadc);
+               System.out.println("Old:   " + o);
+               System.out.println("New:   " + n);
+               System.out.println("Size:   " + buffer.size());
+               // System.out.println("Commits:   " + liveCommitsTable.size());
+               System.out.println("pendingTrans:   " + pendingTransactionQueue.size());
+               System.out.println("Trans Status Out:   " + outstandingTransactionStatus.size());
+
+               for (Long k : lastArbitratedTransactionNumberByArbitratorTable.keySet()) {
+                       System.out.println(k + ": " + lastArbitratedTransactionNumberByArbitratorTable.get(k));
+               }
+
+
+               for (Long a : liveCommitsTable.keySet()) {
+                       for (Long b : liveCommitsTable.get(a).keySet()) {
+                               for (KeyValue kv : liveCommitsTable.get(a).get(b).getKeyValueUpdateSet()) {
+                                       System.out.print(kv + " ");
+                               }
+                               System.out.print("|| ");
+                       }
+                       System.out.println();
+               }
+
+       }
+
+       /**
+        * Initialize the table by inserting a table status as the first entry into the table status
+        * also initialize the crypto stuff.
+        */
+       public synchronized void initTable() throws ServerException {
+               cloud.initSecurity();
+
+               // Create the first insertion into the block chain which is the table status
+               Slot s = new Slot(this, 1, localMachineId, localSequenceNumber);
+               localSequenceNumber++;
+               TableStatus status = new TableStatus(s, numberOfSlots);
+               s.addEntry(status);
+               Slot[] array = cloud.putSlot(s, numberOfSlots);
+
+               if (array == null) {
+                       array = new Slot[] {s};
+                       // update local block chain
+                       validateAndUpdate(array, true);
+               } else if (array.length == 1) {
+                       // in case we did push the slot BUT we failed to init it
+                       validateAndUpdate(array, true);
+               } else {
+                       throw new Error("Error on initialization");
+               }
+       }
+
+       /**
+        * Rebuild the table from scratch by pulling the latest block chain from the server.
+        */
+       public synchronized void rebuild() throws ServerException {
+               // Just pull the latest slots from the server
+               Slot[] newslots = cloud.getSlots(sequenceNumber + 1);
+               validateAndUpdate(newslots, true);
+               sendToServer(null);
+               updateLiveTransactionsAndStatus();
+
+       }
+
+       // public String toString() {
+       //      String retString = " Committed Table: \n";
+       //      retString += "---------------------------\n";
+       //      retString += commitedTable.toString();
+
+       //      retString += "\n\n";
+
+       //      retString += " Speculative Table: \n";
+       //      retString += "---------------------------\n";
+       //      retString += speculativeTable.toString();
+
+       //      return retString;
+       // }
+
+       public synchronized void addLocalCommunication(long arbitrator, String hostName, int portNumber) {
+               localCommunicationTable.put(arbitrator, new Pair<String, Integer>(hostName, portNumber));
+       }
+
+       public synchronized Long getArbitrator(IoTString key) {
+               return arbitratorTable.get(key);
+       }
+
+       public synchronized void close() {
+               cloud.close();
+       }
+
+       public synchronized IoTString getCommitted(IoTString key)  {
+               KeyValue kv = committedKeyValueTable.get(key);
+
+               if (kv != null) {
+                       return kv.getValue();
+               } else {
+                       return null;
+               }
+       }
+
+       public synchronized IoTString getSpeculative(IoTString key) {
+               KeyValue kv = pendingTransactionSpeculatedKeyValueTable.get(key);
+
+               if (kv == null) {
+                       kv = speculatedKeyValueTable.get(key);
+               }
+
+               if (kv == null) {
+                       kv = committedKeyValueTable.get(key);
+               }
+
+               if (kv != null) {
+                       return kv.getValue();
+               } else {
+                       return null;
+               }
+       }
+
+       public synchronized IoTString getCommittedAtomic(IoTString key) {
+               KeyValue kv = committedKeyValueTable.get(key);
+
+               if (arbitratorTable.get(key) == null) {
+                       throw new Error("Key not Found.");
+               }
+
+               // Make sure new key value pair matches the current arbitrator
+               if (!pendingTransactionBuilder.checkArbitrator(arbitratorTable.get(key))) {
+                       // TODO: Maybe not throw en error
+                       throw new Error("Not all Key Values Match Arbitrator.");
+               }
+
+               if (kv != null) {
+                       pendingTransactionBuilder.addKVGuard(new KeyValue(key, kv.getValue()));
+                       return kv.getValue();
+               } else {
+                       pendingTransactionBuilder.addKVGuard(new KeyValue(key, null));
+                       return null;
+               }
+       }
+
+       public synchronized IoTString getSpeculativeAtomic(IoTString key) {
+               if (arbitratorTable.get(key) == null) {
+                       throw new Error("Key not Found.");
+               }
+
+               // Make sure new key value pair matches the current arbitrator
+               if (!pendingTransactionBuilder.checkArbitrator(arbitratorTable.get(key))) {
+                       // TODO: Maybe not throw en error
+                       throw new Error("Not all Key Values Match Arbitrator.");
+               }
+
+               KeyValue kv = pendingTransactionSpeculatedKeyValueTable.get(key);
+
+               if (kv == null) {
+                       kv = speculatedKeyValueTable.get(key);
+               }
+
+               if (kv == null) {
+                       kv = committedKeyValueTable.get(key);
+               }
+
+               if (kv != null) {
+                       pendingTransactionBuilder.addKVGuard(new KeyValue(key, kv.getValue()));
+                       return kv.getValue();
+               } else {
+                       pendingTransactionBuilder.addKVGuard(new KeyValue(key, null));
+                       return null;
+               }
+       }
+
+       public synchronized boolean update()  {
+               try {
+                       Slot[] newSlots = cloud.getSlots(sequenceNumber + 1);
+                       validateAndUpdate(newSlots, false);
+                       sendToServer(null);
+
+
+                       updateLiveTransactionsAndStatus();
+
+                       return true;
+               } catch (Exception e) {
+                       e.printStackTrace();
+
+                       for (Long m : localCommunicationTable.keySet()) {
+                               updateFromLocal(m);
+                       }
+               }
+
+               return false;
+       }
+
+       public synchronized boolean createNewKey(IoTString keyName, long machineId) throws ServerException {
+               while (true) {
+                       if (arbitratorTable.get(keyName) != null) {
+                               // There is already an arbitrator
+                               return false;
+                       }
+
+                       NewKey newKey = new NewKey(null, keyName, machineId);
+
+                       if (sendToServer(newKey)) {
+                               // If successfully inserted
+                               return true;
+                       }
+               }
+       }
+
+       public synchronized void startTransaction() {
+               // Create a new transaction, invalidates any old pending transactions.
+               pendingTransactionBuilder = new PendingTransaction(localMachineId);
+       }
+
+       public synchronized void addKV(IoTString key, IoTString value) {
+
+               // Make sure it is a valid key
+               if (arbitratorTable.get(key) == null) {
+                       throw new Error("Key not Found.");
+               }
+
+               // Make sure new key value pair matches the current arbitrator
+               if (!pendingTransactionBuilder.checkArbitrator(arbitratorTable.get(key))) {
+                       // TODO: Maybe not throw en error
+                       throw new Error("Not all Key Values Match Arbitrator.");
+               }
+
+               // Add the key value to this transaction
+               KeyValue kv = new KeyValue(key, value);
+               pendingTransactionBuilder.addKV(kv);
+       }
+
+       public synchronized TransactionStatus commitTransaction() {
+
+               if (pendingTransactionBuilder.getKVUpdates().size() == 0) {
+                       // transaction with no updates will have no effect on the system
+                       return new TransactionStatus(TransactionStatus.StatusNoEffect, -1);
+               }
+
+               // Set the local transaction sequence number and increment
+               pendingTransactionBuilder.setClientLocalSequenceNumber(localTransactionSequenceNumber);
+               localTransactionSequenceNumber++;
+
+               // Create the transaction status
+               TransactionStatus transactionStatus = new TransactionStatus(TransactionStatus.StatusPending, pendingTransactionBuilder.getArbitrator());
+
+               // Create the new transaction
+               Transaction newTransaction = pendingTransactionBuilder.createTransaction();
+               newTransaction.setTransactionStatus(transactionStatus);
+
+               if (pendingTransactionBuilder.getArbitrator() != localMachineId) {
+                       // Add it to the queue and invalidate the builder for safety
+                       pendingTransactionQueue.add(newTransaction);
+               } else {
+                       arbitrateOnLocalTransaction(newTransaction);
+                       updateLiveStateFromLocal();
+               }
+
+               pendingTransactionBuilder = new PendingTransaction(localMachineId);
+
+               try {
+                       sendToServer(null);
+               } catch (ServerException e) {
+
+                       Set<Long> arbitratorTriedAndFailed = new HashSet<Long>();
+                       for (Iterator<Transaction> iter = pendingTransactionQueue.iterator(); iter.hasNext(); ) {
+                               Transaction transaction = iter.next();
+
+                               if (arbitratorTriedAndFailed.contains(transaction.getArbitrator())) {
+                                       // Already contacted this client so ignore all attempts to contact this client
+                                       // to preserve ordering for arbitrator
+                                       continue;
+                               }
+
+                               Pair<Boolean, Boolean> sendReturn = sendTransactionToLocal(transaction);
+
+                               if (sendReturn.getFirst()) {
+                                       // Failed to contact over local
+                                       arbitratorTriedAndFailed.add(transaction.getArbitrator());
+                               } else {
+                                       // Successful contact or should not contact
+
+                                       if (sendReturn.getSecond()) {
+                                               // did arbitrate
+                                               iter.remove();
+                                       }
+                               }
+                       }
+               }
+
+               updateLiveStateFromLocal();
+
+               return transactionStatus;
+       }
+
+       /**
+        * Get the machine ID for this client
+        */
+       public long getMachineId() {
+               return localMachineId;
+       }
+
+       /**
+        * Decrement the number of live slots that we currently have
+        */
+       public void decrementLiveCount() {
+               liveSlotCount--;
+       }
+
+       /**
+        * Recalculate the new resize threshold
+        */
+       private void setResizeThreshold() {
+               int resizeLower = (int) (RESIZE_THRESHOLD * numberOfSlots);
+               bufferResizeThreshold = resizeLower - 1 + random.nextInt(numberOfSlots - resizeLower);
+       }
+
+       public long getLocalSequenceNumber() {
+               return localSequenceNumber;
+       }
+
+
+       boolean lastInsertedNewKey = false;
+
+       private boolean sendToServer(NewKey newKey) throws ServerException {
+
+               boolean fromRetry = false;
+
+               try {
+                       if (hadPartialSendToServer) {
+                               Slot[] newSlots = cloud.getSlots(sequenceNumber + 1);
+                               if (newSlots.length == 0) {
+                                       fromRetry = true;
+                                       ThreeTuple<Boolean, Boolean, Slot[]> sendSlotsReturn = sendSlotsToServer(lastSlotAttemptedToSend, lastNewSize, lastIsNewKey);
+
+                                       if (sendSlotsReturn.getFirst()) {
+                                               if (newKey != null) {
+                                                       if (lastInsertedNewKey && (lastNewKey.getKey() == newKey.getKey()) && (lastNewKey.getMachineID() == newKey.getMachineID())) {
+                                                               newKey = null;
+                                                       }
+                                               }
+
+                                               for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                                       transaction.resetServerFailure();
+
+                                                       // Update which transactions parts still need to be sent
+                                                       transaction.removeSentParts(lastTransactionPartsSent.get(transaction));
+
+                                                       // Add the transaction status to the outstanding list
+                                                       outstandingTransactionStatus.put(transaction.getSequenceNumber(), transaction.getTransactionStatus());
+
+                                                       // Update the transaction status
+                                                       transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentPartial);
+
+                                                       // Check if all the transaction parts were successfully sent and if so then remove it from pending
+                                                       if (transaction.didSendAllParts()) {
+                                                               transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentFully);
+                                                               pendingTransactionQueue.remove(transaction);
+                                                       }
+                                               }
+                                       } else {
+
+                                               newSlots = sendSlotsReturn.getThird();
+
+                                               boolean isInserted = false;
+                                               for (Slot s : newSlots) {
+                                                       if ((s.getSequenceNumber() == lastSlotAttemptedToSend.getSequenceNumber()) && (s.getMachineID() == localMachineId)) {
+                                                               isInserted = true;
+                                                               break;
+                                                       }
+                                               }
+
+                                               for (Slot s : newSlots) {
+                                                       if (isInserted) {
+                                                               break;
+                                                       }
+
+                                                       // Process each entry in the slot
+                                                       for (Entry entry : s.getEntries()) {
+
+                                                               if (entry.getType() == Entry.TypeLastMessage) {
+                                                                       LastMessage lastMessage = (LastMessage)entry;
+                                                                       if ((lastMessage.getMachineID() == localMachineId) && (lastMessage.getSequenceNumber() == lastSlotAttemptedToSend.getSequenceNumber())) {
+                                                                               isInserted = true;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+
+                                               if (isInserted) {
+                                                       if (newKey != null) {
+                                                               if (lastInsertedNewKey && (lastNewKey.getKey() == newKey.getKey()) && (lastNewKey.getMachineID() == newKey.getMachineID())) {
+                                                                       newKey = null;
+                                                               }
+                                                       }
+
+                                                       for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                                               transaction.resetServerFailure();
+
+                                                               // Update which transactions parts still need to be sent
+                                                               transaction.removeSentParts(lastTransactionPartsSent.get(transaction));
+
+                                                               // Add the transaction status to the outstanding list
+                                                               outstandingTransactionStatus.put(transaction.getSequenceNumber(), transaction.getTransactionStatus());
+
+                                                               // Update the transaction status
+                                                               transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentPartial);
+
+                                                               // Check if all the transaction parts were successfully sent and if so then remove it from pending
+                                                               if (transaction.didSendAllParts()) {
+                                                                       transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentFully);
+                                                                       pendingTransactionQueue.remove(transaction);
+                                                               } else {
+                                                                       transaction.resetServerFailure();
+                                                                       // Set the transaction sequence number back to nothing
+                                                                       if (!transaction.didSendAPartToServer()) {
+                                                                               transaction.setSequenceNumber(-1);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                               transaction.resetServerFailure();
+                                               // Set the transaction sequence number back to nothing
+                                               if (!transaction.didSendAPartToServer()) {
+                                                       transaction.setSequenceNumber(-1);
+                                               }
+                                       }
+
+                                       if (sendSlotsReturn.getThird().length != 0) {
+                                               // insert into the local block chain
+                                               validateAndUpdate(sendSlotsReturn.getThird(), true);
+                                       }
+                                       // continue;
+                               } else {
+                                       boolean isInserted = false;
+                                       for (Slot s : newSlots) {
+                                               if ((s.getSequenceNumber() == lastSlotAttemptedToSend.getSequenceNumber()) && (s.getMachineID() == localMachineId)) {
+                                                       isInserted = true;
+                                                       break;
+                                               }
+                                       }
+
+                                       for (Slot s : newSlots) {
+                                               if (isInserted) {
+                                                       break;
+                                               }
+
+                                               // Process each entry in the slot
+                                               for (Entry entry : s.getEntries()) {
+
+                                                       if (entry.getType() == Entry.TypeLastMessage) {
+                                                               LastMessage lastMessage = (LastMessage)entry;
+                                                               if ((lastMessage.getMachineID() == localMachineId) && (lastMessage.getSequenceNumber() == lastSlotAttemptedToSend.getSequenceNumber())) {
+                                                                       isInserted = true;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (isInserted) {
+                                               if (newKey != null) {
+                                                       if (lastInsertedNewKey && (lastNewKey.getKey() == newKey.getKey()) && (lastNewKey.getMachineID() == newKey.getMachineID())) {
+                                                               newKey = null;
+                                                       }
+                                               }
+
+                                               for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                                       transaction.resetServerFailure();
+
+                                                       // Update which transactions parts still need to be sent
+                                                       transaction.removeSentParts(lastTransactionPartsSent.get(transaction));
+
+                                                       // Add the transaction status to the outstanding list
+                                                       outstandingTransactionStatus.put(transaction.getSequenceNumber(), transaction.getTransactionStatus());
+
+                                                       // Update the transaction status
+                                                       transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentPartial);
+
+                                                       // Check if all the transaction parts were successfully sent and if so then remove it from pending
+                                                       if (transaction.didSendAllParts()) {
+                                                               transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentFully);
+                                                               pendingTransactionQueue.remove(transaction);
+                                                       } else {
+                                                               transaction.resetServerFailure();
+                                                               // Set the transaction sequence number back to nothing
+                                                               if (!transaction.didSendAPartToServer()) {
+                                                                       transaction.setSequenceNumber(-1);
+                                                               }
+                                                       }
+                                               }
+                                       } else {
+                                               for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                                       transaction.resetServerFailure();
+                                                       // Set the transaction sequence number back to nothing
+                                                       if (!transaction.didSendAPartToServer()) {
+                                                               transaction.setSequenceNumber(-1);
+                                                       }
+                                               }
+                                       }
+
+                                       // insert into the local block chain
+                                       validateAndUpdate(newSlots, true);
+                               }
+                       }
+               } catch (ServerException e) {
+                       throw e;
+               }
+
+
+
+               try {
+                       // While we have stuff that needs inserting into the block chain
+                       while ((pendingTransactionQueue.size() > 0) || (pendingSendArbitrationRounds.size() > 0) || (newKey != null)) {
+
+                               fromRetry = false;
+
+                               if (hadPartialSendToServer) {
+                                       throw new Error("Should Be error free");
+                               }
+
+
+
+                               // If there is a new key with same name then end
+                               if ((newKey != null) && (arbitratorTable.get(newKey.getKey()) != null)) {
+                                       return false;
+                               }
+
+                               // Create the slot
+                               Slot slot = new Slot(this, sequenceNumber + 1, localMachineId, buffer.getSlot(sequenceNumber).getHMAC(), localSequenceNumber);
+                               localSequenceNumber++;
+
+                               // Try to fill the slot with data
+                               ThreeTuple<Boolean, Integer, Boolean> fillSlotsReturn = fillSlot(slot, false, newKey);
+                               boolean needsResize = fillSlotsReturn.getFirst();
+                               int newSize = fillSlotsReturn.getSecond();
+                               Boolean insertedNewKey = fillSlotsReturn.getThird();
+
+                               if (needsResize) {
+                                       // Reset which transaction to send
+                                       for (Transaction transaction : transactionPartsSent.keySet()) {
+                                               transaction.resetNextPartToSend();
+
+                                               // Set the transaction sequence number back to nothing
+                                               if (!transaction.didSendAPartToServer() && !transaction.getServerFailure()) {
+                                                       transaction.setSequenceNumber(-1);
+                                               }
+                                       }
+
+                                       // Clear the sent data since we are trying again
+                                       pendingSendArbitrationEntriesToDelete.clear();
+                                       transactionPartsSent.clear();
+
+                                       // We needed a resize so try again
+                                       fillSlot(slot, true, newKey);
+                               }
+
+                               lastSlotAttemptedToSend = slot;
+                               lastIsNewKey = (newKey != null);
+                               lastInsertedNewKey = insertedNewKey;
+                               lastNewSize = newSize;
+                               lastNewKey = newKey;
+                               lastTransactionPartsSent = new HashMap<Transaction, List<Integer>>(transactionPartsSent);
+                               lastPendingSendArbitrationEntriesToDelete = new ArrayList<Entry>(pendingSendArbitrationEntriesToDelete);
+
+
+                               ThreeTuple<Boolean, Boolean, Slot[]> sendSlotsReturn = sendSlotsToServer(slot, newSize, newKey != null);
+
+                               if (sendSlotsReturn.getFirst()) {
+
+                                       // Did insert into the block chain
+
+                                       if (insertedNewKey) {
+                                               // This slot was what was inserted not a previous slot
+
+                                               // New Key was successfully inserted into the block chain so dont want to insert it again
+                                               newKey = null;
+                                       }
+
+                                       // Remove the aborts and commit parts that were sent from the pending to send queue
+                                       for (Iterator<ArbitrationRound> iter = pendingSendArbitrationRounds.iterator(); iter.hasNext(); ) {
+                                               ArbitrationRound round = iter.next();
+                                               round.removeParts(pendingSendArbitrationEntriesToDelete);
+
+                                               if (round.isDoneSending()) {
+                                                       // Sent all the parts
+                                                       iter.remove();
+                                               }
+                                       }
+
+                                       for (Transaction transaction : transactionPartsSent.keySet()) {
+                                               transaction.resetServerFailure();
+
+                                               // Update which transactions parts still need to be sent
+                                               transaction.removeSentParts(transactionPartsSent.get(transaction));
+
+                                               // Add the transaction status to the outstanding list
+                                               outstandingTransactionStatus.put(transaction.getSequenceNumber(), transaction.getTransactionStatus());
+
+                                               // Update the transaction status
+                                               transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentPartial);
+
+                                               // Check if all the transaction parts were successfully sent and if so then remove it from pending
+                                               if (transaction.didSendAllParts()) {
+                                                       transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentFully);
+                                                       pendingTransactionQueue.remove(transaction);
+                                               }
+                                       }
+                               } else {
+
+                                       // if (!sendSlotsReturn.getSecond()) {
+                                       //      for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                       //              transaction.resetServerFailure();
+                                       //      }
+                                       // } else {
+                                       //      for (Transaction transaction : lastTransactionPartsSent.keySet()) {
+                                       //              transaction.resetServerFailure();
+
+                                       //              // Update which transactions parts still need to be sent
+                                       //              transaction.removeSentParts(transactionPartsSent.get(transaction));
+
+                                       //              // Add the transaction status to the outstanding list
+                                       //              outstandingTransactionStatus.put(transaction.getSequenceNumber(), transaction.getTransactionStatus());
+
+                                       //              // Update the transaction status
+                                       //              transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentPartial);
+
+                                       //              // Check if all the transaction parts were successfully sent and if so then remove it from pending
+                                       //              if (transaction.didSendAllParts()) {
+                                       //                      transaction.getTransactionStatus().setStatus(TransactionStatus.StatusSentFully);
+                                       //                      pendingTransactionQueue.remove(transaction);
+
+                                       //                      for (KeyValue kv : transaction.getKeyValueUpdateSet()) {
+                                       //                              System.out.println("Sent: " + kv + "  from: " + localMachineId + "   Slot:" + lastSlotAttemptedToSend.getSequenceNumber() + "  Claimed:" + transaction.getSequenceNumber());
+                                       //                      }
+                                       //              }
+                                       //      }
+                                       // }
+
+                                       // Reset which transaction to send
+                                       for (Transaction transaction : transactionPartsSent.keySet()) {
+                                               transaction.resetNextPartToSend();
+                                               // transaction.resetNextPartToSend();
+
+                                               // Set the transaction sequence number back to nothing
+                                               if (!transaction.didSendAPartToServer() && !transaction.getServerFailure()) {
+                                                       transaction.setSequenceNumber(-1);
+                                               }
+                                       }
+                               }
+
+                               // Clear the sent data in preparation for next send
+                               pendingSendArbitrationEntriesToDelete.clear();
+                               transactionPartsSent.clear();
+
+                               if (sendSlotsReturn.getThird().length != 0) {
+                                       // insert into the local block chain
+                                       validateAndUpdate(sendSlotsReturn.getThird(), true);
+                               }
+                       }
+
+               } catch (ServerException e) {
+
+                       if (e.getType() != ServerException.TypeInputTimeout) {
+                               // e.printStackTrace();
+
+                               // Nothing was able to be sent to the server so just clear these data structures
+                               for (Transaction transaction : transactionPartsSent.keySet()) {
+                                       transaction.resetNextPartToSend();
+
+                                       // Set the transaction sequence number back to nothing
+                                       if (!transaction.didSendAPartToServer() && !transaction.getServerFailure()) {
+                                               transaction.setSequenceNumber(-1);
+                                       }
+                               }
+                       } else {
+                               // There was a partial send to the server
+                               hadPartialSendToServer = true;
+
+
+                               // if (!fromRetry) {
+                               //      lastTransactionPartsSent = new HashMap<Transaction, List<Integer>>(transactionPartsSent);
+                               //      lastPendingSendArbitrationEntriesToDelete = new ArrayList<Entry>(pendingSendArbitrationEntriesToDelete);
+                               // }
+
+                               // Nothing was able to be sent to the server so just clear these data structures
+                               for (Transaction transaction : transactionPartsSent.keySet()) {
+                                       transaction.resetNextPartToSend();
+                                       transaction.setServerFailure();
+                               }
+                       }
+
+                       pendingSendArbitrationEntriesToDelete.clear();
+                       transactionPartsSent.clear();
+
+                       throw e;
+               }
+
+               return newKey == null;
+       }
+
+       private synchronized boolean updateFromLocal(long machineId) {
+               Pair<String, Integer> localCommunicationInformation = localCommunicationTable.get(machineId);
+               if (localCommunicationInformation == null) {
+                       // Cant talk to that device locally so do nothing
+                       return false;
+               }
+
+               // Get the size of the send data
+               //int sendDataSize = Integer.BYTES + Long.BYTES;
+               int sendDataSize = Integer.SIZE/8 + Long.SIZE/8;
+
+               Long lastArbitrationDataLocalSequenceNumber = (long) - 1;
+               if (lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(machineId) != null) {
+                       lastArbitrationDataLocalSequenceNumber = lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(machineId);
+               }
+
+               byte[] sendData = new byte[sendDataSize];
+               ByteBuffer bbEncode = ByteBuffer.wrap(sendData);
+
+               // Encode the data
+               bbEncode.putLong(lastArbitrationDataLocalSequenceNumber);
+               bbEncode.putInt(0);
+
+               // Send by local
+               byte[] returnData = cloud.sendLocalData(sendData, localSequenceNumber, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond());
+               localSequenceNumber++;
+
+               if (returnData == null) {
+                       // Could not contact server
+                       return false;
+               }
+
+               // Decode the data
+               ByteBuffer bbDecode = ByteBuffer.wrap(returnData);
+               int numberOfEntries = bbDecode.getInt();
+
+               for (int i = 0; i < numberOfEntries; i++) {
+                       byte type = bbDecode.get();
+                       if (type == Entry.TypeAbort) {
+                               Abort abort = (Abort)Abort.decode(null, bbDecode);
+                               processEntry(abort);
+                       } else if (type == Entry.TypeCommitPart) {
+                               CommitPart commitPart = (CommitPart)CommitPart.decode(null, bbDecode);
+                               processEntry(commitPart);
+                       }
+               }
+
+               updateLiveStateFromLocal();
+
+               return true;
+       }
+
+       private Pair<Boolean, Boolean> sendTransactionToLocal(Transaction transaction) {
+
+               // Get the devices local communications
+               Pair<String, Integer> localCommunicationInformation = localCommunicationTable.get(transaction.getArbitrator());
+
+               if (localCommunicationInformation == null) {
+                       // Cant talk to that device locally so do nothing
+                       return new Pair<Boolean, Boolean>(true, false);
+               }
+
+               // Get the size of the send data
+               //int sendDataSize = Integer.BYTES + Long.BYTES;
+               int sendDataSize = Integer.SIZE/8 + Long.SIZE/8;
+               for (TransactionPart part : transaction.getParts().values()) {
+                       sendDataSize += part.getSize();
+               }
+
+               Long lastArbitrationDataLocalSequenceNumber = (long) - 1;
+               if (lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(transaction.getArbitrator()) != null) {
+                       lastArbitrationDataLocalSequenceNumber = lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(transaction.getArbitrator());
+               }
+
+               // Make the send data size
+               byte[] sendData = new byte[sendDataSize];
+               ByteBuffer bbEncode = ByteBuffer.wrap(sendData);
+
+               // Encode the data
+               bbEncode.putLong(lastArbitrationDataLocalSequenceNumber);
+               bbEncode.putInt(transaction.getParts().size());
+               for (TransactionPart part : transaction.getParts().values()) {
+                       part.encode(bbEncode);
+               }
+
+
+               // Send by local
+               byte[] returnData = cloud.sendLocalData(sendData, localSequenceNumber, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond());
+               localSequenceNumber++;
+
+               if (returnData == null) {
+                       // Could not contact server
+                       return new Pair<Boolean, Boolean>(true, false);
+               }
+
+               // Decode the data
+               ByteBuffer bbDecode = ByteBuffer.wrap(returnData);
+               boolean didCommit = bbDecode.get() == 1;
+               boolean couldArbitrate = bbDecode.get() == 1;
+               int numberOfEntries = bbDecode.getInt();
+               boolean foundAbort = false;
+
+               for (int i = 0; i < numberOfEntries; i++) {
+                       byte type = bbDecode.get();
+                       if (type == Entry.TypeAbort) {
+                               Abort abort = (Abort)Abort.decode(null, bbDecode);
+
+                               if ((abort.getTransactionMachineId() == localMachineId) && (abort.getTransactionClientLocalSequenceNumber() == transaction.getClientLocalSequenceNumber())) {
+                                       foundAbort = true;
+                               }
+
+                               processEntry(abort);
+                       } else if (type == Entry.TypeCommitPart) {
+                               CommitPart commitPart = (CommitPart)CommitPart.decode(null, bbDecode);
+                               processEntry(commitPart);
+                       }
+               }
+
+               updateLiveStateFromLocal();
+
+               if (couldArbitrate) {
+                       TransactionStatus status =  transaction.getTransactionStatus();
+                       if (didCommit) {
+                               status.setStatus(TransactionStatus.StatusCommitted);
+                       } else {
+                               status.setStatus(TransactionStatus.StatusAborted);
+                       }
+               } else {
+                       TransactionStatus status =  transaction.getTransactionStatus();
+                       if (foundAbort) {
+                               status.setStatus(TransactionStatus.StatusAborted);
+                       } else {
+                               status.setStatus(TransactionStatus.StatusCommitted);
+                       }
+               }
+
+               return new Pair<Boolean, Boolean>(false, true);
+       }
+
+       public synchronized byte[] acceptDataFromLocal(byte[] data) {
+
+               // Decode the data
+               ByteBuffer bbDecode = ByteBuffer.wrap(data);
+               long lastArbitratedSequenceNumberSeen = bbDecode.getLong();
+               int numberOfParts = bbDecode.getInt();
+
+               // If we did commit a transaction or not
+               boolean didCommit = false;
+               boolean couldArbitrate = false;
+
+               if (numberOfParts != 0) {
+
+                       // decode the transaction
+                       Transaction transaction = new Transaction();
+                       for (int i = 0; i < numberOfParts; i++) {
+                               bbDecode.get();
+                               TransactionPart newPart = (TransactionPart)TransactionPart.decode(null, bbDecode);
+                               transaction.addPartDecode(newPart);
+                       }
+
+                       // Arbitrate on transaction and pull relevant return data
+                       Pair<Boolean, Boolean> localArbitrateReturn = arbitrateOnLocalTransaction(transaction);
+                       couldArbitrate = localArbitrateReturn.getFirst();
+                       didCommit = localArbitrateReturn.getSecond();
+
+                       updateLiveStateFromLocal();
+
+                       // Transaction was sent to the server so keep track of it to prevent double commit
+                       if (transaction.getSequenceNumber() != -1) {
+                               offlineTransactionsCommittedAndAtServer.add(transaction.getId());
+                       }
+               }
+
+               // The data to send back
+               int returnDataSize = 0;
+               List<Entry> unseenArbitrations = new ArrayList<Entry>();
+
+               // Get the aborts to send back
+               List<Long> abortLocalSequenceNumbers = new ArrayList<Long >(liveAbortsGeneratedByLocal.keySet());
+               Collections.sort(abortLocalSequenceNumbers);
+               for (Long localSequenceNumber : abortLocalSequenceNumbers) {
+                       if (localSequenceNumber <= lastArbitratedSequenceNumberSeen) {
+                               continue;
+                       }
+
+                       Abort abort = liveAbortsGeneratedByLocal.get(localSequenceNumber);
+                       unseenArbitrations.add(abort);
+                       returnDataSize += abort.getSize();
+               }
+
+               // Get the commits to send back
+               Map<Long, Commit> commitForClientTable = liveCommitsTable.get(localMachineId);
+               if (commitForClientTable != null) {
+                       List<Long> commitLocalSequenceNumbers = new ArrayList<Long>(commitForClientTable.keySet());
+                       Collections.sort(commitLocalSequenceNumbers);
+
+                       for (Long localSequenceNumber : commitLocalSequenceNumbers) {
+                               Commit commit = commitForClientTable.get(localSequenceNumber);
+
+                               if (localSequenceNumber <= lastArbitratedSequenceNumberSeen) {
+                                       continue;
+                               }
+
+                               unseenArbitrations.addAll(commit.getParts().values());
+
+                               for (CommitPart commitPart : commit.getParts().values()) {
+                                       returnDataSize += commitPart.getSize();
+                               }
+                       }
+               }
+
+               // Number of arbitration entries to decode
+               //returnDataSize += 2 * Integer.BYTES;
+               returnDataSize += 2 * Integer.SIZE/8;
+
+               // Boolean of did commit or not
+               if (numberOfParts != 0) {
+                       //returnDataSize += Byte.BYTES;
+                       returnDataSize += Byte.SIZE/8;
+               }
+
+               // Data to send Back
+               byte[] returnData = new byte[returnDataSize];
+               ByteBuffer bbEncode = ByteBuffer.wrap(returnData);
+
+               if (numberOfParts != 0) {
+                       if (didCommit) {
+                               bbEncode.put((byte)1);
+                       } else {
+                               bbEncode.put((byte)0);
+                       }
+                       if (couldArbitrate) {
+                               bbEncode.put((byte)1);
+                       } else {
+                               bbEncode.put((byte)0);
+                       }
+               }
+
+               bbEncode.putInt(unseenArbitrations.size());
+               for (Entry entry : unseenArbitrations) {
+                       entry.encode(bbEncode);
+               }
+
+
+               localSequenceNumber++;
+               return returnData;
+       }
+
+       private ThreeTuple<Boolean, Boolean, Slot[]> sendSlotsToServer(Slot slot, int newSize, boolean isNewKey)  throws ServerException {
+
+               boolean attemptedToSendToServerTmp = attemptedToSendToServer;
+               attemptedToSendToServer = true;
+
+               boolean inserted = false;
+               boolean lastTryInserted = false;
+
+               Slot[] array = cloud.putSlot(slot, newSize);
+               if (array == null) {
+                       array = new Slot[] {slot};
+                       rejectedSlotList.clear();
+                       inserted = true;
+               }       else {
+                       if (array.length == 0) {
+                               throw new Error("Server Error: Did not send any slots");
+                       }
+
+                       // if (attemptedToSendToServerTmp) {
+                       if (hadPartialSendToServer) {
+
+                               boolean isInserted = false;
+                               for (Slot s : array) {
+                                       if ((s.getSequenceNumber() == slot.getSequenceNumber()) && (s.getMachineID() == localMachineId)) {
+                                               isInserted = true;
+                                               break;
+                                       }
+                               }
+
+                               for (Slot s : array) {
+                                       if (isInserted) {
+                                               break;
+                                       }
+
+                                       // Process each entry in the slot
+                                       for (Entry entry : s.getEntries()) {
+
+                                               if (entry.getType() == Entry.TypeLastMessage) {
+                                                       LastMessage lastMessage = (LastMessage)entry;
+
+                                                       if ((lastMessage.getMachineID() == localMachineId) && (lastMessage.getSequenceNumber() == slot.getSequenceNumber())) {
+                                                               isInserted = true;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               if (!isInserted) {
+                                       rejectedSlotList.add(slot.getSequenceNumber());
+                                       lastTryInserted = false;
+                               } else {
+                                       lastTryInserted = true;
+                               }
+                       } else {
+                               rejectedSlotList.add(slot.getSequenceNumber());
+                               lastTryInserted = false;
+                       }
+               }
+
+               return new ThreeTuple<Boolean, Boolean, Slot[]>(inserted, lastTryInserted, array);
+       }
+
+       /**
+        * Returns false if a resize was needed
+        */
+       private ThreeTuple<Boolean, Integer, Boolean> fillSlot(Slot slot, boolean resize, NewKey newKeyEntry) {
+
+
+               int newSize = 0;
+               if (liveSlotCount > bufferResizeThreshold) {
+                       resize = true; //Resize is forced
+
+               }
+
+               if (resize) {
+                       newSize = (int) (numberOfSlots * RESIZE_MULTIPLE);
+                       TableStatus status = new TableStatus(slot, newSize);
+                       slot.addEntry(status);
+               }
+
+               // Fill with rejected slots first before doing anything else
+               doRejectedMessages(slot);
+
+               // Do mandatory rescue of entries
+               ThreeTuple<Boolean, Boolean, Long> mandatoryRescueReturn = doMandatoryResuce(slot, resize);
+
+               // Extract working variables
+               boolean needsResize = mandatoryRescueReturn.getFirst();
+               boolean seenLiveSlot = mandatoryRescueReturn.getSecond();
+               long currentRescueSequenceNumber = mandatoryRescueReturn.getThird();
+
+               if (needsResize && !resize) {
+                       // We need to resize but we are not resizing so return false
+                       return new ThreeTuple<Boolean, Integer, Boolean>(true, null, null);
+               }
+
+               boolean inserted = false;
+               if (newKeyEntry != null) {
+                       newKeyEntry.setSlot(slot);
+                       if (slot.hasSpace(newKeyEntry)) {
+
+                               slot.addEntry(newKeyEntry);
+                               inserted = true;
+                       }
+               }
+
+               // Clear the transactions, aborts and commits that were sent previously
+               transactionPartsSent.clear();
+               pendingSendArbitrationEntriesToDelete.clear();
+
+               for (ArbitrationRound round : pendingSendArbitrationRounds) {
+                       boolean isFull = false;
+                       round.generateParts();
+                       List<Entry> parts = round.getParts();
+
+                       // Insert pending arbitration data
+                       for (Entry arbitrationData : parts) {
+
+                               // If it is an abort then we need to set some information
+                               if (arbitrationData instanceof Abort) {
+                                       ((Abort)arbitrationData).setSequenceNumber(slot.getSequenceNumber());
+                               }
+
+                               if (!slot.hasSpace(arbitrationData)) {
+                                       // No space so cant do anything else with these data entries
+                                       isFull = true;
+                                       break;
+                               }
+
+                               // Add to this current slot and add it to entries to delete
+                               slot.addEntry(arbitrationData);
+                               pendingSendArbitrationEntriesToDelete.add(arbitrationData);
+                       }
+
+                       if (isFull) {
+                               break;
+                       }
+               }
+
+               if (pendingTransactionQueue.size() > 0) {
+
+                       Transaction transaction = pendingTransactionQueue.get(0);
+
+                       // Set the transaction sequence number if it has yet to be inserted into the block chain
+                       // if ((!transaction.didSendAPartToServer() && !transaction.getServerFailure()) || (transaction.getSequenceNumber() == -1)) {
+                       //      transaction.setSequenceNumber(slot.getSequenceNumber());
+                       // }
+
+                       if ((!transaction.didSendAPartToServer()) || (transaction.getSequenceNumber() == -1)) {
+                               transaction.setSequenceNumber(slot.getSequenceNumber());
+                       }
+
+
+                       while (true) {
+                               TransactionPart part = transaction.getNextPartToSend();
+
+                               if (part == null) {
+                                       // Ran out of parts to send for this transaction so move on
+                                       break;
+                               }
+
+                               if (slot.hasSpace(part)) {
+                                       slot.addEntry(part);
+                                       List<Integer> partsSent = transactionPartsSent.get(transaction);
+                                       if (partsSent == null) {
+                                               partsSent = new ArrayList<Integer>();
+                                               transactionPartsSent.put(transaction, partsSent);
+                                       }
+                                       partsSent.add(part.getPartNumber());
+                                       transactionPartsSent.put(transaction, partsSent);
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+
+               // Fill the remainder of the slot with rescue data
+               doOptionalRescue(slot, seenLiveSlot, currentRescueSequenceNumber, resize);
+
+               return new ThreeTuple<Boolean, Integer, Boolean>(false, newSize, inserted);
+       }
+
+       private void doRejectedMessages(Slot s) {
+               if (! rejectedSlotList.isEmpty()) {
+                       /* TODO: We should avoid generating a rejected message entry if
+                        * there is already a sufficient entry in the queue (e.g.,
+                        * equalsto value of true and same sequence number).  */
+
+                       long old_seqn = rejectedSlotList.firstElement();
+                       if (rejectedSlotList.size() > REJECTED_THRESHOLD) {
+                               long new_seqn = rejectedSlotList.lastElement();
+                               RejectedMessage rm = new RejectedMessage(s, s.getSequenceNumber(), localMachineId, old_seqn, new_seqn, false);
+                               s.addEntry(rm);
+                       } else {
+                               long prev_seqn = -1;
+                               int i = 0;
+                               /* Go through list of missing messages */
+                               for (; i < rejectedSlotList.size(); i++) {
+                                       long curr_seqn = rejectedSlotList.get(i);
+                                       Slot s_msg = buffer.getSlot(curr_seqn);
+                                       if (s_msg != null)
+                                               break;
+                                       prev_seqn = curr_seqn;
+                               }
+                               /* Generate rejected message entry for missing messages */
+                               if (prev_seqn != -1) {
+                                       RejectedMessage rm = new RejectedMessage(s, s.getSequenceNumber(), localMachineId, old_seqn, prev_seqn, false);
+                                       s.addEntry(rm);
+                               }
+                               /* Generate rejected message entries for present messages */
+                               for (; i < rejectedSlotList.size(); i++) {
+                                       long curr_seqn = rejectedSlotList.get(i);
+                                       Slot s_msg = buffer.getSlot(curr_seqn);
+                                       long machineid = s_msg.getMachineID();
+                                       RejectedMessage rm = new RejectedMessage(s, s.getSequenceNumber(), machineid, curr_seqn, curr_seqn, true);
+                                       s.addEntry(rm);
+                               }
+                       }
+               }
+       }
+
+       private ThreeTuple<Boolean, Boolean, Long> doMandatoryResuce(Slot slot, boolean resize) {
+               long newestSequenceNumber = buffer.getNewestSeqNum();
+               long oldestSequenceNumber = buffer.getOldestSeqNum();
+               if (oldestLiveSlotSequenceNumver < oldestSequenceNumber) {
+                       oldestLiveSlotSequenceNumver = oldestSequenceNumber;
+               }
+
+               long currentSequenceNumber = oldestLiveSlotSequenceNumver;
+               boolean seenLiveSlot = false;
+               long firstIfFull = newestSequenceNumber + 1 - numberOfSlots;    // smallest seq number in the buffer if it is full
+               long threshold = firstIfFull + FREE_SLOTS;      // we want the buffer to be clear of live entries up to this point
+
+
+               // Mandatory Rescue
+               for (; currentSequenceNumber < threshold; currentSequenceNumber++) {
+                       Slot previousSlot = buffer.getSlot(currentSequenceNumber);
+                       // Push slot number forward
+                       if (! seenLiveSlot) {
+                               oldestLiveSlotSequenceNumver = currentSequenceNumber;
+                       }
+                       
+                       if (previousSlot == null || !previousSlot.isLive()) {
+                               continue;
+                       }
+
+                       // We have seen a live slot
+                       seenLiveSlot = true;
+
+                       // Get all the live entries for a slot
+                       Vector<Entry> liveEntries = previousSlot.getLiveEntries(resize);
+
+                       // Iterate over all the live entries and try to rescue them
+                       for (Entry liveEntry : liveEntries) {
+                               if (slot.hasSpace(liveEntry)) {
+
+                                       // Enough space to rescue the entry
+                                       slot.addEntry(liveEntry);
+                               } else if (currentSequenceNumber == firstIfFull) {
+                                       //if there's no space but the entry is about to fall off the queue
+                                       System.out.println("B"); //?
+                                       return new ThreeTuple<Boolean, Boolean, Long>(true, seenLiveSlot, currentSequenceNumber);
+
+                               }
+                       }
+               }
+
+               // Did not resize
+               return new ThreeTuple<Boolean, Boolean, Long>(false, seenLiveSlot, currentSequenceNumber);
+       }
+
+       private void  doOptionalRescue(Slot s, boolean seenliveslot, long seqn, boolean resize) {
+               /* now go through live entries from least to greatest sequence number until
+                * either all live slots added, or the slot doesn't have enough room
+                * for SKIP_THRESHOLD consecutive entries*/
+               int skipcount = 0;
+               long newestseqnum = buffer.getNewestSeqNum();
+               search:
+               for (; seqn <= newestseqnum; seqn++) {
+                       Slot prevslot = buffer.getSlot(seqn);
+                       //Push slot number forward
+                       if (!seenliveslot)
+                               oldestLiveSlotSequenceNumver = seqn;
+
+                       if (!prevslot.isLive())
+                               continue;
+                       seenliveslot = true;
+                       Vector<Entry> liveentries = prevslot.getLiveEntries(resize);
+                       for (Entry liveentry : liveentries) {
+                               if (s.hasSpace(liveentry))
+                                       s.addEntry(liveentry);
+                               else {
+                                       skipcount++;
+                                       if (skipcount > SKIP_THRESHOLD)
+                                               break search;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Checks for malicious activity and updates the local copy of the block chain.
+        */
+       private void validateAndUpdate(Slot[] newSlots, boolean acceptUpdatesToLocal) {
+
+               // The cloud communication layer has checked slot HMACs already before decoding
+               if (newSlots.length == 0) {
+                       return;
+               }
+
+               // Make sure all slots are newer than the last largest slot this client has seen
+               long firstSeqNum = newSlots[0].getSequenceNumber();
+               if (firstSeqNum <= sequenceNumber) {
+                       throw new Error("Server Error: Sent older slots!");
+               }
+
+               // Create an object that can access both new slots and slots in our local chain
+               // without committing slots to our local chain
+               SlotIndexer indexer = new SlotIndexer(newSlots, buffer);
+
+               // Check that the HMAC chain is not broken
+               checkHMACChain(indexer, newSlots);
+
+               // Set to keep track of messages from clients
+               HashSet<Long> machineSet = new HashSet<Long>(lastMessageTable.keySet());
+
+               // Process each slots data
+               for (Slot slot : newSlots) {
+                       processSlot(indexer, slot, acceptUpdatesToLocal, machineSet);
+
+                       updateExpectedSize();
+               }
+
+               // If there is a gap, check to see if the server sent us everything.
+               if (firstSeqNum != (sequenceNumber + 1)) {
+
+                       // Check the size of the slots that were sent down by the server.
+                       // Can only check the size if there was a gap
+                       checkNumSlots(newSlots.length);
+
+                       // Since there was a gap every machine must have pushed a slot or must have
+                       // a last message message.  If not then the server is hiding slots
+                       if (!machineSet.isEmpty()) {
+                               throw new Error("Missing record for machines: " + machineSet);
+                       }
+               }
+
+               // Update the size of our local block chain.
+               commitNewMaxSize();
+
+               // Commit new to slots to the local block chain.
+               for (Slot slot : newSlots) {
+
+                       // Insert this slot into our local block chain copy.
+                       buffer.putSlot(slot);
+
+                       // Keep track of how many slots are currently live (have live data in them).
+                       liveSlotCount++;
+               }
+
+               // Get the sequence number of the latest slot in the system
+               sequenceNumber = newSlots[newSlots.length - 1].getSequenceNumber();
+
+               updateLiveStateFromServer();
+
+               // No Need to remember after we pulled from the server
+               offlineTransactionsCommittedAndAtServer.clear();
+
+               // This is invalidated now
+               hadPartialSendToServer = false;
+       }
+
+       private void updateLiveStateFromServer() {
+               // Process the new transaction parts
+               processNewTransactionParts();
+
+               // Do arbitration on new transactions that were received
+               arbitrateFromServer();
+
+               // Update all the committed keys
+               boolean didCommitOrSpeculate = updateCommittedTable();
+
+               // Delete the transactions that are now dead
+               updateLiveTransactionsAndStatus();
+
+               // Do speculations
+               didCommitOrSpeculate |= updateSpeculativeTable(didCommitOrSpeculate);
+               updatePendingTransactionSpeculativeTable(didCommitOrSpeculate);
+       }
+
+       private void updateLiveStateFromLocal() {
+               // Update all the committed keys
+               boolean didCommitOrSpeculate = updateCommittedTable();
+
+               // Delete the transactions that are now dead
+               updateLiveTransactionsAndStatus();
+
+               // Do speculations
+               didCommitOrSpeculate |= updateSpeculativeTable(didCommitOrSpeculate);
+               updatePendingTransactionSpeculativeTable(didCommitOrSpeculate);
+       }
+
+       private void initExpectedSize(long firstSequenceNumber, long numberOfSlots) {
+               // if (didFindTableStatus) {
+               // return;
+               // }
+               long prevslots = firstSequenceNumber;
+
+
+               if (didFindTableStatus) {
+                       // expectedsize = (prevslots < ((long) numberOfSlots)) ? (int) prevslots : expectedsize;
+                       // System.out.println("Here2: " + expectedsize + "    " + numberOfSlots + "   " + prevslots);
+
+               } else {
+                       expectedsize = (prevslots < ((long) numberOfSlots)) ? (int) prevslots : numberOfSlots;
+                       // System.out.println("Here: " + expectedsize);
+               }
+
+               // System.out.println(numberOfSlots);
+
+               didFindTableStatus = true;
+               currMaxSize = numberOfSlots;
+       }
+
+       private void updateExpectedSize() {
+               expectedsize++;
+
+               if (expectedsize > currMaxSize) {
+                       expectedsize = currMaxSize;
+               }
+       }
+
+
+       /**
+        * Check the size of the block chain to make sure there are enough slots sent back by the server.
+        * This is only called when we have a gap between the slots that we have locally and the slots
+        * sent by the server therefore in the slots sent by the server there will be at least 1 Table
+        * status message
+        */
+       private void checkNumSlots(int numberOfSlots) {
+               if (numberOfSlots != expectedsize) {
+                       throw new Error("Server Error: Server did not send all slots.  Expected: " + expectedsize + " Received:" + numberOfSlots);
+               }
+       }
+
+       private void updateCurrMaxSize(int newmaxsize) {
+               currMaxSize = newmaxsize;
+       }
+
+
+       /**
+        * Update the size of of the local buffer if it is needed.
+        */
+       private void commitNewMaxSize() {
+               didFindTableStatus = false;
+
+               // Resize the local slot buffer
+               if (numberOfSlots != currMaxSize) {
+                       buffer.resize((int)currMaxSize);
+               }
+
+               // Change the number of local slots to the new size
+               numberOfSlots = (int)currMaxSize;
+
+
+               // Recalculate the resize threshold since the size of the local buffer has changed
+               setResizeThreshold();
+       }
+
+       /**
+        * Process the new transaction parts from this latest round of slots received from the server
+        */
+       private void processNewTransactionParts() {
+
+               if (newTransactionParts.size() == 0) {
+                       // Nothing new to process
+                       return;
+               }
+
+               // Iterate through all the machine Ids that we received new parts for
+               for (Long machineId : newTransactionParts.keySet()) {
+                       Map<Pair<Long, Integer>, TransactionPart> parts = newTransactionParts.get(machineId);
+
+                       // Iterate through all the parts for that machine Id
+                       for (Pair<Long, Integer> partId : parts.keySet()) {
+                               TransactionPart part = parts.get(partId);
+
+                               Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(part.getArbitratorId());
+                               if ((lastTransactionNumber != null) && (lastTransactionNumber >= part.getSequenceNumber())) {
+                                       // Set dead the transaction part
+                                       part.setDead();
+                                       continue;
+                               }
+
+                               // Get the transaction object for that sequence number
+                               Transaction transaction = liveTransactionBySequenceNumberTable.get(part.getSequenceNumber());
+
+                               if (transaction == null) {
+                                       // This is a new transaction that we dont have so make a new one
+                                       transaction = new Transaction();
+
+                                       // Insert this new transaction into the live tables
+                                       liveTransactionBySequenceNumberTable.put(part.getSequenceNumber(), transaction);
+                                       liveTransactionByTransactionIdTable.put(part.getTransactionId(), transaction);
+                               }
+
+                               // Add that part to the transaction
+                               transaction.addPartDecode(part);
+                       }
+               }
+
+               // Clear all the new transaction parts in preparation for the next time the server sends slots
+               newTransactionParts.clear();
+       }
+
+
+       private long lastSeqNumArbOn = 0;
+
+       private void arbitrateFromServer() {
+
+               if (liveTransactionBySequenceNumberTable.size() == 0) {
+                       // Nothing to arbitrate on so move on
+                       return;
+               }
+
+               // Get the transaction sequence numbers and sort from oldest to newest
+               List<Long> transactionSequenceNumbers = new ArrayList<Long>(liveTransactionBySequenceNumberTable.keySet());
+               Collections.sort(transactionSequenceNumbers);
+
+               // Collection of key value pairs that are
+               Map<IoTString, KeyValue> speculativeTableTmp = new HashMap<IoTString, KeyValue>();
+
+               // The last transaction arbitrated on
+               long lastTransactionCommitted = -1;
+               Set<Abort> generatedAborts = new HashSet<Abort>();
+
+               for (Long transactionSequenceNumber : transactionSequenceNumbers) {
+                       Transaction transaction = liveTransactionBySequenceNumberTable.get(transactionSequenceNumber);
+
+
+
+                       // Check if this machine arbitrates for this transaction if not then we cant arbitrate this transaction
+                       if (transaction.getArbitrator() != localMachineId) {
+                               continue;
+                       }
+
+                       if (transactionSequenceNumber < lastSeqNumArbOn) {
+                               continue;
+                       }
+
+                       if (offlineTransactionsCommittedAndAtServer.contains(transaction.getId())) {
+                               // We have seen this already locally so dont commit again
+                               continue;
+                       }
+
+
+                       if (!transaction.isComplete()) {
+                               // Will arbitrate in incorrect order if we continue so just break
+                               // Most likely this
+                               break;
+                       }
+
+
+                       // update the largest transaction seen by arbitrator from server
+                       if (lastTransactionSeenFromMachineFromServer.get(transaction.getMachineId()) == null) {
+                               lastTransactionSeenFromMachineFromServer.put(transaction.getMachineId(), transaction.getClientLocalSequenceNumber());
+                       } else {
+                               Long lastTransactionSeenFromMachine = lastTransactionSeenFromMachineFromServer.get(transaction.getMachineId());
+                               if (transaction.getClientLocalSequenceNumber() > lastTransactionSeenFromMachine) {
+                                       lastTransactionSeenFromMachineFromServer.put(transaction.getMachineId(), transaction.getClientLocalSequenceNumber());
+                               }
+                       }
+
+                       if (transaction.evaluateGuard(committedKeyValueTable, speculativeTableTmp, null)) {
+                               // Guard evaluated as true
+
+                               // Update the local changes so we can make the commit
+                               for (KeyValue kv : transaction.getKeyValueUpdateSet()) {
+                                       speculativeTableTmp.put(kv.getKey(), kv);
+                               }
+
+                               // Update what the last transaction committed was for use in batch commit
+                               lastTransactionCommitted = transactionSequenceNumber;
+                       } else {
+                               // Guard evaluated was false so create abort
+
+                               // Create the abort
+                               Abort newAbort = new Abort(null,
+                                               transaction.getClientLocalSequenceNumber(),
+                                               transaction.getSequenceNumber(),
+                                               transaction.getMachineId(),
+                                               transaction.getArbitrator(),
+                                               localArbitrationSequenceNumber);
+                               localArbitrationSequenceNumber++;
+
+                               generatedAborts.add(newAbort);
+
+                               // Insert the abort so we can process
+                               processEntry(newAbort);
+                       }
+
+                       lastSeqNumArbOn = transactionSequenceNumber;
+
+                       // liveTransactionBySequenceNumberTable.remove(transactionSequenceNumber);
+               }
+
+               Commit newCommit = null;
+
+               // If there is something to commit
+               if (speculativeTableTmp.size() != 0) {
+
+                       // Create the commit and increment the commit sequence number
+                       newCommit = new Commit(localArbitrationSequenceNumber, localMachineId, lastTransactionCommitted);
+                       localArbitrationSequenceNumber++;
+
+                       // Add all the new keys to the commit
+                       for (KeyValue kv : speculativeTableTmp.values()) {
+                               newCommit.addKV(kv);
+                       }
+
+                       // create the commit parts
+                       newCommit.createCommitParts();
+
+                       // Append all the commit parts to the end of the pending queue waiting for sending to the server
+
+                       // Insert the commit so we can process it
+                       for (CommitPart commitPart : newCommit.getParts().values()) {
+                               processEntry(commitPart);
+                       }
+               }
+
+               if ((newCommit != null) || (generatedAborts.size() > 0)) {
+                       ArbitrationRound arbitrationRound = new ArbitrationRound(newCommit, generatedAborts);
+                       pendingSendArbitrationRounds.add(arbitrationRound);
+
+                       if (compactArbitrationData()) {
+                               ArbitrationRound newArbitrationRound = pendingSendArbitrationRounds.get(pendingSendArbitrationRounds.size() - 1);
+                               if (newArbitrationRound.getCommit() != null) {
+                                       for (CommitPart commitPart : newArbitrationRound.getCommit().getParts().values()) {
+                                               processEntry(commitPart);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       private Pair<Boolean, Boolean> arbitrateOnLocalTransaction(Transaction transaction) {
+
+               // Check if this machine arbitrates for this transaction if not then we cant arbitrate this transaction
+               if (transaction.getArbitrator() != localMachineId) {
+                       return new Pair<Boolean, Boolean>(false, false);
+               }
+
+               if (!transaction.isComplete()) {
+                       // Will arbitrate in incorrect order if we continue so just break
+                       // Most likely this
+                       return new Pair<Boolean, Boolean>(false, false);
+               }
+
+               if (transaction.getMachineId() != localMachineId) {
+                       // dont do this check for local transactions
+                       if (lastTransactionSeenFromMachineFromServer.get(transaction.getMachineId()) != null) {
+                               if (lastTransactionSeenFromMachineFromServer.get(transaction.getMachineId()) > transaction.getClientLocalSequenceNumber()) {
+                                       // We've have already seen this from the server
+                                       return new Pair<Boolean, Boolean>(false, false);
+                               }
+                       }
+               }
+
+               if (transaction.evaluateGuard(committedKeyValueTable, null, null)) {
+                       // Guard evaluated as true
+
+                       // Create the commit and increment the commit sequence number
+                       Commit newCommit = new Commit(localArbitrationSequenceNumber, localMachineId, -1);
+                       localArbitrationSequenceNumber++;
+
+                       // Update the local changes so we can make the commit
+                       for (KeyValue kv : transaction.getKeyValueUpdateSet()) {
+                               newCommit.addKV(kv);
+                       }
+
+                       // create the commit parts
+                       newCommit.createCommitParts();
+
+                       // Append all the commit parts to the end of the pending queue waiting for sending to the server
+                       ArbitrationRound arbitrationRound = new ArbitrationRound(newCommit, new HashSet<Abort>());
+                       pendingSendArbitrationRounds.add(arbitrationRound);
+
+                       if (compactArbitrationData()) {
+                               ArbitrationRound newArbitrationRound = pendingSendArbitrationRounds.get(pendingSendArbitrationRounds.size() - 1);
+                               for (CommitPart commitPart : newArbitrationRound.getCommit().getParts().values()) {
+                                       processEntry(commitPart);
+                               }
+                       } else {
+                               // Insert the commit so we can process it
+                               for (CommitPart commitPart : newCommit.getParts().values()) {
+                                       processEntry(commitPart);
+                               }
+                       }
+
+                       if (transaction.getMachineId() == localMachineId) {
+                               TransactionStatus status = transaction.getTransactionStatus();
+                               if (status != null) {
+                                       status.setStatus(TransactionStatus.StatusCommitted);
+                               }
+                       }
+
+                       updateLiveStateFromLocal();
+                       return new Pair<Boolean, Boolean>(true, true);
+               } else {
+
+                       if (transaction.getMachineId() == localMachineId) {
+                               // For locally created messages update the status
+
+                               // Guard evaluated was false so create abort
+                               TransactionStatus status = transaction.getTransactionStatus();
+                               if (status != null) {
+                                       status.setStatus(TransactionStatus.StatusAborted);
+                               }
+                       } else {
+                               Set addAbortSet = new HashSet<Abort>();
+
+
+                               // Create the abort
+                               Abort newAbort = new Abort(null,
+                                               transaction.getClientLocalSequenceNumber(),
+                                               -1,
+                                               transaction.getMachineId(),
+                                               transaction.getArbitrator(),
+                                               localArbitrationSequenceNumber);
+                               localArbitrationSequenceNumber++;
+
+                               addAbortSet.add(newAbort);
+
+
+                               // Append all the commit parts to the end of the pending queue waiting for sending to the server
+                               ArbitrationRound arbitrationRound = new ArbitrationRound(null, addAbortSet);
+                               pendingSendArbitrationRounds.add(arbitrationRound);
+
+                               if (compactArbitrationData()) {
+                                       ArbitrationRound newArbitrationRound = pendingSendArbitrationRounds.get(pendingSendArbitrationRounds.size() - 1);
+                                       for (CommitPart commitPart : newArbitrationRound.getCommit().getParts().values()) {
+                                               processEntry(commitPart);
+                                       }
+                               }
+                       }
+
+                       updateLiveStateFromLocal();
+                       return new Pair<Boolean, Boolean>(true, false);
+               }
+       }
+
+       /**
+        * Compacts the arbitration data my merging commits and aggregating aborts so that a single large push of commits can be done instead of many small updates
+        */
+       private boolean compactArbitrationData() {
+
+               if (pendingSendArbitrationRounds.size() < 2) {
+                       // Nothing to compact so do nothing
+                       return false;
+               }
+
+               ArbitrationRound lastRound = pendingSendArbitrationRounds.get(pendingSendArbitrationRounds.size() - 1);
+               if (lastRound.didSendPart()) {
+                       return false;
+               }
+
+               boolean hadCommit = (lastRound.getCommit() == null);
+               boolean gotNewCommit = false;
+
+               int numberToDelete = 1;
+               while (numberToDelete < pendingSendArbitrationRounds.size()) {
+                       ArbitrationRound round = pendingSendArbitrationRounds.get(pendingSendArbitrationRounds.size() - numberToDelete - 1);
+
+                       if (round.isFull() || round.didSendPart()) {
+                               // Stop since there is a part that cannot be compacted and we need to compact in order
+                               break;
+                       }
+
+                       if (round.getCommit() == null) {
+
+                               // Try compacting aborts only
+                               int newSize = round.getCurrentSize() + lastRound.getAbortsCount();
+                               if (newSize > ArbitrationRound.MAX_PARTS) {
+                                       // Cant compact since it would be too large
+                                       break;
+                               }
+                               lastRound.addAborts(round.getAborts());
+                       } else {
+
+                               // Create a new larger commit
+                               Commit newCommit = Commit.merge(lastRound.getCommit(), round.getCommit(), localArbitrationSequenceNumber);
+                               localArbitrationSequenceNumber++;
+
+                               // Create the commit parts so that we can count them
+                               newCommit.createCommitParts();
+
+                               // Calculate the new size of the parts
+                               int newSize = newCommit.getNumberOfParts();
+                               newSize += lastRound.getAbortsCount();
+                               newSize += round.getAbortsCount();
+
+                               if (newSize > ArbitrationRound.MAX_PARTS) {
+                                       // Cant compact since it would be too large
+                                       break;
+                               }
+
+                               // Set the new compacted part
+                               lastRound.setCommit(newCommit);
+                               lastRound.addAborts(round.getAborts());
+                               gotNewCommit = true;
+                       }
+
+                       numberToDelete++;
+               }
+
+               if (numberToDelete != 1) {
+                       // If there is a compaction
+
+                       // Delete the previous pieces that are now in the new compacted piece
+                       if (numberToDelete == pendingSendArbitrationRounds.size()) {
+                               pendingSendArbitrationRounds.clear();
+                       } else {
+                               for (int i = 0; i < numberToDelete; i++) {
+                                       pendingSendArbitrationRounds.remove(pendingSendArbitrationRounds.size() - 1);
+                               }
+                       }
+
+                       // Add the new compacted into the pending to send list
+                       pendingSendArbitrationRounds.add(lastRound);
+
+                       // Should reinsert into the commit processor
+                       if (hadCommit && gotNewCommit) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+       // private boolean compactArbitrationData() {
+       //      return false;
+       // }
+
+       /**
+        * Update all the commits and the committed tables, sets dead the dead transactions
+        */
+       private boolean updateCommittedTable() {
+
+               if (newCommitParts.size() == 0) {
+                       // Nothing new to process
+                       return false;
+               }
+
+               // Iterate through all the machine Ids that we received new parts for
+               for (Long machineId : newCommitParts.keySet()) {
+                       Map<Pair<Long, Integer>, CommitPart> parts = newCommitParts.get(machineId);
+
+                       // Iterate through all the parts for that machine Id
+                       for (Pair<Long, Integer> partId : parts.keySet()) {
+                               CommitPart part = parts.get(partId);
+
+                               // Get the transaction object for that sequence number
+                               Map<Long, Commit> commitForClientTable = liveCommitsTable.get(part.getMachineId());
+
+                               if (commitForClientTable == null) {
+                                       // This is the first commit from this device
+                                       commitForClientTable = new HashMap<Long, Commit>();
+                                       liveCommitsTable.put(part.getMachineId(), commitForClientTable);
+                               }
+
+                               Commit commit = commitForClientTable.get(part.getSequenceNumber());
+
+                               if (commit == null) {
+                                       // This is a new commit that we dont have so make a new one
+                                       commit = new Commit();
+
+                                       // Insert this new commit into the live tables
+                                       commitForClientTable.put(part.getSequenceNumber(), commit);
+                               }
+
+                               // Add that part to the commit
+                               commit.addPartDecode(part);
+                       }
+               }
+
+               // Clear all the new commits parts in preparation for the next time the server sends slots
+               newCommitParts.clear();
+
+               // If we process a new commit keep track of it for future use
+               boolean didProcessANewCommit = false;
+
+               // Process the commits one by one
+               for (Long arbitratorId : liveCommitsTable.keySet()) {
+
+                       // Get all the commits for a specific arbitrator
+                       Map<Long, Commit> commitForClientTable = liveCommitsTable.get(arbitratorId);
+
+                       // Sort the commits in order
+                       List<Long> commitSequenceNumbers = new ArrayList<Long>(commitForClientTable.keySet());
+                       Collections.sort(commitSequenceNumbers);
+
+                       // Get the last commit seen from this arbitrator
+                       long lastCommitSeenSequenceNumber = -1;
+                       if (lastCommitSeenSequenceNumberByArbitratorTable.get(arbitratorId) != null) {
+                               lastCommitSeenSequenceNumber = lastCommitSeenSequenceNumberByArbitratorTable.get(arbitratorId);
+                       }
+
+                       // Go through each new commit one by one
+                       for (int i = 0; i < commitSequenceNumbers.size(); i++) {
+                               Long commitSequenceNumber = commitSequenceNumbers.get(i);
+                               Commit commit = commitForClientTable.get(commitSequenceNumber);
+
+                               // Special processing if a commit is not complete
+                               if (!commit.isComplete()) {
+                                       if (i == (commitSequenceNumbers.size() - 1)) {
+                                               // If there is an incomplete commit and this commit is the latest one seen then this commit cannot be processed and there are no other commits
+                                               break;
+                                       } else {
+                                               // This is a commit that was already dead but parts of it are still in the block chain (not flushed out yet).
+                                               // Delete it and move on
+                                               commit.setDead();
+                                               commitForClientTable.remove(commit.getSequenceNumber());
+                                               continue;
+                                       }
+                               }
+
+                               // Update the last transaction that was updated if we can
+                               if (commit.getTransactionSequenceNumber() != -1) {
+                                       Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(commit.getMachineId());
+
+                                       // Update the last transaction sequence number that the arbitrator arbitrated on
+                                       if ((lastTransactionNumber == null) || (lastTransactionNumber < commit.getTransactionSequenceNumber())) {
+                                               lastArbitratedTransactionNumberByArbitratorTable.put(commit.getMachineId(), commit.getTransactionSequenceNumber());
+                                       }
+                               }
+
+                               // Update the last arbitration data that we have seen so far
+                               if (lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(commit.getMachineId()) != null) {
+
+                                       long lastArbitrationSequenceNumber = lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(commit.getMachineId());
+                                       if (commit.getSequenceNumber() > lastArbitrationSequenceNumber) {
+                                               // Is larger
+                                               lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.put(commit.getMachineId(), commit.getSequenceNumber());
+                                       }
+                               } else {
+                                       // Never seen any data from this arbitrator so record the first one
+                                       lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.put(commit.getMachineId(), commit.getSequenceNumber());
+                               }
+
+                               // We have already seen this commit before so need to do the full processing on this commit
+                               if (commit.getSequenceNumber() <= lastCommitSeenSequenceNumber) {
+
+                                       // Update the last transaction that was updated if we can
+                                       if (commit.getTransactionSequenceNumber() != -1) {
+                                               Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(commit.getMachineId());
+
+                                               // Update the last transaction sequence number that the arbitrator arbitrated on
+                                               if ((lastTransactionNumber == null) || (lastTransactionNumber < commit.getTransactionSequenceNumber())) {
+                                                       lastArbitratedTransactionNumberByArbitratorTable.put(commit.getMachineId(), commit.getTransactionSequenceNumber());
+                                               }
+                                       }
+
+                                       continue;
+                               }
+
+                               // If we got here then this is a brand new commit and needs full processing
+
+                               // Get what commits should be edited, these are the commits that have live values for their keys
+                               Set<Commit> commitsToEdit = new HashSet<Commit>();
+                               for (KeyValue kv : commit.getKeyValueUpdateSet()) {
+                                       commitsToEdit.add(liveCommitsByKeyTable.get(kv.getKey()));
+                               }
+                               commitsToEdit.remove(null); // remove null since it could be in this set
+
+                               // Update each previous commit that needs to be updated
+                               for (Commit previousCommit : commitsToEdit) {
+
+                                       // Only bother with live commits (TODO: Maybe remove this check)
+                                       if (previousCommit.isLive()) {
+
+                                               // Update which keys in the old commits are still live
+                                               for (KeyValue kv : commit.getKeyValueUpdateSet()) {
+                                                       previousCommit.invalidateKey(kv.getKey());
+                                               }
+
+                                               // if the commit is now dead then remove it
+                                               if (!previousCommit.isLive()) {
+                                                       commitForClientTable.remove(previousCommit);
+                                               }
+                                       }
+                               }
+
+                               // Update the last seen sequence number from this arbitrator
+                               if (lastCommitSeenSequenceNumberByArbitratorTable.get(commit.getMachineId()) != null) {
+                                       if (commit.getSequenceNumber() > lastCommitSeenSequenceNumberByArbitratorTable.get(commit.getMachineId())) {
+                                               lastCommitSeenSequenceNumberByArbitratorTable.put(commit.getMachineId(), commit.getSequenceNumber());
+                                       }
+                               } else {
+                                       lastCommitSeenSequenceNumberByArbitratorTable.put(commit.getMachineId(), commit.getSequenceNumber());
+                               }
+
+                               // We processed a new commit that we havent seen before
+                               didProcessANewCommit = true;
+
+                               // Update the committed table of keys and which commit is using which key
+                               for (KeyValue kv : commit.getKeyValueUpdateSet()) {
+                                       committedKeyValueTable.put(kv.getKey(), kv);
+                                       liveCommitsByKeyTable.put(kv.getKey(), commit);
+                               }
+                       }
+               }
+
+               return didProcessANewCommit;
+       }
+
+       /**
+        * Create the speculative table from transactions that are still live and have come from the cloud
+        */
+       private boolean updateSpeculativeTable(boolean didProcessNewCommits) {
+               if (liveTransactionBySequenceNumberTable.keySet().size() == 0) {
+                       // There is nothing to speculate on
+                       return false;
+               }
+
+               // Create a list of the transaction sequence numbers and sort them from oldest to newest
+               List<Long> transactionSequenceNumbersSorted = new ArrayList<Long>(liveTransactionBySequenceNumberTable.keySet());
+               Collections.sort(transactionSequenceNumbersSorted);
+
+               boolean hasGapInTransactionSequenceNumbers = transactionSequenceNumbersSorted.get(0) != oldestTransactionSequenceNumberSpeculatedOn;
+
+
+               if (hasGapInTransactionSequenceNumbers || didProcessNewCommits) {
+                       // If there is a gap in the transaction sequence numbers then there was a commit or an abort of a transaction
+                       // OR there was a new commit (Could be from offline commit) so a redo the speculation from scratch
+
+                       // Start from scratch
+                       speculatedKeyValueTable.clear();
+                       lastTransactionSequenceNumberSpeculatedOn = -1;
+                       oldestTransactionSequenceNumberSpeculatedOn = -1;
+
+               }
+
+               // Remember the front of the transaction list
+               oldestTransactionSequenceNumberSpeculatedOn = transactionSequenceNumbersSorted.get(0);
+
+               // Find where to start arbitration from
+               int startIndex = transactionSequenceNumbersSorted.indexOf(lastTransactionSequenceNumberSpeculatedOn) + 1;
+
+               if (startIndex >= transactionSequenceNumbersSorted.size()) {
+                       // Make sure we are not out of bounds
+                       return false; // did not speculate
+               }
+
+               Set<Long> incompleteTransactionArbitrator = new HashSet<Long>();
+               boolean didSkip = true;
+
+               for (int i = startIndex; i < transactionSequenceNumbersSorted.size(); i++) {
+                       long transactionSequenceNumber = transactionSequenceNumbersSorted.get(i);
+                       Transaction transaction = liveTransactionBySequenceNumberTable.get(transactionSequenceNumber);
+
+                       if (!transaction.isComplete()) {
+                               // If there is an incomplete transaction then there is nothing we can do
+                               // add this transactions arbitrator to the list of arbitrators we should ignore
+                               incompleteTransactionArbitrator.add(transaction.getArbitrator());
+                               didSkip = true;
+                               continue;
+                       }
+
+                       if (incompleteTransactionArbitrator.contains(transaction.getArbitrator())) {
+                               continue;
+                       }
+
+                       lastTransactionSequenceNumberSpeculatedOn = transactionSequenceNumber;
+
+                       if (transaction.evaluateGuard(committedKeyValueTable, speculatedKeyValueTable, null)) {
+                               // Guard evaluated to true so update the speculative table
+                               for (KeyValue kv : transaction.getKeyValueUpdateSet()) {
+                                       speculatedKeyValueTable.put(kv.getKey(), kv);
+                               }
+                       }
+               }
+
+               if (didSkip) {
+                       // Since there was a skip we need to redo the speculation next time around
+                       lastTransactionSequenceNumberSpeculatedOn = -1;
+                       oldestTransactionSequenceNumberSpeculatedOn = -1;
+               }
+
+               // We did some speculation
+               return true;
+       }
+
+       /**
+        * Create the pending transaction speculative table from transactions that are still in the pending transaction buffer
+        */
+       private void updatePendingTransactionSpeculativeTable(boolean didProcessNewCommitsOrSpeculate) {
+               if (pendingTransactionQueue.size() == 0) {
+                       // There is nothing to speculate on
+                       return;
+               }
+
+
+               if (didProcessNewCommitsOrSpeculate || (firstPendingTransaction != pendingTransactionQueue.get(0))) {
+                       // need to reset on the pending speculation
+                       lastPendingTransactionSpeculatedOn = null;
+                       firstPendingTransaction = pendingTransactionQueue.get(0);
+                       pendingTransactionSpeculatedKeyValueTable.clear();
+               }
+
+               // Find where to start arbitration from
+               int startIndex = pendingTransactionQueue.indexOf(firstPendingTransaction) + 1;
+
+               if (startIndex >= pendingTransactionQueue.size()) {
+                       // Make sure we are not out of bounds
+                       return;
+               }
+
+               for (int i = startIndex; i < pendingTransactionQueue.size(); i++) {
+                       Transaction transaction = pendingTransactionQueue.get(i);
+
+                       lastPendingTransactionSpeculatedOn = transaction;
+
+                       if (transaction.evaluateGuard(committedKeyValueTable, speculatedKeyValueTable, pendingTransactionSpeculatedKeyValueTable)) {
+                               // Guard evaluated to true so update the speculative table
+                               for (KeyValue kv : transaction.getKeyValueUpdateSet()) {
+                                       pendingTransactionSpeculatedKeyValueTable.put(kv.getKey(), kv);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Set dead and remove from the live transaction tables the transactions that are dead
+        */
+       private void updateLiveTransactionsAndStatus() {
+
+               // Go through each of the transactions
+               for (Iterator<Map.Entry<Long, Transaction>> iter = liveTransactionBySequenceNumberTable.entrySet().iterator(); iter.hasNext();) {
+                       Transaction transaction = iter.next().getValue();
+
+                       // Check if the transaction is dead
+                       Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(transaction.getArbitrator());
+                       if ((lastTransactionNumber != null) && (lastTransactionNumber >= transaction.getSequenceNumber())) {
+
+                               // Set dead the transaction
+                               transaction.setDead();
+
+                               // Remove the transaction from the live table
+                               iter.remove();
+                               liveTransactionByTransactionIdTable.remove(transaction.getId());
+                       }
+               }
+
+               // Go through each of the transactions
+               for (Iterator<Map.Entry<Long, TransactionStatus>> iter = outstandingTransactionStatus.entrySet().iterator(); iter.hasNext();) {
+                       TransactionStatus status = iter.next().getValue();
+
+                       // Check if the transaction is dead
+                       Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(status.getTransactionArbitrator());
+                       if ((lastTransactionNumber != null) && (lastTransactionNumber >= status.getTransactionSequenceNumber())) {
+
+                               // Set committed
+                               status.setStatus(TransactionStatus.StatusCommitted);
+
+                               // Remove
+                               iter.remove();
+                       }
+               }
+       }
+
+       /**
+        * Process this slot, entry by entry.  Also update the latest message sent by slot
+        */
+       private void processSlot(SlotIndexer indexer, Slot slot, boolean acceptUpdatesToLocal, HashSet<Long> machineSet) {
+
+               // Update the last message seen
+               updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, acceptUpdatesToLocal, machineSet);
+
+               // Process each entry in the slot
+               for (Entry entry : slot.getEntries()) {
+                       switch (entry.getType()) {
+
+                               case Entry.TypeCommitPart:
+                                       processEntry((CommitPart)entry);
+                                       break;
+
+                               case Entry.TypeAbort:
+                                       processEntry((Abort)entry);
+                                       break;
+
+                               case Entry.TypeTransactionPart:
+                                       processEntry((TransactionPart)entry);
+                                       break;
+
+                               case Entry.TypeNewKey:
+                                       processEntry((NewKey)entry);
+                                       break;
+
+                               case Entry.TypeLastMessage:
+                                       processEntry((LastMessage)entry, machineSet);
+                                       break;
+
+                               case Entry.TypeRejectedMessage:
+                                       processEntry((RejectedMessage)entry, indexer);
+                                       break;
+
+                               case Entry.TypeTableStatus:
+                                       processEntry((TableStatus)entry, slot.getSequenceNumber());
+                                       break;
+
+                               default:
+                                       throw new Error("Unrecognized type: " + entry.getType());
+                       }
+               }
+       }
+
+       /**
+        * Update the last message that was sent for a machine Id
+        */
+       private void processEntry(LastMessage entry, HashSet<Long> machineSet) {
+               // Update what the last message received by a machine was
+               updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), entry, false, machineSet);
+       }
+
+       /**
+        * Add the new key to the arbitrators table and update the set of live new keys (in case of a rescued new key message)
+        */
+       private void processEntry(NewKey entry) {
+
+               // Update the arbitrator table with the new key information
+               arbitratorTable.put(entry.getKey(), entry.getMachineID());
+
+               // Update what the latest live new key is
+               NewKey oldNewKey = liveNewKeyTable.put(entry.getKey(), entry);
+               if (oldNewKey != null) {
+                       // Delete the old new key messages
+                       oldNewKey.setDead();
+               }
+       }
+
+       /**
+        * Process new table status entries and set dead the old ones as new ones come in.
+        * keeps track of the largest and smallest table status seen in this current round
+        * of updating the local copy of the block chain
+        */
+       private void processEntry(TableStatus entry, long seq) {
+               int newNumSlots = entry.getMaxSlots();
+               updateCurrMaxSize(newNumSlots);
+
+               initExpectedSize(seq, newNumSlots);
+
+               if (liveTableStatus != null) {
+                       // We have a larger table status so the old table status is no longer alive
+                       liveTableStatus.setDead();
+               }
+
+               // Make this new table status the latest alive table status
+               liveTableStatus = entry;
+       }
+
+       /**
+        * Check old messages to see if there is a block chain violation. Also
+        */
+       private void processEntry(RejectedMessage entry, SlotIndexer indexer) {
+               long oldSeqNum = entry.getOldSeqNum();
+               long newSeqNum = entry.getNewSeqNum();
+               boolean isequal = entry.getEqual();
+               long machineId = entry.getMachineID();
+               long seq = entry.getSequenceNumber();
+
+
+               // Check if we have messages that were supposed to be rejected in our local block chain
+               for (long seqNum = oldSeqNum; seqNum <= newSeqNum; seqNum++) {
+
+                       // Get the slot
+                       Slot slot = indexer.getSlot(seqNum);
+
+                       if (slot != null) {
+                               // If we have this slot make sure that it was not supposed to be a rejected slot
+
+                               long slotMachineId = slot.getMachineID();
+                               if (isequal != (slotMachineId == machineId)) {
+                                       throw new Error("Server Error: Trying to insert rejected message for slot " + seqNum);
+                               }
+                       }
+               }
+
+
+               // Create a list of clients to watch until they see this rejected message entry.
+               HashSet<Long> deviceWatchSet = new HashSet<Long>();
+               for (Map.Entry<Long, Pair<Long, Liveness>> lastMessageEntry : lastMessageTable.entrySet()) {
+
+                       // Machine ID for the last message entry
+                       long lastMessageEntryMachineId = lastMessageEntry.getKey();
+
+                       // We've seen it, don't need to continue to watch.  Our next
+                       // message will implicitly acknowledge it.
+                       if (lastMessageEntryMachineId == localMachineId) {
+                               continue;
+                       }
+
+                       Pair<Long, Liveness> lastMessageValue = lastMessageEntry.getValue();
+                       long entrySequenceNumber = lastMessageValue.getFirst();
+
+                       if (entrySequenceNumber < seq) {
+
+                               // Add this rejected message to the set of messages that this machine ID did not see yet
+                               addWatchList(lastMessageEntryMachineId, entry);
+
+                               // This client did not see this rejected message yet so add it to the watch set to monitor
+                               deviceWatchSet.add(lastMessageEntryMachineId);
+                       }
+               }
+
+               if (deviceWatchSet.isEmpty()) {
+                       // This rejected message has been seen by all the clients so
+                       entry.setDead();
+               } else {
+                       // We need to watch this rejected message
+                       entry.setWatchSet(deviceWatchSet);
+               }
+       }
+
+       /**
+        * Check if this abort is live, if not then save it so we can kill it later.
+        * update the last transaction number that was arbitrated on.
+        */
+       private void processEntry(Abort entry) {
+
+
+               if (entry.getTransactionSequenceNumber() != -1) {
+                       // update the transaction status if it was sent to the server
+                       TransactionStatus status = outstandingTransactionStatus.remove(entry.getTransactionSequenceNumber());
+                       if (status != null) {
+                               status.setStatus(TransactionStatus.StatusAborted);
+                       }
+               }
+
+               // Abort has not been seen by the client it is for yet so we need to keep track of it
+               Abort previouslySeenAbort = liveAbortTable.put(entry.getAbortId(), entry);
+               if (previouslySeenAbort != null) {
+                       previouslySeenAbort.setDead(); // Delete old version of the abort since we got a rescued newer version
+               }
+
+               if (entry.getTransactionArbitrator() == localMachineId) {
+                       liveAbortsGeneratedByLocal.put(entry.getArbitratorLocalSequenceNumber(), entry);
+               }
+
+               if ((entry.getSequenceNumber() != -1) && (lastMessageTable.get(entry.getTransactionMachineId()).getFirst() >= entry.getSequenceNumber())) {
+
+                       // The machine already saw this so it is dead
+                       entry.setDead();
+                       liveAbortTable.remove(entry.getAbortId());
+
+                       if (entry.getTransactionArbitrator() == localMachineId) {
+                               liveAbortsGeneratedByLocal.remove(entry.getArbitratorLocalSequenceNumber());
+                       }
+
+                       return;
+               }
+
+
+
+
+               // Update the last arbitration data that we have seen so far
+               if (lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(entry.getTransactionArbitrator()) != null) {
+
+                       long lastArbitrationSequenceNumber = lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.get(entry.getTransactionArbitrator());
+                       if (entry.getSequenceNumber() > lastArbitrationSequenceNumber) {
+                               // Is larger
+                               lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.put(entry.getTransactionArbitrator(), entry.getSequenceNumber());
+                       }
+               } else {
+                       // Never seen any data from this arbitrator so record the first one
+                       lastArbitrationDataLocalSequenceNumberSeenFromArbitrator.put(entry.getTransactionArbitrator(), entry.getSequenceNumber());
+               }
+
+
+               // Set dead a transaction if we can
+               Transaction transactionToSetDead = liveTransactionByTransactionIdTable.remove(new Pair<Long, Long>(entry.getTransactionMachineId(), entry.getTransactionClientLocalSequenceNumber()));
+               if (transactionToSetDead != null) {
+                       liveTransactionBySequenceNumberTable.remove(transactionToSetDead.getSequenceNumber());
+               }
+
+               // Update the last transaction sequence number that the arbitrator arbitrated on
+               Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(entry.getTransactionArbitrator());
+               if ((lastTransactionNumber == null) || (lastTransactionNumber < entry.getTransactionSequenceNumber())) {
+
+                       // Is a valid one
+                       if (entry.getTransactionSequenceNumber() != -1) {
+                               lastArbitratedTransactionNumberByArbitratorTable.put(entry.getTransactionArbitrator(), entry.getTransactionSequenceNumber());
+                       }
+               }
+       }
+
+       /**
+        * Set dead the transaction part if that transaction is dead and keep track of all new parts
+        */
+       private void processEntry(TransactionPart entry) {
+               // Check if we have already seen this transaction and set it dead OR if it is not alive
+               Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(entry.getArbitratorId());
+               if ((lastTransactionNumber != null) && (lastTransactionNumber >= entry.getSequenceNumber())) {
+                       // This transaction is dead, it was already committed or aborted
+                       entry.setDead();
+                       return;
+               }
+
+               // This part is still alive
+               Map<Pair<Long, Integer>, TransactionPart> transactionPart = newTransactionParts.get(entry.getMachineId());
+
+               if (transactionPart == null) {
+                       // Dont have a table for this machine Id yet so make one
+                       transactionPart = new HashMap<Pair<Long, Integer>, TransactionPart>();
+                       newTransactionParts.put(entry.getMachineId(), transactionPart);
+               }
+
+               // Update the part and set dead ones we have already seen (got a rescued version)
+               TransactionPart previouslySeenPart = transactionPart.put(entry.getPartId(), entry);
+               if (previouslySeenPart != null) {
+                       previouslySeenPart.setDead();
+               }
+       }
+
+       /**
+        * Process new commit entries and save them for future use.  Delete duplicates
+        */
+       private void processEntry(CommitPart entry) {
+
+
+               // Update the last transaction that was updated if we can
+               if (entry.getTransactionSequenceNumber() != -1) {
+                       Long lastTransactionNumber = lastArbitratedTransactionNumberByArbitratorTable.get(entry.getMachineId());
+
+                       // Update the last transaction sequence number that the arbitrator arbitrated on
+                       if ((lastTransactionNumber == null) || (lastTransactionNumber < entry.getTransactionSequenceNumber())) {
+                               lastArbitratedTransactionNumberByArbitratorTable.put(entry.getMachineId(), entry.getTransactionSequenceNumber());
+                       }
+               }
+
+
+
+
+               Map<Pair<Long, Integer>, CommitPart> commitPart = newCommitParts.get(entry.getMachineId());
+
+               if (commitPart == null) {
+                       // Don't have a table for this machine Id yet so make one
+                       commitPart = new HashMap<Pair<Long, Integer>, CommitPart>();
+                       newCommitParts.put(entry.getMachineId(), commitPart);
+               }
+
+               // Update the part and set dead ones we have already seen (got a rescued version)
+               CommitPart previouslySeenPart = commitPart.put(entry.getPartId(), entry);
+               if (previouslySeenPart != null) {
+                       previouslySeenPart.setDead();
+               }
+       }
+
+       /**
+        * Update the last message seen table.  Update and set dead the appropriate RejectedMessages as clients see them.
+        * Updates the live aborts, removes those that are dead and sets them dead.
+        * Check that the last message seen is correct and that there is no mismatch of our own last message or that
+        * other clients have not had a rollback on the last message.
+        */
+       private void updateLastMessage(long machineId, long seqNum, Liveness liveness, boolean acceptUpdatesToLocal, HashSet<Long> machineSet) {
+
+               // We have seen this machine ID
+               machineSet.remove(machineId);
+
+               // Get the set of rejected messages that this machine Id is has not seen yet
+               HashSet<RejectedMessage> watchset = rejectedMessageWatchListTable.get(machineId);
+
+               // If there is a rejected message that this machine Id has not seen yet
+               if (watchset != null) {
+
+                       // Go through each rejected message that this machine Id has not seen yet
+                       for (Iterator<RejectedMessage> rmit = watchset.iterator(); rmit.hasNext(); ) {
+
+                               RejectedMessage rm = rmit.next();
+
+                               // If this machine Id has seen this rejected message...
+                               if (rm.getSequenceNumber() <= seqNum) {
+
+                                       // Remove it from our watchlist
+                                       rmit.remove();
+
+                                       // Decrement machines that need to see this notification
+                                       rm.removeWatcher(machineId);
+                               }
+                       }
+               }
+
+               // Set dead the abort
+               for (Iterator<Map.Entry<Pair<Long, Long>, Abort>> i = liveAbortTable.entrySet().iterator(); i.hasNext();) {
+                       Abort abort = i.next().getValue();
+
+                       if ((abort.getTransactionMachineId() == machineId) && (abort.getSequenceNumber() <= seqNum)) {
+                               abort.setDead();
+                               i.remove();
+
+                               if (abort.getTransactionArbitrator() == localMachineId) {
+                                       liveAbortsGeneratedByLocal.remove(abort.getArbitratorLocalSequenceNumber());
+                               }
+                       }
+               }
+
+
+
+               if (machineId == localMachineId) {
+                       // Our own messages are immediately dead.
+                       if (liveness instanceof LastMessage) {
+                               ((LastMessage)liveness).setDead();
+                       } else if (liveness instanceof Slot) {
+                               ((Slot)liveness).setDead();
+                       } else {
+                               throw new Error("Unrecognized type");
+                       }
+               }
+
+               // Get the old last message for this device
+               Pair<Long, Liveness> lastMessageEntry = lastMessageTable.put(machineId, new Pair<Long, Liveness>(seqNum, liveness));
+               if (lastMessageEntry == null) {
+                       // If no last message then there is nothing else to process
+                       return;
+               }
+
+               long lastMessageSeqNum = lastMessageEntry.getFirst();
+               Liveness lastEntry = lastMessageEntry.getSecond();
+
+               // If it is not our machine Id since we already set ours to dead
+               if (machineId != localMachineId) {
+                       if (lastEntry instanceof LastMessage) {
+                               ((LastMessage)lastEntry).setDead();
+                       } else if (lastEntry instanceof Slot) {
+                               ((Slot)lastEntry).setDead();
+                       } else {
+                               throw new Error("Unrecognized type");
+                       }
+               }
+
+               // Make sure the server is not playing any games
+               if (machineId == localMachineId) {
+
+                       if (hadPartialSendToServer) {
+                               // We were not making any updates and we had a machine mismatch
+                               if (lastMessageSeqNum > seqNum && !acceptUpdatesToLocal) {
+                                       throw new Error("Server Error: Mismatch on local machine sequence number, needed at least: " +  lastMessageSeqNum  + " got: " + seqNum);
+                               }
+
+                       } else {
+                               // We were not making any updates and we had a machine mismatch
+                               if (lastMessageSeqNum != seqNum && !acceptUpdatesToLocal) {
+                                       throw new Error("Server Error: Mismatch on local machine sequence number, needed: " +  lastMessageSeqNum + " got: " + seqNum);
+                               }
+                       }
+               } else {
+                       if (lastMessageSeqNum > seqNum) {
+                               throw new Error("Server Error: Rollback on remote machine sequence number");
+                       }
+               }
+       }
+
+       /**
+        * Add a rejected message entry to the watch set to keep track of which clients have seen that
+        * rejected message entry and which have not.
+        */
+       private void addWatchList(long machineId, RejectedMessage entry) {
+               HashSet<RejectedMessage> entries = rejectedMessageWatchListTable.get(machineId);
+               if (entries == null) {
+                       // There is no set for this machine ID yet so create one
+                       entries = new HashSet<RejectedMessage>();
+                       rejectedMessageWatchListTable.put(machineId, entries);
+               }
+               entries.add(entry);
+       }
+
+       /**
+        * Check if the HMAC chain is not violated
+        */
+       private void checkHMACChain(SlotIndexer indexer, Slot[] newSlots) {
+               for (int i = 0; i < newSlots.length; i++) {
+                       Slot currSlot = newSlots[i];
+                       Slot prevSlot = indexer.getSlot(currSlot.getSequenceNumber() - 1);
+                       if (prevSlot != null &&
+                                       !Arrays.equals(prevSlot.getHMAC(), currSlot.getPrevHMAC()))
+                               throw new Error("Server Error: Invalid HMAC Chain" + currSlot + " " + prevSlot);
+               }
+       }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TableStatus.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TableStatus.java
new file mode 100644 (file)
index 0000000..1bd6d8c
--- /dev/null
@@ -0,0 +1,46 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * TableStatus entries record the current size of the data structure
+ * in slots.  Used to remember the size and to perform resizes.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+
+class TableStatus extends Entry {
+       private int maxslots;
+
+       TableStatus(Slot slot, int _maxslots) {
+               super(slot);
+               maxslots=_maxslots;
+       }
+
+       int getMaxSlots() {
+               return maxslots;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               int maxslots=bb.getInt();
+               return new TableStatus(slot, maxslots);
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeTableStatus);
+               bb.putInt(maxslots);
+       }
+
+       int getSize() {
+               //return Integer.BYTES+Byte.BYTES;
+               return Integer.SIZE/8+Byte.SIZE/8;
+       }
+
+       byte getType() {
+               return Entry.TypeTableStatus;
+       }
+
+       Entry getCopy(Slot s) {
+               return new TableStatus(s, maxslots);
+       }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ThreeTuple.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/ThreeTuple.java
new file mode 100644 (file)
index 0000000..8a882a4
--- /dev/null
@@ -0,0 +1,29 @@
+package iotcloud;
+
+class ThreeTuple<A, B, C> {
+    private A a;
+    private B b;
+    private C c;
+
+    ThreeTuple(A a, B b, C c) {
+        this.a = a;
+        this.b = b;
+        this.c = c;
+    }
+
+    A getFirst() {
+        return a;
+    }
+
+    B getSecond() {
+        return b;
+    }
+
+    C getThird() {
+        return c;
+    }
+
+    public String toString() {
+        return "<" + a + "," + b + "," + c + ">";
+    }
+}
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TimingSingleton.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TimingSingleton.java
new file mode 100644 (file)
index 0000000..c3ce863
--- /dev/null
@@ -0,0 +1,33 @@
+package iotcloud;
+
+
+class TimingSingleton {
+    private static TimingSingleton singleton = new TimingSingleton( );
+    private static long startTime = 0;
+
+    private static long totalTime = 0;
+
+    private TimingSingleton() {
+
+    }
+
+    public static TimingSingleton getInstance( ) {
+        return singleton;
+    }
+
+
+    public static void startTime( ) {
+        startTime = System.nanoTime();
+    }
+
+    public static void endTime( ) {
+        totalTime += System.nanoTime() - startTime;
+
+    }
+
+    public static long getTime( ) {
+        return totalTime;
+    }
+
+
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Transaction.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/Transaction.java
new file mode 100644 (file)
index 0000000..e25d068
--- /dev/null
@@ -0,0 +1,310 @@
+package iotcloud;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.nio.ByteBuffer;
+
+class Transaction {
+
+    private Map<Integer, TransactionPart> parts = null;
+    private Set<Integer> missingParts = null;
+    private List<Integer> partsPendingSend = null;
+    private boolean isComplete = false;
+    private boolean hasLastPart = false;
+    private Set<KeyValue> keyValueGuardSet = null;
+    private Set<KeyValue> keyValueUpdateSet = null;
+    private boolean isDead = false;
+    private long sequenceNumber = -1;
+    private long clientLocalSequenceNumber = -1;
+    private long arbitratorId = -1;
+    private long machineId = -1;
+    private Pair<Long, Long> transactionId = null;
+
+    private int nextPartToSend = 0;
+    private boolean didSendAPartToServer = false;
+
+    private TransactionStatus transactionStatus = null;
+
+    private boolean hadServerFailure = false;
+
+    public Transaction() {
+        parts = new HashMap<Integer, TransactionPart>();
+        keyValueGuardSet = new HashSet<KeyValue>();
+        keyValueUpdateSet = new HashSet<KeyValue>();
+        partsPendingSend = new ArrayList<Integer>();
+    }
+
+    public void addPartEncode(TransactionPart newPart) {
+        parts.put(newPart.getPartNumber(), newPart);
+        partsPendingSend.add(newPart.getPartNumber());
+
+        // Get the sequence number and other important information
+        sequenceNumber = newPart.getSequenceNumber();
+        arbitratorId = newPart.getArbitratorId();
+        transactionId = newPart.getTransactionId();
+        clientLocalSequenceNumber = newPart.getClientLocalSequenceNumber();
+        machineId = newPart.getMachineId();
+
+        isComplete = true;
+    }
+
+    public void addPartDecode(TransactionPart newPart) {
+
+        if (isDead) {
+            // If dead then just kill this part and move on
+            newPart.setDead();
+            return;
+        }
+
+        // Get the sequence number and other important information
+        sequenceNumber = newPart.getSequenceNumber();
+        arbitratorId = newPart.getArbitratorId();
+        transactionId = newPart.getTransactionId();
+        clientLocalSequenceNumber = newPart.getClientLocalSequenceNumber();
+        machineId = newPart.getMachineId();
+
+        TransactionPart previoslySeenPart = parts.put(newPart.getPartNumber(), newPart);
+
+        if (previoslySeenPart != null) {
+            // Set dead the old one since the new one is a rescued version of this part
+            previoslySeenPart.setDead();
+        } else if (newPart.isLastPart()) {
+            missingParts = new HashSet<Integer>();
+            hasLastPart = true;
+
+            for (int i = 0; i < newPart.getPartNumber(); i++) {
+                if (parts.get(i) == null) {
+                    missingParts.add(i);
+                }
+            }
+        }
+
+        if (!isComplete && hasLastPart) {
+
+            // We have seen this part so remove it from the set of missing parts
+            missingParts.remove(newPart.getPartNumber());
+
+            // Check if all the parts have been seen
+            if (missingParts.size() == 0) {
+
+                // We have all the parts
+                isComplete = true;
+
+                // Decode all the parts and create the key value guard and update sets
+                decodeTransactionData();
+            }
+        }
+    }
+
+    public void addUpdateKV(KeyValue kv) {
+        keyValueUpdateSet.add(kv);
+    }
+
+    public void addGuardKV(KeyValue kv) {
+        keyValueGuardSet.add(kv);
+    }
+
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    public void setSequenceNumber(long _sequenceNumber) {
+        sequenceNumber = _sequenceNumber;
+
+        for (Integer i : parts.keySet()) {
+            parts.get(i).setSequenceNumber(sequenceNumber);
+        }
+    }
+
+    public long getClientLocalSequenceNumber() {
+        return clientLocalSequenceNumber;
+    }
+
+    public Map<Integer, TransactionPart> getParts() {
+        return parts;
+    }
+
+    public boolean didSendAPartToServer() {
+        return didSendAPartToServer;
+    }
+
+    public void resetNextPartToSend() {
+        nextPartToSend = 0;
+    }
+
+    public TransactionPart getNextPartToSend() {
+        if ((partsPendingSend.size() == 0) || (partsPendingSend.size() == nextPartToSend)) {
+            return null;
+        }
+        TransactionPart part = parts.get(partsPendingSend.get(nextPartToSend));
+        nextPartToSend++;
+        return part;
+    }
+
+
+    public void setServerFailure() {
+        hadServerFailure = true;
+    }
+
+    public boolean getServerFailure() {
+        return hadServerFailure;
+    }
+
+
+    public void resetServerFailure() {
+        hadServerFailure = false;
+    }
+
+
+    public void setTransactionStatus(TransactionStatus _transactionStatus) {
+        transactionStatus = _transactionStatus;
+    }
+
+    public TransactionStatus getTransactionStatus() {
+        return transactionStatus;
+    }
+
+    public void removeSentParts(List<Integer> sentParts) {
+        nextPartToSend = 0;
+        if(partsPendingSend.removeAll(sentParts))
+        {
+            didSendAPartToServer = true;
+            transactionStatus.setTransactionSequenceNumber(sequenceNumber);
+        }
+    }
+
+    public boolean didSendAllParts() {
+        return partsPendingSend.isEmpty();
+    }
+
+    public Set<KeyValue> getKeyValueUpdateSet() {
+        return keyValueUpdateSet;
+    }
+
+    public int getNumberOfParts() {
+        return parts.size();
+    }
+
+    public long getMachineId() {
+        return machineId;
+    }
+
+    public long getArbitrator() {
+        return arbitratorId;
+    }
+
+    public boolean isComplete() {
+        return isComplete;
+    }
+
+    public Pair<Long, Long> getId() {
+        return transactionId;
+    }
+
+    public void setDead() {
+        if (isDead) {
+            // Already dead
+            return;
+        }
+
+        // Set dead
+        isDead = true;
+
+        // Make all the parts of this transaction dead
+        for (Integer partNumber : parts.keySet()) {
+            TransactionPart part = parts.get(partNumber);
+            part.setDead();
+        }
+    }
+
+    public TransactionPart getPart(int index) {
+        return parts.get(index);
+    }
+
+    private void decodeTransactionData() {
+
+        // Calculate the size of the data section
+        int dataSize = 0;
+        for (int i = 0; i < parts.keySet().size(); i++) {
+            TransactionPart tp = parts.get(i);
+            dataSize += tp.getDataSize();
+        }
+
+        byte[] combinedData = new byte[dataSize];
+        int currentPosition = 0;
+
+        // Stitch all the data sections together
+        for (int i = 0; i < parts.keySet().size(); i++) {
+            TransactionPart tp = parts.get(i);
+            System.arraycopy(tp.getData(), 0, combinedData, currentPosition, tp.getDataSize());
+            currentPosition += tp.getDataSize();
+        }
+
+        // Decoder Object
+        ByteBuffer bbDecode = ByteBuffer.wrap(combinedData);
+
+        // Decode how many key value pairs need to be decoded
+        int numberOfKVGuards = bbDecode.getInt();
+        int numberOfKVUpdates = bbDecode.getInt();
+
+        // Decode all the guard key values
+        for (int i = 0; i < numberOfKVGuards; i++) {
+            KeyValue kv = (KeyValue)KeyValue.decode(bbDecode);
+            keyValueGuardSet.add(kv);
+        }
+
+        // Decode all the updates key values
+        for (int i = 0; i < numberOfKVUpdates; i++) {
+            KeyValue kv = (KeyValue)KeyValue.decode(bbDecode);
+            keyValueUpdateSet.add(kv);
+        }
+    }
+
+    public boolean evaluateGuard(Map<IoTString, KeyValue> committedKeyValueTable, Map<IoTString, KeyValue> speculatedKeyValueTable, Map<IoTString, KeyValue> pendingTransactionSpeculatedKeyValueTable) {
+        for (KeyValue kvGuard : keyValueGuardSet) {
+
+            // First check if the key is in the speculative table, this is the value of the latest assumption
+            KeyValue kv = null;
+
+            // If we have a speculation table then use it first
+            if (pendingTransactionSpeculatedKeyValueTable != null) {
+                kv = pendingTransactionSpeculatedKeyValueTable.get(kvGuard.getKey());
+            }
+
+            // If we have a speculation table then use it first
+            if ((kv == null) && (speculatedKeyValueTable != null)) {
+                kv = speculatedKeyValueTable.get(kvGuard.getKey());
+            }
+
+            if (kv == null) {
+                // if it is not in the speculative table then check the committed table and use that
+                // value as our latest assumption
+                kv = committedKeyValueTable.get(kvGuard.getKey());
+            }
+
+            if (kvGuard.getValue() != null) {
+                if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
+
+
+                    if (kv != null) {
+                        System.out.println(kvGuard.getValue() + "       " + kv.getValue());
+                    } else {
+                        System.out.println(kvGuard.getValue() + "       " + kv);
+                    }
+
+                    return false;
+                }
+            } else {
+                if (kv != null) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionPart.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionPart.java
new file mode 100644 (file)
index 0000000..12b5dd3
--- /dev/null
@@ -0,0 +1,141 @@
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+class TransactionPart extends Entry {
+
+    // Max size of the part excluding the fixed size header
+    public static final int MAX_NON_HEADER_SIZE = 512;
+
+    private long sequenceNumber = -1;
+    private long machineId = -1;
+    private long arbitratorId = -1;
+    private long clientLocalSequenceNumber = -1; // Sequence number of the transaction that this is a part of
+    private int partNumber = -1; // Parts position in the
+    private Boolean isLastPart = false;
+
+    private Pair<Long, Long> transactionId = null;
+    private Pair<Long, Integer> partId = null;
+
+    private byte[] data = null;
+
+    public TransactionPart(Slot s, long _machineId, long _arbitratorId, long _clientLocalSequenceNumber, int _partNumber, byte[] _data, Boolean _isLastPart) {
+        super(s);
+        machineId = _machineId;
+        arbitratorId = _arbitratorId;
+        clientLocalSequenceNumber = _clientLocalSequenceNumber;
+        partNumber = _partNumber;
+        data = _data;
+        isLastPart = _isLastPart;
+
+        transactionId = new Pair<Long, Long>(machineId, clientLocalSequenceNumber);
+        partId = new Pair<Long, Integer>(clientLocalSequenceNumber, partNumber);
+
+    }
+
+    public int getSize() {
+        if (data == null) {
+            //return (4 * Long.BYTES) + (2 * Integer.BYTES) + (2 * Byte.BYTES);
+            return (4 * Long.SIZE/8) + (2 * Integer.SIZE/8) + (2 * Byte.SIZE/8);
+        }
+        //return (4 * Long.BYTES) + (2 * Integer.BYTES) + (2 * Byte.BYTES) + data.length;
+        return (4 * Long.SIZE/8) + (2 * Integer.SIZE/8) + (2 * Byte.SIZE/8) + data.length;
+    }
+
+    public void setSlot(Slot s) {
+        parentslot = s;
+    }
+
+    public Pair<Long, Long> getTransactionId() {
+        return transactionId;
+    }
+
+    public long getArbitratorId() {
+        return arbitratorId;
+    }
+
+    public Pair<Long, Integer> getPartId() {
+        return partId;
+    }
+
+    public int getPartNumber() {
+        return partNumber;
+    }
+
+    public int getDataSize() {
+        return data.length;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public Boolean isLastPart() {
+        return isLastPart;
+    }
+
+    public long getMachineId() {
+        return machineId;
+    }
+
+    public long getClientLocalSequenceNumber() {
+        return clientLocalSequenceNumber;
+    }
+
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    public void setSequenceNumber(long _sequenceNumber) {
+        sequenceNumber = _sequenceNumber;
+    }
+
+    static Entry decode(Slot s, ByteBuffer bb) {
+        long sequenceNumber = bb.getLong();
+        long machineId = bb.getLong();
+        long arbitratorId = bb.getLong();
+        long clientLocalSequenceNumber = bb.getLong();
+        int partNumber = bb.getInt();
+        int dataSize = bb.getInt();
+        Boolean isLastPart = (bb.get() == 1);
+        // Get the data
+        byte[] data = new byte[dataSize];
+        bb.get(data);
+
+        TransactionPart returnTransactionPart = new TransactionPart(s, machineId, arbitratorId, clientLocalSequenceNumber, partNumber, data, isLastPart);
+        returnTransactionPart.setSequenceNumber(sequenceNumber);
+
+        return returnTransactionPart;
+    }
+
+    public void encode(ByteBuffer bb) {
+        bb.put(Entry.TypeTransactionPart);
+        bb.putLong(sequenceNumber);
+        bb.putLong(machineId);
+        bb.putLong(arbitratorId);
+        bb.putLong(clientLocalSequenceNumber);
+        bb.putInt(partNumber);
+        bb.putInt(data.length);
+
+        if (isLastPart) {
+            bb.put((byte)1);
+        } else {
+            bb.put((byte)0);
+        }
+
+        bb.put(data);
+    }
+
+    public byte getType() {
+        return Entry.TypeTransactionPart;
+    }
+
+    public Entry getCopy(Slot s) {
+
+        TransactionPart copyTransaction = new TransactionPart(s, machineId, arbitratorId, clientLocalSequenceNumber, partNumber, data, isLastPart);
+        copyTransaction.setSequenceNumber(sequenceNumber);
+
+        return copyTransaction;
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionStatus.java b/version2/src/Control-2bulbs/app/src/main/java/iotcloud/TransactionStatus.java
new file mode 100644 (file)
index 0000000..e397d6c
--- /dev/null
@@ -0,0 +1,51 @@
+package iotcloud;
+
+class TransactionStatus {
+    static final byte StatusAborted = 1;
+    static final byte StatusPending = 2;
+    static final byte StatusCommitted = 3;
+    // static final byte StatusRetrying = 4;
+    static final byte StatusSentPartial = 5;
+    static final byte StatusSentFully = 6;
+    static final byte StatusNoEffect = 10;
+
+    private byte status = 0;
+    private boolean applicationReleased = false;
+    private boolean wasSentInChain = false;
+    private long transactionSequenceNumber = 0;
+    private long arbitrator = -1;
+
+
+    public TransactionStatus(byte _status, long _arbitrator) {
+        status = _status;
+        arbitrator = _arbitrator;
+    }
+
+    public byte getStatus() {
+        return status;
+    }
+
+    public void setStatus(byte _status) {
+        status = _status;
+    }
+
+    public long getTransactionSequenceNumber() {
+        return transactionSequenceNumber;
+    }
+
+    public void setTransactionSequenceNumber(long _transactionSequenceNumber) {
+        transactionSequenceNumber = _transactionSequenceNumber;
+    }
+
+    public long getTransactionArbitrator() {
+        return arbitrator;
+    }
+
+    public void release() {
+        applicationReleased = true;
+    }
+
+    public boolean getReleased() {
+        return applicationReleased;
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/app/src/main/res/layout/activity_main.xml b/version2/src/Control-2bulbs/app/src/main/res/layout/activity_main.xml
new file mode 100644 (file)
index 0000000..580ce62
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    tools:context="com.example.ali.control.MainActivity">
+
+    <android.support.design.widget.AppBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:theme="@style/AppTheme.AppBarOverlay">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/content_main" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/layout/content_main.xml b/version2/src/Control-2bulbs/app/src/main/res/layout/content_main.xml
new file mode 100644 (file)
index 0000000..3da3345
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    app:layout_behavior="@string/appbar_scrolling_view_behavior"
+    tools:context="com.example.ali.control.MainActivity"
+    tools:showIn="@layout/activity_main">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="250dp"
+        android:layout_height="30dp"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="116dp"
+        android:gravity="center"
+        android:text="Alarm Status"
+        android:textColor="#000000"
+        android:textSize="24sp" />
+
+    <TextView
+
+        android:id="@+id/alarmStatus"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:layout_alignEnd="@+id/title"
+        android:layout_alignLeft="@+id/title"
+        android:layout_alignRight="@+id/title"
+        android:layout_alignStart="@+id/title"
+        android:layout_below="@+id/title"
+        android:layout_marginTop="14dp"
+        android:gravity="center"
+        android:inputType="text"
+        android:text="OFF"
+        android:textIsSelectable="true"
+        android:textSize="36sp"
+        android:textStyle="bold" />
+
+    <ToggleButton
+        android:id="@+id/alarmButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="OFF"
+        android:layout_centerVertical="true"
+        android:layout_centerHorizontal="true" />
+
+</RelativeLayout>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/menu/menu_main.xml b/version2/src/Control-2bulbs/app/src/main/res/menu/menu_main.xml
new file mode 100644 (file)
index 0000000..026a8a1
--- /dev/null
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.example.ali.control.MainActivity">
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:title="@string/action_settings"
+        app:showAsAction="never" />
+</menu>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/mipmap-hdpi/ic_launcher.png b/version2/src/Control-2bulbs/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..cde69bc
Binary files /dev/null and b/version2/src/Control-2bulbs/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/version2/src/Control-2bulbs/app/src/main/res/mipmap-mdpi/ic_launcher.png b/version2/src/Control-2bulbs/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..c133a0c
Binary files /dev/null and b/version2/src/Control-2bulbs/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/version2/src/Control-2bulbs/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..bfa42f0
Binary files /dev/null and b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..324e72c
Binary files /dev/null and b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..aee44e1
Binary files /dev/null and b/version2/src/Control-2bulbs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values-v21/styles.xml b/version2/src/Control-2bulbs/app/src/main/res/values-v21/styles.xml
new file mode 100644 (file)
index 0000000..251fb9f
--- /dev/null
@@ -0,0 +1,9 @@
+<resources>>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+    </style>
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values-w820dp/dimens.xml b/version2/src/Control-2bulbs/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644 (file)
index 0000000..63fc816
--- /dev/null
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values/colors.xml b/version2/src/Control-2bulbs/app/src/main/res/values/colors.xml
new file mode 100644 (file)
index 0000000..3ab3e9c
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values/dimens.xml b/version2/src/Control-2bulbs/app/src/main/res/values/dimens.xml
new file mode 100644 (file)
index 0000000..812cb7b
--- /dev/null
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values/strings.xml b/version2/src/Control-2bulbs/app/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..cf6719a
--- /dev/null
@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">Control</string>
+    <string name="action_settings">Settings</string>
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/main/res/values/styles.xml b/version2/src/Control-2bulbs/app/src/main/res/values/styles.xml
new file mode 100644 (file)
index 0000000..545b9c6
--- /dev/null
@@ -0,0 +1,20 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/version2/src/Control-2bulbs/app/src/test/java/com/example/ali/control/ExampleUnitTest.java b/version2/src/Control-2bulbs/app/src/test/java/com/example/ali/control/ExampleUnitTest.java
new file mode 100644 (file)
index 0000000..4a08f22
--- /dev/null
@@ -0,0 +1,15 @@
+package com.example.ali.control;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * To work on unit tests, switch the Test Artifact in the Build Variants view.
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() throws Exception {
+        assertEquals(4, 2 + 2);
+    }
+}
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/build.gradle b/version2/src/Control-2bulbs/build.gradle
new file mode 100644 (file)
index 0000000..fda248f
--- /dev/null
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+
+
+allprojects {
+    repositories {
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/version2/src/Control-2bulbs/gradle.properties b/version2/src/Control-2bulbs/gradle.properties
new file mode 100644 (file)
index 0000000..1d3591c
--- /dev/null
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.jar b/version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.jar
new file mode 100644 (file)
index 0000000..05ef575
Binary files /dev/null and b/version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.properties b/version2/src/Control-2bulbs/gradle/wrapper/gradle-wrapper.properties
new file mode 100644 (file)
index 0000000..17ff946
--- /dev/null
@@ -0,0 +1,6 @@
+#Thu Mar 01 15:03:06 PST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/version2/src/Control-2bulbs/gradlew b/version2/src/Control-2bulbs/gradlew
new file mode 100644 (file)
index 0000000..9d82f78
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/version2/src/Control-2bulbs/gradlew.bat b/version2/src/Control-2bulbs/gradlew.bat
new file mode 100644 (file)
index 0000000..aec9973
--- /dev/null
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem  Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS=\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windowz variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+if "%@eval[2+2]" == "4" goto 4NT_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+goto execute\r
+\r
+:4NT_args\r
+@rem Get arguments from the 4NT Shell from JP Software\r
+set CMD_LINE_ARGS=%$\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
diff --git a/version2/src/Control-2bulbs/java_pid6346.hprof b/version2/src/Control-2bulbs/java_pid6346.hprof
new file mode 100644 (file)
index 0000000..6bdf9e9
Binary files /dev/null and b/version2/src/Control-2bulbs/java_pid6346.hprof differ
diff --git a/version2/src/Control-2bulbs/settings.gradle b/version2/src/Control-2bulbs/settings.gradle
new file mode 100644 (file)
index 0000000..e7b4def
--- /dev/null
@@ -0,0 +1 @@
+include ':app'
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/BulbColor.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/BulbColor.java
new file mode 100644 (file)
index 0000000..3463fc9
--- /dev/null
@@ -0,0 +1,65 @@
+import java.security.InvalidParameterException;
+
+public class BulbColor {
+
+       private int hue;
+       private int saturation;
+       private int brightness;
+       private int kelvin;
+
+       public BulbColor(int _hue, int _saturation, int _brightness, int _kelvin) {
+
+               if ((hue > 65535) || (hue < 0)) {
+                       throw new InvalidParameterException("BulbColor: Invalid parameter value for _hue (0-65535)");
+               }
+
+               if ((saturation > 65535) || (saturation < 0)) {
+                       throw new InvalidParameterException("BulbColor: Invalid parameter value for _saturation (0-65535)");
+               }
+
+               if ((brightness > 65535) || (brightness < 0)) {
+                       throw new InvalidParameterException("BulbColor: Invalid parameter value for _brightness (0-65535)");
+               }
+
+               if ((kelvin > 65535) || (kelvin < 0)) {
+                       throw new InvalidParameterException("BulbColor: Invalid parameter value for _kelvin (0-65535)");
+               }
+
+               hue = _hue;
+               saturation = _saturation;
+               brightness = _brightness;
+               kelvin = _kelvin;
+       }
+
+       public BulbColor(byte[] data) {
+               hue = ((data[1] & 0xFF) << 8);
+               hue |= (data[0] & 0xFF);
+
+               saturation = ((data[3] & 0xFF) << 8);
+               saturation |= (data[2] & 0xFF);
+
+               brightness = ((data[5] & 0xFF) << 8);
+               brightness |= (data[4] & 0xFF);
+
+               kelvin = ((data[7] & 0xFF) << 8);
+               kelvin |= (data[6] & 0xFF);
+       }
+
+       public int getHue() {
+               return hue;
+       }
+
+       public int getSaturation() {
+               return saturation;
+       }
+
+       public int getBrightness() {
+               return brightness;
+       }
+
+       public int getKelvin() {
+               return kelvin;
+       }
+}
+
+
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/BulbSwitch.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/BulbSwitch.java
new file mode 100644 (file)
index 0000000..172446d
--- /dev/null
@@ -0,0 +1,68 @@
+
+
+import java.util.Scanner;
+import iotcloud.*;
+
+class BulbSwitch {
+    public static void main(String[] args) throws Exception {
+
+
+        System.out.println(Integer.parseInt(args[0]));
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", Integer.parseInt(args[0]), -1);
+        t1.rebuild(); // update
+
+
+        String a = "bulb";
+        String b = "fan";
+        IoTString ib = new IoTString(b);
+        IoTString ia = new IoTString(a);
+
+        t1.createNewKey(ia, 321);
+
+
+        String valueA = "on";
+        String valueB = "off";
+        IoTString iValueA = new IoTString(valueA);
+        IoTString iValueB = new IoTString(valueB);
+
+
+
+        System.out.println("Starting System");
+        Scanner keyboard = new Scanner(System.in);
+
+        while (true) {
+
+
+            System.out.println("Enter 0 for off, 1 for on for bulb");
+            System.out.println("Enter 3 for off, 2 for on for fan");
+            int myint = keyboard.nextInt();
+
+            if (myint == 0) {
+                t1.update();
+                t1.startTransaction();
+                t1.addKV(ia, iValueB);
+                t1.commitTransaction();
+
+            } else if (myint == 1) {
+                t1.update();
+                t1.startTransaction();
+                t1.addKV(ia, iValueA);
+                t1.commitTransaction();
+            }
+            else if (myint == 2) {
+                t1.update();
+                t1.startTransaction();
+                t1.addKV(ib, iValueA);
+                t1.commitTransaction();
+            }
+            else if (myint == 3) {
+                t1.update();
+                t1.startTransaction();
+                t1.addKV(ib, iValueB);
+                t1.commitTransaction();
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateGroup.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateGroup.java
new file mode 100644 (file)
index 0000000..2ff3af7
--- /dev/null
@@ -0,0 +1,23 @@
+public class DeviceStateGroup {
+       byte[] group = new byte[16];
+       final String label;
+       final long updatedAt;
+
+       public DeviceStateGroup(byte[] _location, String _label, long _updatedAt) {
+               group = _location;
+               label = _label;
+               updatedAt = _updatedAt;
+       }
+
+       public byte[] getGroup() {
+               return group;
+       }
+
+       public String getLabel() {
+               return label;
+       }
+
+       public long getUpdatedAt() {
+               return updatedAt;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostFirmware.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostFirmware.java
new file mode 100644 (file)
index 0000000..d64483a
--- /dev/null
@@ -0,0 +1,19 @@
+public class DeviceStateHostFirmware {
+       // time of build in nanosecond accuracy
+       // after some tests
+       final long build;
+       final long version;                                                                                                                                                                                                                                                                                                                                             // firmware version
+
+       public DeviceStateHostFirmware(long _build, long _version) {
+               build = _build;
+               version = _version;
+       }
+
+       public long getBuild() {
+               return build;
+       }
+
+       public long getVersion() {
+               return version;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostInfo.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateHostInfo.java
new file mode 100644 (file)
index 0000000..cb45cdd
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+public class DeviceStateHostInfo {
+       final long signal;
+       final long tx;
+       final long rx;
+
+       public DeviceStateHostInfo(long _signal, long _tx, long _rx) {
+               signal = _signal;
+               tx = _tx;
+               rx = _rx;
+       }
+
+       public long getSignal() {
+               return signal;
+       }
+
+       public long getTx() {
+               return tx;
+       }
+
+       public long getRx() {
+               return rx;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateInfo.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateInfo.java
new file mode 100644 (file)
index 0000000..ba4330f
--- /dev/null
@@ -0,0 +1,26 @@
+
+
+public class DeviceStateInfo {
+       // all values are in nanoseconds
+       private final long time;
+       private final long upTime;
+       private final long downTime;
+
+       public DeviceStateInfo(long _time, long _upTime, long _downTime) {
+               time = _time;
+               upTime = _upTime;
+               downTime = _downTime;
+       }
+
+       public long getTime() {
+               return time;
+       }
+
+       public long getUpTime() {
+               return upTime;
+       }
+
+       public long getDownTime() {
+               return downTime;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateLocation.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateLocation.java
new file mode 100644 (file)
index 0000000..fc04980
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+public class DeviceStateLocation {
+       byte[] location = new byte[16];
+       final String label;
+       final long updatedAt;
+
+       public DeviceStateLocation(byte[] _location, String _label, long _updatedAt) {
+               location = _location;
+               label = _label;
+               updatedAt = _updatedAt;
+       }
+
+       public byte[] getLocation() {
+               return location;
+       }
+
+       public String getLabel() {
+               return label;
+       }
+
+       public long getUpdatedAt() {
+               return updatedAt;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateService.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateService.java
new file mode 100644 (file)
index 0000000..ec89595
--- /dev/null
@@ -0,0 +1,19 @@
+
+
+public class DeviceStateService {
+       private final int service;
+       private final long port;
+
+       public DeviceStateService(int _service, long _port) {
+               service = _service;
+               port = _port;
+       }
+
+       public int getService() {
+               return service;
+       }
+
+       public long getPort() {
+               return port;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateVersion.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateVersion.java
new file mode 100644 (file)
index 0000000..e4f7c88
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+public class DeviceStateVersion {
+       final long vender;
+       final long product;
+       final long version;
+
+       public DeviceStateVersion(long _vender, long _product, long _version) {
+               vender = _vender;
+               product = _product;
+               version = _version;
+       }
+
+       public long getVender() {
+               return vender;
+       }
+
+       public long getProduct() {
+               return product;
+       }
+
+       public long getVersion() {
+               return version;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiFirmware.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiFirmware.java
new file mode 100644 (file)
index 0000000..5e49867
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+public class DeviceStateWifiFirmware {
+       // time of build in nanosecond accuracy
+       // after some tests
+       final long build;
+       final long version;                                                                                                                                                                                                                                                                                                                                             // firmware version
+
+       public DeviceStateWifiFirmware(long _build, long _version) {
+               build = _build;
+               version = _version;
+       }
+
+       public long getBuild() {
+               return build;
+       }
+
+       public long getVersion() {
+               return version;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiInfo.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/DeviceStateWifiInfo.java
new file mode 100644 (file)
index 0000000..8c84103
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+public class DeviceStateWifiInfo {
+       final long signal;
+       final long tx;
+       final long rx;
+
+       public DeviceStateWifiInfo(long _signal, long _tx, long _rx) {
+               signal = _signal;
+               tx = _tx;
+               rx = _rx;
+       }
+
+       public long getSignal() {
+               return signal;
+       }
+
+       public long getTx() {
+               return tx;
+       }
+
+       public long getRx() {
+               return rx;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/Filler.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/Filler.java
new file mode 100644 (file)
index 0000000..82871f5
--- /dev/null
@@ -0,0 +1,45 @@
+
+
+
+import java.util.Scanner;
+import iotcloud.*;
+
+import java.util.Scanner;
+import iotcloud.*;
+
+import java.util.Scanner;
+import iotcloud.*;
+class Filler {
+    public static void main(String[] args) throws Exception {
+
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 400, -1);
+        t1.rebuild(); // update
+
+        String valueA = "on";
+        String valueB = "off";
+        IoTString iValueA = new IoTString(valueA);
+        IoTString iValueB = new IoTString(valueB);
+
+
+        System.out.println("Starting System");
+        Scanner keyboard = new Scanner(System.in);
+
+        for (int i = 0; i < 10; i++) {
+
+
+            String a1 = "bulb" + (i % 100);
+            IoTString ia1 = new IoTString(a1);
+
+
+
+            t1.update();
+            t1.startTransaction();
+            t1.addKV(ia1, iValueB);
+            t1.commitTransaction();
+
+
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/Filler2.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/Filler2.java
new file mode 100644 (file)
index 0000000..0e84979
--- /dev/null
@@ -0,0 +1,44 @@
+
+
+
+import java.util.Scanner;
+import iotcloud.*;
+
+import java.util.Scanner;
+import iotcloud.*;
+class Filler2 {
+    public static void main(String[] args) throws Exception {
+
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 400, -1);
+        t1.rebuild(); // update
+
+        String valueA = "on";
+        String valueB = "off";
+        IoTString iValueA = new IoTString(valueA);
+        IoTString iValueB = new IoTString(valueB);
+
+
+        System.out.println("Starting System");
+        String a1 = "bulb1";
+        IoTString ia1 = new IoTString(a1);
+
+
+        while (true) {
+
+
+
+            // t1.update();
+            t1.startTransaction();
+            t1.addKV(ia1, iValueB);
+            t1.commitTransaction();
+
+            try {
+                Thread.sleep(500);
+            } catch (Exception e) {
+
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTAddress.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTAddress.java
new file mode 100644 (file)
index 0000000..ee96322
--- /dev/null
@@ -0,0 +1,77 @@
+\r
+// Java packages\r
+import java.net.Socket;\r
+import java.net.ServerSocket;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+\r
+/** Class IoTAddress is a wrapper class to pass\r
+ *  IoTSet of any addresses from master to slave\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-04-22\r
+ */\r
+public class IoTAddress {\r
+\r
+       /**\r
+        * IoTDeviceAddress class properties\r
+        */\r
+       protected final InetAddress inetAddress;\r
+\r
+       /**\r
+        * Class constructor\r
+        *\r
+        * @param   sAddress  String address\r
+        */\r
+       protected IoTAddress(String sAddress) throws UnknownHostException {\r
+\r
+               inetAddress = InetAddress.getByName(sAddress);\r
+       }\r
+\r
+       /**\r
+        * getHostAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getHostAddress() {\r
+\r
+               return inetAddress.getHostAddress();\r
+\r
+       }\r
+\r
+       /**\r
+        * getHostName() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getHostName() {\r
+\r
+               return inetAddress.getHostName();\r
+\r
+       }\r
+\r
+       /**\r
+        * getUrl() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getURL(String strURLComplete) {\r
+\r
+               //e.g. http:// + inetAddress.getHostAddress() + strURLComplete\r
+               //     http://192.168.2.254/cgi-bin/mjpg/video.cgi?\r
+               return "http://" + inetAddress.getHostAddress() + strURLComplete;\r
+               \r
+       }\r
+\r
+       /**\r
+        * getCompleteAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getCompleteAddress() {\r
+\r
+               return inetAddress.toString();\r
+\r
+       }\r
+}\r
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTDeviceAddress.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTDeviceAddress.java
new file mode 100644 (file)
index 0000000..d738f3f
--- /dev/null
@@ -0,0 +1,151 @@
+// Java packages\r
+import java.net.Socket;\r
+import java.net.ServerSocket;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+\r
+/** Class IoTDeviceAddress is a wrapper class to pass\r
+ *  IoTSet of device addresses from master to slave\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-02-18\r
+ */\r
+public class IoTDeviceAddress extends IoTAddress {\r
+\r
+       /**\r
+        * IoTDeviceAddress class properties\r
+        */\r
+       private int iSrcPort;\r
+       private int iDstPort;\r
+       private final String sAddress;\r
+\r
+       // the wildcard status of this address\r
+       private final boolean isSrcPortWildCard;\r
+       private final boolean isDstPortWildCard;\r
+\r
+\r
+       /**\r
+        * Class constructor\r
+        *\r
+        * @param   sAddress                    String address\r
+        * @param   _iSrcPort                   Source port number\r
+        * @param   _iDstPort                   Destination port number\r
+        * @param   _isSrcPortWildCard  Is this source port a wild card (=can change port number)?\r
+        * @param   _isDstPortWildCard  Is this destination port a wild card (=can change port number)?\r
+        */\r
+       protected IoTDeviceAddress(String _sAddress, int _iSrcPort, int _iDstPort, boolean _isSrcPortWildCard, \r
+               boolean _isDstPortWildCard) throws UnknownHostException {\r
+\r
+               super(_sAddress);\r
+               sAddress = _sAddress;\r
+               iSrcPort = _iSrcPort;\r
+               iDstPort = _iDstPort;\r
+\r
+               isSrcPortWildCard = _isSrcPortWildCard;\r
+               isDstPortWildCard = _isDstPortWildCard;\r
+       }\r
+\r
+       /**\r
+        * getSourcePortNumber() method\r
+        *\r
+        * @return  int\r
+        */\r
+       public int getSourcePortNumber() {\r
+\r
+               return iSrcPort;\r
+\r
+       }\r
+\r
+       /**\r
+        * getDestinationPortNumber() method\r
+        *\r
+        * @return  int\r
+        */\r
+       public int getDestinationPortNumber() {\r
+\r
+               return iDstPort;\r
+\r
+       }\r
+\r
+       /**\r
+        * setSrcPort() method\r
+        *\r
+        * @param   port        Port number\r
+        * @return  void\r
+        */\r
+       public void setSrcPort(int port) {\r
+               if (isSrcPortWildCard) {\r
+                       iSrcPort = port;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * setDstPort() method\r
+        *\r
+        * @param   port        Port number\r
+        * @return  void\r
+        */\r
+       public void setDstPort(int port) {\r
+               if (isDstPortWildCard) {\r
+                       iDstPort = port;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * getAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getAddress() {\r
+               return sAddress;\r
+       }\r
+\r
+       /**\r
+        * getHostAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public static String getLocalHostAddress() {\r
+\r
+               String strLocalHostAddress = null;\r
+               try {\r
+                       strLocalHostAddress = InetAddress.getLocalHost().getHostAddress();\r
+               } catch (UnknownHostException ex) {\r
+                       ex.printStackTrace();\r
+               }               \r
+               return strLocalHostAddress;\r
+       }\r
+\r
+       /**\r
+        * getIsSrcPortWildcard() method\r
+        *\r
+        * @return  boolean\r
+        */\r
+       public boolean getIsSrcPortWildcard() {\r
+               return isSrcPortWildCard;\r
+       }\r
+\r
+       /**\r
+        * getIsDstPortWildcard() method\r
+        *\r
+        * @return  boolean\r
+        */\r
+       public boolean getIsDstPortWildcard() {\r
+               return isDstPortWildCard;\r
+       }\r
+\r
+\r
+       /**\r
+        * getUrl() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getURL(String strURLComplete) {\r
+\r
+               //e.g. http:// + inetAddress.getHostAddress() + strURLComplete\r
+               //     http://192.168.2.254/cgi-bin/mjpg/video.cgi?\r
+               return "http://" + inetAddress.getHostAddress() + ":" + iDstPort + strURLComplete;\r
+               \r
+       }\r
+}\r
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTHTTP.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTHTTP.java
new file mode 100644 (file)
index 0000000..c364c4e
--- /dev/null
@@ -0,0 +1,150 @@
+\r
+// Java packages\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.net.MalformedURLException;\r
+import java.net.UnknownHostException;\r
+import java.net.URL;\r
+import java.net.ProtocolException;\r
+\r
+\r
+/** Class IoTHTTP is a wrapper class that provides\r
+ *  minimum interfaces for user to interact with IoT\r
+ *  devices in our system\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-02-18\r
+ */\r
+public class IoTHTTP {\r
+\r
+       /**\r
+        * IoTHTTP class properties\r
+        */\r
+       private IoTDeviceAddress iotDevAdd;\r
+       private URL url;\r
+       private HttpURLConnection httpConnection;\r
+\r
+       /**\r
+        * Class constructor\r
+        */\r
+       public IoTHTTP(IoTDeviceAddress _iotDevAdd) {\r
+\r
+               iotDevAdd = _iotDevAdd;\r
+               url = null;\r
+               httpConnection = null;\r
+       }\r
+\r
+       /**\r
+        * setURL() method\r
+        *\r
+        * @param  strUrlComplete  String to complete the URL\r
+        * @return void\r
+        */\r
+       public void setURL(String strUrlComplete) throws MalformedURLException {\r
+\r
+               url = new URL(iotDevAdd.getURL(strUrlComplete));\r
+               System.out.println(url.toString());\r
+\r
+       }\r
+\r
+       /**\r
+        * openConnection() method\r
+        */\r
+       public void openConnection() throws IOException {\r
+\r
+               httpConnection = (HttpURLConnection) url.openConnection();\r
+\r
+       }\r
+\r
+       /**\r
+        * setDoInput() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  bSetDoInput\r
+        * @return void\r
+        */\r
+       public void setDoInput(boolean bSetDoInput) {\r
+\r
+               httpConnection.setDoInput(bSetDoInput);\r
+\r
+       }\r
+\r
+       /**\r
+        * setRequestProperty() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  strProperty             String property\r
+        * @param  strHttpAuthCredentials  String HTTP authentication credentials\r
+        * @return void\r
+        */\r
+       public void setRequestProperty(String strProperty, String strHttpAuthCredentials) {\r
+\r
+               httpConnection.setRequestProperty(strProperty, strHttpAuthCredentials);\r
+\r
+       }\r
+\r
+       /**\r
+        * setRequestMethod() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  strMethod             String method\r
+        * @return void\r
+        */\r
+       public void setRequestMethod(String strMethod) throws ProtocolException {\r
+\r
+               httpConnection.setRequestMethod(strMethod);\r
+\r
+       }\r
+\r
+       /**\r
+        * setDoOutput() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  doOut\r
+        * @return void\r
+        */\r
+       public void setDoOutput(boolean doOut) {\r
+\r
+               httpConnection.setDoOutput(doOut);\r
+\r
+       }\r
+\r
+       /**\r
+        * getOutputStream() method inherited from HttpURLConnection class\r
+        *\r
+        * @return OutputStream\r
+        */\r
+       public OutputStream getOutputStream() throws IOException {\r
+\r
+               return httpConnection.getOutputStream();\r
+\r
+       }\r
+\r
+       /**\r
+        * getInputStream() method inherited from HttpURLConnection class\r
+        *\r
+        * @return InputStream\r
+        */\r
+       public InputStream getInputStream() throws IOException {\r
+\r
+               return httpConnection.getInputStream();\r
+\r
+       }\r
+\r
+       /**\r
+        * connect() method inherited from HttpURLConnection class\r
+        */\r
+       public void connect() throws IOException {\r
+\r
+               httpConnection.connect();\r
+\r
+       }\r
+\r
+       /**\r
+        * disconnect() method inherited from HttpURLConnection class\r
+        */\r
+       public void disconnect() throws IOException {\r
+\r
+               httpConnection.disconnect();\r
+\r
+       }\r
+}\r
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTSet.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTSet.java
new file mode 100644 (file)
index 0000000..ccf8543
--- /dev/null
@@ -0,0 +1,79 @@
+import java.lang.UnsupportedOperationException;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+
+
+/** Class IoTSet is the actual implementation of @config IoTSet<...>.
+ *  Upon extracting DB information, SetInstrumenter class will use
+ *  this class to actually instantiate the Set as IoTSet that uses
+ *  Java Set<T> to implement; we don't provide interfaces to modify
+ *  the contents, but we do provide means to read them out
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public final class IoTSet<T> {
+
+       /**
+        * Reference to an object Set<T>
+        */
+       private Set<T> set;
+
+       /**
+        * Class constructor (pass the reference to this immutable wrapper)
+        */
+       protected IoTSet(Set<T> s) {
+
+               set = s;
+       }
+
+       /**
+        * contains() method inherited from Set interface
+        */
+       public boolean contains(T o) {
+
+               return set.contains(o);
+
+       }
+
+       /**
+        * isEmpty() method inherited from Set interface
+        */
+       public boolean isEmpty() {
+
+               return set.isEmpty();
+
+       }
+
+       /**
+        * iterator() method inherited from Set interface
+        */
+       public Iterator<T> iterator() {
+
+               return new HashSet<T>(set).iterator();
+
+       }
+
+       /**
+        * size() method inherited from Set interface
+        */
+       public int size() {
+
+               return set.size();
+
+       }
+
+       /**
+        * values() method to return Set object values for easy iteration
+        */
+       public Set<T> values() {
+
+               return new HashSet<T>(set);
+
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTUDP.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/IoTUDP.java
new file mode 100644 (file)
index 0000000..e8966e8
--- /dev/null
@@ -0,0 +1,133 @@
+
+// Java packages
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+
+/** Class IoTUDP is a wrapper class that provides
+ *  minimum interfaces for user to interact with IoT
+ *  devices in our system - adapted from my colleague's
+ *  work (Ali Younis - ayounis @ uci.edu)
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-20
+ */
+public class IoTUDP {
+
+       /**
+        * IoTUDP class properties
+        */
+       private final String strHostAddress;
+       private final int iSrcPort;
+       private final int iDstPort;
+       private DatagramSocket socket;  // the socket interface that we are guarding
+       private boolean didClose;               // make sure that the clean up was done correctly
+
+       /**
+        * Class constructor
+        */
+       public IoTUDP(IoTDeviceAddress iotDevAdd) throws SocketException, IOException {
+
+               strHostAddress = iotDevAdd.getHostAddress();
+               iSrcPort = iotDevAdd.getSourcePortNumber();
+               iDstPort = iotDevAdd.getDestinationPortNumber();
+
+               socket = new DatagramSocket(iSrcPort);
+               didClose = false;
+       }
+
+       /**
+        * sendData() method
+        *
+        * @param  bData     Byte type that passes the data to be sent
+        * @return void
+        */
+       public void sendData(byte[] bData) throws UnknownHostException, IOException {
+
+               DatagramPacket dpSendPacket = new DatagramPacket(bData, bData.length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(dpSendPacket);
+       }
+
+       /**
+        * recieveData() method
+        *
+        * @param  iMaxDataLength  Integer maximum data length as reference
+        * @return byte[]
+        */
+       public byte[] recieveData(int iMaxDataLength) throws IOException {
+
+               byte[] bReceiveData = new byte[iMaxDataLength];
+               DatagramPacket dpReceivePacket = new DatagramPacket(bReceiveData, bReceiveData.length);
+               socket.receive(dpReceivePacket);
+
+               return dpReceivePacket.getData();
+       }
+
+       /**
+        * setSoTimeout() method
+        *
+        * @param  iTimeout  Integer timeout time
+        */
+       public void setSoTimeout(int iTimeout) throws SocketException {
+
+               socket.setSoTimeout(iTimeout);
+
+       }
+
+       /**
+        * setSendBufferSize() method
+        *
+        * @param  iSize  Integer buffer size
+        */
+       public void setSendBufferSize(int iSize) throws SocketException {
+
+               socket.setSendBufferSize(iSize);
+
+       }
+
+       /**
+        * setReceiveBufferSize() method
+        *
+        * @param  iSize  Integer buffer size
+        */
+       public void setReceiveBufferSize(int iSize) throws SocketException {
+
+               socket.setReceiveBufferSize(iSize);
+
+       }
+
+       /**
+       * setReuseAddress(boolean on) method
+       */
+       public void setReuseAddress(boolean on) throws SocketException {
+
+               socket.setReuseAddress(on);
+       }
+
+       /**
+        * close() method
+        */
+       public void close() {
+
+               socket.close();
+               didClose = true;
+
+       }
+
+       /**
+        * close() called by the garbage collector right before trashing object
+        */
+       public void finalize() throws SocketException {
+
+               if (!didClose) {
+                       close();
+                       throw new SocketException("Socket not closed before object destruction, must call close method.");
+               }
+
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/LifxHeader.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/LifxHeader.java
new file mode 100644 (file)
index 0000000..b90422e
--- /dev/null
@@ -0,0 +1,263 @@
+
+
+import java.security.InvalidParameterException;
+
+public class LifxHeader {
+       // Frame Variables
+       private int size;
+       private int origin;
+       private boolean tagged;
+       private boolean addressable;
+       private int protocol;
+       private long source;
+
+       //Frame Adress Variables
+       private byte[] macAddress = new byte[8];
+       private boolean ack_required;
+       private boolean res_required;
+       private int sequence;
+
+       //Protocol Header
+       private int type;
+
+       public LifxHeader() {
+               // needed values as per spec
+               origin = 0;
+               addressable = true;
+               protocol = 1024;
+       }
+
+       public void setSize(int _size) {
+               if (_size < 0) {
+                       throw new InvalidParameterException("Header: size cannot be less than 0");
+               } else if (_size > 65535) {
+                       throw new InvalidParameterException("Header: size to large");
+               }
+               size = _size;
+       }
+
+       public void setOrigin(int _origin) {
+               if (_origin < 0) {
+                       throw new InvalidParameterException("Header: origin cannot be less than 0");
+               } else if (_origin > 3) {
+                       throw new InvalidParameterException("Header: origin to large");
+               }
+
+               origin = _origin;
+       }
+
+       public void setTagged(boolean _tagged) {
+               tagged = _tagged;
+       }
+
+       public void setAddressable(boolean _addressable) {
+               addressable = _addressable;
+       }
+
+       public void setProtocol(int _protocol) {
+               if (_protocol < 0) {
+                       throw new InvalidParameterException("Header: protocol cannot be less than 0");
+               } else if (_protocol > 4095) {
+                       throw new InvalidParameterException("Header: protocol to large");
+               }
+
+               protocol = _protocol;
+       }
+
+       public void setSource(long _source) {
+               if (_source < 0) {
+                       throw new InvalidParameterException("Header: source cannot be less than 0");
+               } else if (_source > (long)4294967295l) {
+                       throw new InvalidParameterException("Header: source to large");
+               }
+               source = _source;
+       }
+
+       public void setSequence(int _sequence) {
+               if (_sequence < 0) {
+                       throw new InvalidParameterException("Header: sequence cannot be less than 0");
+               } else if (_sequence > 255) {
+                       throw new InvalidParameterException("Header: sequence to large");
+               }
+               sequence = _sequence;
+       }
+
+       public void setType(int _type) {
+               if (_type < 0) {
+                       throw new InvalidParameterException("Header: type cannot be less than 0");
+               } else if (_type > 65535) {
+                       throw new InvalidParameterException("Header: type to large");
+               }
+               type = _type;
+       }
+
+       public void setAck_required(boolean _ack_required) {
+               ack_required = _ack_required;
+       }
+
+       public void setRes_required(boolean _res_required) {
+               res_required = _res_required;
+       }
+
+       public void setMacAddress(byte[] _macAddress) {
+               macAddress = _macAddress;
+       }
+
+       public int getSize() {
+               return size;
+       }
+
+       public int getOrigin() {
+               return origin;
+       }
+
+       public boolean getTagged() {
+               return tagged;
+       }
+
+       public boolean getAddressable() {
+               return addressable;
+       }
+
+       public int getProtocol() {
+               return protocol;
+       }
+
+       public long getSource() {
+               return source;
+       }
+
+       public int getSequence() {
+               return sequence;
+       }
+
+       public int getType() {
+               return type;
+       }
+
+       public byte[] getMacAddress() {
+               return macAddress;
+       }
+
+       public boolean getAck_required() {
+               return ack_required;
+       }
+
+       public boolean getRes_required() {
+               return res_required;
+       }
+
+       public byte[] getHeaderBytes() {
+               byte[] headerBytes = new byte[36];
+               headerBytes[0] = (byte)(size & 0xFF);
+               headerBytes[1] = (byte)((size >> 8) & 0xFF);
+
+
+               headerBytes[2] = (byte)(protocol & 0xFF);
+               headerBytes[3] = (byte)((protocol >> 8) & 0x0F);
+
+               headerBytes[3] |= (byte)((origin & 0x03) << 6);
+
+               if (tagged) {
+                       headerBytes[3] |= (1 << 5);
+               }
+
+               if (addressable) {
+                       headerBytes[3] |= (1 << 4);
+               }
+
+               headerBytes[4] = (byte)((source >> 0) & 0xFF);
+               headerBytes[5] = (byte)((source >> 8) & 0xFF);
+               headerBytes[6] = (byte)((source >> 16) & 0xFF);
+               headerBytes[7] = (byte)((source >> 24) & 0xFF);
+
+
+               // fix in a bit
+               headerBytes[8] = macAddress[0];
+               headerBytes[9] = macAddress[1];
+               headerBytes[10] = macAddress[2];
+               headerBytes[11] = macAddress[3];
+               headerBytes[12] = macAddress[4];
+               headerBytes[13] = macAddress[5];
+               headerBytes[14] = macAddress[6];
+               headerBytes[15] = macAddress[7];
+
+               // Reserved and set to 0
+               // headerBytes[16] = 0;
+               // headerBytes[17] = 0;
+               // headerBytes[18] = 0;
+               // headerBytes[19] = 0;
+               // headerBytes[20] = 0;
+               // headerBytes[21] = 0;
+
+               if (ack_required) {
+                       headerBytes[22] = (1 << 1);
+               }
+
+               if (res_required) {
+                       headerBytes[22] |= (1);
+               }
+
+               headerBytes[23] = (byte)(sequence & 0xFF);
+
+               // Reserved and set to 0
+               //headerBytes[24] = 0;
+               //headerBytes[25] = 0;
+               //headerBytes[26] = 0;
+               //headerBytes[27] = 0;
+               //headerBytes[28] = 0;
+               //headerBytes[29] = 0;
+               //headerBytes[30] = 0;
+               //headerBytes[31] = 0;
+
+               headerBytes[32] = (byte)((type >> 0) & 0xFF);
+               headerBytes[33] = (byte)((type >> 8) & 0xFF);
+
+               // Reserved and set to 0
+               //headerBytes[34] = 0;
+               //headerBytes[35] = 0;
+
+               return headerBytes;
+       }
+
+       public void setFromBytes(byte[] dataBytes) {
+               if (dataBytes.length != 36) {
+                       throw new InvalidParameterException("Header: invalid number of bytes");
+               }
+
+               size = dataBytes[0] & 0xFF;
+               size |= ((dataBytes[1] & 0xFF) << 8);
+               size &= 0xFFFF;
+
+               origin = (dataBytes[3] >> 6) & 0x03;
+               tagged = ((dataBytes[3] >> 5) & 0x01) == 1;
+               addressable = ((dataBytes[3] >> 4) & 0x01) == 1;
+
+
+               protocol = (dataBytes[3] & 0x0F) << 8;
+               protocol |= dataBytes[2];
+               protocol &= 0x0FFF;
+
+               source = (dataBytes[7] & 0xFFl) << 24;
+               source |= ((dataBytes[6] & 0xFFl) << 16);
+               source |= ((dataBytes[5] & 0xFFl) << 8);
+               source |= ((dataBytes[4] & 0xFFl));
+
+               macAddress[0] = dataBytes[8];
+               macAddress[1] = dataBytes[9];
+               macAddress[2] = dataBytes[10];
+               macAddress[3] = dataBytes[11];
+               macAddress[4] = dataBytes[12];
+               macAddress[5] = dataBytes[13];
+               macAddress[6] = dataBytes[14];
+               macAddress[7] = dataBytes[15];
+
+               ack_required = (dataBytes[22] & 0x02) == 0x02;
+               res_required = (dataBytes[22] & 0x01) == 0x01;
+
+               sequence = (dataBytes[23] & 0xFF);
+
+               type = ((dataBytes[33] & 0xFF) << 8);
+               type |= (dataBytes[32] & 0xFF);
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/LifxLightBulb.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/LifxLightBulb.java
new file mode 100644 (file)
index 0000000..400ee08
--- /dev/null
@@ -0,0 +1,1209 @@
+
+
+// Standard Java Packages
+import java.io.*;
+import java.net.*;
+import java.util.concurrent.Semaphore;
+import java.security.InvalidParameterException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+// IoT Packages
+//import iotcode.annotation.*;
+
+// String to byte conversion
+import javax.xml.bind.DatatypeConverter;
+
+
+public class LifxLightBulb implements LightBulb {
+
+       /*******************************************************************************************************************************************
+       **
+       **  Constants
+       **
+       *******************************************************************************************************************************************/
+       public static final long GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
+
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Variables
+       **
+       *******************************************************************************************************************************************/
+       private IoTUDP communicationSockect;
+       private byte[] bulbMacAddress = new byte[8];
+       static Semaphore socketMutex = new Semaphore(1);
+       static boolean sendSocketFlag = false;
+       private long lastSentGetBulbVersionRequest = 0;                                                                                                                                                                                                                                                         // time last request sent
+
+       // Current Bulb Values
+       private int currentHue = 0;
+       private int currentSaturation = 0;
+       private int currentBrightness = 65535;
+       private int currentTemperature = 9000;
+       private boolean bulbIsOn = false;
+
+
+
+       private AtomicBoolean didAlreadyInit = new AtomicBoolean(false);
+
+       private AtomicBoolean didGetBulbVersion = new AtomicBoolean(false);
+       static Semaphore settingBulbColorMutex = new Semaphore(1);
+       static Semaphore settingBulbTempuraturerMutex = new Semaphore(1);
+       static Semaphore bulbStateMutex = new Semaphore(1);
+
+       // color and temperature ranges for the bulbs
+       private int hueLowerBound = 0;
+       private int hueUpperBound = 0;
+       private int saturationLowerBound = 0;
+       private int saturationUpperBound = 0;
+       private int brightnessLowerBound = 0;
+       private int brightnessUpperBound = 0;
+       private int temperatureLowerBound = 2500;
+       private int temperatureUpperBound = 9000;
+
+
+
+       // Check if a state change was requested, used to poll the bulb for if the bulb did
+       // preform the requested state change
+       private boolean stateDidChange = false;
+
+       /*******************************************************************************************************************************************
+       **
+       **  Threads
+       **
+       *******************************************************************************************************************************************/
+
+       // Main worker thread will do the receive loop
+       Thread workerThread = null;
+
+       /*******************************************************************************************************************************************
+       **
+       **  IoT Sets and Relations
+       **
+       *******************************************************************************************************************************************/
+
+       // IoTSet of Device Addresses.
+       // Will be filled with only 1 address.
+       private IoTSet<IoTDeviceAddress> lb_addresses;
+
+       /**
+        * Used for testing only
+        */
+       public LifxLightBulb(IoTUDP udp, byte[] macAddress) {
+               communicationSockect = udp;
+               bulbMacAddress = macAddress;
+       }
+
+       public LifxLightBulb(String macAddress) {
+               communicationSockect = null;
+
+               // Set the Mac Address to a default value
+               // Probably not needed for anything
+               /*bulbMacAdd[0] = (byte)0x00;
+                  bulbMacAdd[1] = (byte)0x00;
+                  bulbMacAdd[2] = (byte)0x00;
+                  bulbMacAdd[3] = (byte)0x00;
+                  bulbMacAdd[4] = (byte)0x00;
+                  bulbMacAdd[5] = (byte)0x00;
+                  bulbMacAdd[6] = (byte)0x00;
+                  bulbMacAdd[7] = (byte)0x00;*/
+
+               bulbMacAddress = DatatypeConverter.parseHexBinary(macAddress);
+       }
+
+
+
+       /*******************************************************************************************************************************************
+       **  Sending
+       **  Device Messages
+       **
+       *******************************************************************************************************************************************/
+       private void sendGetServicePacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(true);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(0);                                                                                                                                                                                                                                                                                                                                                                                                                            // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(2);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetHostInfoPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(12);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetHostFirmwarePacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(14);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetWifiInfoPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(16);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetWifiFirmwarePacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(18);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetPowerPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(20);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendSetPowerPacket(int level) {
+               // Currently only 0 and 65535 are supported
+               // This is a fix for now
+               if ((level != 65535) && (level != 0)) {
+                       throw new InvalidParameterException("Invalid parameter values");
+               }
+
+               if ((level > 65535) || (level < 0)) {
+                       throw new InvalidParameterException("Invalid parameter values");
+               }
+
+               byte[] packetBytes = new byte[38];
+
+               LifxHeader header = new LifxHeader();
+               header.setSize(38);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(21);
+               byte[] headerBytes = header.getHeaderBytes();
+
+               for (int i = 0; i < 36; i++) {
+                       packetBytes[i] = headerBytes[i];
+               }
+
+               packetBytes[36] = (byte)(level & 0xFF);
+               packetBytes[37] = (byte)((level >> 8) & 0xFF);
+
+               sendPacket(packetBytes);
+       }
+
+       private void sendGetLabelPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(23);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendSetLabelPacket(String label) {
+               // Currently only 0 and 65535 are supported
+               // This is a fix for now
+               if (label.length() != 32) {
+                       throw new InvalidParameterException("Invalid parameter values, label must be 32 bytes long");
+               }
+
+               byte[] packetBytes = new byte[68];
+
+               LifxHeader header = new LifxHeader();
+               header.setSize(68);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(24);
+               byte[] headerBytes = header.getHeaderBytes();
+
+               for (int i = 0; i < 36; i++) {
+                       packetBytes[i] = headerBytes[i];
+               }
+
+               for (int i = 0; i < 32; i++) {
+                       packetBytes[i + 36] = label.getBytes()[i];
+               }
+
+               sendPacket(packetBytes);
+       }
+
+       private void sendGetVersionPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(32);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetInfoPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(34);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetLocationPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(34);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendGetGroupPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(51);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+
+       /*******************************************************************************************************************************************
+       **  Sending
+       **  Light Messages
+       **
+       *******************************************************************************************************************************************/
+       private void sendGetLightStatePacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(101);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendSetLightColorPacket(BulbColor bulbColor, long duration) {
+
+               if ((duration > 4294967295l) || (duration < 0)) {
+                       throw new InvalidParameterException("Invalid parameter value, duration out of range (0 - 4294967295)");
+               }
+
+               byte[] packetBytes = new byte[49];
+
+               LifxHeader header = new LifxHeader();
+               header.setSize(49);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(102);
+               byte[] headerBytes = header.getHeaderBytes();
+
+               for (int i = 0; i < 36; i++) {
+                       packetBytes[i] = headerBytes[i];
+               }
+
+               // 1 reserved packet
+               packetBytes[37] = (byte)(bulbColor.getHue() & 0xFF);
+               packetBytes[38] = (byte)((bulbColor.getHue() >> 8) & 0xFF);
+
+               packetBytes[39] = (byte)(bulbColor.getSaturation() & 0xFF);
+               packetBytes[40] = (byte)((bulbColor.getSaturation() >> 8) & 0xFF);
+
+               packetBytes[41] = (byte)(bulbColor.getBrightness() & 0xFF);
+               packetBytes[42] = (byte)((bulbColor.getBrightness() >> 8) & 0xFF);
+
+               packetBytes[43] = (byte)(bulbColor.getKelvin() & 0xFF);
+               packetBytes[44] = (byte)((bulbColor.getKelvin() >> 8) & 0xFF);
+
+               packetBytes[45] = (byte)((duration >> 0) & 0xFF);
+               packetBytes[46] = (byte)((duration >> 8) & 0xFF);
+               packetBytes[47] = (byte)((duration >> 16) & 0xFF);
+               packetBytes[48] = (byte)((duration >> 24) & 0xFF);
+
+               sendPacket(packetBytes);
+       }
+
+       private void sendGetLightPowerPacket() {
+               LifxHeader header = new LifxHeader();
+               header.setSize(36);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(116);
+
+               byte[] dataBytes = header.getHeaderBytes();
+               sendPacket(dataBytes);
+       }
+
+       private void sendSetLightPowerPacket(int level, long duration) {
+
+               if ((level > 65535) || (duration > 4294967295l)
+                       || (level < 0) || (duration < 0)) {
+                       throw new InvalidParameterException("Invalid parameter values");
+               }
+
+               byte[] packetBytes = new byte[42];
+
+
+               LifxHeader header = new LifxHeader();
+               header.setSize(42);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(117);
+               byte[] headerBytes = header.getHeaderBytes();
+
+               for (int i = 0; i < 36; i++) {
+                       packetBytes[i] = headerBytes[i];
+               }
+
+               packetBytes[36] = (byte)(level & 0xFF);
+               packetBytes[37] = (byte)((level >> 8) & 0xFF);
+
+               packetBytes[38] = (byte)((duration >> 0) & 0xFF);
+               packetBytes[39] = (byte)((duration >> 8) & 0xFF);
+               packetBytes[40] = (byte)((duration >> 16) & 0xFF);
+               packetBytes[41] = (byte)((duration >> 24) & 0xFF);
+
+               sendPacket(packetBytes);
+       }
+
+       private void sendEchoRequestPacket(byte[] data) {
+               // Currently only 0 and 65535 are supported
+               // This is a fix for now
+               if (data.length != 64) {
+                       throw new InvalidParameterException("Invalid parameter values, must have 64 bytes");
+               }
+
+               byte[] packetBytes = new byte[100];
+
+               LifxHeader header = new LifxHeader();
+               header.setSize(100);
+               header.setTagged(false);
+               header.setMacAddress(bulbMacAddress);
+               header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
+               header.setAck_required(false);
+               header.setRes_required(false);
+               header.setSequence(0);
+               header.setType(58);
+               byte[] headerBytes = header.getHeaderBytes();
+
+               for (int i = 0; i < 36; i++) {
+                       packetBytes[i] = headerBytes[i];
+               }
+
+               for (int i = 0; i < 64; i++) {
+                       packetBytes[i + 36] = data[i];
+               }
+
+               sendPacket(packetBytes);
+       }
+
+
+       /*******************************************************************************************************************************************
+       **  Receiving
+       **  Device Messages
+       **
+       *******************************************************************************************************************************************/
+       private DeviceStateService parseDeviceStateServiceMessage(LifxHeader header, byte[] payloadData) {
+               int service = payloadData[0];
+               long port = ((payloadData[3] & 0xFF) << 24);
+               port |= ((payloadData[2] & 0xFF) << 16);
+               port |= ((payloadData[1] & 0xFF) << 8);
+               port |= (payloadData[0] & 0xFF);
+
+               return new DeviceStateService(service, port);
+       }
+
+       private DeviceStateHostInfo parseDeviceStateHostInfoMessage(LifxHeader header, byte[] payloadData) {
+               long signal = ((payloadData[3] & 0xFF) << 24);
+               signal |= ((payloadData[2] & 0xFF) << 16);
+               signal |= ((payloadData[1] & 0xFF) << 8);
+               signal |= (payloadData[0] & 0xFF);
+
+               long tx = ((payloadData[7] & 0xFF) << 24);
+               tx |= ((payloadData[6] & 0xFF) << 16);
+               tx |= ((payloadData[5] & 0xFF) << 8);
+               tx |= (payloadData[4] & 0xFF);
+
+               long rx = ((payloadData[11] & 0xFF) << 24);
+               rx |= ((payloadData[10] & 0xFF) << 16);
+               rx |= ((payloadData[9] & 0xFF) << 8);
+               rx |= (payloadData[8] & 0xFF);
+
+               return new DeviceStateHostInfo(signal, tx, rx);
+       }
+
+       private DeviceStateHostFirmware parseDeviceStateHostFirmwareMessage(LifxHeader header, byte[] payloadData) {
+               long build = 0;
+               for (int i = 0; i < 8; i++) {
+                       build += ((long) payloadData[i] & 0xffL) << (8 * i);
+               }
+
+               // 8 reserved bytes
+
+               long version = ((payloadData[19] & 0xFF) << 24);
+               version |= ((payloadData[18] & 0xFF) << 16);
+               version |= ((payloadData[17] & 0xFF) << 8);
+               version |= (payloadData[16] & 0xFF);
+
+               return new DeviceStateHostFirmware(build, version);
+       }
+
+       private DeviceStateWifiInfo parseDeviceStateWifiInfoMessage(LifxHeader header, byte[] payloadData) {
+               long signal = ((payloadData[3] & 0xFF) << 24);
+               signal |= ((payloadData[2] & 0xFF) << 16);
+               signal |= ((payloadData[1] & 0xFF) << 8);
+               signal |= (payloadData[0] & 0xFF);
+
+               long tx = ((payloadData[7] & 0xFF) << 24);
+               tx |= ((payloadData[6] & 0xFF) << 16);
+               tx |= ((payloadData[5] & 0xFF) << 8);
+               tx |= (payloadData[4] & 0xFF);
+
+               long rx = ((payloadData[11] & 0xFF) << 24);
+               rx |= ((payloadData[10] & 0xFF) << 16);
+               rx |= ((payloadData[9] & 0xFF) << 8);
+               rx |= (payloadData[8] & 0xFF);
+
+               return new DeviceStateWifiInfo(signal, tx, rx);
+       }
+
+       private DeviceStateWifiFirmware parseDeviceStateWifiFirmwareMessage(LifxHeader header, byte[] payloadData) {
+               long build = 0;
+               for (int i = 0; i < 8; i++) {
+                       build += ((long) payloadData[i] & 0xffL) << (8 * i);
+               }
+
+               // 8 reserved bytes
+
+               long version = ((payloadData[19] & 0xFF) << 24);
+               version |= ((payloadData[18] & 0xFF) << 16);
+               version |= ((payloadData[17] & 0xFF) << 8);
+               version |= (payloadData[16] & 0xFF);
+
+               return new DeviceStateWifiFirmware(build, version);
+       }
+
+       private int parseStatePowerMessage(LifxHeader header, byte[] payloadData) {
+               int level = ((payloadData[1] & 0xFF) << 8);
+               level |= (payloadData[0] & 0xFF);
+               return level;
+       }
+
+       private String parseStateLabelMessage(LifxHeader header, byte[] payloadData) {
+               return new String(payloadData);
+       }
+
+
+       private DeviceStateVersion parseDeviceStateVersionMessage(LifxHeader header, byte[] payloadData) {
+               long vender = ((payloadData[3] & 0xFF) << 24);
+               vender |= ((payloadData[2] & 0xFF) << 16);
+               vender |= ((payloadData[1] & 0xFF) << 8);
+               vender |= (payloadData[0] & 0xFF);
+
+               long product = ((payloadData[7] & 0xFF) << 24);
+               product |= ((payloadData[6] & 0xFF) << 16);
+               product |= ((payloadData[5] & 0xFF) << 8);
+               product |= (payloadData[4] & 0xFF);
+
+               long version = ((payloadData[11] & 0xFF) << 24);
+               version |= ((payloadData[10] & 0xFF) << 16);
+               version |= ((payloadData[9] & 0xFF) << 8);
+               version |= (payloadData[8] & 0xFF);
+
+               return new DeviceStateVersion(vender, product, version);
+       }
+
+       private DeviceStateInfo parseDeviceStateInfoMessage(LifxHeader header, byte[] payloadData) {
+               long time = 0;
+               long upTime = 0;
+               long downTime = 0;
+               for (int i = 0; i < 8; i++) {
+                       time += ((long) payloadData[i] & 0xffL) << (8 * i);
+                       upTime += ((long) payloadData[i + 8] & 0xffL) << (8 * i);
+                       downTime += ((long) payloadData[i + 16] & 0xffL) << (8 * i);
+               }
+
+               return new DeviceStateInfo(time, upTime, downTime);
+       }
+
+       private DeviceStateLocation parseDeviceStateLocationMessage(LifxHeader header, byte[] payloadData) {
+               byte[] location = new byte[16];
+               for (int i = 0; i < 16; i++) {
+                       location[i] = payloadData[i];
+               }
+
+               byte[] labelBytes = new byte[32];
+               for (int i = 0; i < 32; i++) {
+                       labelBytes[i] = payloadData[i + 16];
+               }
+
+               long updatedAt = 0;
+               for (int i = 0; i < 8; i++) {
+                       updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
+               }
+
+               return new DeviceStateLocation(location, new String(labelBytes), updatedAt);
+       }
+
+       private DeviceStateGroup parseDeviceStateGroupMessage(LifxHeader header, byte[] payloadData) {
+               byte[] group = new byte[16];
+               for (int i = 0; i < 16; i++) {
+                       group[i] = payloadData[i];
+               }
+
+               byte[] labelBytes = new byte[32];
+               for (int i = 0; i < 32; i++) {
+                       labelBytes[i] = payloadData[i + 16];
+               }
+
+               long updatedAt = 0;
+               for (int i = 0; i < 8; i++) {
+                       updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
+               }
+
+               return new DeviceStateGroup(group, new String(labelBytes), updatedAt);
+       }
+
+       private byte[] parseDeviceEchoResponseMessage(LifxHeader header, byte[] payloadData) {
+               return payloadData;
+       }
+
+       /*******************************************************************************************************************************************
+       **  Receiving
+       **  Light Messages
+       **
+       *******************************************************************************************************************************************/
+       private LightState parseLightStateMessage(LifxHeader header, byte[] payloadData) {
+
+               byte[] colorData = new byte[8];
+               for (int i = 0; i < 8; i++) {
+                       colorData[i] = payloadData[i];
+               }
+               BulbColor color = new BulbColor(colorData);
+
+               int power = ((payloadData[11] & 0xFF) << 8);
+               power |= (payloadData[10] & 0xFF);
+
+               String label = new String(payloadData);
+
+               byte[] labelArray = new byte[32];
+               for (int i = 0; i < 32; i++) {
+                       labelArray[i] = payloadData[12 + i];
+               }
+
+               return new LightState(color, power, label);
+       }
+
+       private int parseLightStatePowerMessage(LifxHeader header, byte[] payloadData) {
+               int level = ((payloadData[1] & 0xFF) << 8);
+               level |= (payloadData[0] & 0xFF);
+               return level;
+       }
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Private Handlers
+       **
+       *******************************************************************************************************************************************/
+       private void handleStateVersionMessageRecieved(LifxHeader header, byte[] payloadData) {
+
+               DeviceStateVersion deviceState = parseDeviceStateVersionMessage(header, payloadData);
+               int productNumber = (int)deviceState.getProduct();
+
+               boolean isColor = false;
+
+               if (productNumber == 1) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Original 1000
+                       isColor = true;
+               } else if (productNumber == 3) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                //Color 650
+                       isColor = true;
+               } else if (productNumber == 10) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (Low Voltage)
+                       isColor = false;
+               } else if (productNumber == 11) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (High Voltage)
+                       isColor = false;
+               } else if (productNumber == 18) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 900 BR30 (Low Voltage)
+                       isColor = false;
+               } else if (productNumber == 20) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000 BR30
+                       isColor = true;
+               } else if (productNumber == 22) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000
+                       isColor = true;
+               }
+
+               if (isColor) {
+                       hueLowerBound = 0;
+                       hueUpperBound = 65535;
+                       saturationLowerBound = 0;
+                       saturationUpperBound = 65535;
+                       brightnessLowerBound = 0;
+                       brightnessUpperBound = 65535;
+                       temperatureLowerBound = 2500;
+                       temperatureUpperBound = 9000;
+               } else {
+                       hueLowerBound = 0;
+                       hueUpperBound = 0;
+                       saturationLowerBound = 0;
+                       saturationUpperBound = 0;
+                       brightnessLowerBound = 0;
+                       brightnessUpperBound = 65535;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   // still can dim bulb
+                       temperatureLowerBound = 2500;
+                       temperatureUpperBound = 9000;
+               }
+
+               didGetBulbVersion.set(true);
+
+       }
+
+       private void handleLightStateMessageRecieved(LifxHeader header, byte[] payloadData) {
+               LightState lightState = parseLightStateMessage(header, payloadData);
+
+               BulbColor color = lightState.getColor();
+               int power = lightState.getPower();
+
+               boolean bulbWrongColor = false;
+               bulbWrongColor = bulbWrongColor || (color.getHue() != currentHue);
+               bulbWrongColor = bulbWrongColor || (color.getSaturation() != currentSaturation);
+               bulbWrongColor = bulbWrongColor || (color.getBrightness() != currentBrightness);
+               bulbWrongColor = bulbWrongColor || (color.getKelvin() != currentTemperature);
+
+
+               // gets set to true if any of the below if statements are taken
+               stateDidChange = false;
+
+               if (bulbWrongColor) {
+                       BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
+                       sendSetLightColorPacket(newColor, 250);
+                       // System.out.println("Failed Check 1");
+               }
+
+               try {
+                       bulbStateMutex.acquire();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               boolean bulbIsOnTmp = bulbIsOn;
+               bulbStateMutex.release();
+
+               if ((!bulbIsOnTmp) && (power != 0)) {
+                       turnOff();
+                       // System.out.println("Failed Check 2:  " + Integer.toString(power));
+
+               }
+
+               if (bulbIsOnTmp && (power < 65530)) {
+                       turnOn();
+                       // System.out.println("Failed Check 3:  " + Integer.toString(power));
+
+               }
+       }
+
+       /*******************************************************************************************************************************************
+       **
+       **  Light Bulb Interface Methods
+       **
+       *******************************************************************************************************************************************/
+       public double getHue() {
+               double tmp = 0;
+               try {
+                       settingBulbColorMutex.acquire();
+                       tmp = ((double)currentHue / 65535.0) * 360.0;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               settingBulbColorMutex.release();
+
+
+               return tmp;
+       }
+
+       public double getSaturation() {
+               double tmp = 0;
+               try {
+                       settingBulbColorMutex.acquire();
+                       tmp = ((double)currentSaturation / 65535.0) * 360.0;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               settingBulbColorMutex.release();
+
+
+               return tmp;
+       }
+
+       public double getBrightness() {
+               double tmp = 0;
+               try {
+                       settingBulbColorMutex.acquire();
+                       tmp = ((double)currentBrightness / 65535.0) * 360.0;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               settingBulbColorMutex.release();
+
+               return tmp;
+       }
+
+       public int getTemperature() {
+
+               int tmp = 0;
+               try {
+                       settingBulbTempuraturerMutex.acquire();
+                       tmp = currentTemperature;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               settingBulbTempuraturerMutex.release();
+
+               return tmp;
+       }
+
+       public double getHueRangeLowerBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)hueLowerBound / 65535.0) * 360.0;
+       }
+
+       public double getHueRangeUpperBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)hueUpperBound / 65535.0) * 360.0;
+       }
+
+       public double getSaturationRangeLowerBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)saturationLowerBound / 65535.0) * 100.0;
+       }
+
+       public double getSaturationRangeUpperBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)saturationUpperBound / 65535.0) * 100.0;
+       }
+
+       public double getBrightnessRangeLowerBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)brightnessLowerBound / 65535.0) * 100.0;
+       }
+
+       public double getBrightnessRangeUpperBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return ((double)brightnessUpperBound / 65535.0) * 100.0;
+       }
+
+       public int getTemperatureRangeLowerBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return temperatureLowerBound;
+       }
+
+       public int getTemperatureRangeUpperBound() {
+               if (!didGetBulbVersion.get()) {
+                       return -1;
+               }
+               return temperatureUpperBound;
+       }
+
+       public void setTemperature(int _temperature) {
+
+               try {
+                       settingBulbTempuraturerMutex.acquire();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
+               sendSetLightColorPacket(newColor, 250);
+
+               currentTemperature = _temperature;
+               stateDidChange = true;
+
+               settingBulbTempuraturerMutex.release();
+       }
+
+       public void setColor(double _hue, double _saturation, double _brightness) {
+
+               try {
+                       settingBulbColorMutex.acquire();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+
+               _hue /= 360.0;
+               _saturation /= 100.0;
+               _brightness /= 100.0;
+
+
+               int newHue = (int)(_hue * 65535.0);
+               int newSaturation = (int)(_saturation * 65535.0);
+               int newBrightness = (int)(_brightness * 65535.0);
+
+               BulbColor newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
+               sendSetLightColorPacket(newColor, 250);
+
+               currentHue = newHue;
+               currentSaturation = newSaturation;
+               currentBrightness = newBrightness;
+               stateDidChange = true;
+
+               settingBulbColorMutex.release();
+       }
+
+
+       public void turnOff() {
+
+               try {
+                       bulbStateMutex.acquire();
+                       bulbIsOn = false;
+                       sendSetLightPowerPacket(0, 0);
+                       stateDidChange = true;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               bulbStateMutex.release();
+       }
+
+       public void turnOn() {
+               try {
+                       bulbStateMutex.acquire();
+                       bulbIsOn = true;
+                       sendSetLightPowerPacket(65535, 0);
+                       stateDidChange = true;
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+
+               bulbStateMutex.release();
+       }
+
+       public boolean getState() {
+
+               boolean tmp = false;
+               try {
+                       bulbStateMutex.acquire();
+                       tmp = bulbIsOn;
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               bulbStateMutex.release();
+
+               return tmp;
+       }
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Communication Helpers
+       **
+       *******************************************************************************************************************************************/
+       private void recievedPacket(byte[] packetData) {
+
+               byte[] headerBytes = new byte[36];
+               for (int i = 0; i < 36; i++) {
+                       headerBytes[i] = packetData[i];
+               }
+
+               LifxHeader recHeader = new LifxHeader();
+               recHeader.setFromBytes(headerBytes);
+
+               // load the payload bytes (strip away the header)
+               byte[] payloadBytes = new byte[recHeader.getSize()];
+               for (int i = 36; i < recHeader.getSize(); i++) {
+                       payloadBytes[i - 36] = packetData[i];
+               }
+
+               System.out.println("Received: " + Integer.toString(recHeader.getType()));
+
+               switch (recHeader.getType()) {
+               case 3:
+                       DeviceStateService dat = parseDeviceStateServiceMessage(recHeader, payloadBytes);
+                       // System.out.println("Service: " + Integer.toString(dat.getService()));
+                       // System.out.println("Port   : " + Long.toString(dat.getPort()));
+                       break;
+
+
+               case 33:
+                       handleStateVersionMessageRecieved(recHeader, payloadBytes);
+                       break;
+
+               case 35:
+                       parseDeviceStateInfoMessage(recHeader, payloadBytes);
+                       break;
+
+
+               case 107:
+                       handleLightStateMessageRecieved(recHeader, payloadBytes);
+                       break;
+
+               default:
+                       // System.out.println("unknown packet Type");
+               }
+
+       }
+
+       private void sendPacket(byte[] packetData) {
+               // System.out.println("About to send");
+               sendSocketFlag = true;
+
+               try {
+                       socketMutex.acquire();
+               } catch (InterruptedException e) {
+                       System.out.println("mutex Error");
+               }
+
+               try {
+                       communicationSockect.sendData(packetData);
+
+               } catch (IOException e) {
+                       System.out.println("Socket Send Error");
+               }
+
+               sendSocketFlag = false;
+               socketMutex.release();
+       }
+
+
+       /**
+        *   Worker function which runs the while loop for receiving data from the bulb.
+        *   Is blocking
+        */
+       private void workerFunction() {
+               LifxHeader h = new LifxHeader();
+
+               try {
+                       // Need timeout on receives since we are not sure if a packet will be available
+                       // for processing so don't block waiting
+                       communicationSockect.setSoTimeout(50);
+               } catch (IOException e) {
+               }
+
+               // Start the bulb in the off state
+               turnOff();
+
+
+               while (true) {
+
+                       // Check if we got the bulb version yet
+                       // could have requested it but message could have gotten lost (UDP)
+                       if (!didGetBulbVersion.get()) {
+                               long currentTime = (new Date().getTime()) / 1000;
+                               if ((currentTime - lastSentGetBulbVersionRequest) > GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
+                                       // Get the bulb version so we know what type of bulb this is.
+                                       sendGetVersionPacket();
+                                       lastSentGetBulbVersionRequest = currentTime;
+                               }
+                       }
+
+                       // Communication resource is busy so try again later
+                       if (sendSocketFlag) {
+                               continue;
+                       }
+
+                       try {
+                               socketMutex.acquire();
+                       } catch (InterruptedException e) {
+                       }
+
+                       byte[] dat = null;
+                       try {
+                               dat = communicationSockect.recieveData(1024);
+                       } catch (java.net.SocketTimeoutException e) {
+                               // Timeout occurred
+
+                       } catch (IOException e) {
+                               // Problem but might be able to recover??
+                               e.printStackTrace();
+
+                       }
+
+                       // Never forget to release!
+                       socketMutex.release();
+
+                       // A packed arrived
+                       if (dat != null) {
+                               recievedPacket(dat);
+                       }
+
+                       // If a state change occurred then request the bulb state to ensure that the
+                       // bulb did indeed change its state to the correct state
+                       if (stateDidChange) {
+                               sendGetLightStatePacket();
+                       }
+
+                       // Wait a bit as to not tie up system resources
+                       try {
+                               Thread.sleep(100);
+                       } catch (Exception e) {
+
+                       }
+
+
+               }
+       }
+
+
+       public void init() {
+
+               if (didAlreadyInit.compareAndSet(false, true) == false) {
+                       return; // already init
+               }
+
+               try {
+                       // Get the bulb address from the IoTSet
+                       Iterator itr = lb_addresses.iterator();
+                       IoTDeviceAddress deviceAddress = (IoTDeviceAddress)itr.next();
+
+                       System.out.println("Address: " + deviceAddress.getCompleteAddress());
+
+                       // Create the communication channel
+                       communicationSockect = new IoTUDP(deviceAddress);
+
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+
+               // Launch the worker function in a separate thread.
+               workerThread = new Thread(new Runnable() {
+                       public void run() {
+                               workerFunction();
+                       }
+               });
+               workerThread.start();
+
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/LightBulb.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/LightBulb.java
new file mode 100644 (file)
index 0000000..8d7f6a5
--- /dev/null
@@ -0,0 +1,159 @@
+/** Class LightBulb interface for the light bulb devices.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-01-27
+ */
+
+
+public interface LightBulb {
+
+       /** Method to turn the light bulb on (Physically illuminate the area).
+        *
+        *   @param None.
+        *
+        *   @return [void] None.
+        */
+
+       public void turnOff();
+
+       /** Method to turn the light bulb off.
+        *
+        *   @return [void] None.
+        */
+       public void turnOn();
+
+
+       /** Method to get the current on/off state of the light bulb.
+        *
+        *   @return [boolean] True means bulb on.
+        */
+       public boolean getState();
+
+
+       /** Method to set the light bulb color using Standard Hue, Saturation and Brightness
+        * conventions. See "http://www.tydac.ch/color/" for reference.
+        *
+        *   @param _hue [double]: Hue value (in degrees).
+        *   @param _saturation [double]: Saturation value (percentage).
+        *   @param _brightness [double]: Brightness value (percentage).
+        *
+        *   @return [void] None.
+        */
+       public void setColor(double _hue, double _saturation, double _brightness);
+
+
+       /** Method to set the color temperature.
+        *
+        *   @param _temperature [int]: Color temperature in degrees kelvin.
+        *
+        *   @return [void] None.
+        */
+       public void setTemperature(int _temperature);
+
+
+       /** Method to get the current hue value of the bulb.
+        *
+        *   @return [double] Current hue value of the bulb in degrees.
+        */
+       public double getHue();
+
+
+       /** Method to get the current saturation value of the bulb.
+        *
+        *   @return [double] Current saturation value of the bulb as a percentage.
+        */
+       public double getSaturation();
+
+
+       /** Method to get the current brightness value of the bulb.
+        *
+        *   @return [double] Current brightness value of the bulb as a percentage.
+        */
+       public double getBrightness();
+
+
+       /** Method to get the current color temperature value of the bulb.
+        *
+        *   @return [double] Current color temperature value of the bulb in kelvin.
+        */
+       public int getTemperature();
+
+
+       /** Method to get the hue range lower bound supported by the bulb.
+        *
+        *   @return [double] Hue lower bound in degrees.
+        */
+       public double getHueRangeLowerBound();
+
+
+       /** Method to get the hue range upper bound supported by the bulb.
+        *
+        *   @return [double] Hue upper bound in degrees.
+        */
+       public double getHueRangeUpperBound();
+
+
+       /** Method to get the saturation range lower bound supported by the bulb.
+        *
+        *   @return [double] Saturation lower bound as a percentage.
+        */
+       public double getSaturationRangeLowerBound();
+
+
+       /** Method to get the saturation range upper bound supported by the bulb.
+        *
+        *   @return [double] Saturation upper bound as a percentage.
+        */
+       public double getSaturationRangeUpperBound();
+
+
+       /** Method to get the brightness range lower bound supported by the bulb.
+        *
+        *   @return [double] Brightness lower bound as a percentage.
+        */
+       public double getBrightnessRangeLowerBound();
+
+
+       /** Method to get the brightness range upper bound supported by the bulb.
+        *
+        *   @return [double] Brightness upper bound as a percentage.
+        */
+       public double getBrightnessRangeUpperBound();
+
+
+       /** Method to get the temperature range lower bound supported by the bulb.
+        *
+        *   @return [int] Temperature lower bound as a percentage.
+        */
+       public int getTemperatureRangeLowerBound();
+
+
+       /** Method to get the temperature range upper bound supported by the bulb.
+        *
+        *   @return [int] Temperature upper bound as a percentage.
+        */
+       public int getTemperatureRangeUpperBound();
+
+
+       /** Method to initialize the bulb, if the bulb needs to be initialized.
+        *
+        *   @return [void] None.
+        */
+       public void init();
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/LightState.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/LightState.java
new file mode 100644 (file)
index 0000000..80bc77c
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+public class LightState {
+       private final BulbColor color;
+       private final int power;
+       private final String label;
+
+       public LightState(BulbColor _color, int _power, String _label) {
+               color = _color;
+               power = _power;
+               label = _label;
+       }
+
+       public BulbColor getColor() {
+               return color;
+       }
+
+       public int getPower() {
+               return power;
+       }
+
+       public String getLabel() {
+               return label;
+       }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/LightsController.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/LightsController.java
new file mode 100644 (file)
index 0000000..9be0b02
--- /dev/null
@@ -0,0 +1,137 @@
+import iotcloud.*;
+import java.util.*;
+
+class LightsController {
+
+    public static void main(String[] args) throws Exception {
+
+
+        // Bulb 1
+        byte[] bulbMacAdd1 = new byte[8];
+        bulbMacAdd1[0] = (byte)0xD0;
+        bulbMacAdd1[1] = (byte)0x73;
+        bulbMacAdd1[2] = (byte)0xD5;
+        bulbMacAdd1[3] = (byte)0x02;
+        bulbMacAdd1[4] = (byte)0x41;
+        bulbMacAdd1[5] = (byte)0xDA;
+        bulbMacAdd1[6] = (byte)0x00;
+        bulbMacAdd1[7] = (byte)0x00;
+
+        IoTDeviceAddress devAddr1 = new IoTDeviceAddress("192.168.1.232", 56700, 56700, false, false);
+        IoTUDP udp1 = new IoTUDP(devAddr1);
+        LightBulb bulb1 = new LifxLightBulb(udp1, bulbMacAdd1);
+
+
+
+        byte[] bulbMacAdd2 = new byte[8];
+        bulbMacAdd2[0] = (byte)0xD0;
+        bulbMacAdd2[1] = (byte)0x73;
+        bulbMacAdd2[2] = (byte)0xD5;
+        bulbMacAdd2[3] = (byte)0x12;
+        bulbMacAdd2[4] = (byte)0x8E;
+        bulbMacAdd2[5] = (byte)0x30;
+        bulbMacAdd2[6] = (byte)0x00;
+        bulbMacAdd2[7] = (byte)0x00;
+
+        IoTDeviceAddress devAddr2 = new IoTDeviceAddress("192.168.1.126", 56701, 56700, false, false);
+        IoTUDP udp2 = new IoTUDP(devAddr2);
+        LightBulb bulb2 = new LifxLightBulb(udp2, bulbMacAdd2);
+
+
+        List<LightBulb> bulbs = new ArrayList<LightBulb>();
+        bulbs.add(bulb1);
+        bulbs.add(bulb2);
+
+               String a = "bulb";
+        //String a1 = "bulb1";
+        //String a2 = "bulb2";
+
+               IoTString ia = new IoTString(a);
+        //IoTString ia1 = new IoTString(a1);
+        //IoTString ia2 = new IoTString(a2);
+
+        //List<IoTString> keys = new ArrayList<IoTString>();
+        //keys.add(ia1);
+        //keys.add(ia2);
+
+        String valueA = "on";
+        IoTString iValueA = new IoTString(valueA);
+
+        System.out.println("Starting System");
+        int counter = 0;
+
+
+        Table t1 = null;
+        try {
+            t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 260, 6000);
+            //t1.addLocalCommunication(400, "192.168.1.108", 6000);
+            t1.addLocalCommunication(260, "192.168.1.192", 6000);
+
+            t1.rebuild();
+        } catch (Error e) {
+
+            e.printStackTrace();
+            for (int i = 0; i < bulbs.size(); i++) {
+                bulbs.get(i).setColor(0, 100, 100);
+            }
+
+            while (true) {
+                for (int i = 0; i < bulbs.size(); i++) {
+                    bulbs.get(i).turnOff();
+                }
+                Thread.sleep(1000);
+
+                for (int i = 0; i < bulbs.size(); i++) {
+                    bulbs.get(i).turnOn();
+                }
+                Thread.sleep(1000);
+            }
+        }
+
+
+        while (true) {
+
+            try {
+
+                System.out.println("Loop");
+
+                for (int i = 0; i < bulbs.size(); i++) {
+                       t1.update();
+                       IoTString testValA1 = t1.getCommitted(ia);
+                    //IoTString testValA1 = t1.getCommitted(keys.get(i));
+                    bulbs.get(i).setColor(200, 200, 200);
+                    if ((testValA1 != null) && (testValA1.equals(iValueA) == true)) {
+                        bulbs.get(i).turnOn();
+                               System.out.println("Turning on bulbs");
+                    } else {
+                               System.out.println("Turning off bulbs");
+                        bulbs.get(i).turnOff();
+                        
+                    }
+                }
+
+                Thread.sleep(1000);
+
+            } catch (Error e) {
+
+                e.printStackTrace();
+                for (int i = 0; i < bulbs.size(); i++) {
+                    bulbs.get(i).setColor(0, 100, 100);
+                }
+
+
+                while (true) {
+                    for (int i = 0; i < bulbs.size(); i++) {
+                        bulbs.get(i).turnOff();
+                    }
+                    Thread.sleep(1000);
+
+                    for (int i = 0; i < bulbs.size(); i++) {
+                        bulbs.get(i).turnOn();
+                    }
+                    Thread.sleep(1000);
+                }
+            }
+        }
+    }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/README.txt b/version2/src/java/light_fan_embed_benchmark_2bulbs/README.txt
new file mode 100644 (file)
index 0000000..8cb0d0b
--- /dev/null
@@ -0,0 +1,24 @@
+First build using:
+    ./build.bash
+
+To run this example run:
+    # Set up the table on the cloud
+    ./runSetup.bash
+    
+    # Starts the light bulb controller
+    ./run1.bash   
+
+    # Starts the fan controller
+    ./run3.bash   
+
+
+    # For each switch you need to run (can launch as many of these as desired as long as input number is different)
+    ./run2.bash <a unique integer not equal to 321 or 351>
+
+
+Dont forget to clear the cloud server directory
+
+
+
+
+https://javatutorial.net/raspberry-pi-java-tutorial
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/Sensor.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/Sensor.java
new file mode 100644 (file)
index 0000000..a9c9e45
--- /dev/null
@@ -0,0 +1,172 @@
+import iotcloud.*;
+import java.util.*;
+import java.lang.*;
+import java.io.*;
+
+class Sensor {
+    public static void main(String[] args) throws Exception {
+
+
+        long pstart = System.currentTimeMillis();
+
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 361, -1);
+
+        try {
+            Thread.sleep(5000);
+        } catch (Exception e) {
+
+        }
+
+        long start = System.currentTimeMillis();
+        t1.rebuild();
+
+
+        System.out.println("Sleeping......");
+
+        try {
+            Thread.sleep(10000);
+        } catch (Exception e) {
+
+        }
+
+        System.out.println("Pulling......");
+        long stop1 = System.currentTimeMillis();
+
+
+
+
+
+        System.out.println(stop1 - pstart);
+        t1.update();
+
+
+
+
+        Runtime runTime = Runtime.getRuntime();
+        // Process proc = runTime.exec("/opt/vc/bin/vcgencmd measure_temp | tr -d 'temp=' |  tr -d \"'C\"");
+        Process proc = runTime.exec("/opt/vc/bin/vcgencmd measure_temp");
+        BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+        String line = null;
+        String dat = "";
+        while ((line = reader.readLine()) != null) {
+            System.out.println(line);
+            dat = line;
+        }
+        reader.close();
+
+
+
+        // String pingTimer = Long.toString(System.currentTimeMillis());
+        // IoTString ipingTimer = new IoTString(pingTimer);
+
+
+
+        String a1 = "bulb1";
+        IoTString ia1 = new IoTString(a1);
+
+
+
+        IoTString senDat = new IoTString(dat);
+
+        t1.update();
+        t1.startTransaction();
+        t1.addKV(ia1, senDat);
+        t1.commitTransaction();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        long stop2 = System.currentTimeMillis();
+
+        System.out.println("Done......");
+        System.out.println(stop1 - start);
+        System.out.println(stop2 - stop1);
+
+        // t1.startTransaction();
+        // t1.addKV(ipingTimerKey, ipingTimer);
+        // t1.addKV(ia1, senDat);
+        // t1.commitTransaction();
+
+
+
+
+
+        // String pingTimerKey = "sensorController";
+        // IoTString ipingTimerKey = new IoTString(pingTimerKey);
+
+        // String a1 = "sensor";
+        // IoTString ia1 = new IoTString(a1);
+
+
+        // System.out.println("Starting System");
+
+
+
+
+        // while (true) {
+        //     try {
+
+
+
+        //         // Runtime runTime = Runtime.getRuntime();
+        //         // // Process proc = runTime.exec("/opt/vc/bin/vcgencmd measure_temp | tr -d 'temp=' |  tr -d \"'C\"");
+        //         // Process proc = runTime.exec("/opt/vc/bin/vcgencmd measure_temp");
+        //         // BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+        //         // String line = null;
+        //         // String dat = "";
+        //         // while ((line = reader.readLine()) != null) {
+        //         //     System.out.println(line);
+        //         //     dat = line;
+        //         // }
+        //         // reader.close();
+
+
+
+        //         // String pingTimer = Long.toString(System.currentTimeMillis());
+        //         // IoTString ipingTimer = new IoTString(pingTimer);
+
+
+        //         IoTString senDat = new IoTString(dat);
+
+        //         t1.update();
+        //         t1.startTransaction();
+        //         t1.addKV(ipingTimerKey, ipingTimer);
+        //         t1.addKV(ia1, senDat);
+        //         t1.commitTransaction();
+
+
+
+
+
+
+
+        //         Thread.sleep(5000);
+
+        //     } catch (Error e) {
+        //         e.printStackTrace();
+
+        //         Runtime runTime = Runtime.getRuntime();
+        //         runTime.exec("gpio mode 4 out");
+
+
+        //         while (true) {
+        //             runTime.exec("gpio write 4 1");
+        //             Thread.sleep(500);
+        //             runTime.exec("gpio write 4 0");
+        //             Thread.sleep(500);
+        //         }
+        //     }
+        // }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/Setup.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/Setup.java
new file mode 100644 (file)
index 0000000..c1d3d7b
--- /dev/null
@@ -0,0 +1,18 @@
+import iotcloud.*;
+import java.util.*;
+
+class Setup {
+
+    public static void main(String[] args) throws Exception {
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 260, -1);
+        t1.initTable();
+
+               String a = "bulb";
+        IoTString ia = new IoTString(a);
+
+        t1.createNewKey(ia, 260);
+
+        t1.update();
+    }
+}
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/Wemo.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/Wemo.java
new file mode 100644 (file)
index 0000000..98b620f
--- /dev/null
@@ -0,0 +1,109 @@
+// IoT Packages
+
+//import iotcode.annotation.*;
+
+// Native Java Packages
+import java.util.Iterator;
+import javax.xml.parsers.*;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.w3c.dom.*;
+import org.xml.sax.SAXException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Semaphore;
+import java.util.List;
+import java.util.ArrayList;
+
+public class Wemo {
+
+    private IoTDeviceAddress deviceAddress = null;
+
+    public Wemo(IoTDeviceAddress _deviceAddress) {
+        deviceAddress = _deviceAddress;
+
+    }
+
+    public void turnOff() throws IOException {
+        IoTHTTP httpConnection = null;
+        try {
+            httpConnection = new IoTHTTP(deviceAddress);
+            httpConnection.setURL("/upnp/control/basicevent1");
+
+            httpConnection.openConnection();
+            httpConnection.setDoOutput(true);
+            httpConnection.setRequestMethod("POST");
+            httpConnection.setRequestProperty("Connection", "close");
+            httpConnection.setRequestProperty("Content-type", "text/xml; charset=\"utf-8\"");
+            httpConnection.setRequestProperty("SOAPACTION", "\"urn:Belkin:service:basicevent:1#SetBinaryState\"");
+            
+            httpConnection.setRequestProperty("User-Agent", "Java/1.8.0");
+            httpConnection.setRequestProperty("Host", "\"192.168.1.5:49153");
+            httpConnection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
+
+            String reqXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>0</BinaryState></u:SetBinaryState></s:Body></s:Envelope>\n";
+
+            OutputStream reqStream = httpConnection.getOutputStream();
+            reqStream.write(reqXML.getBytes());
+
+            InputStream resStream = httpConnection.getInputStream();
+            byte[] byteBuf = new byte[10240];
+            int len = resStream.read(byteBuf);
+
+            reqStream.close();
+            resStream.close();
+
+
+        } finally {
+            if (httpConnection != null) {
+                try {
+                    httpConnection.disconnect();
+
+                } catch (Exception e) {
+                    e.printStackTrace();
+
+                }
+            }
+        }
+
+    }
+
+    public void turnOn() throws IOException {
+        IoTHTTP httpConnection = null;
+        try {
+            httpConnection = new IoTHTTP(deviceAddress);
+            httpConnection.setURL("/upnp/control/basicevent1");
+
+            httpConnection.openConnection();
+            httpConnection.setDoOutput(true);
+            httpConnection.setRequestMethod("POST");
+            httpConnection.setRequestProperty("Content-type", "text/xml; charset=\"utf-8\"");
+            httpConnection.setRequestProperty("SOAPACTION", "\"urn:Belkin:service:basicevent:1#SetBinaryState\"");
+            httpConnection.setRequestProperty("Accept", "");
+
+            String reqXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>1</BinaryState></u:SetBinaryState></s:Body></s:Envelope>\n";
+
+            OutputStream reqStream = httpConnection.getOutputStream();
+            reqStream.write(reqXML.getBytes());
+
+            InputStream resStream = httpConnection.getInputStream();
+            byte[] byteBuf = new byte[10240];
+            int len = resStream.read(byteBuf);
+
+            reqStream.close();
+            resStream.close();
+
+        } finally {
+            if (httpConnection != null) {
+                try {
+                    httpConnection.disconnect();
+
+                } catch (Exception e) {
+                    e.printStackTrace();
+
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/WemoController.java b/version2/src/java/light_fan_embed_benchmark_2bulbs/WemoController.java
new file mode 100644 (file)
index 0000000..8495fdc
--- /dev/null
@@ -0,0 +1,84 @@
+import iotcloud.*;
+import java.util.*;
+
+
+class WemoController {
+    public static void main(String[] args) throws Exception {
+
+        Table t1 = new Table("http://dc-6.calit2.uci.edu/test.iotcloud/", "reallysecret", 351, -1);
+        t1.rebuild();
+
+        String a1 = "wemo1";
+        String a2 = "wemo2";
+
+        IoTString ia1 = new IoTString(a1);
+        IoTString ia2 = new IoTString(a2);
+
+
+        List<IoTString> keys = new ArrayList<IoTString>();
+        keys.add(ia1);
+        keys.add(ia2);
+
+
+        IoTDeviceAddress devAddr1 = new IoTDeviceAddress("192.168.2.145", 49153, 49153, false, false);
+        Wemo wemo1 = new Wemo(devAddr1);
+
+        IoTDeviceAddress devAddr2 = new IoTDeviceAddress("192.168.2.186", 49154, 49153, false, false);
+        Wemo wemo2 = new Wemo(devAddr2);
+
+        List<Wemo> wemos = new ArrayList<Wemo>();
+        wemos.add(wemo1);
+        wemos.add(wemo2);
+
+
+        String pingTimerKey = "wemoController";
+        IoTString ipingTimerKey = new IoTString(pingTimerKey);
+
+
+        String valueA = "on";
+        IoTString iValueA = new IoTString(valueA);
+
+        System.out.println("Starting System");
+        int counter = 0;
+
+
+        while (true) {
+            try {
+                String pingTimer = Long.toString(System.currentTimeMillis());
+                IoTString ipingTimer = new IoTString(pingTimer);
+
+                t1.update();
+                t1.startTransaction();
+                t1.addKV(ipingTimerKey, ipingTimer);
+                t1.commitTransaction();
+
+
+                t1.update();
+                Thread.sleep(1000);
+
+                for (int i = 0; i < 2; i++) {
+                    IoTString testValA1 = t1.getCommitted(keys.get(i));
+                    if ((testValA1 != null) && (testValA1.equals(iValueA) == true)) {
+                        wemos.get(i).turnOn();
+                    } else {
+                        wemos.get(i).turnOff();
+                    }
+                }
+
+            } catch (Error e) {
+                e.printStackTrace();
+
+                Runtime runTime = Runtime.getRuntime();
+                runTime.exec("gpio mode 4 out");
+
+
+                while (true) {
+                    runTime.exec("gpio write 4 1");
+                    Thread.sleep(500);
+                    runTime.exec("gpio write 4 0");
+                    Thread.sleep(500);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/build.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/build.bash
new file mode 100755 (executable)
index 0000000..6fb96e8
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# javac -cp .:/Users/Ali/Desktop/iotcloud/version2/src/java/iotcloud/bin *.java
+
+javac -cp .:../iotcloud/bin *.java
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/run1.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/run1.bash
new file mode 100755 (executable)
index 0000000..6f97f18
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin LightsController
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/run2.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/run2.bash
new file mode 100755 (executable)
index 0000000..c12e81c
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin WemoController
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/run3.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/run3.bash
new file mode 100755 (executable)
index 0000000..0b71cec
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin Sensor
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller.bash
new file mode 100755 (executable)
index 0000000..a687509
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin Filler
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller2.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/runFiller2.bash
new file mode 100755 (executable)
index 0000000..7a37caf
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin Filler2
\ No newline at end of file
diff --git a/version2/src/java/light_fan_embed_benchmark_2bulbs/runSetup.bash b/version2/src/java/light_fan_embed_benchmark_2bulbs/runSetup.bash
new file mode 100755 (executable)
index 0000000..1b0a696
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -cp .:../iotcloud/bin Setup
\ No newline at end of file
index ffc97731eb1e1bf602df53bc6ee05941039bd8e2..978f5f6a779a399e1e6456af31a05304002b1822 100644 (file)
@@ -22,6 +22,9 @@ flash1:
 flash2:
        particle flash IoT-2 photon*.bin
 
+flash14:
+       particle flash IoT-14 photon*.bin
+
 PHONY += clean
 clean:
        rm -f *.bin
index cf27477a216c42c3e85159431a8224fe3fc3182e..cab6e5c065c561d8f7d8982ae401474bcbd04671 100644 (file)
@@ -88,10 +88,11 @@ void setup() {
 void loop() {
 
        // Machine ID
-       sprintf(keyBuffer, "ir%04x", machineId);
+       sprintf(keyBuffer, "i%04x", machineId);
        IoTString * iKey = new IoTString(keyBuffer);
        // Do updates for the motion detection
-       sprintf(dataBuffer, "%s -> motion-detected", wakeupTime.c_str());
+       //sprintf(dataBuffer, "%s -> motion-detected", wakeupTime.c_str());
+       sprintf(dataBuffer, "%s", "motion");
        IoTString * iValue = new IoTString(dataBuffer);
 
        // Check and create a new key if it isn't created yet
index e9afd623a39850370949877715dc362dc77d29eb..f6adf28e5a5350bb5e1662b84ffb175abab0969c 100644 (file)
@@ -85,10 +85,11 @@ void setup() {
 void loop() {
 
        // Machine ID
-       sprintf(keyBuffer, "mag%04x", machineId);
+       sprintf(keyBuffer, "m%04x", machineId);
        IoTString * iKey = new IoTString(keyBuffer);
        // Do updates for the magnetic action
-       sprintf(dataBuffer, "%s -> closing-door-detected", wakeupTime.c_str());
+       //sprintf(dataBuffer, "%s -> closing-door-detected", wakeupTime.c_str());
+       sprintf(dataBuffer, "%s", "close");
        IoTString * iValue = new IoTString(dataBuffer);
 
        // Check and create a new key if it isn't created yet
index 3e4441e37d56c4fb63316559585e258952ca61c7..966f04a84bf3c874ae643bbd88428ad0f0e97176 100644 (file)
@@ -14,7 +14,7 @@ SYSTEM_THREAD(ENABLED)
 #define ERRPIN                         D7              // Error pin
 #define DHTTYPE                        DHT22   // DHT 22  (AM2302)
 // IoTCloud
-#define SLEEP_TIME                     15              // Sleep time in seconds
+#define SLEEP_TIME                     300             // Sleep time in seconds
 #define RETRY_SLEEP_TIME       5               // Sleep time in seconds
 #define RETRY_TIME                     10000   // stop trying after 10 seconds
 #define CONNECTION_DELAY       2100000 // Need to delay after connecting WiFi to wait for sensor
@@ -168,7 +168,7 @@ void loop() {
        */
        
        // TODO: Collapse temperature and humidity into one key
-       sprintf(keyBuffer, "humtemp%04x", machineId);
+       sprintf(keyBuffer, "h%04x", machineId);
        IoTString * iKey = new IoTString(keyBuffer);
        // Do updates for the temperature
        sprintf(dataBuffer, "%0.2f-%0.2f", humid, tempF);
@@ -199,6 +199,7 @@ void loop() {
        //Serial.println(micros());
        //while(true);
        
-       System.sleep(SLEEP_MODE_DEEP, SLEEP_TIME);
+       // We randomize sleep/wakeup time
+       System.sleep(SLEEP_MODE_DEEP, random(SLEEP_TIME));
 }