All Projects → contentful → Vault

contentful / Vault

Licence: apache-2.0
Easy persistence of Contentful data for Android over SQLite.

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Vault

Dexie.js
A Minimalistic Wrapper for IndexedDB
Stars: ✭ 7,337 (+9071.25%)
Mutual labels:  database, storage, offline
Akubra
Simple solution to keep a independent S3 storages in sync
Stars: ✭ 79 (-1.25%)
Mutual labels:  sync, storage
Redux Storage
Persistence layer for redux with flexible backends
Stars: ✭ 681 (+751.25%)
Mutual labels:  database, storage
React Native Background Task
Periodic background tasks for React Native apps, cross-platform (iOS and Android), which run even when the app is closed.
Stars: ✭ 873 (+991.25%)
Mutual labels:  sync, offline
Rxfirebase
Rxjava 2.0 wrapper on Google's Android Firebase library.
Stars: ✭ 509 (+536.25%)
Mutual labels:  database, storage
Db
GroundDB is a thin layer providing Meteor offline database and methods
Stars: ✭ 569 (+611.25%)
Mutual labels:  database, offline
Realm Dotnet
Realm is a mobile database: a replacement for SQLite & ORMs
Stars: ✭ 927 (+1058.75%)
Mutual labels:  sync, database
Mailchimp Api 3.0 Php
A feature rich object-oriented PHP library for interacting with MailChimp's API v3 💌🐵
Stars: ✭ 61 (-23.75%)
Mutual labels:  sync, sdk
Couchbase Lite C
C language bindings for the Couchbase Lite embedded NoSQL database engine
Stars: ✭ 58 (-27.5%)
Mutual labels:  sync, database
Hexa
Hexa: The ultimate companion for Azure. Setup and deploy in seconds
Stars: ✭ 56 (-30%)
Mutual labels:  database, storage
Offline Plugin
Offline plugin (ServiceWorker, AppCache) for webpack (https://webpack.js.org/)
Stars: ✭ 4,444 (+5455%)
Mutual labels:  storage, offline
Directus Docker
Directus 6 Docker — Legacy Container [EOL]
Stars: ✭ 68 (-15%)
Mutual labels:  database, sdk
Sol Journal
✎ Simple, personal journaling progressive web app
Stars: ✭ 470 (+487.5%)
Mutual labels:  database, offline
Weibo Picture Store
🖼 新浪微博图床 Chrome/Firefox 扩展,支持同步到微相册
Stars: ✭ 624 (+680%)
Mutual labels:  sync, storage
App
Directus Admin Application — An Intuitive WebApp for Managing Database Content
Stars: ✭ 464 (+480%)
Mutual labels:  database, sdk
Sleekdb
Pure PHP NoSQL database with no dependency. Flat file, JSON based document database.
Stars: ✭ 450 (+462.5%)
Mutual labels:  database, storage
Firebase Instagram
📸 Instagram clone with Firebase Cloud Firestore, Expo, and React Native 😁😍
Stars: ✭ 389 (+386.25%)
Mutual labels:  database, storage
Dotmim.sync
A brand new database synchronization framework, multi platform, multi databases, developed on top of .Net Standard 2.0. https://dotmimsync.readthedocs.io/
Stars: ✭ 406 (+407.5%)
Mutual labels:  sync, database
Storage Based Queue
Javascript queue library with persistent storage based queue mechanism for the browsers environments. Specially designed for offline.
Stars: ✭ 33 (-58.75%)
Mutual labels:  storage, offline
Oblecto
Oblecto is a media server, which streams media you already own, and is designed to be at the heart of your entertainment experience. It runs on your home server to index and analyze your media such as Movies and TV Shows and presents them in an interface tailored for your media consupmtion needs.
Stars: ✭ 67 (-16.25%)
Mutual labels:  database, storage

Contentful Java SDK
Join Contentful Community Slack   Join Contentful Community Forum

vault - Contentful Offline Persistence for Android

Build Status

Vault is an Android library that simplifies persistence of Resources from Contentful via SQLite. It defines a Java representation of Contentful models. At compile-time Vault creates a corresponding database schema by generating all the required boilerplate code and injecting it into the classpath. It is also bundled with a complementary lightweight runtime which exposes a simple ORM-like API for pulling resources from the generated database.

What is Contentful?

Contentful provides a content infrastructure for digital teams to power content in websites, apps, and devices. Contentful, unlike any other CMS, is built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.

Table of contents

Setup

Install the dependency by

  • Maven
<dependency>
  <groupId>com.contentful.vault</groupId>
  <artifactId>compiler</artifactId>
  <version>3.2.5</version>
</dependency>
<dependency>
  <groupId>com.contentful.vault</groupId>
  <artifactId>core</artifactId>
  <version>3.2.5</version>
</dependency>
  • Gradle
apt 'com.contentful.vault:compiler:3.2.5'
compile 'com.contentful.vault:core:3.2.5'
  • Gradle 3.+
annotationProcessor 'com.contentful.vault:compiler:3.2.5'
annotationProcessor 'com.contentful.vault:core:3.2.5'
compile 'com.contentful.vault:core:3.2.5'

Note for Gradle: Use the android-apt Gradle plugin, which configures compile-time dependencies only. Note for Gradle 3.0 and newer: Use the annotationProcessor instead of apt.

Snapshots

Snapshots of the development version are available in Sonatype's snapshots repository.

Usage

Models and Fields

Models are defined by declaring a subclass of the Resource class. Annotate the class with @ContentType, which takes the Content Type's ID as its value.

Fields are defined by annotating class attributes with the @Field annotation:

@ContentType("cat")
public class Cat extends Resource {
  @Field public String name;
  @Field public Cat bestFriend;
  @Field public Asset image;
}

By default, the name of the attribute is used as the field's ID, but can also be specified explicitly:

@Field("field-id-goes-here") 
public String someField; 

Field ids are escaped, however when making queries with a WHERE condition it is up to the caller to escape the field name in case it is a reserved keyword. For example:

@ContentType("...")
public class Foo extends Resource {
  @Field public String order;
}

Since order is a reserved SQLite keyword, making a query which references that field is done as following:

vault.fetch(Foo.class)
    .where("`" + Foo$Fields.ORDER "` = ?", "bar")
    .first();

Spaces

Spaces are classes annotated with the @Space annotation. It is required to specify the Space ID, an array of Model classes and an array of locale codes wanted to be persisted:

@Space(
    value = "cfexampleapi",
    models = { Cat.class },
    locales = { "en-US", "tlh" }
)
public class DemoSpace { }

Synchronization

Once a Space is defined, Vault is invoked to synchronize the local database with Contentful:

// Client
CDAClient client = CDAClient.builder()
    .setSpace("cfexampleapi")
    .setToken("b4c0n73n7fu1")
    .build();

// Sync
Vault.with(context, DemoSpace.class).requestSync(client);

Vault uses a worker thread to request updates from the Sync API and reflect the changes in its database. Once sync is completed, Vault fires a broadcast with the action Vault.ACTION_SYNC_COMPLETE.

Providing a SyncCallback results in it beeing invoked once sync is completed:

class SomeActivity extends Activity {
  SyncCallback callback;
  
  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    Vault.with(this, DemoSpace.class).requestSync(client, callback = new SyncCallback() {
      @Override public void onResult(SyncResult result) {
        if (result.isSuccessful()) {
          // Success \o/
        } else {
          // Failure
        }
      }
    });
  }
  
  @Override protected void onDestroy() {
    Vault.cancel(callback);
    super.onDestroy();
  }
}

