├── .gitignore
├── .idea
├── gradle.xml
├── modules.xml
└── runConfigurations.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── claudiodegio
│ │ └── dbsync
│ │ └── sample
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── slf4j-android.properties
│ ├── java
│ │ └── com
│ │ │ └── claudiodegio
│ │ │ └── dbsync
│ │ │ └── sample
│ │ │ ├── BaseActivity.java
│ │ │ ├── BaseMainDbActivity.java
│ │ │ ├── DbSyncApplication.java
│ │ │ ├── MainActivity.java
│ │ │ ├── SAFUtils.java
│ │ │ ├── Utility.java
│ │ │ ├── core
│ │ │ └── TableViewerFragment.java
│ │ │ ├── db1
│ │ │ ├── Db1Callback.java
│ │ │ ├── InsertNameActivity.java
│ │ │ └── MainDb1Activity.java
│ │ │ ├── db2
│ │ │ ├── CategoriesActivity.java
│ │ │ ├── Db2Callback.java
│ │ │ ├── InsertCategoryActivity.java
│ │ │ ├── InsertNameActivity.java
│ │ │ ├── MainDb2Activity.java
│ │ │ └── NamesActivity.java
│ │ │ ├── db3
│ │ │ ├── Db3Callback.java
│ │ │ ├── InsertNameActivity.java
│ │ │ └── MainDb3Activity.java
│ │ │ ├── db4
│ │ │ ├── ArticlesActivity.java
│ │ │ ├── CategoriesActivity.java
│ │ │ ├── Db4Callback.java
│ │ │ ├── InsertArticleActivity.java
│ │ │ ├── InsertCategoryActivity.java
│ │ │ └── MainDb4Activity.java
│ │ │ └── db5
│ │ │ ├── Db5Callback.java
│ │ │ ├── InsertNameActivity.java
│ │ │ └── MainDb5Activity.java
│ └── res
│ │ ├── layout
│ │ ├── activity_fragment.xml
│ │ ├── activity_insert_article.xml
│ │ ├── activity_insert_category.xml
│ │ ├── activity_insert_name.xml
│ │ ├── activity_insert_name_db3.xml
│ │ ├── activity_main.xml
│ │ ├── activity_main_db1.xml
│ │ ├── activity_main_db2.xml
│ │ ├── activity_main_db3.xml
│ │ ├── activity_main_db4.xml
│ │ ├── activity_main_db5.xml
│ │ ├── activity_test_gdrive_activity.xml
│ │ ├── fragment_table_view.xml
│ │ ├── view_actions.xml
│ │ └── view_status.xml
│ │ ├── menu
│ │ └── menu_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── raw
│ │ └── db_20170114_184802_3200_records.json
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── claudiodegio
│ └── dbsync
│ └── sample
│ └── ExampleUnitTest.java
├── build.gradle
├── db_gen.json
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── icone.txt
├── lib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── claudiodegio
│ │ └── dbsync
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── claudiodegio
│ │ │ └── dbsync
│ │ │ ├── DBSync.java
│ │ │ ├── SyncResult.java
│ │ │ ├── SyncStatus.java
│ │ │ ├── TableToSync.java
│ │ │ ├── core
│ │ │ ├── Database.java
│ │ │ ├── DatabaseReader.java
│ │ │ ├── DatabaseWriter.java
│ │ │ ├── JoinTable.java
│ │ │ ├── Record.java
│ │ │ ├── RecordChanged.java
│ │ │ ├── RecordSyncResult.java
│ │ │ ├── SqlLiteManager.java
│ │ │ ├── SqlLiteUtility.java
│ │ │ ├── Table.java
│ │ │ ├── Utility.java
│ │ │ ├── Value.java
│ │ │ └── ValueMetadata.java
│ │ │ ├── exception
│ │ │ ├── SyncBuildException.java
│ │ │ └── SyncException.java
│ │ │ ├── json
│ │ │ ├── JSonConverter.java
│ │ │ ├── JSonConverterFactory.java
│ │ │ ├── JSonDatabaseReader.java
│ │ │ ├── JSonDatabaseWriter.java
│ │ │ ├── JSonLongConverter.java
│ │ │ └── JSonStringConverter.java
│ │ │ └── provider
│ │ │ ├── CloudProvider.java
│ │ │ └── GDriveCloudProvider.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── claudiodegio
│ └── dbsync
│ └── ExampleUnitTest.java
├── settings.gradle
└── test
├── .gitignore
├── build.gradle
└── src
└── main
├── groovy
└── com
│ └── example
│ ├── DatabaseGenerator.groovy
│ ├── db_20170114_002331_9_records.json
│ └── db_20170114_184802_3200_records.json
└── java
└── com
└── example
├── JSonDatabaseWriter.java
├── JsonDatabaseReader.java
└── Main.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 |
39 | # Keystore files
40 | *.jks
41 | .idea/
42 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## DbSync
2 |
3 | Small library for sync android SqlLite database to cloud storage (for now only GDrive)
4 |
5 | ## Motivation
6 |
7 | There is not solution to sync SqLite database between device without the of custom
8 | server application or use of paid online cloud service. My solution it's base
9 | a json file on GDrive cloud account of user with no server involved, so all
10 | data are private to user e non saved on server.
11 |
12 | ## How work
13 |
14 | The library write a file on GDrive called cloud file like:
15 | ```json
16 | {
17 | "name" : "db2.db",
18 | "formatVersion" : 1,
19 | "schemaVersion" : 1,
20 | "tableCount" : 2,
21 | "tables" : [ {
22 | "name" : "name",
23 | "recordsCount" : 1,
24 | "records" : [ {
25 | "NAME" : "myname",
26 | "SEND_TIME" : 1487887189513,
27 | "CLOUD_ID" : "c2bd71ee-3f1b-4dca-b478-ebecaaa1f835"
28 | } ]
29 | }, {
30 | "name" : "category",
31 | "recordsCount" : 2,
32 | "records" : [ {
33 | "NAME" : "cat1",
34 | "SEND_TIME" : 1488038770858,
35 | "CLOUD_ID" : "6f2a8bcc-f1ee-4f14-8987-9f4275205793"
36 | }, {
37 | "NAME" : "musica",
38 | "SEND_TIME" : 1487887376113,
39 | "CLOUD_ID" : "52a292b5-8f38-4f30-b13f-7f86bbff49a6"
40 | } ]
41 | } ]
42 | }
43 | ```
44 |
45 | The library download the file from cloud storage and update the local database using the cloud id used
46 | to connect a record in 2 different device and and the send time use to understand is the record
47 | it's to update.
48 | The solution try to update only the record who are been update from last sync time, for
49 | performance reason don't update all database, after the sync process it generates the cloud id (uuid)
50 | and rewrite the json cloud file and upload to file storage.
51 |
52 | Note: with GDrive you can share between more user
53 |
54 | Your table need to have two columns for syn SEND_TIME long and CLOUD_ID TEXT unique
55 |
56 | ## Features
57 |
58 | The library support:
59 |
60 | * Sync of 1 o more table
61 | * Sync join table (updating the correct id)
62 | * Support more match rule (default use CLOUD_ID counted with uiid faction)
63 | * Support for ignore selected column
64 | * Support for filter on what to sync (usefull for multi account application but different sync file)
65 |
66 | Not supported yet
67 | * Other cloud storage
68 | * Support for images and file
69 | * Delete elements (to solve use a state column or column whit deleted flag)
70 |
71 | # Usage
72 |
73 | Simple example usage of library
74 |
75 | #### 1 Table
76 | ```java
77 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
78 | .setSyncFileByDriveId(mDriveId)
79 | .setGoogleApiClient(mGoogleApiClient)
80 | .build();
81 |
82 | DBSync dbSync = new DBSync.Builder(this.getBaseContext())
83 | .setCloudProvider(gDriveProvider)
84 | .setSQLiteDatabase(mDB)
85 | .setDataBaseName("db1")
86 | .addTable(new TableToSync.Builder("name").build())
87 | .build();
88 | ```
89 | #### 2 Table
90 | ```java
91 |
92 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
93 | .setSyncFileByDriveId(mDriveId)
94 | .setGoogleApiClient(mGoogleApiClient)
95 | .build();
96 |
97 | DBSync dbSync = new DBSync.Builder(this.getBaseContext())
98 | .setCloudProvider(gDriveProvider)
99 | .setSQLiteDatabase(mDb)
100 | .setDataBaseName("db2")
101 | .addTable(new TableToSync.Builder("name").build())
102 | .addTable(new TableToSync.Builder("category").build())
103 | .build();
104 | ```
105 |
106 | #### 1 Table whit filter
107 | ```java
108 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
109 | .setSyncFileByDriveId(mDriveId)
110 | .setGoogleApiClient(mGoogleApiClient)
111 | .build();
112 |
113 | TableToSync tableName = new TableToSync.Builder("name")
114 | .setFilter("FILTER = 0") // send data with apply FILTER = 0 before send
115 | .build();
116 |
117 | DBSync dbSync = new DBSync.Builder(this.getBaseContext())
118 | .setCloudProvider(gDriveProvider)
119 | .setSQLiteDatabase(mDB)
120 | .setDataBaseName("db3")
121 | .addTable(tableName)
122 | .build();
123 | ```
124 |
125 | #### 2 Table whit join
126 | ```java
127 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
128 | .setSyncFileByDriveId(mDriveId)
129 | .setGoogleApiClient(mGoogleApiClient)
130 | .build();
131 |
132 | // Keep the order
133 | TableToSync tableCategory = new TableToSync.Builder("CATEGORY")
134 | .build();
135 |
136 | TableToSync tableArticle = new TableToSync.Builder("ARTICLE")
137 | .addJoinTable(tableCategory, "CATEGORY_ID")
138 | .build();
139 |
140 | DBSync dbSync = new DBSync.Builder(this.getBaseContext())
141 | .setCloudProvider(gDriveProvider)
142 | .setSQLiteDatabase(mDB)
143 | .setDataBaseName("db4")
144 | .addTable(tableCategory)
145 | .addTable(tableArticle)
146 | .build();
147 | ```
148 |
149 | ### How sync
150 |
151 | To start sync process
152 |
153 | ```java
154 | dbSync.sync();
155 | ```
156 |
157 | ### How Insert/Update Data
158 |
159 | Every time you insert or update a record simple set SEND_TIME to null
160 |
161 | # Installation
162 | **Add the dependencies to your gradle file:**
163 | ```javascript
164 | allprojects {
165 | repositories {
166 | ...
167 | maven { url 'https://jitpack.io' }
168 | }
169 | }
170 | dependencies {
171 | compile 'com.github.claudiodegio:dbsync:X.Y.Z'
172 | }
173 | ```
174 |
175 | ## License
176 |
177 | Copyright 2020 Claudio Degioanni
178 |
179 | Licensed under the Apache License, Version 2.0 (the "License");
180 | you may not use this file except in compliance with the License.
181 | You may obtain a copy of the License at
182 |
183 | http://www.apache.org/licenses/LICENSE-2.0
184 |
185 | Unless required by applicable law or agreed to in writing, software
186 | distributed under the License is distributed on an "AS IS" BASIS,
187 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
188 | See the License for the specific language governing permissions and
189 | limitations under the License.
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion "28.0.3"
6 | defaultConfig {
7 | applicationId "com.claudiodegio.dbsync.sample"
8 | minSdkVersion 19
9 | targetSdkVersion 28
10 | versionCode 4
11 | versionName "2.0.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | multiDexEnabled true
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | compileOptions {
24 | sourceCompatibility JavaVersion.VERSION_1_8
25 | targetCompatibility JavaVersion.VERSION_1_8
26 | }
27 | }
28 |
29 |
30 | dependencies {
31 | implementation project(":lib")
32 |
33 | implementation 'androidx.appcompat:appcompat:1.1.0'
34 | implementation 'com.google.android.material:material:1.1.0'
35 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
36 |
37 | implementation 'com.jakewharton:butterknife:10.2.0'
38 | annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0'
39 |
40 | implementation 'com.github.claudiodegio:sfl4j-android:1.0.0'
41 | implementation 'im.dino:dbinspector:4.0.0'
42 | implementation 'de.codecrafters.tableview:tableview:2.4.2'
43 | implementation 'commons-io:commons-io:2.6'
44 |
45 | implementation "androidx.sqlite:sqlite:2.1.0"
46 | implementation "androidx.sqlite:sqlite-framework:2.1.0"
47 |
48 | // Migration to google drive api rest
49 | implementation 'com.google.android.gms:play-services-auth:17.0.0'
50 | implementation 'com.google.http-client:google-http-client-gson:1.28.0'
51 | implementation('com.google.api-client:google-api-client-android:1.28.0') {
52 | exclude group: 'org.apache.httpcomponents'
53 | }
54 | implementation('com.google.apis:google-api-services-drive:v3-rev152-1.25.0') {
55 | exclude group: 'org.apache.httpcomponents'
56 | }
57 |
58 | implementation 'androidx.multidex:multidex:2.0.1'
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\IDE\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/claudiodegio/dbsync/sample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.claudiodegio.dbsync.sample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
39 |
40 |
41 |
45 |
46 |
47 |
51 |
52 |
53 |
57 |
58 |
59 |
63 |
64 |
65 |
69 |
70 |
71 |
75 |
76 |
77 |
81 |
82 |
83 |
84 |
85 |
89 |
90 |
91 |
95 |
96 |
97 |
101 |
102 |
103 |
107 |
108 |
109 |
113 |
114 |
115 |
119 |
120 |
121 |
125 |
126 |
127 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/app/src/main/assets/slf4j-android.properties:
--------------------------------------------------------------------------------
1 | # slf4j-android.properties
2 | # ROOT level
3 | # ERROR,WARN,INFO,DEBUG,TRACE,NONE,ALL
4 | LEVEL=ALL
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.Nullable;
5 | import androidx.appcompat.app.AppCompatActivity;
6 |
7 |
8 | public abstract class BaseActivity extends AppCompatActivity {
9 |
10 | protected DbSyncApplication app;
11 |
12 | @Override
13 | protected void onCreate(@Nullable Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | app = (DbSyncApplication) getApplication();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/DbSyncApplication.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import androidx.multidex.MultiDexApplication;
4 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
5 | import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
6 |
7 | import com.claudiodegio.dbsync.sample.db1.Db1Callback;
8 | import com.claudiodegio.dbsync.sample.db2.Db2Callback;
9 | import com.claudiodegio.dbsync.sample.db3.Db3Callback;
10 | import com.claudiodegio.dbsync.sample.db4.Db4Callback;
11 | import com.claudiodegio.dbsync.sample.db5.Db5Callback;
12 |
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.slf4j.impl.StaticLoggerBinder;
16 |
17 |
18 | public class DbSyncApplication extends MultiDexApplication {
19 | static private Logger log;
20 |
21 | public SupportSQLiteOpenHelper db1OpenHelper;
22 | public SupportSQLiteOpenHelper db2OpenHelper;
23 | public SupportSQLiteOpenHelper db3OpenHelper;
24 | public SupportSQLiteOpenHelper db4OpenHelper;
25 | public SupportSQLiteOpenHelper db5OpenHelper;
26 |
27 | @Override
28 | public void onCreate() {
29 | SupportSQLiteOpenHelper.Configuration configuration;
30 | super.onCreate();
31 |
32 | StaticLoggerBinder.init(this);
33 | log = LoggerFactory.getLogger(DbSyncApplication.class);
34 |
35 | log.info("onCreate");
36 |
37 |
38 | configuration = SupportSQLiteOpenHelper.Configuration.builder(this)
39 | .name("db1")
40 | .callback(new Db1Callback())
41 | .build();
42 | db1OpenHelper = new FrameworkSQLiteOpenHelperFactory()
43 | .create(configuration);
44 | db1OpenHelper.getReadableDatabase();
45 |
46 | configuration = SupportSQLiteOpenHelper.Configuration.builder(this)
47 | .name("db2")
48 | .callback(new Db2Callback())
49 | .build();
50 | db2OpenHelper = new FrameworkSQLiteOpenHelperFactory()
51 | .create(configuration);
52 | db2OpenHelper.getReadableDatabase();
53 |
54 | configuration = SupportSQLiteOpenHelper.Configuration.builder(this)
55 | .name("db3")
56 | .callback(new Db3Callback())
57 | .build();
58 | db3OpenHelper = new FrameworkSQLiteOpenHelperFactory()
59 | .create(configuration);
60 | db3OpenHelper.getReadableDatabase();
61 |
62 | configuration = SupportSQLiteOpenHelper.Configuration.builder(this)
63 | .name("db4")
64 | .callback(new Db4Callback())
65 | .build();
66 | db4OpenHelper = new FrameworkSQLiteOpenHelperFactory()
67 | .create(configuration);
68 | db4OpenHelper.getReadableDatabase();
69 |
70 |
71 | configuration = SupportSQLiteOpenHelper.Configuration.builder(this)
72 | .name("db5")
73 | .callback(new Db5Callback())
74 | .build();
75 | db5OpenHelper = new FrameworkSQLiteOpenHelperFactory()
76 | .create(configuration);
77 | db5OpenHelper.getReadableDatabase();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 |
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import androidx.appcompat.widget.Toolbar;
8 |
9 | import android.view.Menu;
10 | import android.view.MenuItem;
11 |
12 |
13 | import com.claudiodegio.dbsync.sample.db1.MainDb1Activity;
14 | import com.claudiodegio.dbsync.sample.db2.MainDb2Activity;
15 | import com.claudiodegio.dbsync.sample.db3.MainDb3Activity;
16 | import com.claudiodegio.dbsync.sample.db4.MainDb4Activity;
17 | import com.claudiodegio.dbsync.sample.db5.MainDb5Activity;
18 |
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 |
22 | import butterknife.ButterKnife;
23 | import butterknife.OnClick;
24 | import im.dino.dbinspector.activities.DbInspectorActivity;
25 |
26 | public class MainActivity extends AppCompatActivity {
27 |
28 | static final private Logger log = LoggerFactory.getLogger(MainActivity.class);
29 |
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 | ButterKnife.bind(this);
36 | }
37 |
38 | @Override
39 | public boolean onCreateOptionsMenu(Menu menu) {
40 | // Inflate the menu; this adds items to the action bar if it is present.
41 | getMenuInflater().inflate(R.menu.menu_main, menu);
42 | return true;
43 | }
44 |
45 | @Override
46 | public boolean onOptionsItemSelected(MenuItem item) {
47 | // Handle action bar item clicks here. The action bar will
48 | // automatically handle clicks on the Home/Up button, so long
49 | // as you specify a parent activity in AndroidManifest.xml.
50 | int id = item.getItemId();
51 |
52 | //noinspection SimplifiableIfStatement
53 | if (id == R.id.action_settings) {
54 | return true;
55 | }
56 |
57 | return super.onOptionsItemSelected(item);
58 | }
59 |
60 |
61 |
62 | @OnClick(R.id.btToDbManager)
63 | public void goToDBManager(){
64 |
65 | startActivity(new Intent(this, DbInspectorActivity.class));
66 | }
67 |
68 | @OnClick(R.id.btDb1)
69 | public void goToDB1(){
70 | startActivity(new Intent(this, MainDb1Activity.class));
71 | }
72 |
73 | @OnClick(R.id.btDb2)
74 | public void goToDB2(){
75 | startActivity(new Intent(this, MainDb2Activity.class));
76 | }
77 |
78 | @OnClick(R.id.btDb3)
79 | public void goToDB3(){
80 | startActivity(new Intent(this, MainDb3Activity.class));
81 | }
82 |
83 |
84 | @OnClick(R.id.btDb4)
85 | public void goToDB4(){
86 | startActivity(new Intent(this, MainDb4Activity.class));
87 | }
88 |
89 | @OnClick(R.id.btDb5)
90 | public void goToDB5(){
91 | startActivity(new Intent(this, MainDb5Activity.class));
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/SAFUtils.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import android.content.Intent;
4 |
5 | public class SAFUtils {
6 |
7 | /**
8 | * Returns an {@link Intent} for opening the Storage Access Framework file picker.
9 | */
10 | static public Intent createAddFilePickerIntent(String fileName) {
11 | Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
12 | intent.addCategory(Intent.CATEGORY_OPENABLE);
13 | intent.putExtra(Intent.EXTRA_TITLE, fileName);
14 | intent.setType("text/plain");
15 |
16 | return intent;
17 | }
18 |
19 |
20 | static public Intent createSelectFilePickerIntent() {
21 | Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
22 | intent.addCategory(Intent.CATEGORY_OPENABLE);
23 | intent.setType("text/plain");
24 |
25 | return intent;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/Utility.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import java.util.Date;
4 | import java.text.SimpleDateFormat;
5 | import java.util.TimeZone;
6 |
7 | /**
8 | * Created by claud on 20/02/2017.
9 | */
10 |
11 | public class Utility {
12 |
13 |
14 | final static String formatDateTimeNoTimeZone(Date date){
15 | SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS");
16 | dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+0"));
17 | return dateFormat.format(date);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/core/TableViewerFragment.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.core;
2 |
3 | import android.app.Fragment;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.Button;
12 | import android.widget.TextView;
13 |
14 | import com.claudiodegio.dbsync.sample.R;
15 |
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | import java.io.File;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | import butterknife.BindView;
24 | import butterknife.ButterKnife;
25 | import butterknife.OnClick;
26 | import de.codecrafters.tableview.TableDataAdapter;
27 | import de.codecrafters.tableview.TableHeaderAdapter;
28 | import de.codecrafters.tableview.TableView;
29 | import de.codecrafters.tableview.listeners.TableDataClickListener;
30 | import de.codecrafters.tableview.model.TableColumnDpWidthModel;
31 | import de.codecrafters.tableview.toolkit.SimpleTableDataAdapter;
32 | import de.codecrafters.tableview.toolkit.SimpleTableHeaderAdapter;
33 |
34 |
35 | public class TableViewerFragment extends Fragment implements TableDataClickListener {
36 |
37 | static final private Logger log = LoggerFactory.getLogger(TableViewerFragment.class);
38 |
39 | final private static int PAGE_SIZE = 5;
40 |
41 | @BindView(R.id.tvTable)
42 | TableView mTableView;
43 |
44 | @BindView(R.id.tvPage)
45 | TextView mTVPage;
46 |
47 | String mDbName;
48 | String mTableName;
49 |
50 | @BindView(R.id.btNext)
51 | Button btNext;
52 | @BindView(R.id.btPrev)
53 | Button btPrev;
54 |
55 | SQLiteDatabase mDB;
56 |
57 | private int mCurrentPage = 0;
58 | private int mNumPages = 0;
59 |
60 | private OnEditListener mOnItemClicked;
61 |
62 | public static TableViewerFragment newInstance(String dbName, String tableName) {
63 |
64 | Bundle args = new Bundle();
65 |
66 | args.putString("db_name", dbName);
67 | args.putString("table_name", tableName);
68 |
69 | TableViewerFragment fragment = new TableViewerFragment();
70 | fragment.setArguments(args);
71 | return fragment;
72 | }
73 |
74 |
75 | @Override
76 | public void onCreate(Bundle savedInstanceState) {
77 | super.onCreate(savedInstanceState);
78 |
79 | mDbName = getArguments().getString("db_name");
80 | mTableName = getArguments().getString("table_name");
81 |
82 | openDatabase();
83 | }
84 |
85 | @Nullable
86 | @Override
87 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
88 |
89 | View view = inflater.inflate(R.layout.fragment_table_view, container, false);
90 |
91 | ButterKnife.bind(this, view);
92 |
93 | mTableView.addDataClickListener(this);
94 | return view;
95 | }
96 |
97 | @Override
98 | public void onStart() {
99 | super.onStart();
100 |
101 | initHeader();
102 | countPages();
103 | mCurrentPage = 1;
104 | showPage(mCurrentPage);
105 | }
106 |
107 | @Override
108 | public void onDestroy() {
109 | super.onDestroy();
110 |
111 | if (mDB != null) {
112 | mDB.close();
113 | }
114 | }
115 |
116 | private void openDatabase(){
117 | log.info("open database {}", mDbName);
118 |
119 | File dbFile = new File("/data/data/com.claudiodegio.dbsync.sample/databases", mDbName);
120 |
121 | mDB = SQLiteDatabase.openDatabase(dbFile.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY);
122 | }
123 |
124 | private void initHeader(){
125 | TableHeaderAdapter tableHeaderAdapter;
126 | Cursor cursor = mDB.query(mTableName, null, " 1 = 0", null, null, null, null);
127 |
128 | tableHeaderAdapter = new SimpleTableHeaderAdapter(getActivity(), cursor.getColumnNames());
129 |
130 | mTableView.setHeaderAdapter(tableHeaderAdapter);
131 | cursor.close();
132 |
133 | int headerCount = cursor.getColumnNames().length;
134 |
135 | TableColumnDpWidthModel model = new TableColumnDpWidthModel(getActivity(), headerCount, 200);
136 | model.setColumnWidth(0, 50);
137 |
138 | mTableView.setColumnModel(model);
139 | }
140 |
141 | private void showPage(int page){
142 | log.info("Show Page {}", page);
143 |
144 | String sqlSelect = "SELECT * FROM " + mTableName + " LIMIT " + (page - 1) * PAGE_SIZE + ", " + PAGE_SIZE;
145 |
146 | Cursor selectCursor = mDB.rawQuery(sqlSelect, null);
147 |
148 | List list = new ArrayList<>();
149 |
150 | while (selectCursor.moveToNext()) {
151 | String [] records = new String[selectCursor.getColumnCount()];
152 |
153 | for (int i = 0; i < selectCursor.getColumnCount(); ++i) {
154 | if (!selectCursor.isNull(i)) {
155 | records[i] = selectCursor.getString(i);
156 | } else {
157 | records[i] = "[NULL]";
158 | }
159 | }
160 |
161 | list.add(records);
162 | }
163 |
164 | TableDataAdapter tableDataAdapter = new SimpleTableDataAdapter(getActivity(), list);
165 | mTableView.setDataAdapter(tableDataAdapter);
166 |
167 | selectCursor.close();
168 |
169 | updatePage(page);
170 | updateButton(page);
171 | }
172 |
173 | private void countPages(){
174 | String sqlCount = "SELECT COUNT(*) FROM " + mTableName;
175 |
176 | Cursor countCursor = mDB.rawQuery(sqlCount, null);
177 |
178 | countCursor.moveToFirst();
179 |
180 | int count = countCursor.getInt(0);
181 | countCursor.close();
182 |
183 | mNumPages = (int) Math.ceil((float)count / (float)PAGE_SIZE);
184 |
185 | log.info("Found {} records, pages {}", count, mNumPages);
186 | }
187 |
188 | private void updatePage(int page){
189 | mTVPage.setText( page + "/" + mNumPages);
190 | }
191 |
192 | private void updateButton(int page){
193 | if (mNumPages == 1) {
194 | btNext.setEnabled(false);
195 | btPrev.setEnabled(false);
196 | } else {
197 | if (page == 1) {
198 | btNext.setEnabled(true);
199 | btPrev.setEnabled(false);
200 | } else if (page == mNumPages){
201 | btNext.setEnabled(false);
202 | btPrev.setEnabled(true);
203 | } else {
204 | btNext.setEnabled(true);
205 | btPrev.setEnabled(true);
206 | }
207 | }
208 | }
209 |
210 | @OnClick(R.id.btNext)
211 | public void buttonNext(){
212 | mCurrentPage++;
213 | showPage(mCurrentPage);
214 | }
215 |
216 | @OnClick(R.id.btPrev)
217 | public void buttonPrev(){
218 | mCurrentPage--;
219 | showPage(mCurrentPage);
220 | }
221 |
222 | @OnClick(R.id.btAdd)
223 | public void buttonAdd(){
224 | if (mOnItemClicked != null) {
225 | mOnItemClicked.onAdd();
226 | }
227 | }
228 |
229 | public void reload(){
230 | countPages();
231 | mCurrentPage = 1;
232 | showPage(mCurrentPage);
233 | }
234 |
235 | @Override
236 | public void onDataClicked(int rowIndex, Object clickedData) {
237 | String [] data = (String[]) clickedData;
238 |
239 | long id = Long.parseLong(data[0]);
240 |
241 | if (mOnItemClicked != null) {
242 | mOnItemClicked.onItemEdit(id, data);
243 | }
244 | }
245 |
246 | @OnClick(R.id.btAdd)
247 | public void onBtAdd(){
248 |
249 | }
250 |
251 | public interface OnEditListener {
252 | void onItemEdit(long id, String [] data );
253 | void onAdd();
254 | }
255 |
256 |
257 | public void setOnItemClicked(OnEditListener mOnItemClicked) {
258 | this.mOnItemClicked = mOnItemClicked;
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db1/Db1Callback.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db1;
2 |
3 |
4 | import androidx.annotation.NonNull;
5 | import androidx.sqlite.db.SupportSQLiteDatabase;
6 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | public class Db1Callback extends SupportSQLiteOpenHelper.Callback {
12 |
13 | static final private Logger log = LoggerFactory.getLogger(Db1Callback.class);
14 |
15 | public static final int DATABASE_VERSION = 1;
16 |
17 | private static final String DDL = "CREATE TABLE name (\n" +
18 | " _id INTEGER PRIMARY KEY,\n" +
19 | " NAME TEXT,\n" +
20 | " SEND_TIME INTEGER,\n" +
21 | " CLOUD_ID TEXT UNIQUE);";
22 |
23 | public Db1Callback() {
24 | super(DATABASE_VERSION);
25 | }
26 |
27 | @Override
28 | public void onCreate(@NonNull SupportSQLiteDatabase db) {
29 | log.info("onCreate");
30 | db.execSQL(DDL);
31 | }
32 |
33 | @Override
34 | public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
35 | onCreate(db);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db1/InsertNameActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db1;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.app.AppCompatActivity;
9 | import androidx.sqlite.db.SupportSQLiteDatabase;
10 |
11 | import android.view.View;
12 | import android.widget.Button;
13 | import android.widget.CheckBox;
14 | import android.widget.EditText;
15 |
16 | import com.claudiodegio.dbsync.sample.BaseActivity;
17 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
18 | import com.claudiodegio.dbsync.sample.R;
19 |
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 | import butterknife.OnClick;
23 |
24 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
25 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE;
26 |
27 | public class InsertNameActivity extends BaseActivity {
28 |
29 | @BindView(R.id.etName)
30 | EditText mETName;
31 |
32 | @BindView(R.id.btUpdate)
33 | Button btUpdate;
34 |
35 | @BindView(R.id.btInsert)
36 | Button btInsert;
37 |
38 | @BindView(R.id.cbNull)
39 | CheckBox mCheckBoxNull;
40 | private long mId = -1;
41 |
42 | SupportSQLiteDatabase mDB;
43 |
44 | @Override
45 | protected void onCreate(@Nullable Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_insert_name);
48 | app = (DbSyncApplication) getApplication();
49 | mDB = app.db1OpenHelper.getWritableDatabase();
50 | ButterKnife.bind(this);
51 |
52 | mId = getIntent().getLongExtra("ID", -1);
53 |
54 | }
55 |
56 |
57 | @OnClick(R.id.btInsert)
58 | public void insertName(){
59 |
60 | mDB = app.db1OpenHelper.getWritableDatabase();
61 |
62 | ContentValues contentValues = new ContentValues();
63 |
64 | if (mCheckBoxNull.isChecked()) {
65 | contentValues.put("NAME", (String)null);
66 | } else {
67 | contentValues.put("NAME", mETName.getEditableText().toString());
68 | }
69 | contentValues.putNull("SEND_TIME");
70 |
71 | mDB.insert("name", CONFLICT_REPLACE, contentValues);
72 |
73 | finish();
74 | }
75 |
76 | @OnClick(R.id.btUpdate)
77 | public void updateName(){
78 |
79 | ContentValues contentValues = new ContentValues();
80 |
81 | if (mCheckBoxNull.isChecked()) {
82 | contentValues.put("NAME", (String)null);
83 | } else {
84 | contentValues.put("NAME", mETName.getEditableText().toString());
85 | }
86 | contentValues.putNull("SEND_TIME");
87 |
88 | mDB.update("name", CONFLICT_NONE, contentValues, "_id = ? ", new String[] {Long.toString(mId)});
89 |
90 | finish();
91 | }
92 |
93 | @Override
94 | protected void onStart() {
95 | super.onStart();
96 | loadById();
97 | }
98 |
99 | public void loadById() {
100 | Cursor cur;
101 |
102 | if (mId != -1) {
103 | cur = mDB.query("SELECT * FROM name WHERE _id = ?", new String[] {Long.toString(mId)});
104 | cur.moveToFirst();
105 | mETName.setText(cur.getString(1));
106 | cur.close();
107 | btInsert.setVisibility(View.GONE);
108 | btUpdate.setVisibility(View.VISIBLE);
109 | } else {
110 | btInsert.setVisibility(View.VISIBLE);
111 | btUpdate.setVisibility(View.GONE);
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db1/MainDb1Activity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db1;
2 |
3 |
4 | import android.app.FragmentManager;
5 | import android.app.FragmentTransaction;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import androidx.annotation.Nullable;
9 | import android.util.Log;
10 |
11 | import com.claudiodegio.dbsync.provider.CloudProvider;
12 | import com.claudiodegio.dbsync.DBSync;
13 | import com.claudiodegio.dbsync.provider.GDriveCloudProvider;
14 | import com.claudiodegio.dbsync.TableToSync;
15 | import com.claudiodegio.dbsync.sample.BaseMainDbActivity;
16 | import com.claudiodegio.dbsync.sample.R;
17 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
18 |
19 | public class MainDb1Activity extends BaseMainDbActivity implements TableViewerFragment.OnEditListener {
20 |
21 | private final static String TAG = "MainDb5Activity";
22 |
23 | TableViewerFragment mFragment;
24 |
25 | @Override
26 | protected void onCreate(@Nullable Bundle savedInstanceState) {
27 | setContentView(R.layout.activity_main_db1);
28 | super.onCreate(savedInstanceState);
29 |
30 |
31 | mFragment = TableViewerFragment.newInstance("db1", "name");
32 | mFragment.setOnItemClicked(this);
33 |
34 | FragmentManager fm = getFragmentManager();
35 | FragmentTransaction ft = fm.beginTransaction();
36 |
37 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
38 | }
39 |
40 | @Override
41 | public void onItemEdit(long id, String[] data) {
42 | Intent intent = new Intent(this, InsertNameActivity.class);
43 | intent.putExtra("ID", id);
44 | startActivity(intent);
45 | }
46 |
47 | @Override
48 | public void onAdd() {
49 | startActivity(new Intent(this, InsertNameActivity.class));
50 | }
51 |
52 | @Override
53 | public void onPostSync() {
54 | mFragment.reload();
55 | }
56 |
57 | @Override
58 | public void onPostSelectFile() {
59 | Log.d(TAG, "onPostSelectFile");
60 |
61 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
62 | .setDriveID(driveId)
63 | .setDriveService(googleDriveService)
64 | .build();
65 |
66 | dbSync = new DBSync.Builder(this.getBaseContext())
67 | .setCloudProvider(gDriveProvider)
68 | .setSQLiteDatabase(app.db1OpenHelper.getWritableDatabase())
69 | .setDataBaseName(app.db1OpenHelper.getDatabaseName())
70 | .addTable(new TableToSync.Builder("name").build())
71 | .setSchemaVersion(2)
72 | .build();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/CategoriesActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 | import android.app.FragmentManager;
4 | import android.app.FragmentTransaction;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.claudiodegio.dbsync.sample.BaseActivity;
10 | import com.claudiodegio.dbsync.sample.R;
11 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
12 |
13 | public class CategoriesActivity extends BaseActivity implements TableViewerFragment.OnEditListener {
14 |
15 | TableViewerFragment mFragment;
16 |
17 | @Override
18 | protected void onCreate(@Nullable Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_fragment);
21 |
22 | mFragment = TableViewerFragment.newInstance("db2", "CATEGORY");
23 | mFragment.setOnItemClicked(this);
24 |
25 | FragmentManager fm = getFragmentManager();
26 | FragmentTransaction ft = fm.beginTransaction();
27 |
28 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
29 | }
30 |
31 | @Override
32 | public void onItemEdit(long id, String[] data) {
33 | Intent intent = new Intent(this, InsertCategoryActivity.class);
34 | intent.putExtra("ID", id);
35 | startActivity(intent);
36 | }
37 |
38 | @Override
39 | public void onAdd() {
40 | startActivity(new Intent(this, InsertCategoryActivity.class));
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/Db2Callback.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.sqlite.db.SupportSQLiteDatabase;
5 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class Db2Callback extends SupportSQLiteOpenHelper.Callback {
11 |
12 | static final private Logger log = LoggerFactory.getLogger(Db2Callback.class);
13 |
14 | public static final int DATABASE_VERSION = 1;
15 |
16 | private static final String DDL_1 = "CREATE TABLE name (\n" +
17 | " _id INTEGER PRIMARY KEY,\n" +
18 | " NAME TEXT,\n" +
19 | " SEND_TIME INTEGER,\n" +
20 | " CLOUD_ID TEXT UNIQUE);";
21 |
22 | private static final String DDL_2 = "CREATE TABLE CATEGORY (\n" +
23 | " _id INTEGER PRIMARY KEY,\n" +
24 | " NAME TEXT,\n" +
25 | " SEND_TIME INTEGER,\n" +
26 | " CLOUD_ID TEXT UNIQUE);";
27 |
28 | public Db2Callback() {
29 | super(DATABASE_VERSION);
30 | }
31 |
32 |
33 | @Override
34 | public void onCreate(@NonNull SupportSQLiteDatabase db) {
35 | log.info("onCreate");
36 | db.execSQL(DDL_1);
37 | db.execSQL(DDL_2);
38 | }
39 |
40 | @Override
41 | public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
42 | onCreate(db);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/InsertCategoryActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertCategoryActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.btUpdate)
31 | Button btUpdate;
32 |
33 | @BindView(R.id.btInsert)
34 | Button btInsert;
35 |
36 | @BindView(R.id.cbNull)
37 | CheckBox mCheckBoxNull;
38 | private long mId = -1;
39 |
40 | SupportSQLiteDatabase mDB;
41 |
42 | @Override
43 | protected void onCreate(@Nullable Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_insert_category);
46 | app = (DbSyncApplication) getApplication();
47 | mDB = app.db2OpenHelper.getWritableDatabase();
48 | ButterKnife.bind(this);
49 |
50 | mId = getIntent().getLongExtra("ID", -1);
51 | }
52 |
53 | @OnClick(R.id.btInsert)
54 | public void insertName(){
55 |
56 | ContentValues contentValues = new ContentValues();
57 |
58 | if (mCheckBoxNull.isChecked()) {
59 | contentValues.put("NAME", (String)null);
60 | } else {
61 | contentValues.put("NAME", mETName.getEditableText().toString());
62 | }
63 | contentValues.putNull("SEND_TIME");
64 |
65 | mDB.insert("category", CONFLICT_NONE, contentValues);
66 |
67 | finish();
68 | }
69 |
70 | @OnClick(R.id.btUpdate)
71 | public void updateName(){
72 |
73 | ContentValues contentValues = new ContentValues();
74 |
75 | if (mCheckBoxNull.isChecked()) {
76 | contentValues.put("NAME", (String)null);
77 | } else {
78 | contentValues.put("NAME", mETName.getEditableText().toString());
79 | }
80 | contentValues.putNull("SEND_TIME");
81 |
82 | mDB.update("category",CONFLICT_NONE, contentValues, "_id = ? ", new String[] {Long.toString(mId)});
83 |
84 | finish();
85 | }
86 |
87 | @Override
88 | protected void onStart() {
89 | super.onStart();
90 | loadById();
91 | }
92 |
93 | public void loadById() {
94 | Cursor cur;
95 |
96 | if (mId != -1) {
97 | cur = mDB.query("SELECT name FROM category WHERE _id = ?", new String[] {Long.toString(mId)});
98 | cur.moveToFirst();
99 | mETName.setText(cur.getString(1));
100 | cur.close();
101 | btInsert.setVisibility(View.GONE);
102 | btUpdate.setVisibility(View.VISIBLE);
103 | } else {
104 | btInsert.setVisibility(View.VISIBLE);
105 | btUpdate.setVisibility(View.GONE);
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/InsertNameActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertNameActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.btUpdate)
31 | Button btUpdate;
32 |
33 | @BindView(R.id.btInsert)
34 | Button btInsert;
35 |
36 | @BindView(R.id.cbNull)
37 | CheckBox mCheckBoxNull;
38 | private long mId = -1;
39 |
40 | SupportSQLiteDatabase mDB;
41 |
42 | @Override
43 | protected void onCreate(@Nullable Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_insert_name);
46 | app = (DbSyncApplication) getApplication();
47 | mDB = app.db2OpenHelper.getWritableDatabase();
48 | ButterKnife.bind(this);
49 |
50 | mId = getIntent().getLongExtra("ID", -1);
51 |
52 | }
53 |
54 |
55 | @OnClick(R.id.btInsert)
56 | public void insertName(){
57 |
58 | ContentValues contentValues = new ContentValues();
59 |
60 | if (mCheckBoxNull.isChecked()) {
61 | contentValues.put("NAME", (String)null);
62 | } else {
63 | contentValues.put("NAME", mETName.getEditableText().toString());
64 | }
65 | contentValues.putNull("SEND_TIME");
66 |
67 | mDB.insert("name", CONFLICT_NONE, contentValues);
68 |
69 | finish();
70 | }
71 |
72 | @OnClick(R.id.btUpdate)
73 | public void updateName(){
74 |
75 | ContentValues contentValues = new ContentValues();
76 |
77 | if (mCheckBoxNull.isChecked()) {
78 | contentValues.put("NAME", (String)null);
79 | } else {
80 | contentValues.put("NAME", mETName.getEditableText().toString());
81 | }
82 | contentValues.putNull("SEND_TIME");
83 |
84 | mDB.update("name", CONFLICT_NONE, contentValues, "_id = ? ", new String[] {Long.toString(mId)});
85 |
86 | finish();
87 | }
88 |
89 | @Override
90 | protected void onStart() {
91 | super.onStart();
92 | loadById();
93 | }
94 |
95 | public void loadById() {
96 | Cursor cur;
97 |
98 | if (mId != -1) {
99 | cur = mDB.query("SELECT * FROM name WHERE _id = ?", new String[] {Long.toString(mId)});
100 | cur.moveToFirst();
101 | mETName.setText(cur.getString(1));
102 | cur.close();
103 | btInsert.setVisibility(View.GONE);
104 | btUpdate.setVisibility(View.VISIBLE);
105 | } else {
106 | btInsert.setVisibility(View.VISIBLE);
107 | btUpdate.setVisibility(View.GONE);
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/MainDb2Activity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 |
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import androidx.annotation.Nullable;
7 |
8 | import com.claudiodegio.dbsync.provider.CloudProvider;
9 | import com.claudiodegio.dbsync.DBSync;
10 | import com.claudiodegio.dbsync.provider.GDriveCloudProvider;
11 | import com.claudiodegio.dbsync.TableToSync;
12 | import com.claudiodegio.dbsync.sample.BaseMainDbActivity;
13 | import com.claudiodegio.dbsync.sample.R;
14 |
15 | import butterknife.OnClick;
16 |
17 | public class MainDb2Activity extends BaseMainDbActivity {
18 |
19 | private final static String TAG = "MainDb2Activity";
20 |
21 |
22 | @Override
23 | protected void onCreate(@Nullable Bundle savedInstanceState) {
24 | setContentView(R.layout.activity_main_db2);
25 | super.onCreate(savedInstanceState);
26 | }
27 |
28 | @Override
29 | public void onPostSync() {
30 | }
31 |
32 | @Override
33 | public void onPostSelectFile() {
34 |
35 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
36 | .setDriveID(driveId)
37 | .setDriveService(googleDriveService)
38 | .build();
39 |
40 | dbSync = new DBSync.Builder(this.getBaseContext())
41 | .setCloudProvider(gDriveProvider)
42 | .setSQLiteDatabase(app.db2OpenHelper.getWritableDatabase())
43 | .setDataBaseName(app.db2OpenHelper.getDatabaseName())
44 | .addTable(new TableToSync.Builder("name").build())
45 | .addTable(new TableToSync.Builder("category").build())
46 | .setSchemaVersion(1)
47 | .build();
48 | }
49 |
50 |
51 | @OnClick(R.id.btName)
52 | public void goToNames(){
53 | startActivity(new Intent(this, NamesActivity.class));
54 | }
55 |
56 |
57 | @OnClick(R.id.btCat)
58 | public void goToCats(){
59 | startActivity(new Intent(this, CategoriesActivity.class));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db2/NamesActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db2;
2 |
3 | import android.app.FragmentManager;
4 | import android.app.FragmentTransaction;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.claudiodegio.dbsync.sample.BaseActivity;
10 | import com.claudiodegio.dbsync.sample.R;
11 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
12 |
13 | public class NamesActivity extends BaseActivity implements TableViewerFragment.OnEditListener {
14 |
15 | TableViewerFragment mFragment;
16 |
17 | @Override
18 | protected void onCreate(@Nullable Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_fragment);
21 |
22 | mFragment = TableViewerFragment.newInstance("db2", "name");
23 | mFragment.setOnItemClicked(this);
24 |
25 | FragmentManager fm = getFragmentManager();
26 | FragmentTransaction ft = fm.beginTransaction();
27 |
28 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
29 | }
30 |
31 | @Override
32 | public void onItemEdit(long id, String[] data) {
33 | Intent intent = new Intent(this, InsertNameActivity.class);
34 | intent.putExtra("ID", id);
35 | startActivity(intent);
36 | }
37 |
38 | @Override
39 | public void onAdd() {
40 | startActivity(new Intent(this, InsertNameActivity.class));
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db3/Db3Callback.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db3;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.sqlite.db.SupportSQLiteDatabase;
5 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class Db3Callback extends SupportSQLiteOpenHelper.Callback {
11 |
12 | static final private Logger log = LoggerFactory.getLogger(Db3Callback.class);
13 |
14 | public static final int DATABASE_VERSION = 1;
15 |
16 | private static final String DDL = "CREATE TABLE name (\n" +
17 | " _id INTEGER PRIMARY KEY,\n" +
18 | " NAME TEXT,\n" +
19 | " SEND_TIME INTEGER,\n" +
20 | " FILTER INTEGER,\n" +
21 | " CLOUD_ID TEXT UNIQUE);";
22 |
23 | public Db3Callback() {
24 | super(DATABASE_VERSION);
25 | }
26 |
27 |
28 | @Override
29 | public void onCreate(@NonNull SupportSQLiteDatabase db) {
30 | log.info("onCreate");
31 | db.execSQL(DDL);
32 | }
33 |
34 | @Override
35 | public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
36 | onCreate(db);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db3/InsertNameActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db3;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertNameActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.etFilter)
31 | EditText mETFilter;
32 |
33 | @BindView(R.id.btUpdate)
34 | Button btUpdate;
35 |
36 | @BindView(R.id.btInsert)
37 | Button btInsert;
38 |
39 | @BindView(R.id.cbNull)
40 | CheckBox mCheckBoxNull;
41 | private long mId = -1;
42 |
43 | SupportSQLiteDatabase mDB;
44 |
45 | @Override
46 | protected void onCreate(@Nullable Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_insert_name_db3);
49 | app = (DbSyncApplication) getApplication();
50 | mDB = app.db3OpenHelper.getWritableDatabase();
51 | ButterKnife.bind(this);
52 |
53 | mId = getIntent().getLongExtra("ID", -1);
54 |
55 | }
56 |
57 |
58 | @OnClick(R.id.btInsert)
59 | public void insertName(){
60 |
61 | ContentValues contentValues = new ContentValues();
62 |
63 | if (mCheckBoxNull.isChecked()) {
64 | contentValues.put("NAME", (String)null);
65 | } else {
66 | contentValues.put("NAME", mETName.getEditableText().toString());
67 | }
68 | contentValues.put("FILTER", Integer.parseInt(mETFilter.getEditableText().toString()));
69 | contentValues.putNull("SEND_TIME");
70 |
71 | mDB.insert("name", CONFLICT_NONE, contentValues);
72 |
73 | finish();
74 | }
75 |
76 | @OnClick(R.id.btUpdate)
77 | public void updateName(){
78 |
79 | ContentValues contentValues = new ContentValues();
80 |
81 | if (mCheckBoxNull.isChecked()) {
82 | contentValues.put("NAME", (String)null);
83 | } else {
84 | contentValues.put("NAME", mETName.getEditableText().toString());
85 | }
86 |
87 | contentValues.put("FILTER", Integer.parseInt(mETFilter.getEditableText().toString()));
88 | contentValues.putNull("SEND_TIME");
89 |
90 | mDB.update("name", CONFLICT_NONE, contentValues, "_id = ? ", new String[] {Long.toString(mId)});
91 |
92 | finish();
93 | }
94 |
95 | @Override
96 | protected void onStart() {
97 | super.onStart();
98 | loadById();
99 | }
100 |
101 | public void loadById() {
102 | Cursor cur;
103 |
104 | if (mId != -1) {
105 | cur = mDB.query("SELECT * FROM name WHERE _id = ?", new String[] {Long.toString(mId)});
106 | cur.moveToFirst();
107 | mETName.setText(cur.getString(1));
108 | cur.close();
109 | btInsert.setVisibility(View.GONE);
110 | btUpdate.setVisibility(View.VISIBLE);
111 | } else {
112 | btInsert.setVisibility(View.VISIBLE);
113 | btUpdate.setVisibility(View.GONE);
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db3/MainDb3Activity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db3;
2 |
3 |
4 | import android.app.FragmentManager;
5 | import android.app.FragmentTransaction;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import androidx.annotation.Nullable;
9 |
10 | import com.claudiodegio.dbsync.provider.CloudProvider;
11 | import com.claudiodegio.dbsync.DBSync;
12 | import com.claudiodegio.dbsync.provider.GDriveCloudProvider;
13 | import com.claudiodegio.dbsync.TableToSync;
14 | import com.claudiodegio.dbsync.sample.BaseMainDbActivity;
15 | import com.claudiodegio.dbsync.sample.R;
16 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
17 |
18 | public class MainDb3Activity extends BaseMainDbActivity implements TableViewerFragment.OnEditListener {
19 |
20 | private final static String TAG = "MainDb3Activity";
21 |
22 | TableViewerFragment mFragment;
23 |
24 | @Override
25 | protected void onCreate(@Nullable Bundle savedInstanceState) {
26 | setContentView(R.layout.activity_main_db3);
27 | super.onCreate(savedInstanceState);
28 |
29 |
30 | mFragment = TableViewerFragment.newInstance("db3", "name");
31 | mFragment.setOnItemClicked(this);
32 |
33 | FragmentManager fm = getFragmentManager();
34 | FragmentTransaction ft = fm.beginTransaction();
35 |
36 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
37 | }
38 |
39 | @Override
40 | public void onItemEdit(long id, String[] data) {
41 | Intent intent = new Intent(this, InsertNameActivity.class);
42 | intent.putExtra("ID", id);
43 | startActivity(intent);
44 | }
45 |
46 |
47 | @Override
48 | public void onAdd() {
49 | startActivity(new Intent(this, InsertNameActivity.class));
50 | }
51 |
52 | @Override
53 | public void onPostSync() {
54 | mFragment.reload();
55 | }
56 |
57 | @Override
58 | public void onPostSelectFile() {
59 |
60 |
61 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
62 | .setDriveID(driveId)
63 | .setDriveService(googleDriveService)
64 | .build();
65 |
66 | TableToSync tableName = new TableToSync.Builder("name")
67 | .setFilter("FILTER = 0")
68 | .build();
69 |
70 | dbSync = new DBSync.Builder(this.getBaseContext())
71 | .setCloudProvider(gDriveProvider)
72 | .setSQLiteDatabase(app.db3OpenHelper.getWritableDatabase())
73 | .setDataBaseName(app.db3OpenHelper.getDatabaseName())
74 | .addTable(tableName)
75 | .setSchemaVersion(2)
76 | .build();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/ArticlesActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 | import android.app.FragmentManager;
4 | import android.app.FragmentTransaction;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.claudiodegio.dbsync.sample.BaseActivity;
10 | import com.claudiodegio.dbsync.sample.R;
11 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
12 |
13 |
14 | public class ArticlesActivity extends BaseActivity implements TableViewerFragment.OnEditListener {
15 |
16 | TableViewerFragment mFragment;
17 |
18 | @Override
19 | protected void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_fragment);
22 |
23 | mFragment = TableViewerFragment.newInstance("db4", "article");
24 |
25 | mFragment.setOnItemClicked(this);
26 |
27 | FragmentManager fm = getFragmentManager();
28 | FragmentTransaction ft = fm.beginTransaction();
29 |
30 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
31 | }
32 |
33 | @Override
34 | public void onItemEdit(long id, String[] data) {
35 | Intent intent = new Intent(this, InsertArticleActivity.class);
36 |
37 | intent.putExtra("ID", id);
38 | startActivity(intent);
39 | }
40 |
41 | @Override
42 | public void onAdd() {
43 | startActivity(new Intent(this, InsertArticleActivity.class));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/CategoriesActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 | import android.app.FragmentManager;
4 | import android.app.FragmentTransaction;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.claudiodegio.dbsync.sample.BaseActivity;
10 | import com.claudiodegio.dbsync.sample.R;
11 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
12 |
13 |
14 | public class CategoriesActivity extends BaseActivity implements TableViewerFragment.OnEditListener {
15 |
16 | TableViewerFragment mFragment;
17 |
18 | @Override
19 | protected void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_fragment);
22 |
23 | mFragment = TableViewerFragment.newInstance("db4", "CATEGORY");
24 |
25 | mFragment.setOnItemClicked(this);
26 |
27 | FragmentManager fm = getFragmentManager();
28 | FragmentTransaction ft = fm.beginTransaction();
29 |
30 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
31 | }
32 |
33 | @Override
34 | public void onItemEdit(long id, String[] data) {
35 | Intent intent = new Intent(this, InsertCategoryActivity.class);
36 |
37 | intent.putExtra("ID", id);
38 | startActivity(intent);
39 | }
40 |
41 | @Override
42 | public void onAdd() {
43 | startActivity(new Intent(this, InsertCategoryActivity.class));
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/Db4Callback.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.sqlite.db.SupportSQLiteDatabase;
5 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class Db4Callback extends SupportSQLiteOpenHelper.Callback {
11 |
12 | static final private Logger log = LoggerFactory.getLogger(Db4Callback.class);
13 |
14 | public static final int DATABASE_VERSION = 1;
15 |
16 | private static final String DDL_CATEGORY = "CREATE TABLE category (\n" +
17 | " _id INTEGER PRIMARY KEY,\n" +
18 | " NAME TEXT,\n" +
19 | " SEND_TIME INTEGER,\n" +
20 | " CLOUD_ID TEXT UNIQUE);";
21 |
22 | private static final String DDL_ARTICLE = "CREATE TABLE article (\n" +
23 | " _id INTEGER PRIMARY KEY,\n" +
24 | " NAME TEXT,\n" +
25 | " SEND_TIME INTEGER,\n" +
26 | " CLOUD_ID TEXT UNIQUE,\n" +
27 | " CATEGORY_ID INTEGER REFERENCES category (_id));";
28 |
29 | public Db4Callback() {
30 | super(DATABASE_VERSION);
31 | }
32 |
33 |
34 | @Override
35 | public void onCreate(@NonNull SupportSQLiteDatabase db) {
36 | log.info("onCreate");
37 | db.execSQL(DDL_CATEGORY);
38 | db.execSQL(DDL_ARTICLE);
39 | }
40 |
41 | @Override
42 | public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
43 | onCreate(db);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/InsertArticleActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertArticleActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.etCategoryId)
31 | EditText mETCategoryId;
32 |
33 | @BindView(R.id.btUpdate)
34 | Button btUpdate;
35 |
36 | @BindView(R.id.btInsert)
37 | Button btInsert;
38 |
39 | @BindView(R.id.cbNull)
40 | CheckBox mCheckBoxNull;
41 |
42 | @BindView(R.id.cbNullCategory)
43 | CheckBox mCheckBoxNullCategoryId;
44 | private long mId = -1;
45 |
46 | SupportSQLiteDatabase mDB;
47 |
48 | @Override
49 | protected void onCreate(@Nullable Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | setContentView(R.layout.activity_insert_article);
52 | app = (DbSyncApplication) getApplication();
53 | mDB = app.db4OpenHelper.getWritableDatabase();
54 |
55 | ButterKnife.bind(this);
56 |
57 | mId = getIntent().getLongExtra("ID", -1);
58 |
59 | }
60 |
61 |
62 | @OnClick(R.id.btInsert)
63 | public void insertName(){
64 |
65 | mDB.insert("article", CONFLICT_NONE, buildContentValue());
66 |
67 | finish();
68 | }
69 |
70 | @OnClick(R.id.btUpdate)
71 | public void updateName(){
72 |
73 | mDB.update("article", CONFLICT_NONE, buildContentValue(), "_id = ? ", new String[] {Long.toString(mId)});
74 |
75 | finish();
76 | }
77 |
78 | private ContentValues buildContentValue(){
79 |
80 | ContentValues contentValues = new ContentValues();
81 |
82 | if (mCheckBoxNull.isChecked()) {
83 | contentValues.putNull("NAME");
84 | } else {
85 | contentValues.put("NAME", mETName.getEditableText().toString());
86 | }
87 |
88 | String categoryID = mETCategoryId.getEditableText().toString();
89 |
90 | if (mCheckBoxNullCategoryId.isChecked() || categoryID.isEmpty()) {
91 | contentValues.putNull("CATEGORY_ID");
92 | } else {
93 | contentValues.put("CATEGORY_ID", Integer.parseInt(categoryID));
94 | }
95 | contentValues.putNull("SEND_TIME");
96 |
97 | return contentValues;
98 | }
99 |
100 | @Override
101 | protected void onStart() {
102 | super.onStart();
103 | loadById();
104 | }
105 |
106 | public void loadById() {
107 | Cursor cur;
108 |
109 | if (mId != -1) {
110 | cur = mDB.query("SELECT * FROM article WHERE _id = ?", new String[] {Long.toString(mId)});
111 | cur.moveToFirst();
112 | mETName.setText(cur.getString(1));
113 |
114 | if (!cur.isNull(4)){
115 | mETCategoryId.setText(cur.getString(4));
116 | }
117 |
118 | cur.close();
119 | btInsert.setVisibility(View.GONE);
120 | btUpdate.setVisibility(View.VISIBLE);
121 | } else {
122 | btInsert.setVisibility(View.VISIBLE);
123 | btUpdate.setVisibility(View.GONE);
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/InsertCategoryActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertCategoryActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.btUpdate)
31 | Button btUpdate;
32 |
33 | @BindView(R.id.btInsert)
34 | Button btInsert;
35 |
36 | @BindView(R.id.cbNull)
37 | CheckBox mCheckBoxNull;
38 | private long mId = -1;
39 |
40 | SupportSQLiteDatabase mDB;
41 |
42 | @Override
43 | protected void onCreate(@Nullable Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_insert_category);
46 | app = (DbSyncApplication) getApplication();
47 | mDB = app.db4OpenHelper.getWritableDatabase();
48 |
49 | ButterKnife.bind(this);
50 |
51 | mId = getIntent().getLongExtra("ID", -1);
52 | }
53 |
54 | @OnClick(R.id.btInsert)
55 | public void insertName(){
56 |
57 | mDB.insert("category", CONFLICT_NONE, buildContentValue());
58 |
59 | finish();
60 | }
61 |
62 | @OnClick(R.id.btUpdate)
63 | public void updateName(){
64 |
65 | mDB.update("category", CONFLICT_NONE, buildContentValue(), "_id = ? ", new String[] {Long.toString(mId)});
66 |
67 | finish();
68 | }
69 |
70 | private ContentValues buildContentValue(){
71 | ContentValues contentValues = new ContentValues();
72 |
73 | if (mCheckBoxNull.isChecked()) {
74 | contentValues.putNull("NAME");
75 | } else {
76 | contentValues.put("NAME", mETName.getEditableText().toString());
77 | }
78 | contentValues.putNull("SEND_TIME");
79 |
80 | return contentValues;
81 |
82 | }
83 |
84 | @Override
85 | protected void onStart() {
86 | super.onStart();
87 | loadById();
88 | }
89 |
90 | public void loadById() {
91 | Cursor cur;
92 |
93 | if (mId != -1) {
94 | cur = mDB.query("SELECT name FROM category WHERE _id = ?", new String[] {Long.toString(mId)});
95 | cur.moveToFirst();
96 | mETName.setText(cur.getString(1));
97 | cur.close();
98 | btInsert.setVisibility(View.GONE);
99 | btUpdate.setVisibility(View.VISIBLE);
100 | } else {
101 | btInsert.setVisibility(View.VISIBLE);
102 | btUpdate.setVisibility(View.GONE);
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db4/MainDb4Activity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db4;
2 |
3 |
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import androidx.annotation.Nullable;
7 |
8 | import com.claudiodegio.dbsync.provider.CloudProvider;
9 | import com.claudiodegio.dbsync.DBSync;
10 | import com.claudiodegio.dbsync.provider.GDriveCloudProvider;
11 | import com.claudiodegio.dbsync.TableToSync;
12 | import com.claudiodegio.dbsync.sample.BaseMainDbActivity;
13 | import com.claudiodegio.dbsync.sample.R;
14 |
15 | import butterknife.OnClick;
16 |
17 | public class MainDb4Activity extends BaseMainDbActivity {
18 |
19 | private final static String TAG = "MainDb4Activity";
20 |
21 | @Override
22 | protected void onCreate(@Nullable Bundle savedInstanceState) {
23 | setContentView(R.layout.activity_main_db4);
24 | super.onCreate(savedInstanceState);
25 | }
26 |
27 | @Override
28 | public void onPostSync() {
29 | }
30 |
31 | @Override
32 | public void onPostSelectFile() {
33 |
34 |
35 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
36 | .setDriveID(driveId)
37 | .setDriveService(googleDriveService)
38 | .build();
39 |
40 | TableToSync tableCategory = new TableToSync.Builder("CATEGORY")
41 | .build();
42 |
43 | TableToSync tableArticle = new TableToSync.Builder("ARTICLE")
44 | .addJoinTable(tableCategory, "CATEGORY_ID")
45 | .build();
46 |
47 | dbSync = new DBSync.Builder(this.getBaseContext())
48 | .setCloudProvider(gDriveProvider)
49 | .setSQLiteDatabase(app.db4OpenHelper.getWritableDatabase())
50 | .setDataBaseName(app.db4OpenHelper.getDatabaseName())
51 | .addTable(tableCategory)
52 | .addTable(tableArticle)
53 | .setSchemaVersion(1)
54 | .build();
55 |
56 | }
57 |
58 |
59 | @OnClick(R.id.btArticle)
60 | public void goToNames(){
61 | startActivity(new Intent(this, ArticlesActivity.class));
62 | }
63 |
64 |
65 | @OnClick(R.id.btCat)
66 | public void goToCats(){
67 | startActivity(new Intent(this, CategoriesActivity.class));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db5/Db5Callback.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db5;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.sqlite.db.SupportSQLiteDatabase;
5 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class Db5Callback extends SupportSQLiteOpenHelper.Callback {
11 |
12 | static final private Logger log = LoggerFactory.getLogger(Db5Callback.class);
13 |
14 | public static final int DATABASE_VERSION = 1;
15 |
16 | private static final String DDL = "CREATE TABLE category (\n" +
17 | " _id INTEGER PRIMARY KEY,\n" +
18 | " NAME TEXT,\n" +
19 | " SEND_TIME INTEGER,\n" +
20 | " CLOUD_ID TEXT UNIQUE);";
21 |
22 | public Db5Callback() {
23 | super(DATABASE_VERSION);
24 | }
25 |
26 | @Override
27 | public void onCreate(@NonNull SupportSQLiteDatabase db) {
28 | log.info("onCreate");
29 | db.execSQL(DDL);
30 | }
31 |
32 | @Override
33 | public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
34 | onCreate(db);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db5/InsertNameActivity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db5;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Bundle;
7 | import androidx.annotation.Nullable;
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.CheckBox;
13 | import android.widget.EditText;
14 |
15 | import com.claudiodegio.dbsync.sample.BaseActivity;
16 | import com.claudiodegio.dbsync.sample.DbSyncApplication;
17 | import com.claudiodegio.dbsync.sample.R;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
24 |
25 | public class InsertNameActivity extends BaseActivity {
26 |
27 | @BindView(R.id.etName)
28 | EditText mETName;
29 |
30 | @BindView(R.id.btUpdate)
31 | Button btUpdate;
32 |
33 | @BindView(R.id.btInsert)
34 | Button btInsert;
35 |
36 | @BindView(R.id.cbNull)
37 | CheckBox mCheckBoxNull;
38 | private long mId = -1;
39 |
40 | SupportSQLiteDatabase mDB;
41 |
42 | @Override
43 | protected void onCreate(@Nullable Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_insert_name);
46 | app = (DbSyncApplication) getApplication();
47 | mDB = app.db5OpenHelper.getWritableDatabase();
48 | ButterKnife.bind(this);
49 |
50 | mId = getIntent().getLongExtra("ID", -1);
51 |
52 | }
53 |
54 |
55 | @OnClick(R.id.btInsert)
56 | public void insertName(){
57 |
58 | ContentValues contentValues = new ContentValues();
59 |
60 | if (mCheckBoxNull.isChecked()) {
61 | contentValues.put("NAME", (String)null);
62 | } else {
63 | contentValues.put("NAME", mETName.getEditableText().toString());
64 | }
65 | contentValues.putNull("SEND_TIME");
66 |
67 | mDB.insert("category", CONFLICT_NONE, contentValues);
68 |
69 | finish();
70 | }
71 |
72 | @OnClick(R.id.btUpdate)
73 | public void updateName(){
74 |
75 | ContentValues contentValues = new ContentValues();
76 |
77 | if (mCheckBoxNull.isChecked()) {
78 | contentValues.put("NAME", (String)null);
79 | } else {
80 | contentValues.put("NAME", mETName.getEditableText().toString());
81 | }
82 | contentValues.putNull("SEND_TIME");
83 |
84 | mDB.update("category", CONFLICT_NONE, contentValues, "_id = ? ", new String[] {Long.toString(mId)});
85 |
86 | finish();
87 | }
88 |
89 | @Override
90 | protected void onStart() {
91 | super.onStart();
92 | loadById();
93 | }
94 |
95 | public void loadById() {
96 | Cursor cur;
97 |
98 | if (mId != -1) {
99 | cur = mDB.query("SELECT * FROM name WHERE _id = ?", new String[] {Long.toString(mId)});
100 | cur.moveToFirst();
101 | mETName.setText(cur.getString(1));
102 | cur.close();
103 | btInsert.setVisibility(View.GONE);
104 | btUpdate.setVisibility(View.VISIBLE);
105 | } else {
106 | btInsert.setVisibility(View.VISIBLE);
107 | btUpdate.setVisibility(View.GONE);
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/claudiodegio/dbsync/sample/db5/MainDb5Activity.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample.db5;
2 |
3 |
4 | import android.app.FragmentManager;
5 | import android.app.FragmentTransaction;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import androidx.annotation.Nullable;
9 | import android.util.Log;
10 |
11 | import com.claudiodegio.dbsync.provider.CloudProvider;
12 | import com.claudiodegio.dbsync.DBSync;
13 | import com.claudiodegio.dbsync.provider.GDriveCloudProvider;
14 | import com.claudiodegio.dbsync.TableToSync;
15 | import com.claudiodegio.dbsync.sample.BaseMainDbActivity;
16 | import com.claudiodegio.dbsync.sample.R;
17 | import com.claudiodegio.dbsync.sample.core.TableViewerFragment;
18 |
19 | public class MainDb5Activity extends BaseMainDbActivity implements TableViewerFragment.OnEditListener {
20 |
21 | private final static String TAG = "MainDb5Activity";
22 |
23 | TableViewerFragment mFragment;
24 |
25 | @Override
26 | protected void onCreate(@Nullable Bundle savedInstanceState) {
27 | setContentView(R.layout.activity_main_db5);
28 | super.onCreate(savedInstanceState);
29 |
30 |
31 | mFragment = TableViewerFragment.newInstance("db5", "category");
32 | mFragment.setOnItemClicked(this);
33 |
34 | FragmentManager fm = getFragmentManager();
35 | FragmentTransaction ft = fm.beginTransaction();
36 |
37 | ft.add(R.id.flFragment, mFragment, "TAG").commit();
38 | }
39 |
40 | @Override
41 | public void onItemEdit(long id, String[] data) {
42 | Intent intent = new Intent(this, InsertNameActivity.class);
43 | intent.putExtra("ID", id);
44 | startActivity(intent);
45 | }
46 |
47 | @Override
48 | public void onAdd() {
49 | startActivity(new Intent(this, InsertNameActivity.class));
50 | }
51 |
52 | @Override
53 | public void onPostSync() {
54 | mFragment.reload();
55 | }
56 |
57 | @Override
58 | public void onPostSelectFile() {
59 | Log.d(TAG, "onPostSelectFile");
60 |
61 | CloudProvider gDriveProvider = new GDriveCloudProvider.Builder(this.getBaseContext())
62 | .setDriveID(driveId)
63 | .setDriveService(googleDriveService)
64 | .build();
65 | TableToSync tableToSync = new TableToSync.Builder("category")
66 | .addMatchRule("NAME = :NAME")
67 | .build();
68 |
69 | dbSync = new DBSync.Builder(this.getBaseContext())
70 | .setCloudProvider(gDriveProvider)
71 | .setSQLiteDatabase(app.db5OpenHelper.getWritableDatabase())
72 | .setDataBaseName(app.db5OpenHelper.getDatabaseName())
73 | .addTable(tableToSync)
74 | .setSchemaVersion(2)
75 | .build();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_insert_article.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
18 |
19 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_insert_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
18 |
19 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_insert_name.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
18 |
19 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_insert_name_db3.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
20 |
21 |
26 |
27 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
27 |
28 |
29 |
34 |
35 |
40 |
41 |
46 |
47 |
53 |
54 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_db1.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_db2.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_db3.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_db4.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_db5.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test_gdrive_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
23 |
24 |
29 |
30 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_table_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
19 |
20 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
46 |
47 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
45 |
46 |
53 |
54 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_status.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
16 |
20 |
21 |
25 |
26 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DbSyncSample
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/test/java/com/claudiodegio/dbsync/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.6.1'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | maven {
20 | url "https://jitpack.io"
21 | }
22 | maven {
23 | url "https://maven.google.com"
24 | }
25 | google()
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | android.enableJetifier=true
13 | android.useAndroidX=true
14 | org.gradle.jvmargs=-Xmx1536m
15 |
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/claudiodegio/dbsync/f18e3e381a6bd0d779d7cf6cec7a10da8331b316/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Oct 15 22:46:43 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/icone.txt:
--------------------------------------------------------------------------------
1 | Icons made by
2 | Madebyoliver from www.flaticon.com
3 | is licensed by CC 3.0 BY
--------------------------------------------------------------------------------
/lib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion "28.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 28
10 | multiDexEnabled true
11 | versionCode 6
12 | versionName "3.0.0"
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 | }
29 |
30 | dependencies {
31 | api fileTree(dir: 'libs', include: ['*.jar'])
32 |
33 | // Library for serialize json
34 | implementation 'com.fasterxml.jackson.core:jackson-core:2.10.2'
35 | implementation 'commons-io:commons-io:2.6'
36 | implementation 'org.apache.commons:commons-collections4:4.4'
37 |
38 | implementation "androidx.sqlite:sqlite:2.1.0"
39 | implementation "androidx.sqlite:sqlite-framework:2.1.0"
40 |
41 | // Migration to google drive api rest
42 | implementation 'com.google.android.gms:play-services-auth:17.0.0'
43 | implementation 'com.google.http-client:google-http-client-gson:1.28.0'
44 | implementation('com.google.api-client:google-api-client-android:1.28.0') {
45 | exclude group: 'org.apache.httpcomponents'
46 | }
47 | implementation('com.google.apis:google-api-services-drive:v3-rev152-1.25.0') {
48 | exclude group: 'org.apache.httpcomponents'
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\IDE\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/lib/src/androidTest/java/com/claudiodegio/dbsync/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.claudiodegio.dbsync.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/SyncResult.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync;
2 |
3 | import com.claudiodegio.dbsync.core.RecordSyncResult;
4 |
5 | /**
6 | * Result of sync process
7 | */
8 | public class SyncResult {
9 |
10 | private SyncStatus mSyncStatus;
11 | private RecordSyncResult mResult;
12 |
13 | public SyncResult(SyncStatus syncStatus) {
14 | this.mSyncStatus = syncStatus;
15 | }
16 |
17 | public SyncResult(SyncStatus syncStatus, RecordSyncResult result) {
18 | this.mSyncStatus = syncStatus;
19 | this.mResult = result;
20 | }
21 |
22 | public SyncStatus getStatus() {
23 | return mSyncStatus;
24 | }
25 |
26 | public RecordSyncResult getResult() {
27 | return mResult;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/SyncStatus.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync;
2 |
3 |
4 | import androidx.annotation.IntDef;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 |
9 | /**
10 | * Sync status
11 | */
12 | public class SyncStatus {
13 |
14 | @Retention(RetentionPolicy.SOURCE)
15 | @IntDef({Code.OK, Code.ERROR_WRITING_TMP_DB, Code.ERROR_UPLOAD_CLOUD, Code.ERROR_GENERATE_UUID, Code.ERROR_DOWNLOAD_CLOUD, Code.ERROR_SYNC_COULD_DB, Code.ERROR, Code.ERROR_NEW_SCHEMA_VERSION,Code.ERROR_NO_CONNECTION })
16 | public @interface Code {
17 | int OK = 0;
18 | int ERROR = 100;
19 | int ERROR_WRITING_TMP_DB = 101;
20 | int ERROR_UPLOAD_CLOUD = 102;
21 | int ERROR_GENERATE_UUID = 103;
22 | int ERROR_DOWNLOAD_CLOUD = 104;
23 | int ERROR_SYNC_COULD_DB = 105;
24 | int ERROR_NEW_SCHEMA_VERSION = 106;
25 | int ERROR_NO_CONNECTION = 107;
26 | }
27 |
28 | private @Code int mStatusCode;
29 | private String mMessage;
30 |
31 | public SyncStatus(@Code int statusCode, String message) {
32 | this.mStatusCode = statusCode;
33 | this.mMessage = message;
34 | }
35 |
36 | public SyncStatus(@Code int statusCode) {
37 | this(statusCode, null);
38 | }
39 |
40 | /**
41 | * Retrun the status code
42 | * @return the status code
43 | */
44 | @Code
45 | public int getStatusCode() {
46 | return mStatusCode;
47 | }
48 |
49 | /**
50 | * Return the error message on error
51 | * @return
52 | */
53 | public String getStatusMessage() {
54 | return mMessage;
55 | }
56 |
57 | /**
58 | * Return if operation is success or not
59 | * @return true on success otherwise false
60 | */
61 | public boolean isSuccess(){
62 | return mStatusCode == Code.OK;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/TableToSync.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync;
2 |
3 | import com.claudiodegio.dbsync.core.JoinTable;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * Class to describe a table to sync
10 | */
11 | public class TableToSync {
12 |
13 | private String mName;
14 | final private List mIgnoreColumns;
15 | final private String mCloudIdColumn;
16 | private String mIdColumn;
17 | private String mSendTimeColumn;
18 | private List mMatchRules;
19 | final private String mFilter;
20 |
21 | final private List mJoinTable;
22 |
23 | private TableToSync(final String name, final List ignoreColumns, final String cloudIdColumn, final String idColumn, final String sendTimeColumn, final List matchRules, final String filter, final List joinTable){
24 | this.mName = name;
25 | this.mIgnoreColumns = ignoreColumns;
26 | this.mCloudIdColumn = cloudIdColumn;
27 | this.mIdColumn = idColumn;
28 | this.mSendTimeColumn = sendTimeColumn;
29 | this.mMatchRules = matchRules;
30 | this.mFilter = filter;
31 | this.mJoinTable = joinTable;
32 | }
33 |
34 | public String getName() {
35 | return mName;
36 | }
37 |
38 | public boolean isColumnToIgnore(final String columnName) {
39 | return mIgnoreColumns.contains(columnName);
40 | }
41 |
42 | public String getCloudIdColumn() {
43 | return mCloudIdColumn;
44 | }
45 |
46 | public String getIdColumn() {
47 | return mIdColumn;
48 | }
49 |
50 | public String getSendTimeColumn() {
51 | return mSendTimeColumn;
52 | }
53 |
54 | public List getMatchRules(){
55 | return mMatchRules;
56 | }
57 |
58 | public String getFilter() {return mFilter; }
59 |
60 | public List getJoinTable() {
61 | return mJoinTable;
62 | }
63 |
64 | /**
65 | * Builder class
66 | */
67 | public static class Builder {
68 |
69 | final private String mName;
70 | final private List mIgnoreColumns;
71 | private String mCloudIdColumn;
72 | private String mIdColumn;
73 | private String mSendTimeColumn;
74 | private List mMatchRules;
75 |
76 | private String mFilter = "";
77 |
78 | final private List mJoinTable = new ArrayList<>();
79 |
80 | public Builder(final String name){
81 | this.mName = name;
82 | this.mIgnoreColumns = new ArrayList<>(1);
83 | this.mIgnoreColumns.add("_id");
84 | this.mCloudIdColumn = "CLOUD_ID";
85 | this.mIdColumn = "_id";
86 | this.mSendTimeColumn = "SEND_TIME";
87 | this.mMatchRules = new ArrayList<>(1);
88 | this.mMatchRules.add("CLOUD_ID = :CLOUD_ID");
89 | }
90 |
91 | /**
92 | * Add a ignore column
93 | */
94 | public Builder addIgnoreColumns(final String ignoreColumn){
95 | this.mIgnoreColumns.add(ignoreColumn);
96 | return this;
97 | }
98 |
99 | /**
100 | * Set the cloud id column
101 | * @param cloudIdColumn the name o column
102 | */
103 | public Builder setCloudIdColumn(final String cloudIdColumn) {
104 | this.mCloudIdColumn = cloudIdColumn;
105 | return this;
106 | }
107 |
108 | /**
109 | * Set the id column
110 | * @param idColumn the name o column
111 | */
112 | public Builder setIdColumn(final String idColumn) {
113 | this.mIdColumn = idColumn;
114 | return this;
115 | }
116 |
117 | /**
118 | * Set the send time column
119 | * @param sendTimeColumn the name o column
120 | */
121 | public Builder setSendTimeColumn(final String sendTimeColumn) {
122 | this.mSendTimeColumn = sendTimeColumn;
123 | return this;
124 | }
125 |
126 | /**
127 | * Add a match rule
128 | * @param matchRule the rule to add
129 | */
130 | public Builder addMatchRule(final String matchRule) {
131 | mMatchRules.add(matchRule);
132 | return this;
133 | }
134 |
135 | /**
136 | * Set the filter in table
137 | * @param mFilter the filter to use
138 | */
139 | public Builder setFilter(String mFilter) {
140 | this.mFilter = mFilter;
141 | return this;
142 | }
143 |
144 | /**
145 | * Add a join table
146 | * @param refTable the reference table
147 | * @param joinColumn the join columns
148 | ì */
149 | public Builder addJoinTable(final TableToSync refTable, final String joinColumn) {
150 | mJoinTable.add(new JoinTable(refTable, joinColumn));
151 | return this;
152 | }
153 |
154 | /**
155 | * Build a new table to sync
156 | */
157 | public TableToSync build(){
158 | return new TableToSync(mName, mIgnoreColumns, mCloudIdColumn, mIdColumn, mSendTimeColumn, mMatchRules, mFilter, mJoinTable);
159 | }
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/Database.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | public class Database {
4 |
5 | final private String mName;
6 | final private int mFormatVersion;
7 | final private int mTableCount;
8 | final private int mSchemaVersion;
9 |
10 | public Database(String name, int formatVersion, int tableCount, int schemaVersion) {
11 | this.mName = name;
12 | this.mFormatVersion = formatVersion;
13 | this.mTableCount = tableCount;
14 | this.mSchemaVersion = schemaVersion;
15 | }
16 | public int getTableCount() {
17 | return mTableCount;
18 | }
19 |
20 | public int getFormatVersion() {
21 | return mFormatVersion;
22 | }
23 |
24 | public String getName() {
25 | return mName;
26 | }
27 |
28 | public int getSchemaVersion() {
29 | return mSchemaVersion;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "Database{" +
35 | "mName='" + mName + '\'' +
36 | ", mFormatVersion=" + mFormatVersion +
37 | ", mSchemaVersion=" + mSchemaVersion +
38 | ", mTableCount=" + mTableCount +
39 | '}';
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/DatabaseReader.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | import java.io.IOException;
4 | import java.util.Map;
5 |
6 | public interface DatabaseReader {
7 |
8 | int nextElement();
9 |
10 | Database readDatabase() throws IOException;
11 |
12 | Table readTable() throws IOException;
13 |
14 | Record readRecord(Map columnMetadataMap) throws IOException;
15 |
16 | void close();
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/DatabaseWriter.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | import java.io.IOException;
4 |
5 | public interface DatabaseWriter {
6 |
7 | void writeDatabase(String name, int numOfTable, int schemaVersion) throws IOException;
8 |
9 | void writeTable(String name, int numOfRecord) throws IOException;
10 |
11 | void writeRecord(Record record) throws IOException;
12 |
13 | void close() throws IOException;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/JoinTable.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | import com.claudiodegio.dbsync.TableToSync;
5 |
6 | public class JoinTable {
7 | final private TableToSync mReferenceTable;
8 | final private String mJoinColumn;
9 |
10 | public JoinTable(final TableToSync table, String joinColumn) {
11 | this.mReferenceTable = table;
12 | this.mJoinColumn = joinColumn;
13 | }
14 |
15 | public String getJoinColumn() {
16 | return mJoinColumn;
17 | }
18 |
19 | public TableToSync getReferenceTable() {
20 | return mReferenceTable;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/Record.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | import org.apache.commons.collections4.IterableUtils;
4 | import org.apache.commons.collections4.Predicate;
5 |
6 | import java.util.ArrayList;
7 |
8 |
9 | public class Record extends ArrayList {
10 |
11 |
12 | public Value findField(final String fieldName){
13 |
14 | Value value;
15 |
16 | value = IterableUtils.find(this, object -> object.getMetadata().getName().equals(fieldName));
17 |
18 | return value;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/RecordChanged.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by claud on 10/03/2018.
8 | */
9 |
10 | public class RecordChanged {
11 |
12 |
13 | private List mInseredId = new ArrayList<>();
14 | private List mUpdatedId = new ArrayList<>();
15 |
16 | private int mRecordUpdated = 0;
17 | private int mRecordInserted = 0;
18 |
19 |
20 | void addInseredId(Long id) {
21 | mInseredId.add(id);
22 | }
23 |
24 | void addUpdatedId(Long id) {
25 | mUpdatedId.add(id);
26 | }
27 |
28 | public List getInseredId() {
29 | return mInseredId;
30 | }
31 |
32 | public List getUpdatedId() {
33 | return mUpdatedId;
34 | }
35 |
36 | public int getRecordInserted() {
37 | return mInseredId.size();
38 | }
39 |
40 | public int getRecordUpdated() {
41 | return mUpdatedId.size();
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/RecordSyncResult.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | import org.apache.commons.collections4.IterableUtils;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import java.util.Set;
9 | import java.util.concurrent.atomic.AtomicLong;
10 |
11 | public class RecordSyncResult {
12 |
13 | // Count of records Updated/Inserted and relative id
14 | private Map mRecordChanged;
15 |
16 | public RecordSyncResult() {
17 | this.mRecordChanged = new HashMap<>();
18 | }
19 |
20 | public int getTableSyncedCount(){
21 | return mRecordChanged.size();
22 | }
23 |
24 | public Map getTableSynced(){
25 | return mRecordChanged;
26 | }
27 |
28 | RecordChanged findOrCreateTableCounter(final String tableName) {
29 |
30 | if (!mRecordChanged.containsKey(tableName)) {
31 | mRecordChanged.put(tableName, new RecordChanged());
32 | }
33 |
34 | return mRecordChanged.get(tableName);
35 | }
36 |
37 | public int getRecordInserted() {
38 | int total = 0;
39 |
40 | for (RecordChanged recordChanged : mRecordChanged.values()) {
41 | total += recordChanged.getRecordInserted();
42 | }
43 |
44 | return total;
45 | }
46 |
47 | public int getRecordUpdated() {
48 | int total = 0;
49 |
50 | for (RecordChanged recordChanged : mRecordChanged.values()) {
51 | total += recordChanged.getRecordUpdated();
52 | }
53 |
54 | return total;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/SqlLiteUtility.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | import android.content.ContentValues;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 |
8 | import androidx.sqlite.db.SupportSQLiteDatabase;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.regex.Matcher;
15 | import java.util.regex.Pattern;
16 |
17 | public class SqlLiteUtility {
18 |
19 |
20 | public static Map readTableMetadataAsMap(final SupportSQLiteDatabase db, final String tableName) {
21 | List columns;
22 | Map maps;
23 |
24 | columns = readTableMetadata(db, tableName);
25 |
26 | maps = new HashMap<>();
27 |
28 | for (ValueMetadata column : columns) {
29 | maps.put(column.getName(), column);
30 | }
31 |
32 | return maps;
33 | }
34 |
35 | public static List readTableMetadata(final SupportSQLiteDatabase db, final String tableName) {
36 |
37 | Cursor cursor = null;
38 | String columnName;
39 | String columnType;
40 | int notNull, pk, type;
41 |
42 | List list = new ArrayList<>();
43 |
44 | cursor = db.query("PRAGMA table_info('" + tableName + "')", null);
45 |
46 | while (cursor.moveToNext()){
47 |
48 | columnName = getCursorString(cursor, "name");
49 | columnType = getCursorString(cursor, "type");
50 | notNull = getCursorInt(cursor, "notnull");
51 | pk = getCursorInt(cursor, "pk");
52 |
53 | switch (columnType) {
54 | case "INTEGER":
55 | type = ValueMetadata.TYPE_LONG;
56 | break;
57 | case "TEXT":
58 | type = ValueMetadata.TYPE_STRING;
59 | break;
60 | default:
61 | throw new RuntimeException("Type " + columnType + " non supported !!!");
62 | }
63 |
64 | list.add(new ValueMetadata(columnName, type, notNull == 1, pk == 1));
65 | }
66 |
67 | cursor.close();
68 |
69 | return list;
70 | }
71 |
72 | public static String getCursorString(final Cursor cursor, final String columnName) {
73 | int index = cursor.getColumnIndex(columnName);
74 | return cursor.getString(index);
75 | }
76 |
77 | public static int getCursorInt(final Cursor cursor, final String columnName) {
78 | int index = cursor.getColumnIndex(columnName);
79 | return cursor.getInt(index);
80 | }
81 |
82 | public static long getCursorLong(final Cursor cursor, final String columnName) {
83 | int index = cursor.getColumnIndex(columnName);
84 | return cursor.getLong(index);
85 | }
86 |
87 | public static Value getCursorColumnValue(final Cursor cursor, final String columnName, @ValueMetadata.Type int type) {
88 | return SqlLiteUtility.getCursorColumnValue(cursor, new ValueMetadata(columnName, type));
89 | }
90 |
91 | public static Value getCursorColumnValue(final Cursor cursor, final ValueMetadata metadata) {
92 | String columnName;
93 | int index;
94 | long valueLong;
95 | String valueString;
96 | Value value;
97 |
98 | columnName = metadata.getName();
99 | index = cursor.getColumnIndex(columnName);
100 |
101 | if (cursor.isNull(index)) {
102 | value = new Value(metadata);
103 | } else if(metadata.getType() == ValueMetadata.TYPE_LONG) {
104 | valueLong = getCursorLong(cursor, columnName);
105 | value = new Value(valueLong, metadata);
106 | } else {
107 | valueString = getCursorString(cursor, columnName);
108 | value = new Value(valueString, metadata);
109 | }
110 |
111 | return value;
112 | }
113 |
114 | public static void columnValueToContentValues(final Value value, final ContentValues contentValues) {
115 | ValueMetadata metadata;
116 | String fieldName;
117 |
118 | fieldName = value.getMetadata().getName();
119 |
120 | if (value.isNull()) {
121 | contentValues.putNull(fieldName);
122 | return;
123 | }
124 |
125 | metadata = value.getMetadata();
126 |
127 | switch (metadata.getType()) {
128 | case ValueMetadata.TYPE_LONG:
129 | contentValues.put(fieldName, value.getValueLong());
130 | break;
131 | case ValueMetadata.TYPE_STRING:
132 | contentValues.put(fieldName, value.getValueString());
133 | break;
134 | }
135 | }
136 |
137 | static SqlWithBinding sqlWithMapToSqlWithBinding(final String sql){
138 | String sqlWithBind;
139 | List selectionArg;
140 | Pattern p;
141 | Matcher m;
142 |
143 | // Find the binding params
144 | p = Pattern.compile(":([\\w]+)");
145 | m = p.matcher(sql);
146 |
147 | selectionArg = new ArrayList<>();
148 | while (m.find()) {
149 | selectionArg.add(m.group(1));
150 | }
151 |
152 | sqlWithBind = sql.replaceAll(":([\\w]+)", "?");
153 |
154 | return new SqlWithBinding(sql, sqlWithBind, selectionArg);
155 | }
156 |
157 | static public class SqlWithBinding {
158 | private String original;
159 | private String parsed;
160 | private List selectionArgs;
161 |
162 | private SqlWithBinding(String original, String parsed, List selectionArgs) {
163 | this.original = original;
164 | this.parsed = parsed;
165 | this.selectionArgs = selectionArgs;
166 | }
167 |
168 | public String getParsed() {
169 | return parsed;
170 | }
171 |
172 | public String getOriginal() {
173 | return original;
174 | }
175 |
176 | public String [] getArgs(){
177 | return selectionArgs.toArray( new String[selectionArgs.size()]);
178 | }
179 |
180 | @Override
181 | public String toString() {
182 | return "SqlWithBinding{" +
183 | "original='" + original + '\'' +
184 | ", parsed='" + parsed + '\'' +
185 | ", selectionArgs=" + selectionArgs +
186 | '}';
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/Table.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | public class Table {
5 |
6 | final private String mName;
7 | final private int mRecordCount;
8 |
9 | public Table(String name, int recordCount) {
10 | this.mName = name;
11 | this.mRecordCount = recordCount;
12 | }
13 |
14 | public int getRecordCount() {
15 | return mRecordCount;
16 | }
17 |
18 | public String getName() {
19 | return mName;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "Table{" +
25 | "mName='" + mName + '\'' +
26 | ", mRecordCount=" + mRecordCount +
27 | '}';
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/Utility.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | import android.content.Context;
5 | import android.net.ConnectivityManager;
6 | import android.net.NetworkInfo;
7 |
8 | public class Utility {
9 |
10 | public static boolean isConnectionUp(final Context ctx) {
11 | ConnectivityManager cm;
12 | cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
13 | NetworkInfo netInfo = cm.getActiveNetworkInfo();
14 | return netInfo != null && netInfo.isConnectedOrConnecting();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/Value.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 | /**
4 | * Class to hold column value
5 | */
6 | public class Value {
7 |
8 | private String mValueString;
9 | private long mValueLong;
10 | private ValueMetadata mMetadata;
11 | private boolean mNull = false;
12 |
13 | public Value(String valueString, ValueMetadata metadata) {
14 | this.mValueString = valueString;
15 | this.mMetadata = metadata;
16 | this.mNull = false;
17 | }
18 |
19 | public Value(long valueLong, ValueMetadata metadata) {
20 | this.mValueLong = valueLong;
21 | this.mMetadata = metadata;
22 | this.mNull = false;
23 | }
24 |
25 | public Value(ValueMetadata metadata) {
26 | this.mMetadata = metadata;
27 | this.mNull = true;
28 | }
29 |
30 | public String getValueString() {
31 | return mValueString;
32 | }
33 |
34 | public long getValueLong() {
35 | return mValueLong;
36 | }
37 |
38 | public ValueMetadata getMetadata() {
39 | return mMetadata;
40 | }
41 |
42 | public boolean isNull(){
43 | return mNull;
44 | }
45 |
46 | public String toSelectionArg(){
47 | switch (mMetadata.getType()) {
48 | case ValueMetadata.TYPE_LONG:
49 | return Long.toString(mValueLong);
50 | case ValueMetadata.TYPE_STRING:
51 | return mValueString;
52 | default:
53 | return null;
54 | }
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | if (isNull()) {
60 | return "[NULL]";
61 | } else if (mMetadata.getType() == ValueMetadata.TYPE_LONG) {
62 | return Long.toString(mValueLong) + "L";
63 | } else {
64 | return mValueString;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/core/ValueMetadata.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.core;
2 |
3 |
4 | import androidx.annotation.IntDef;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 |
9 | /**
10 | * Database column metadata
11 | */
12 | public class ValueMetadata {
13 |
14 | @Retention(RetentionPolicy.SOURCE)
15 | @IntDef({TYPE_LONG, TYPE_STRING})
16 | public @interface Type {}
17 | static final public int TYPE_LONG = 0;
18 | static final public int TYPE_STRING = 1;
19 |
20 | private String name;
21 | private @Type int type;
22 | private boolean notNull;
23 | private boolean pk;
24 |
25 | public ValueMetadata(String name, int type, boolean notNull, boolean pk) {
26 | this.name = name;
27 | this.type = type;
28 | this.notNull = notNull;
29 | this.pk = pk;
30 | }
31 |
32 | public ValueMetadata(String name, int type) {
33 | this(name, type, false, false);
34 | }
35 |
36 | public boolean isPk() {
37 | return pk;
38 | }
39 |
40 | public boolean isNotNull() {
41 | return notNull;
42 | }
43 |
44 | public int getType() {
45 | return type;
46 | }
47 |
48 | public String getName() {
49 | return name;
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return "ValueMetadata{" +
55 | "name='" + name + '\'' +
56 | ", type=" + type +
57 | ", notNull=" + notNull +
58 | ", pk=" + pk +
59 | '}';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/exception/SyncBuildException.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.exception;
2 |
3 |
4 | /**
5 | * Exeption throw on error during build procedure
6 | */
7 | public class SyncBuildException extends RuntimeException {
8 |
9 | public SyncBuildException(String message) {
10 | super(message);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/exception/SyncException.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.exception;
2 |
3 |
4 | import com.claudiodegio.dbsync.SyncStatus;
5 |
6 | public class SyncException extends RuntimeException {
7 |
8 | private SyncStatus mSyncStatus;
9 |
10 | public SyncException(@SyncStatus.Code int statusCode, String message) {
11 | super(message);
12 | this.mSyncStatus = new SyncStatus(statusCode, message);
13 | }
14 |
15 | public SyncException(@SyncStatus.Code int statusCode, Exception ex) {
16 | super(ex);
17 | this.mSyncStatus = new SyncStatus(statusCode, ex.getMessage());
18 | }
19 |
20 | public SyncStatus getStatus() {
21 | return mSyncStatus;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonConverter.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 | import com.claudiodegio.dbsync.core.ValueMetadata;
4 | import com.claudiodegio.dbsync.core.Value;
5 | import com.fasterxml.jackson.core.JsonGenerator;
6 | import com.fasterxml.jackson.core.JsonParser;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * Json Converter class for convert from db -> json and json -> to db
12 | */
13 | public interface JSonConverter {
14 |
15 | /**
16 | * Convert json value to column value
17 | * @param parser the parser
18 | * @param metadata the column metadata
19 | * @return the value of columns
20 | * @throws IOException
21 | */
22 | Value jsonToColumnValue(JsonParser parser, ValueMetadata metadata) throws IOException;
23 |
24 | /**
25 | * Convert column value to json (write directly into generator=
26 | * @param gen the generator to use
27 | * @param value the value to write
28 | * @throws IOException
29 | */
30 | void columnValueToJson(JsonGenerator gen, Value value) throws IOException;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonConverterFactory.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 | import com.claudiodegio.dbsync.core.ValueMetadata;
4 |
5 | /**
6 | * Factory for create right converter
7 | */
8 | public class JSonConverterFactory {
9 |
10 | static JSonConverter buildConverter(final ValueMetadata metadata) {
11 | switch (metadata.getType()) {
12 | case ValueMetadata.TYPE_LONG:
13 | return new JSonLongConverter();
14 | case ValueMetadata.TYPE_STRING:
15 | return new JSonStringConverter();
16 | default:
17 | throw new RuntimeException("Format non supported");
18 | }
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonDatabaseReader.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.claudiodegio.dbsync.core.Database;
6 | import com.claudiodegio.dbsync.core.Table;
7 | import com.claudiodegio.dbsync.core.ValueMetadata;
8 | import com.claudiodegio.dbsync.core.Record;
9 | import com.claudiodegio.dbsync.core.Value;
10 | import com.claudiodegio.dbsync.core.DatabaseReader;
11 | import com.fasterxml.jackson.core.JsonFactory;
12 | import com.fasterxml.jackson.core.JsonParser;
13 | import com.fasterxml.jackson.core.JsonToken;
14 |
15 | import org.apache.commons.io.IOUtils;
16 |
17 | import java.io.IOException;
18 | import java.io.InputStream;
19 | import java.util.Map;
20 |
21 | public class JSonDatabaseReader implements DatabaseReader {
22 |
23 | final static public int START_DB = 1;
24 | final static public int START_TABLE = 2;
25 | final static public int RECORD = 3;
26 | final static public int END = 4;
27 |
28 | private State mState;
29 |
30 | private JsonParser mJp;
31 |
32 | private Database mDatabase;
33 | private Table mCurrentTable;
34 | private Record mCurrentRecord;
35 | private InputStream mInputStream;
36 |
37 | public JSonDatabaseReader(InputStream inputStream) throws IOException {
38 | JsonFactory jsonFactory;
39 |
40 | jsonFactory = new JsonFactory(); // or, for data binding, org.codehaus.jackson.mapper.MappingJsonFactory
41 | this.mJp = jsonFactory.createParser(inputStream); // or URL, Stream, Reader, String, byte[]
42 | this.mState = new DatabaseState();
43 | this.mInputStream = inputStream;
44 | }
45 |
46 | @Override
47 | public int nextElement() {
48 | return mState.getElementType();
49 | }
50 |
51 | @Override
52 | public Database readDatabase() throws IOException {
53 |
54 | if (mState.getElementType() != START_DB) {
55 | throw new IOException("Unable to read wrong current element type " + mState.getElementType());
56 | }
57 |
58 | mState.handle();
59 |
60 | return mDatabase;
61 | }
62 |
63 | @Override
64 | public Table readTable() throws IOException {
65 | if (mState.getElementType() != START_TABLE) {
66 | throw new IOException("Unable to read wrong current element type " + mState.getElementType());
67 | }
68 |
69 | mState.handle();
70 |
71 | return mCurrentTable;
72 | }
73 |
74 | @Override
75 | public Record readRecord(final Map colMetadataMap) throws IOException {
76 | if (mState.getElementType() != RECORD) {
77 | throw new IOException("Unable to read wrong current element type " + mState.getElementType());
78 | }
79 |
80 | if (colMetadataMap == null) {
81 | throw new RuntimeException("columnMetadataMap cannot be null");
82 | }
83 |
84 | if (colMetadataMap.isEmpty()) {
85 | throw new RuntimeException("columnMetadataMap cannot be empty");
86 | }
87 |
88 | ((RecordTableState)mState).handle(colMetadataMap);
89 |
90 | return mCurrentRecord;
91 | }
92 |
93 | @Override
94 | public void close() {
95 | if (!mJp.isClosed()){
96 | IOUtils.closeQuietly(mJp);
97 | }
98 | }
99 |
100 | private String readNextTokenAsString() throws IOException {
101 | if (mJp.nextToken() != JsonToken.VALUE_STRING) {
102 | if (mJp.getCurrentToken() == JsonToken.VALUE_NULL) {
103 | throw new IOException("Unable to parse token as STRING is null line:" + mJp.getCurrentLocation().getLineNr());
104 | } else {
105 | throw new IOException("Unable to parse token as STRING line:" + mJp.getCurrentLocation().getLineNr());
106 | }
107 | }
108 | return mJp.getValueAsString();
109 | }
110 |
111 | private Integer readNextTokenAsInt() throws IOException {
112 | if (mJp.nextToken() != JsonToken.VALUE_NUMBER_INT) {
113 | if (mJp.getCurrentToken() == JsonToken.VALUE_NULL) {
114 | throw new IOException("Unable to parse token as NUMBER_INT is null line:" + mJp.getCurrentLocation().getLineNr());
115 | } else {
116 | throw new IOException("Unable to parse token as NUMBER_INT line:" + mJp.getCurrentLocation().getLineNr());
117 | }
118 | }
119 | return mJp.getIntValue();
120 | }
121 |
122 |
123 | private abstract class State {
124 | abstract int getElementType();
125 | abstract void handle() throws IOException;
126 | }
127 |
128 | private class DatabaseState extends State {
129 |
130 | @Override
131 | int getElementType() {
132 | return START_DB;
133 | }
134 |
135 | @Override
136 | void handle() throws IOException {
137 | String fieldName;
138 | String databaseName = null;
139 | int tableCount = -1;
140 | int formatVersion = -1;
141 | int schemaVersion = -1;
142 | boolean foundTable = false;
143 |
144 | // The first token is {
145 | if(mJp.nextToken() != JsonToken.START_OBJECT){
146 | throw new IOException("Unable to read start object of db element line:" + mJp.getCurrentLocation().getLineNr());
147 | }
148 |
149 | // Read the info of database
150 | while (mJp.nextToken() == JsonToken.FIELD_NAME) {
151 | fieldName = mJp.getCurrentName();
152 |
153 | if (fieldName.equals("name")) {
154 | databaseName = readNextTokenAsString();
155 | } else if (fieldName.equals("tableCount")){
156 | tableCount = readNextTokenAsInt();
157 | } else if (fieldName.equals("formatVersion")){
158 | formatVersion = readNextTokenAsInt();
159 | } else if (fieldName.equals("schemaVersion")){
160 | schemaVersion = readNextTokenAsInt();
161 | } else if (fieldName.equals("tables")){
162 | foundTable = true;
163 | break;
164 | } else {
165 | throw new IOException("Unable to parse found token:"+ fieldName + " line:" + mJp.getCurrentLocation().getLineNr());
166 | }
167 | }
168 |
169 | if (TextUtils.isEmpty(databaseName)) {
170 | throw new IOException("Unable to read database name field empty");
171 | }
172 |
173 | if (tableCount == -1) {
174 | throw new IOException("Unable to read table count");
175 | }
176 |
177 | if (formatVersion == -1) {
178 | throw new IOException("Unable to read format version");
179 | }
180 |
181 | if (schemaVersion == -1) {
182 | throw new IOException("Unable to read schema version");
183 | }
184 |
185 | // Il sezione delle tabelle deve essere l'ultimo della sezione
186 | if (!foundTable || !mJp.getCurrentName().equals("tables")) {
187 | throw new IOException("Unable to read tables section");
188 | }
189 |
190 | mDatabase = new Database(databaseName, formatVersion, tableCount, schemaVersion);
191 |
192 | // The first token is [
193 | if(mJp.nextToken() != JsonToken.START_ARRAY){
194 | throw new IOException("Unable to read start array of of tables line:" + mJp.getCurrentLocation().getLineNr());
195 | }
196 |
197 | if(mJp.nextToken() != JsonToken.START_OBJECT){
198 | throw new IOException("Unable to read start object of table element line:" + mJp.getCurrentLocation().getLineNr());
199 | }
200 |
201 | // passo allo stato successivo (inizio di una tabella)
202 | mState = new StartTableState();
203 | }
204 | }
205 |
206 | private class StartTableState extends State {
207 |
208 | @Override
209 | int getElementType() {
210 | return START_TABLE;
211 | }
212 |
213 | @Override
214 | void handle() throws IOException {
215 | String fieldName;
216 | int recordsCount = -1;
217 | String tableName = "";
218 | boolean foundRecord = false;
219 |
220 | // Read the first part of table
221 | if(mJp.getCurrentToken() != JsonToken.START_OBJECT){
222 | throw new IOException("Unable to read start table object line:" + mJp.getCurrentLocation().getLineNr());
223 | }
224 |
225 | while (mJp.nextToken() == JsonToken.FIELD_NAME) {
226 | fieldName = mJp.getCurrentName();
227 |
228 | if (fieldName.equals("name")) {
229 | tableName = readNextTokenAsString();
230 | } else if (fieldName.equals("recordsCount")) {
231 | recordsCount = readNextTokenAsInt();
232 | } else if (fieldName.equals("records")) {
233 | foundRecord = true;
234 | break;
235 | }
236 | }
237 |
238 | if (TextUtils.isEmpty(tableName)) {
239 | throw new IOException("Unable to read table name");
240 | }
241 |
242 | if (recordsCount == -1) {
243 | throw new IOException("Unable to read table recordsCount");
244 | }
245 |
246 | if (!foundRecord || !mJp.getCurrentName().equals("records")) {
247 | throw new IOException("Unable to read table records fields");
248 | }
249 |
250 | // the first token of record is open array
251 | if(mJp.nextToken() != JsonToken.START_ARRAY){
252 | throw new IOException("Unable to read start array of of records line:" + mJp.getCurrentLocation().getLineNr());
253 | }
254 |
255 | mCurrentTable = new Table(tableName, recordsCount);
256 | mState = new RecordTableState();
257 | }
258 | }
259 |
260 | private class RecordTableState extends State {
261 |
262 | @Override
263 | int getElementType() {
264 | return RECORD;
265 | }
266 |
267 | @Override
268 | void handle() throws IOException {
269 | }
270 |
271 | void handle(final Map colMetadataMap) throws IOException {
272 | String fieldName;
273 | ValueMetadata columnMetadata;
274 | JSonConverter converter;
275 | Value value;
276 |
277 | // Create a new record
278 | mCurrentRecord = new Record();
279 | while (mJp.nextToken() != JsonToken.END_OBJECT) {
280 |
281 |
282 | if (mJp.getCurrentToken() == JsonToken.FIELD_NAME) {
283 | fieldName = mJp.getCurrentName();
284 |
285 | // Get column metadata
286 | if (!colMetadataMap.containsKey(fieldName)){
287 | throw new IOException("Unable to find columns metadata for columns " + fieldName);
288 | }
289 |
290 | columnMetadata = colMetadataMap.get(fieldName);
291 |
292 | // Build the data converter and convert
293 | converter = JSonConverterFactory.buildConverter(columnMetadata);
294 | value = converter.jsonToColumnValue(mJp, columnMetadata);
295 |
296 | mCurrentRecord.add(value);
297 | }
298 | if (mJp.getCurrentToken() == JsonToken.END_ARRAY) {
299 | // End Array also no records
300 | break;
301 | }
302 |
303 | }
304 |
305 | // Go to next token, only if not the end of records
306 | if (mJp.getCurrentToken() != JsonToken.END_ARRAY) {
307 | mJp.nextToken();
308 | }
309 |
310 | if (mJp.getCurrentToken() == JsonToken.START_OBJECT) {
311 | // The current token is start of object -> new record no change state required
312 | return;
313 | } else if (mJp.getCurrentToken() == JsonToken.END_ARRAY) {
314 | // The current token is end of array -> end of record, end of table, end of database
315 |
316 | // Consume end of object of current table
317 | mJp.nextToken();
318 | if(mJp.getCurrentToken() != JsonToken.END_OBJECT){
319 | throw new IOException("Unable to read end of table expected end of object line :" + mJp.getCurrentLocation().getLineNr());
320 | }
321 |
322 | // Consume other token to dete end of database
323 | // if START_OBJECT -> new TableToSync
324 | // if END_ARRAY -> end of database
325 | mJp.nextToken();
326 | if (mJp.getCurrentToken() == JsonToken.START_OBJECT) {
327 | mState = new StartTableState();
328 | } else if (mJp.getCurrentToken() == JsonToken.END_ARRAY) {
329 | mState = new EndState();
330 | } else {
331 | throw new IOException("Unable to read start of table expected { or ] line:" + mJp.getCurrentLocation().getLineNr());
332 | }
333 | } else {
334 | throw new IOException("Unexpected token " + mJp.getCurrentToken() + " line:" + mJp.getCurrentLocation().getLineNr());
335 | }
336 | }
337 | }
338 |
339 | private class EndState extends State {
340 |
341 | @Override
342 | int getElementType() {
343 | return END;
344 | }
345 |
346 | @Override
347 | void handle() throws IOException {
348 |
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonDatabaseWriter.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 |
4 | import com.claudiodegio.dbsync.core.ValueMetadata;
5 | import com.claudiodegio.dbsync.core.Record;
6 | import com.claudiodegio.dbsync.core.Value;
7 | import com.claudiodegio.dbsync.core.DatabaseWriter;
8 | import com.fasterxml.jackson.core.JsonEncoding;
9 | import com.fasterxml.jackson.core.JsonFactory;
10 | import com.fasterxml.jackson.core.JsonGenerator;
11 | import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
12 |
13 | import java.io.IOException;
14 | import java.io.OutputStream;
15 |
16 | public class JSonDatabaseWriter implements DatabaseWriter {
17 |
18 | private final static String TAG = "JSonDatabaseWriter";
19 | private final OutputStream mOutStream;
20 | private final JsonGenerator mGen;
21 | private boolean mTableWritten = false;
22 |
23 | public JSonDatabaseWriter(final OutputStream outStream) throws IOException {
24 | this.mOutStream = outStream;
25 |
26 | JsonFactory f = new JsonFactory();
27 | mGen = f.createGenerator(outStream, JsonEncoding.UTF8);
28 | mGen.setPrettyPrinter(new DefaultPrettyPrinter());
29 | }
30 |
31 | @Override
32 | public void writeDatabase(String name, int numOfTable, int schemaVersion) throws IOException {
33 | mGen.writeStartObject();
34 | mGen.writeStringField("name", name);
35 | mGen.writeNumberField("formatVersion", 1);
36 | mGen.writeNumberField("schemaVersion", schemaVersion);
37 | mGen.writeNumberField("tableCount", numOfTable);
38 | mGen.writeFieldName("tables");
39 | mGen.writeStartArray();
40 | }
41 |
42 | @Override
43 | public void writeTable(String name, int numOfRecord) throws IOException {
44 |
45 | if (mTableWritten) {
46 | // If some table has been written must close the last element
47 | writeEndTable();
48 | }
49 |
50 | mGen.writeStartObject();
51 | mGen.writeStringField("name", name);
52 | mGen.writeNumberField("recordsCount", numOfRecord);
53 | mGen.writeFieldName("records");
54 | mGen.writeStartArray();
55 | mTableWritten = true;
56 | }
57 | @Override
58 | public void writeRecord(Record record) throws IOException {
59 | ValueMetadata metadata;
60 | JSonConverter converter;
61 |
62 | mGen.writeStartObject();
63 | for (Value value : record) {
64 |
65 | metadata = value.getMetadata();
66 |
67 | converter = JSonConverterFactory.buildConverter(metadata);
68 |
69 | converter.columnValueToJson(mGen, value);
70 | }
71 | mGen.writeEndObject();
72 | }
73 |
74 | @Override
75 | public void close() throws IOException {
76 | writeEndTable();
77 | writeEndDatabase();
78 |
79 | mGen.flush();
80 | mGen.close();
81 | mOutStream.close();
82 | }
83 |
84 | private void writeEndTable() throws IOException {
85 | mGen.writeEndArray(); // records
86 | mGen.writeEndObject();
87 | }
88 | private void writeEndDatabase() throws IOException {
89 | mGen.writeEndArray();
90 | mGen.writeEndObject();
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonLongConverter.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 | import com.claudiodegio.dbsync.core.ValueMetadata;
4 | import com.claudiodegio.dbsync.core.Value;
5 | import com.fasterxml.jackson.core.JsonGenerator;
6 | import com.fasterxml.jackson.core.JsonParser;
7 | import com.fasterxml.jackson.core.JsonToken;
8 |
9 | import java.io.IOException;
10 |
11 |
12 | public class JSonLongConverter implements JSonConverter {
13 | @Override
14 | public Value jsonToColumnValue(final JsonParser parser, final ValueMetadata metadata) throws IOException {
15 |
16 | JsonToken token;
17 | Value value;
18 |
19 | // Go to the next token
20 | token = parser.nextToken();
21 |
22 | if (token != JsonToken.VALUE_NUMBER_INT && token != JsonToken.VALUE_NULL) {
23 | throw new IOException("Unable to parse field " + metadata.getName() + " expected int or null at line " + parser.getCurrentLocation().getLineNr());
24 | }
25 |
26 | // Can be a integer or null
27 | if (token == JsonToken.VALUE_NUMBER_INT) {
28 | value = new Value(parser.getValueAsLong(), metadata);
29 | } else {
30 | // null
31 | if (metadata.isNotNull()) {
32 | throw new IOException("Unable to parse field " + metadata.getName() + " expected int bu found null at line " + parser.getCurrentLocation().getLineNr());
33 | }
34 |
35 | value = new Value(metadata);
36 | }
37 |
38 | return value;
39 | }
40 |
41 | @Override
42 | public void columnValueToJson(JsonGenerator gen, Value value) throws IOException {
43 |
44 | String fieldName;
45 |
46 | fieldName = value.getMetadata().getName();
47 |
48 | if (value.isNull()) {
49 | gen.writeNullField(fieldName);
50 | } else {
51 | gen.writeNumberField(fieldName, value.getValueLong());
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/json/JSonStringConverter.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.json;
2 |
3 | import com.claudiodegio.dbsync.core.ValueMetadata;
4 | import com.claudiodegio.dbsync.core.Value;
5 | import com.fasterxml.jackson.core.JsonGenerator;
6 | import com.fasterxml.jackson.core.JsonParser;
7 | import com.fasterxml.jackson.core.JsonToken;
8 |
9 | import java.io.IOException;
10 |
11 |
12 | public class JSonStringConverter implements JSonConverter {
13 | @Override
14 | public Value jsonToColumnValue(JsonParser parser, ValueMetadata metadata) throws IOException {
15 | JsonToken token;
16 | Value value;
17 |
18 | // Go to the next token
19 | token = parser.nextToken();
20 |
21 | if (token != JsonToken.VALUE_STRING && token != JsonToken.VALUE_NULL) {
22 | throw new IOException("Unable to parse field " + metadata.getName() + " expected string or null at line " + parser.getCurrentLocation().getLineNr());
23 | }
24 |
25 | // Can be a integer or null
26 | if (token == JsonToken.VALUE_STRING) {
27 | value = new Value(parser.getValueAsString(), metadata);
28 | } else {
29 | // null
30 | if (metadata.isNotNull()) {
31 | throw new IOException("Unable to parse field " + metadata.getName() + " expected string but found null at line " + parser.getCurrentLocation().getLineNr());
32 | }
33 |
34 | value = new Value(metadata);
35 | }
36 |
37 | return value;
38 | }
39 |
40 | @Override
41 | public void columnValueToJson(JsonGenerator gen, Value value) throws IOException {
42 | String fieldName;
43 |
44 | fieldName = value.getMetadata().getName();
45 |
46 | if (value.isNull()) {
47 | gen.writeNullField(fieldName);
48 | } else {
49 | gen.writeStringField(fieldName, value.getValueString());
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/provider/CloudProvider.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.provider;
2 |
3 |
4 | import androidx.annotation.IntDef;
5 |
6 | import java.io.File;
7 | import java.io.InputStream;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 |
11 | /**
12 | * Interface for generic cloud provider
13 | */
14 | public interface CloudProvider {
15 |
16 | int UPLOAD_OK = 0;
17 | int UPLOAD_CONFLICT = 1;
18 |
19 | @Retention(RetentionPolicy.SOURCE)
20 | @IntDef({UPLOAD_OK, UPLOAD_CONFLICT})
21 | @interface UploadStatus {}
22 |
23 | /**
24 | * Function to upload of file
25 | * @param tempFile the temp file where save the file
26 | * @return UPLOAD_OK, UPLOAD_CONFLICT
27 | */
28 | @UploadStatus int uploadFile(File tempFile);
29 |
30 | /**
31 | * Function to download the file
32 | * @return the input stream of download file
33 | */
34 | InputStream downloadFile();
35 |
36 | /**
37 | * Close the provider
38 | */
39 | void close();
40 | }
41 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/claudiodegio/dbsync/provider/GDriveCloudProvider.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync.provider;
2 |
3 |
4 | import android.content.Context;
5 | import android.util.Log;
6 |
7 | import com.claudiodegio.dbsync.exception.SyncException;
8 | import com.claudiodegio.dbsync.SyncStatus;
9 | import com.google.api.client.http.FileContent;
10 | import com.google.api.services.drive.Drive;
11 |
12 | import java.io.File;
13 | import java.io.InputStream;
14 |
15 | /**
16 | * Cloud provider implementation for Driver
17 | */
18 | public class GDriveCloudProvider implements CloudProvider {
19 |
20 | private final static String TAG = "GDriveCloudProvider";
21 |
22 |
23 | final private Context mCtx;
24 |
25 | // New version
26 | private final Drive mDriveService;
27 | private final String mNewDriveID;
28 | private String md5Sum;
29 |
30 | private GDriveCloudProvider(final Context ctx,
31 | final Drive driveService,
32 | final String newDriveId){
33 | this.mDriveService = driveService;
34 | this.mNewDriveID = newDriveId;
35 | this.mCtx = ctx;
36 | }
37 |
38 | @Override
39 | public int uploadFile(File tempFile) {
40 |
41 |
42 | com.google.api.services.drive.model.File fileMetadata;
43 | String md5sumCurrent;
44 |
45 | try {
46 | Log.i(TAG, "start upload of DB file temp:" + tempFile.getName());
47 |
48 | // Check collision
49 | fileMetadata = mDriveService.files()
50 | .get(mNewDriveID)
51 | .setFields("md5Checksum")
52 | .execute();
53 |
54 | md5sumCurrent = fileMetadata.getMd5Checksum();
55 |
56 | Log.i(TAG, "md5Checksum to check " + md5sumCurrent);
57 |
58 | if (!md5sumCurrent.equals(md5Sum)) {
59 | Log.w(TAG, "conflict detected");
60 |
61 | return UPLOAD_CONFLICT;
62 | }
63 |
64 | mDriveService
65 | .files()
66 | .update(mNewDriveID, null, new FileContent("text/json", tempFile))
67 | .execute();
68 |
69 | Log.i(TAG, "file uploaded ");
70 |
71 | return UPLOAD_OK;
72 |
73 | } catch (Exception e) {
74 | Log.e(TAG, "uploadFile: " + e.getMessage());
75 | throw new SyncException(SyncStatus.Code.ERROR_UPLOAD_CLOUD, "Error writing file to GDrive message:" + e.getMessage());
76 | }
77 | }
78 |
79 | @Override
80 | public InputStream downloadFile() {
81 | InputStream inputStream;
82 | com.google.api.services.drive.model.File metadata;
83 | Log.i(TAG, "start download of DB file:" + mNewDriveID);
84 |
85 | try {
86 |
87 | // Get metadata
88 | metadata = mDriveService.files()
89 | .get(mNewDriveID)
90 | .setFields("version,size,name,mimeType,kind,modifiedTime,md5Checksum")
91 | .execute();
92 |
93 | Log.i(TAG, "downloaded DB file:" + metadata.getName() + " modified on: " + metadata.getModifiedTime() + " size:" + metadata.getSize() + " bytes version:" + metadata.getVersion());
94 |
95 | md5Sum = metadata.getMd5Checksum();
96 |
97 | if (metadata.getSize() < 3) {
98 | return null;
99 | }
100 |
101 | inputStream = mDriveService.files()
102 | .get(mNewDriveID)
103 | .executeMediaAsInputStream();
104 |
105 | return inputStream;
106 | } catch (Exception e) {
107 |
108 | Log.e(TAG, "downloadFile: " + e.getMessage());
109 |
110 | throw new SyncException(SyncStatus.Code.ERROR_DOWNLOAD_CLOUD, "Error reading file from Drive message:" + e.getMessage());
111 |
112 | }
113 | }
114 |
115 | @Override
116 | public void close() {
117 | }
118 |
119 |
120 | /**
121 | * Builder class for Drive Provider
122 | */
123 | public static class Builder {
124 |
125 | private Context mCtx;
126 |
127 | private Drive mDriveService;
128 | private String mDriveID;
129 |
130 | public Builder(final Context ctx) {
131 | this.mCtx = ctx;
132 | }
133 |
134 | public Builder setDriveService(Drive mDriveService) {
135 | this.mDriveService = mDriveService;
136 | return this;
137 | }
138 |
139 | public Builder setDriveID(String mNewDriveID) {
140 | this.mDriveID = mNewDriveID;
141 | return this;
142 | }
143 |
144 | /**
145 | * Build a new GDriveCloudProvider
146 | * @return the new created cloud provider
147 | */
148 | public GDriveCloudProvider build(){
149 |
150 | return new GDriveCloudProvider(mCtx, mDriveService, mDriveID);
151 | }
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | My Library
3 |
4 |
--------------------------------------------------------------------------------
/lib/src/test/java/com/claudiodegio/dbsync/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.claudiodegio.dbsync;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':test', ':lib'
2 |
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/test/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'application'
3 | apply plugin: 'groovy'
4 |
5 | dependencies {
6 | compile fileTree(dir: 'libs', include: ['*.jar'])
7 | compile 'com.fasterxml.jackson.core:jackson-core:2.8.6'
8 | compile 'org.codehaus.groovy:groovy-all:2.4.7'
9 | }
10 |
11 | sourceCompatibility = "1.7"
12 | targetCompatibility = "1.7"
13 |
14 | mainClassName = "com.example.Main"
15 |
16 |
--------------------------------------------------------------------------------
/test/src/main/groovy/com/example/DatabaseGenerator.groovy:
--------------------------------------------------------------------------------
1 | def wdFile = new File(".")
2 |
3 |
4 | println "Inizio"
5 | println "WD:${wdFile.absolutePath}"
6 |
7 | def builder = new groovy.json.JsonBuilder()
8 |
9 | builder.database {
10 | name "db2"
11 |
12 | tables ({
13 | name "names"
14 |
15 | records((0..3000).collect {
16 | [
17 | cId: new Date().time,
18 | name : "Nome $it",
19 | dateCreated : new Date(),
20 | dateUpdated : new Date()
21 | ]
22 | }
23 | )
24 | },
25 | {
26 | name "cities"
27 |
28 | records((0..100).collect {
29 | [
30 | cId: new Date().time,
31 | name : "City $it",
32 | dateCreated : new Date(),
33 | dateUpdated : new Date()
34 | ]
35 | }
36 | )
37 | },
38 | {
39 | name "states"
40 |
41 | records((0..100).collect {
42 | [
43 | cId: new Date().time,
44 | state : "state $it",
45 | dateCreated : new Date(),
46 | dateUpdated : new Date()
47 | ]
48 | }
49 | )
50 | })
51 | }
52 |
53 | def file = new File("db_${new Date().format("yyyyMMdd_HHmmss")}.json")
54 |
55 | file.write builder.toPrettyString()
56 |
57 | println "Generated File ${file.absolutePath}"
58 |
59 | println "Fine"
60 |
61 |
--------------------------------------------------------------------------------
/test/src/main/groovy/com/example/db_20170114_002331_9_records.json:
--------------------------------------------------------------------------------
1 | {
2 | "database": {
3 | "name": "db1",
4 | "tables": [
5 | {
6 | "name": "names",
7 | "records": [
8 | {
9 | "cId": 1484349811160,
10 | "name": "Nome 0",
11 | "dateCreated": "2017-01-13T23:23:31+0000",
12 | "dateUpdated": "2017-01-13T23:23:31+0000"
13 | },
14 | {
15 | "cId": 1484349811160,
16 | "name": "Nome 1",
17 | "dateCreated": "2017-01-13T23:23:31+0000",
18 | "dateUpdated": "2017-01-13T23:23:31+0000"
19 | },
20 | {
21 | "cId": 1484349811160,
22 | "name": "Nome 2",
23 | "dateCreated": "2017-01-13T23:23:31+0000",
24 | "dateUpdated": "2017-01-13T23:23:31+0000"
25 | }
26 | ]
27 | },
28 | {
29 | "name": "cities",
30 | "records": [
31 | {
32 | "cId": 1484349811164,
33 | "name": "City 0",
34 | "dateCreated": "2017-01-13T23:23:31+0000",
35 | "dateUpdated": "2017-01-13T23:23:31+0000"
36 | },
37 | {
38 | "cId": 1484349811164,
39 | "name": "City 1",
40 | "dateCreated": "2017-01-13T23:23:31+0000",
41 | "dateUpdated": "2017-01-13T23:23:31+0000"
42 | },
43 | {
44 | "cId": 1484349811165,
45 | "name": "City 2",
46 | "dateCreated": "2017-01-13T23:23:31+0000",
47 | "dateUpdated": "2017-01-13T23:23:31+0000"
48 | }
49 | ]
50 | },
51 | {
52 | "name": "states",
53 | "records": [
54 | {
55 | "cId": 1484349811167,
56 | "state": "state 0",
57 | "dateCreated": "2017-01-13T23:23:31+0000",
58 | "dateUpdated": "2017-01-13T23:23:31+0000"
59 | },
60 | {
61 | "cId": 1484349811167,
62 | "state": "state 1",
63 | "dateCreated": "2017-01-13T23:23:31+0000",
64 | "dateUpdated": "2017-01-13T23:23:31+0000"
65 | },
66 | {
67 | "cId": 1484349811167,
68 | "state": "state 2",
69 | "dateCreated": "2017-01-13T23:23:31+0000",
70 | "dateUpdated": "2017-01-13T23:23:31+0000"
71 | }
72 | ]
73 | }
74 | ]
75 | }
76 | }
--------------------------------------------------------------------------------
/test/src/main/java/com/example/JSonDatabaseWriter.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 |
4 | import com.fasterxml.jackson.core.JsonEncoding;
5 | import com.fasterxml.jackson.core.JsonFactory;
6 | import com.fasterxml.jackson.core.JsonGenerator;
7 | import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
8 |
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.text.SimpleDateFormat;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 | import java.util.Date;
15 |
16 | public class JSonDatabaseWriter {
17 |
18 | Map tablesToWrite;
19 | String databaseName;
20 |
21 |
22 | private JSonDatabaseWriter(String databaseName, Map tablesToWrite){
23 | this.databaseName = databaseName;
24 | this.tablesToWrite = tablesToWrite;
25 | }
26 |
27 | long write(File file) throws IOException {
28 |
29 | long timestamp = System.currentTimeMillis();
30 |
31 | if (file.exists()) {
32 | file.delete();
33 | }
34 |
35 | JsonFactory f = new JsonFactory();
36 | JsonGenerator g = f.createGenerator(file, JsonEncoding.UTF8);
37 | g.setPrettyPrinter(new DefaultPrettyPrinter() );
38 |
39 | g.writeStartObject();
40 |
41 | g.writeFieldName("database");
42 | g.writeStartObject();
43 | // Nome database
44 | g.writeStringField("name",databaseName);
45 |
46 | // Tabelle
47 | g.writeFieldName("tables");
48 | g.writeStartArray();
49 |
50 | for (Map.Entry entry : tablesToWrite.entrySet()) {
51 |
52 | g.writeStartObject();
53 |
54 | g.writeStringField("name",entry.getKey());
55 |
56 | g.writeArrayFieldStart("records");
57 |
58 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
59 | for (int i = 0; i < entry.getValue();++i) {
60 |
61 | g.writeStartObject();
62 |
63 | g.writeNumberField("cId", new Date().getTime());
64 |
65 | String name = entry.getKey();
66 | name = name + " " + i;
67 |
68 | g.writeStringField("name", name);
69 |
70 | g.writeStringField("dateCreated", simpleDateFormat.format(new Date()));
71 | g.writeStringField("dateUpdated", simpleDateFormat.format(new Date()));
72 |
73 |
74 | g.writeEndObject();
75 | }
76 |
77 | g.writeEndArray();
78 |
79 | g.writeEndObject();
80 | }
81 |
82 | g.writeEndArray();
83 | g.writeEndObject();
84 |
85 | g.writeEndObject();
86 | g.close();
87 |
88 | return System.currentTimeMillis() - timestamp;
89 | }
90 |
91 | public static class Builder {
92 |
93 | String databaseName;
94 | Map tablesToWrite = new HashMap<>();
95 |
96 |
97 | public Builder setDbName(String name) {
98 | this.databaseName = name;
99 | return this;
100 | }
101 |
102 | public Builder addTable(String name, int recordCount) {
103 | tablesToWrite.put(name, recordCount);
104 | return this;
105 | }
106 |
107 | public JSonDatabaseWriter build(){
108 | return new JSonDatabaseWriter(databaseName, tablesToWrite);
109 | }
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/test/src/main/java/com/example/JsonDatabaseReader.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.fasterxml.jackson.core.JsonFactory;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonToken;
6 |
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.Collections;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 | import java.util.concurrent.SynchronousQueue;
15 |
16 |
17 | public class JsonDatabaseReader {
18 |
19 |
20 | public Map numeriche;
21 |
22 |
23 | long readDatabase(File file) throws IOException {
24 | return readDatabase(new FileInputStream(file));
25 | }
26 |
27 | long readDatabase(InputStream stream) throws IOException {
28 | long timestamp = 0;
29 |
30 | numeriche = new HashMap<>();
31 |
32 | timestamp = System.currentTimeMillis();
33 | JsonFactory jsonFactory = new JsonFactory(); // or, for data binding, org.codehaus.jackson.mapper.MappingJsonFactory
34 | JsonParser jp = jsonFactory.createParser(stream); // or URL, Stream, Reader, String, byte[]
35 |
36 | jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
37 |
38 | // passo a leggere il database
39 | String fieldName;
40 | if (jp.nextToken() == JsonToken.FIELD_NAME) {
41 | fieldName = jp.getCurrentName();
42 | jp.nextToken(); // START_OBJECT INIZIO di un nuovo oggetto database
43 |
44 | // Passo al campo nome
45 | while (jp.nextToken() == JsonToken.FIELD_NAME) {
46 | fieldName = jp.getCurrentName();
47 | jp.nextToken(); // Vado al valore
48 | if ("name".equals(fieldName)) {
49 | System.out.println("Database Name:" + jp.getValueAsString());
50 | } else if ("tables".equals(fieldName)) {
51 | while (jp.nextToken() != JsonToken.END_ARRAY) {
52 | readTable(jp);
53 | }
54 | }
55 | }
56 | }
57 |
58 | jp.close();
59 |
60 | long duration = System.currentTimeMillis() - timestamp;
61 |
62 | return duration;
63 | }
64 |
65 |
66 | private void readTable(JsonParser jp) throws IOException {
67 | JsonToken token;
68 | String tableName = "";
69 | int recordCount = 0;
70 |
71 | while((token = jp.nextToken()) != JsonToken.END_OBJECT) {
72 |
73 | if (token == JsonToken.FIELD_NAME) {
74 | if ("name".equals(jp.getCurrentName())) {
75 | tableName = jp.nextTextValue();
76 | } else if ("records".equals(jp.getCurrentName())){
77 | // Ciclo la lista dei records
78 | while((token = jp.nextToken()) != JsonToken.END_ARRAY) {
79 | readRecord(jp);
80 | recordCount++;
81 | }
82 | }
83 | }
84 | }
85 | System.out.println("\tTable: " + tableName + " records:" + recordCount);
86 |
87 | numeriche.put(tableName, recordCount);
88 | }
89 |
90 | Map readRecord(JsonParser jp) throws IOException {
91 |
92 | Map record = new HashMap<>();
93 | String fielName = "";
94 | Object value;
95 | JsonToken token;
96 |
97 | while((token = jp.nextToken()) != JsonToken.END_OBJECT) {
98 | if (token == JsonToken.FIELD_NAME) {
99 | fielName = jp.getCurrentName();
100 | } else if (token == JsonToken.VALUE_STRING) {
101 | value = jp.getValueAsString();
102 | record.put(fielName, value);
103 | } else if (token == JsonToken.VALUE_NUMBER_INT) {
104 | value = jp.getValueAsLong();
105 | record.put(fielName, value);
106 | }
107 | }
108 |
109 | //System.out.println(record.toString());
110 | return record;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/test/src/main/java/com/example/Main.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.Date;
6 |
7 | import static com.example.JSonDatabaseWriter.*;
8 |
9 | public class Main {
10 |
11 | public static void main(String[] args) {
12 |
13 | File wdFile = new File(".");
14 | System.out.println(" - Inizio -");
15 | System.out.println("WD:" + wdFile.getAbsolutePath());
16 |
17 | testWrite();
18 |
19 |
20 | System.out.println(" - Fine -");
21 |
22 | }
23 |
24 | static void testRead(){
25 |
26 | JsonDatabaseReader jsonDatabaseReader = new JsonDatabaseReader();
27 |
28 | try {
29 | long duration = jsonDatabaseReader.readDatabase(new File("D:\\git\\easy-mobile\\DbSyncSample\\test\\src\\main\\groovy\\com\\example\\db_20170114_002331_9_records.json"));
30 |
31 | System.out.println("Duration: " + duration + " ms");
32 | System.out.println("Duration: " + duration/1000 + " s");
33 |
34 | duration = jsonDatabaseReader.readDatabase(new File("D:\\git\\easy-mobile\\DbSyncSample\\test\\src\\main\\groovy\\com\\example\\db_20170114_184802_3200_records.json"));
35 |
36 | System.out.println("Duration: " + duration + " ms");
37 | System.out.println("Duration: " + duration/1000 + " s");
38 |
39 |
40 | } catch (IOException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 |
45 | static void testWrite(){
46 |
47 | JSonDatabaseWriter jSonDatabaseWriter = new JSonDatabaseWriter.Builder()
48 | .setDbName("db1_gen")
49 | .addTable("names_gen", 3000)
50 | .addTable("cities_gen", 100)
51 | .addTable("states_gen", 100).build();
52 |
53 |
54 | try {
55 | long duration = jSonDatabaseWriter.write(new File("D:\\git\\easy-mobile\\DbSyncSample\\db_gen.json"));
56 | System.out.println("Duration: " + duration + " ms");
57 | System.out.println("Duration: " + duration/1000 + " s");
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | }
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------