Java tutorial
/* * The MIT License (MIT) * Copyright (c) 2016 Ubiqueworks Ltd and contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE * OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.neotree.support.datastore; import android.text.TextUtils; import android.util.Log; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import org.neotree.model.firebase.Field; import org.neotree.model.firebase.Item; import org.neotree.model.firebase.Metadata; import org.neotree.model.realm.AdminPassword; import org.neotree.model.realm.Session; import org.neotree.model.realm.SessionEntry; import org.neotree.model.realm.SessionValue; import org.neotree.player.type.DataType; import org.neotree.player.type.FieldType; import org.neotree.player.type.ScreenType; import java.io.BufferedReader; import java.io.StringReader; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; import io.realm.Realm; import io.realm.RealmChangeListener; import io.realm.RealmQuery; import io.realm.RealmResults; import io.realm.Sort; /** * Created by matteo on 13/09/2016. */ public class RealmStore { private static final String TAG = RealmStore.class.getSimpleName(); private static MessageDigest sMessageDigest; public interface OnRealmTransactionListener { void onTransactionDone(); } public interface OnRealmDetachedResultListener<T> { void onRealmQueryDetachedResult(List<T> results); } static { try { sMessageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { Log.e(TAG, "Error creating MD5 message digest", e); } } public static Session createSession(Realm realm, String sessionId, String scriptId) { final Session session = new Session(sessionId, scriptId); realm.executeTransactionAsync(bgRealm -> { bgRealm.copyToRealmOrUpdate(session); }, () -> { // Transaction was a success. Log.v(TAG, "createSession(): success"); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "createSession(): failure", error); }); return session; } public static void finishSession(Realm realm, Session session) { realm.executeTransactionAsync(bgRealm -> { session.setCompletedAt(DateTime.now().toString(ISODateTimeFormat.dateTimeNoMillis())); bgRealm.copyToRealmOrUpdate(session); }, () -> { // Transaction was a success. Log.v(TAG, "finishSession(): success"); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "finishSession(): failure", error); }); } public static void storeValue(Realm realm, String scriptId, String sessionId, String sectionTitle, int position, SessionValue value) { realm.executeTransactionAsync(bgRealm -> { String entryId = buildEntryId(scriptId, sessionId, position, value.getDataType(), value.getKey()); RealmResults<SessionEntry> results = bgRealm.where(SessionEntry.class).equalTo("entryId", entryId) .findAll(); if (results.size() > 0) { results.first().getValues().deleteAllFromRealm(); } SessionEntry entry = new SessionEntry(scriptId, sessionId, sectionTitle, position, value.getDataType(), value.getKey(), value.getLabel(), value); bgRealm.copyToRealmOrUpdate(entry); }, () -> { // Transaction was a success. Log.v(TAG, "storeValue(single): success"); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "storeValue(single): failure", error); }); } public static void storeValue(Realm realm, String scriptId, String sessionId, String sectionTitle, int position, String key, String label, ArrayList<SessionValue> values) { realm.executeTransactionAsync(bgRealm -> { String entryId = buildEntryId(scriptId, sessionId, position, DataType.SET_ID.toString(), key); RealmResults<SessionEntry> results = bgRealm.where(SessionEntry.class).equalTo("entryId", entryId) .findAll(); if (results.size() > 0) { results.first().getValues().deleteAllFromRealm(); } SessionEntry entry = new SessionEntry(scriptId, sessionId, sectionTitle, position, DataType.SET_ID.toString(), key, label, values); bgRealm.copyToRealmOrUpdate(entry); }, () -> { // Transaction was a success. Log.v(TAG, "storeValue(multiple) : success"); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "storeValue(multiple): failure", error); }); } public static void loadSessions(Realm realm, RealmChangeListener<RealmResults<Session>> callback) { RealmResults<Session> result = realm.where(Session.class).findAllSortedAsync("createdAt", Sort.DESCENDING); result.addChangeListener(callback); } public static Session loadSession(Realm realm, String sessionId) { Session result = realm.where(Session.class).equalTo("sessionId", sessionId).findFirst(); return realm.copyFromRealm(result); } public static void loadEntriesForSession(Realm realm, String sessionId, boolean confidential, RealmChangeListener<RealmResults<SessionEntry>> callback) { RealmQuery<SessionEntry> query = realm.where(SessionEntry.class).equalTo("sessionId", sessionId); // If confidential mode, make sure confidential records are not retrieved if (confidential) { query.equalTo("confidential", false); } RealmResults<SessionEntry> results = query.findAllSortedAsync("position", Sort.ASCENDING); results.addChangeListener(callback); } public static List<SessionEntry> loadEntriesForSession(Realm realm, String sessionId, boolean confidential) { RealmQuery<SessionEntry> query = realm.where(SessionEntry.class).equalTo("sessionId", sessionId); // If confidential mode, make sure confidential records are not retrieved if (confidential) { query.equalTo("confidential", false); } RealmResults<SessionEntry> results = query.findAllSorted("position", Sort.ASCENDING); return realm.copyFromRealm(results); } public static List<SessionEntry> loadEntriesForScript(Realm realm, String scriptId, boolean confidential) { RealmQuery<SessionEntry> query = realm.where(SessionEntry.class).equalTo("scriptId", scriptId); // If confidential mode, make sure confidential records are not retrieved if (confidential) { query.equalTo("confidential", false); } RealmResults<SessionEntry> results = query.findAllSorted(new String[] { "sessionId", "position" }, new Sort[] { Sort.ASCENDING, Sort.ASCENDING }); return realm.copyFromRealm(results); } public static void storeAdminPassword(AdminPassword value) { Realm realm = null; try { realm = Realm.getDefaultInstance(); realm.executeTransaction(bgRealm -> bgRealm.copyToRealmOrUpdate(value)); } catch (Exception e) { Log.e(TAG, "Error storing admin password", e); } finally { if (realm != null && !realm.isClosed()) { realm.close(); } } } public static AdminPassword loadAdminPassword(Realm realm) { return realm.where(AdminPassword.class).findFirst(); } public static void deleteAllSessions(Realm realm, OnRealmTransactionListener listener) { // Delete all in a transaction realm.executeTransactionAsync(bgRealm -> { RealmQuery<Session> query = bgRealm.where(Session.class); deleteSessions(bgRealm, query); }, () -> { // Transaction was a success. Log.v(TAG, "deleteAllSessions() : success"); listener.onTransactionDone(); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "deleteAllSessions(): failure", error); }); } public static void deleteIncompleteSessions(Realm realm, OnRealmTransactionListener listener) { // Delete all in a transaction realm.executeTransactionAsync(bgRealm -> { RealmQuery<Session> query = bgRealm.where(Session.class).isNull("completedAt"); deleteSessions(bgRealm, query); }, () -> { // Transaction was a success. Log.v(TAG, "deleteIncompleteSessions() : success"); listener.onTransactionDone(); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "deleteIncompleteSessions(): failure", error); }); } public static void deleteSingleSession(String sessionId, Realm realm, OnRealmTransactionListener listener) { // Delete all in a transaction realm.executeTransactionAsync(bgRealm -> { RealmQuery<Session> query = bgRealm.where(Session.class).equalTo("sessionId", sessionId); deleteSessions(bgRealm, query); }, () -> { // Transaction was a success. Log.v(TAG, "deleteSingleSession() : success"); listener.onTransactionDone(); }, error -> { // Transaction failed and was automatically canceled. Log.e(TAG, "deleteSingleSession(): failure", error); }); } private static void deleteSessions(Realm realm, RealmQuery<Session> sessionsQuery) { RealmResults<Session> sessions = sessionsQuery.findAll(); if (sessions.size() > 0) { String[] sessionIDs = new String[sessions.size()]; final ArrayList<String> sessionList = new ArrayList<>(); for (Session session : sessions) { sessionList.add(session.getSessionId()); } sessionList.toArray(sessionIDs); RealmResults<SessionEntry> sessionEntries = realm.where(SessionEntry.class).in("sessionId", sessionIDs) .findAll(); for (SessionEntry sessionEntry : sessionEntries) { sessionEntry.getValues().deleteAllFromRealm(); } sessionEntries.deleteAllFromRealm(); sessions.deleteAllFromRealm(); } } public static String buildEntryId(String scriptId, String sessionId, int position, String dataType, String key) { String payload = String.format(Locale.getDefault(), "%s:%s:%d:%s:%s", scriptId, sessionId, position, dataType, key); sMessageDigest.reset(); sMessageDigest.update(payload.getBytes(), 0, payload.length()); return new BigInteger(1, sMessageDigest.digest()).toString(16); } public static SessionValue getSessionValue(Item item, Object value) { return new SessionValue(item.dataType, item.key.trim(), item.label, null, item.label, value, item.confidential); } public static SessionValue getSessionValue(Field field, Object value) { String valueLabel = null; if (FieldType.fromString(field.type) == FieldType.DROPDOWN) { valueLabel = getLabelForDropDownValue((String) value, field.values); } return new SessionValue(field.dataType, field.key.trim(), field.label, field.format, valueLabel, value, field.confidential); } public static SessionValue getSessionValue(ScreenType screenType, Metadata metadata, Object value) { String valueLabel = null; if (value != null) { switch (screenType) { case SINGLE_SELECT: valueLabel = getItemLabelForValue(metadata, (String) value); break; case YESNO: valueLabel = ((Boolean) value) ? metadata.positiveLabel : metadata.negativeLabel; break; } } return new SessionValue(metadata.dataType, metadata.key.trim(), metadata.label, null, valueLabel, value, metadata.confidential); } public static ArrayList<SessionValue> getSessionValue(Metadata metadata, Set<String> values) { ArrayList<SessionValue> sessionValues = null; if (values != null && values.size() > 0) { sessionValues = new ArrayList<>(); for (String value : values) { String valueLabel = getItemLabelForValue(metadata, value); sessionValues.add(new SessionValue(metadata.dataType, metadata.key.trim(), metadata.label, null, valueLabel, value, metadata.confidential)); } } return sessionValues; } private static String getItemLabelForValue(Metadata metadata, String value) { if (metadata.items != null) { for (Item item : metadata.items) { if (value.equals(item.id)) { return item.label; } } } return null; } private static String getLabelForDropDownValue(String id, String values) { if (TextUtils.isEmpty(values) || TextUtils.isEmpty(id)) { return null; } try { BufferedReader reader = new BufferedReader(new StringReader(values)); String line; while ((line = reader.readLine()) != null) { String[] item = line.split(","); String valueId = item[0].trim(); if (id.equals(valueId)) { return item[1].trim(); } } } catch (Exception e) { Log.e(TAG, "", e); } return null; } }