Note: Extra care needs to be taken for the lifecycle: Cancelling the callback on lifecycle events is important.

Similarly using RxJava notifies of sync results via an Observable:

Vault.observeSyncResults() // returns Observable<SyncResult>

Queries

Vault provides a wrapper around its generated database which fetches persisted objects:

Vault vault = Vault.with(context, DemoSpace.class);

// Fetch the first Cat
vault.fetch(Cat.class).first();
    
// Fetch the most recently updated Cat
vault.fetch(Cat.class)
    .order(Cat$Fields.UPDATED_AT + " DESC")
    .first();

// Fetch a Cat with a specific name
vault.fetch(Cat.class)
    .where(Cat$Fields.NAME + " = ?", "Nyan Cat")
    .first();

// Fetch a Cat with a specific name pattern
vault.fetch(Cat.class)
    .where(Cat$Fields.NAME + " LIKE ?", "%Nyan%")
    .first();

// Fetch a Cat with a specific boolean field
// SQLite is storing booleans as 0/1 
vault.fetch(Cat.class)
    .where(Cat$Fields.IS_GRUMPY + " = ?", "1")
    .first();
    
// Fetch all Cats, ordered by creation date:
vault.fetch(Cat.class)
    .order(Cat$Fields.CREATED_AT)
    .all();

