com.weebly.opus1269.clipman.model.BackupContents.java Source code

Java tutorial

Introduction

Here is the source code for com.weebly.opus1269.clipman.model.BackupContents.java

Source

/*
 * Copyright (c) 2016-2017, Michael A. Updike All rights reserved.
 * Licensed under Apache 2.0
 * https://opensource.org/licenses/Apache-2.0
 * https://github.com/Pushy-Clipboard/pushy-android/blob/master/LICENSE.md
 */

package com.weebly.opus1269.clipman.model;

import android.content.Context;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.weebly.opus1269.clipman.app.App;
import com.weebly.opus1269.clipman.db.MainDB;
import com.weebly.opus1269.clipman.db.entity.Clip;
import com.weebly.opus1269.clipman.db.entity.ClipLabelJoin;
import com.weebly.opus1269.clipman.db.entity.Label;
import com.weebly.opus1269.clipman.repos.MainRepo;

import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Class for the contents of a backup */
public class BackupContents {
    // Important: Don't changes these names
    @Expose
    private List<Label> labels;

    @Expose
    private List<Clip> clipItems;

    public BackupContents() {
        this.labels = new ArrayList<>(0);
        this.clipItems = new ArrayList<>(0);
    }

    private BackupContents(@NonNull List<Label> labels, @NonNull List<Clip> clipItems) {
        this.labels = labels;
        this.clipItems = clipItems;
    }

    /**
     * Get the database data
     * @return database contents
     */
    @NonNull
    public static BackupContents getDB() {
        List<Clip> clips = MainRepo.INST(App.INST()).getClipsSync();
        List<Label> labels = MainRepo.INST(App.INST()).getLabelsSync();
        return new BackupContents(labels, clips);
    }

    /**
     * Get the database data as a JSON string
     * @return Stringified data
     */
    public static String getDBAsJSON() {
        String ret;
        BackupContents contents = getDB();
        // stringify it
        final Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        ret = gson.toJson(contents);
        return ret;
    }

    /**
     * Get the contents from a raw byte array
     * @param data raw content
     * @return content of a backup
     */
    public static BackupContents get(@NonNull byte[] data) {
        final JsonReader reader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(data)));
        final Gson gson = new Gson();
        final Type type = new TypeToken<BackupContents>() {
        }.getType();
        return gson.fromJson(reader, type);
    }

    /**
     * Get the largest {@link Label} PK in the list
     * @param labels label list
     * @return largest id, 0 if empty
     */
    private static long getLargestId(@NonNull List<Label> labels) {
        long ret = 0;
        for (Label label : labels) {
            long id = label.get_Id();
            ret = (id > ret) ? id : ret;
        }
        return ret;
    }

    /**
     * Update the id for the {@link Label} in all the {@link Clip} objects
     * @param clips clipItems list
     * @param label label to chage
     */
    private static void updateLabelId(@NonNull List<Clip> clips, @NonNull Label label) {
        for (Clip clip : clips) {
            clip.updateLabelId(label);
        }
    }

    @NonNull
    public List<Label> getLabels() {
        return labels;
    }

    public void setLabels(@NonNull List<Label> labels) {
        this.labels = labels;
    }

    @NonNull
    public List<Clip> getClipItems() {
        return clipItems;
    }

    public void setClipItems(@NonNull List<Clip> clipItems) {
        this.clipItems = clipItems;
    }

    /**
     * Get our contents as a JSON string
     * @return Stringified contents
     */
    public String getAsJSON() {
        String ret;
        // stringify it
        final Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        ret = gson.toJson(this);
        return ret;
    }

    /**
     * Merge the contents of the given item with this
     * @param context  A Context
     * @param contents contents to merge
     */
    public void merge(@NonNull Context context, @NonNull final BackupContents contents) {
        // Merged items
        final List<Label> outLabels = this.labels;
        final List<Clip> outClips = this.clipItems;

        // Items to be merged
        final List<Label> inLabels = contents.getLabels();
        final List<Clip> inClips = contents.getClipItems();

        // Largest label PK being used by us
        long newLabelId = getLargestId(outLabels);
        newLabelId++;

        // merge labels
        for (Label inLabel : inLabels) {
            final int pos = outLabels.indexOf(inLabel);
            if (pos == -1) {
                // new label - add one with unique id to outgoing and
                // update incoming clip references to it
                final Label addLabel = new Label(inLabel.getName(), newLabelId);
                outLabels.add(addLabel);
                newLabelId++;
                updateLabelId(inClips, addLabel);
            } else {
                // shared label - update incoming clip references if id's don't match
                final Label sharedLabel = outLabels.get(pos);
                if (inLabel.getId() != sharedLabel.getId()) {
                    updateLabelId(inClips, sharedLabel);
                }
            }
        }

        // merge clipItems
        for (Clip inClip : inClips) {
            final int pos = getPos(outClips, inClip.getText());
            if (pos == -1) {
                // new clip - add to outgoing
                if (inClip.getDevice().equals(MyDevice.INST(context).getDisplayName())) {
                    inClip.setRemote(false);
                } else {
                    inClip.setRemote(true);
                }
                final Clip outClip = new Clip(inClip, inClip.getLabels(), inClip.getLabelsId());
                outClips.add(outClip);
            } else {
                // shared clip - merge into outgoing clip
                final Clip outClip = outClips.get(pos);
                if (inClip.getFav()) {
                    // true fav has priority
                    outClip.setFav(true);
                }
                if (inClip.getDate() > outClip.getDate()) {
                    // newest has priority
                    outClip.setDate(inClip.getDate());
                    if (inClip.getDevice().equals(MyDevice.INST(context).getDisplayName())) {
                        outClip.setRemote(false);
                    } else {
                        outClip.setRemote(true);
                    }
                    outClip.setDevice(inClip.getDevice());
                }
                // merge labels and labelsId
                outClip.addLabels(inClip.getLabels());
            }
        }
    }

    /**
     * Replace the contents of the database
     */
    public void replaceDB() {
        App.getExecutors().diskIO().execute(() -> {
            MainDB.INST(App.INST()).runInTransaction(() -> {
                MainDB.INST(App.INST()).labelDao().deleteAll();
                MainDB.INST(App.INST()).clipDao().deleteAll();

                MainDB.INST(App.INST()).labelDao().insertAll(labels);
                // get mapping between name and id
                final List<Label> newLabels = MainDB.INST(App.INST()).labelDao().getAllSync();
                final Map<String, Long> labelsMap = new HashMap<>(newLabels.size());
                for (final Label label : newLabels) {
                    labelsMap.put(label.getName(), label.getId());
                }

                for (Clip clip : clipItems) {
                    final long clipId = MainDB.INST(App.INST()).clipDao().insert(clip);
                    final List<Label> clipLabels = clip.getLabels();
                    for (Label label : clipLabels) {
                        ClipLabelJoin join = new ClipLabelJoin(clipId, labelsMap.get(label.getName()));
                        MainDB.INST(App.INST()).clipLabelJoinDao().insert(join);
                    }
                }
            });
        });
    }

    /**
     * Get the position of the given text
     * @param list list to check
     * @param text text to check
     * @return position if text exists, -1 if not found
     */
    private int getPos(@NonNull List<Clip> list, @NonNull String text) {
        int ret = -1;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getText().equals(text)) {
                ret = i;
                break;
            }
        }
        return ret;
    }
}