|
@@ -1,4 +1,8 @@
|
|
|
-package de.tudarmstadt.informatik.hostage.dao;
|
|
|
+package de.tudarmstadt.informatik.hostage.persistence;
|
|
|
+
|
|
|
+import org.json.JSONArray;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
@@ -6,8 +10,7 @@ import java.io.FileInputStream;
|
|
|
import java.io.FileNotFoundException;
|
|
|
import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
-import java.io.ObjectInputStream;
|
|
|
-import java.io.ObjectOutputStream;
|
|
|
+import java.io.InputStream;
|
|
|
import java.io.StreamCorruptedException;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
@@ -20,25 +23,59 @@ import java.util.Random;
|
|
|
|
|
|
import de.tudarmstadt.informatik.hostage.R;
|
|
|
import de.tudarmstadt.informatik.hostage.model.Profile;
|
|
|
-import de.tudarmstadt.informatik.hostage.model.ProfilesHolder;
|
|
|
import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
|
|
|
import de.tudarmstadt.informatik.hostage.ui2.adapter.ProfileManagerListAdapter;
|
|
|
|
|
|
/**
|
|
|
+ * The profile manager is responsible for persisting and deleting profiles
|
|
|
+ *
|
|
|
* @author Alexander Brakowski
|
|
|
* @created 10.02.14 20:24
|
|
|
*/
|
|
|
public class ProfileManager {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The singleton instance holder
|
|
|
+ */
|
|
|
private static ProfileManager INSTANCE = null;
|
|
|
|
|
|
+ /**
|
|
|
+ * An list adapter, which the profile manager informs about data changes
|
|
|
+ */
|
|
|
private ProfileManagerListAdapter mProfileListAdapter = null;
|
|
|
- private Profile mCurrentActivatedProfile = null;
|
|
|
- private Profile mRandomProfile = null;
|
|
|
|
|
|
- private static final String PERSIST_FILENAME = "hostage_profiles.dat";
|
|
|
+ /**
|
|
|
+ * Holds a reference to the currently active profile
|
|
|
+ */
|
|
|
+ private Profile mCurrentActivatedProfile = null;
|
|
|
|
|
|
- private ProfilesHolder holder;
|
|
|
+ /**
|
|
|
+ * Holds a reference to the random profile
|
|
|
+ */
|
|
|
+ private Profile mRandomProfile = null;
|
|
|
|
|
|
+ /**
|
|
|
+ * The profiles are being serialized and persisted into this file
|
|
|
+ */
|
|
|
+ private static final String PERSIST_FILENAME = "hostage_profiles.json";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Hold the current profile id, it will be incremented each time a new profile is added.
|
|
|
+ * The new profile will get the newly incremented value as an id.
|
|
|
+ */
|
|
|
+ public int mIncrementValue = 1;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Holds all the available profiles. The key in the map is the ID of the profile.
|
|
|
+ */
|
|
|
+ public HashMap<Integer, Profile> mProfiles;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Since the profile manager should only have one instance in the whole app, we are using the singleton pattern.
|
|
|
+ * This method creates a new instance of the profile manager, if no instance already exists, and returns it.
|
|
|
+ *
|
|
|
+ * @return the singleton instance
|
|
|
+ */
|
|
|
public static ProfileManager getInstance(){
|
|
|
if(INSTANCE == null){
|
|
|
INSTANCE = new ProfileManager();
|
|
@@ -51,45 +88,82 @@ public class ProfileManager {
|
|
|
return INSTANCE;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * A private constructor, that can/should only be called by getInstance, since we want to enforce the usage of the singleton.
|
|
|
+ */
|
|
|
private ProfileManager(){
|
|
|
- holder = new ProfilesHolder();
|
|
|
- holder.mProfiles = new HashMap<Integer, Profile>();
|
|
|
+ mProfiles = new HashMap<Integer, Profile>();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Reads all data from an inputstream and appends it to a string
|
|
|
+ *
|
|
|
+ * @param is The input stream to read the data from
|
|
|
+ * @return the whole data from the input stream as an string
|
|
|
+ */
|
|
|
+ public String readAll( final InputStream is ) {
|
|
|
+ if( null == is ) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ int rc;
|
|
|
+ try {
|
|
|
+ while( (rc = is.read()) >= 0 ){
|
|
|
+ sb.append( (char) rc );
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return sb.toString();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Reads all the data of the the profiles, that were persisted and unserializes them.
|
|
|
+ *
|
|
|
+ * The profiles were serialized into JSON and persisted into the android private file.
|
|
|
+ * See {@see ProfileManager#persistData}.
|
|
|
+ */
|
|
|
public void loadData(){
|
|
|
try {
|
|
|
FileInputStream fin = MainActivity.getContext().openFileInput(PERSIST_FILENAME);
|
|
|
- ObjectInputStream ois = new ObjectInputStream(fin);
|
|
|
-
|
|
|
- Object obj = ois.readObject();
|
|
|
- ois.close();
|
|
|
+ JSONArray arr = new JSONArray(readAll(fin));
|
|
|
fin.close();
|
|
|
|
|
|
- if(obj != null && obj instanceof ProfilesHolder){
|
|
|
- this.holder = (ProfilesHolder) obj;
|
|
|
+ for(int i=0; i<arr.length(); i++){
|
|
|
+ JSONObject obj = arr.getJSONObject(i);
|
|
|
+
|
|
|
+ Profile p = new Profile();
|
|
|
+ p.fromJSON(obj);
|
|
|
|
|
|
- for(Map.Entry<Integer, Profile> entry: holder.mProfiles.entrySet()){
|
|
|
- if(entry.getValue().mActivated){
|
|
|
- this.mCurrentActivatedProfile = entry.getValue();
|
|
|
- }
|
|
|
+ mProfiles.put(p.mId, p);
|
|
|
|
|
|
- if(entry.getValue().mIsRandom){
|
|
|
- this.mRandomProfile = entry.getValue();
|
|
|
- }
|
|
|
+ if(p.mId > mIncrementValue){
|
|
|
+ mIncrementValue = p.mId;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(p.mActivated){
|
|
|
+ this.mCurrentActivatedProfile = p;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(p.mIsRandom){
|
|
|
+ this.mRandomProfile = p;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
} catch (FileNotFoundException e) {
|
|
|
e.printStackTrace();
|
|
|
} catch (StreamCorruptedException e) {
|
|
|
e.printStackTrace();
|
|
|
} catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
- } catch (ClassNotFoundException e) {
|
|
|
+ } catch (JSONException e) {
|
|
|
e.printStackTrace();
|
|
|
} finally {
|
|
|
- if(holder.mProfiles.size() == 0){
|
|
|
+ if(mProfiles.size() == 0){
|
|
|
this.fillWithDefaultData();
|
|
|
- loadData();
|
|
|
}
|
|
|
|
|
|
if(this.mRandomProfile != null){
|
|
@@ -98,13 +172,19 @@ public class ProfileManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * All the profiles that are hold by the profile manager are being serialized into JSON and then written into an private android file.
|
|
|
+ */
|
|
|
public void persistData(){
|
|
|
try {
|
|
|
FileOutputStream fout = MainActivity.getContext().openFileOutput(PERSIST_FILENAME, Context.MODE_PRIVATE);
|
|
|
- ObjectOutputStream oos = new ObjectOutputStream(fout);
|
|
|
|
|
|
- oos.writeObject(holder);
|
|
|
- oos.close();
|
|
|
+ JSONArray arr = new JSONArray();
|
|
|
+ for(Profile p: mProfiles.values()){
|
|
|
+ arr.put(p.toJSON());
|
|
|
+ }
|
|
|
+
|
|
|
+ fout.write(arr.toString().getBytes());
|
|
|
fout.close();
|
|
|
} catch (FileNotFoundException e) {
|
|
|
e.printStackTrace();
|
|
@@ -114,22 +194,39 @@ public class ProfileManager {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves all the profiles as an List
|
|
|
+ * @return a list that holds all the profiles
|
|
|
+ */
|
|
|
public List<Profile> getProfilesList(){
|
|
|
return new ArrayList<Profile>(getProfilesCollection());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves all the profiles as an collection
|
|
|
+ * @return a collection of all the profiles
|
|
|
+ */
|
|
|
public Collection<Profile> getProfilesCollection(){
|
|
|
- if(holder.mProfiles.size() == 0 || holder.mProfiles == null){
|
|
|
+ if(mProfiles.size() == 0 || mProfiles == null){
|
|
|
this.loadData();
|
|
|
}
|
|
|
|
|
|
- return holder.mProfiles.values();
|
|
|
+ return mProfiles.values();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves an map of all the profiles. The key in the map is the ID of an profile.
|
|
|
+ * @return a map of profiles
|
|
|
+ */
|
|
|
public Map<Integer, Profile> getMapProfiles(){
|
|
|
- return holder.mProfiles;
|
|
|
+ return mProfiles;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Activates and deactivates protocols randomly in the given profile
|
|
|
+ *
|
|
|
+ * @param profile the profile to randomize the protocols for
|
|
|
+ */
|
|
|
public void randomizeProtocols(Profile profile){
|
|
|
LinkedList<String> protocols = new LinkedList<String>(Arrays.asList(MainActivity.getContext().getResources().getStringArray(R.array.protocols)));
|
|
|
protocols.remove("GHOST");
|
|
@@ -150,12 +247,18 @@ public class ProfileManager {
|
|
|
persistData();
|
|
|
}
|
|
|
|
|
|
- public long persistProfile(Profile profile){
|
|
|
+ /**
|
|
|
+ * Adds or updates a given profile.
|
|
|
+ *
|
|
|
+ * @param profile the profile to persist
|
|
|
+ * @return the id the profile was assigned to
|
|
|
+ */
|
|
|
+ public int persistProfile(Profile profile){
|
|
|
if(profile.mId == -1){
|
|
|
- profile.mId = ++holder.mIncrementValue;
|
|
|
+ profile.mId = ++mIncrementValue;
|
|
|
}
|
|
|
|
|
|
- holder.mProfiles.put(profile.mId, profile);
|
|
|
+ mProfiles.put(profile.mId, profile);
|
|
|
|
|
|
this.persistData();
|
|
|
|
|
@@ -166,29 +269,48 @@ public class ProfileManager {
|
|
|
return profile.mId;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves the profile with the given id
|
|
|
+ *
|
|
|
+ * @param id the id of the profile
|
|
|
+ * @return the profile
|
|
|
+ */
|
|
|
public Profile getProfile(int id){
|
|
|
- if(holder.mProfiles.size() == 0){
|
|
|
+ if(mProfiles.size() == 0){
|
|
|
loadData();
|
|
|
}
|
|
|
|
|
|
- if(this.holder.mProfiles.containsKey(id)){
|
|
|
- return this.holder.mProfiles.get(id);
|
|
|
+ if(this.mProfiles.containsKey(id)){
|
|
|
+ return this.mProfiles.get(id);
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Adds a profile
|
|
|
+ *
|
|
|
+ * @param profile the profile to add
|
|
|
+ */
|
|
|
public void addProfile(Profile profile){
|
|
|
this.addProfile(profile, true);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Adds a given profile to the profile manager.
|
|
|
+ *
|
|
|
+ * @param profile the profile to add
|
|
|
+ * @param persist true, if the profile should also be persisted immediatly,
|
|
|
+ * false, if the profile should just be added internally without being persisted
|
|
|
+ * (Note: you can still call persistData later to persist all the profiles)
|
|
|
+ */
|
|
|
public void addProfile(Profile profile, boolean persist){
|
|
|
|
|
|
if(profile.mId == -1){
|
|
|
- profile.mId = ++holder.mIncrementValue;
|
|
|
+ profile.mId = ++mIncrementValue;
|
|
|
}
|
|
|
|
|
|
- holder.mProfiles.put(profile.mId, profile);
|
|
|
+ mProfiles.put(profile.mId, profile);
|
|
|
|
|
|
if(persist){
|
|
|
persistData();
|
|
@@ -200,10 +322,15 @@ public class ProfileManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Deletes a given profile. These changes will be persisted immediatly.
|
|
|
+ *
|
|
|
+ * @param profile the profile to delete
|
|
|
+ */
|
|
|
public void deleteProfile(Profile profile){
|
|
|
- if(this.holder.mProfiles.containsKey(profile.mId)){
|
|
|
+ if(this.mProfiles.containsKey(profile.mId)){
|
|
|
Profile p = getProfile(profile.mId);
|
|
|
- this.holder.mProfiles.remove(profile.mId);
|
|
|
+ this.mProfiles.remove(profile.mId);
|
|
|
|
|
|
if(p.mActivated || this.mCurrentActivatedProfile.mId == p.mId){
|
|
|
mCurrentActivatedProfile = mRandomProfile;
|
|
@@ -220,11 +347,19 @@ public class ProfileManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Removes all profiles.
|
|
|
+ */
|
|
|
public void clearProfiles(){
|
|
|
- holder.mProfiles.clear();
|
|
|
+ mProfiles.clear();
|
|
|
persistData();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Makes a given profile active.
|
|
|
+ *
|
|
|
+ * @param profile the profile to activate
|
|
|
+ */
|
|
|
public void activateProfile(Profile profile){
|
|
|
if(profile.equals(this.mCurrentActivatedProfile)) return;
|
|
|
|
|
@@ -235,35 +370,68 @@ public class ProfileManager {
|
|
|
|
|
|
profile.mActivated = true;
|
|
|
this.mCurrentActivatedProfile = profile;
|
|
|
- this.holder.mProfiles.put(profile.mId, profile);
|
|
|
+ this.mProfiles.put(profile.mId, profile);
|
|
|
persistData();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Checks if the "random" profile is currently active
|
|
|
+ *
|
|
|
+ * @return true, if active
|
|
|
+ * false, otherwise
|
|
|
+ */
|
|
|
public boolean isRandomActive(){
|
|
|
return this.mCurrentActivatedProfile.equals(this.mRandomProfile);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves the "random" profile
|
|
|
+ *
|
|
|
+ * @return the "random" profile
|
|
|
+ */
|
|
|
public Profile getRandomProfile(){
|
|
|
return this.mRandomProfile;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves the currently active profile
|
|
|
+ *
|
|
|
+ * @return the active profile
|
|
|
+ */
|
|
|
public Profile getCurrentActivatedProfile(){
|
|
|
return mCurrentActivatedProfile;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Sets the list adapter that should also be managed by the profile manager
|
|
|
+ *
|
|
|
+ * @param profileListAdapter the list adapter to manage
|
|
|
+ */
|
|
|
public void setProfileListAdapter(ProfileManagerListAdapter profileListAdapter){
|
|
|
this.mProfileListAdapter = profileListAdapter;
|
|
|
}
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves the list adapter, that is being managed by the profile manager
|
|
|
+ * @return the list adapter
|
|
|
+ */
|
|
|
public ProfileManagerListAdapter getProfileListAdapter(){
|
|
|
return this.mProfileListAdapter;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Retrieves the number of profiles
|
|
|
+ *
|
|
|
+ * @return the number of profiles
|
|
|
+ */
|
|
|
public int getNumberOfProfiles(){
|
|
|
- return holder.mProfiles.size();
|
|
|
+ return mProfiles.size();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Fills the profiles manager with default profiles
|
|
|
+ */
|
|
|
public void fillWithDefaultData(){
|
|
|
Profile windowsVista = new Profile(
|
|
|
0,
|
|
@@ -385,7 +553,7 @@ public class ProfileManager {
|
|
|
paranoidProfile.mActivated = true;
|
|
|
this.addProfile(paranoidProfile, false);
|
|
|
|
|
|
- holder.mIncrementValue = 8;
|
|
|
+ mIncrementValue = 8;
|
|
|
this.mCurrentActivatedProfile = paranoidProfile;
|
|
|
|
|
|
persistData();
|