// Fetch all Cats, using the Klingon locale:
vault.fetch(Cat.class)
    .all("tlh");

Using RxJava queries are created by the observe() method, for example:

vault.observe(Cat.class)
    .where(Cat$Fields.NAME + " = ?", "Happy Cat")
    .all() // returns Observable<Cat>

The above example creates an Observable that subscribes and observes on the same thread initiating the query. However, it changes if this typical use-case is used:

vault.observe(Cat.class)
    .all()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

Migrations

Whenever changes are introduced to any of the previously used Models, a migration has to be applied. Increment the version number to trigger a migration:

@Space(value = "cfexampleapi", models = { Cat.class }, dbVersion = 2)
public class DemoSpace { }

Note: this deletes any previously persisted data and reaquires them.

Preseeding

Depending on the amount of content in a given space, initial synchronization might take some time. For that support to pre-seed the database with static content got added.

For creating an initial database file, use the VaultDatabaseExporter. This class takes an Android Context and a Vault Space. Calling the .export(..) method, it creates a sqlite database in src/main/assets/initial_seed.db. Vault is instructed to use this as follows:

@Space(
    value = "{spaceid}", // space id of the space to use
    models = { Cat.class },  // model classes to be used
    copyPath = "initial_seed.db" // name of the just created database file.
)
public class VaultSpace { }

The database file is updated by leveraging a robolectric test before releasing. This test syncs Contentful data to the existing database.

A simple test suite looks like this:

@RunWith(RobolectricTestRunner.class)
public class TestSeedDB {
 @literal @Test
  public void testSyncDBtoSqlite() throws Exception {
    final Activity activity = Robolectric.setupActivity(Activity.class);

    assertTrue(new VaultDatabaseExporter().export(activity, VaultSpace.class, VaultSpace.TOKEN));
  }
}

The database content will always be uptodate when those tests get executed. If an error happens this test will fail and information about next steps will be given.

Note: In order to add this functionality to an already shipped app, the dbVersion value has to be increased, as it causes invalidation of any pre-existing content.

ProGuard

Grab the ProGuard configuration file and apply to your project.

Documentation

Javadoc is available here.

License

Copyright 2017 Contentful, GmbH.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Reaching Contentful

Questions

  • Use the community forum: Contentful Community Forum
  • Use the community slack channel: Contentful Community Slack

Bugs and Feature Requests

  • File an issue here File an issue.

Sharing Confidential Information

  • File a support ticket at Contentful Customer Support: File support ticket

Getting involved

PRs Welcome

Code of Conduct

Contentful wants to provide a safe, inclusive, welcoming, and harassment-free space and experience for all participants, regardless of gender identity and expression, sexual orientation, disability, physical appearance, socioeconomic status, body size, ethnicity, nationality, level of experience, age, religion (or lack thereof), or other identity markers.

Full Code of Conduct.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].