001/*
002 * Stallion Core: A Modern Web Framework
003 *
004 * Copyright (C) 2015 - 2016 Stallion Software LLC.
005 *
006 * This program is free software: you can redistribute it and/or modify it under the terms of the
007 * GNU General Public License as published by the Free Software Foundation, either version 2 of
008 * the License, or (at your option) any later version. This program is distributed in the hope that
009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
011 * License for more details. You should have received a copy of the GNU General Public License
012 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
013 *
014 *
015 *
016 */
017
018package io.stallion.dataAccess;
019
020import io.stallion.dataAccess.filtering.FilterChain;
021
022import java.util.ArrayList;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Set;
026
027/**
028 * The Stash sits between the ModelController and the Persister. ModelController
029 * is what is used externally to access the data. The Persister controls the
030 * interaction between Stallion and the actual data store, whether that be your
031 * file system or database. The Stash can either be a complete pass-through and
032 * do nothing at all, or it can actually sync all the objects from the datastore
033 * into local memory (using LocalMemoryStash).
034 *
035 *
036 * @param <T>
037 */
038public abstract class Stash<T extends Model> {
039    private ModelController<T> controller;
040    private String bucket;
041    private Persister<T> persister;
042    private Class<? extends T> modelClass;
043    private Set<String> keyFields = new HashSet<>();
044    private Set<String> uniqueFields = new HashSet<>();
045
046    /**
047     * Initialized the Stash with required attributes, this is
048     * called via dataAccess registration.
049     *
050     * @param registration
051     * @param controller
052     * @param persister
053     */
054    public void init(DataAccessRegistration registration, ModelController<T> controller, Persister<T> persister) {
055        this.controller = controller;
056        this.bucket = registration.getBucket();
057        this.persister = persister;
058        this.modelClass = (Class<? extends T>)registration.getModelClass();
059    }
060
061    /**
062     * Get the associated controller
063     * @return
064     */
065    public ModelController<T> getController() {
066        return controller;
067    }
068
069    /**
070     * Get the associated persister
071     * @return
072     */
073    public Persister<T> getPersister() {
074        return persister;
075    }
076
077    /**
078     * Get the bucket name
079     * @return
080     */
081    public String getBucket() {
082        return bucket;
083    }
084
085    /**
086     * Get the fields that have been defined as alternative lookup keys. A LocalMemoryStash
087     * will create lookup tables for all these fields, for fast access.
088     *
089     * @return
090     */
091    public Set<String> getKeyFields() {
092        return keyFields;
093    }
094
095
096    public Stash<T> setKeyFields(Set<String> keyFields) {
097        this.keyFields = keyFields;
098        return this;
099    }
100
101    /**
102     * Get the field names that have been defined as unique keys. A LocalMemoryStash
103     * will create lookup tables for all these fields, for fast access.
104     * @return
105     */
106    public Set<String> getUniqueFields() {
107        return uniqueFields;
108    }
109
110
111    public Stash<T> setUniqueFields(Set<String> uniqueFields) {
112        this.uniqueFields = uniqueFields;
113        return this;
114    }
115
116    /**
117     * Take the passed in object, find the object in the stash with the same id, and
118     * sync the data of the passed in object to the stashed object.
119     *
120     * This is used when saving a detached object -- first you have to sync the changes
121     * to the stashed version of the object, then persist it.
122     *
123     * By default, sync will not sync builtin or internal fields
124     *
125     * @param obj
126     */
127    public abstract void sync(T obj);
128
129
130    public void syncForSave(T obj) {
131        sync(obj);
132    }
133
134    /**
135     * Return a cloned version of the object.
136     *
137     * @param obj
138     * @return
139     */
140    public abstract T detach(T obj);
141
142    /**
143     * Save the object to the stash and the underlying data store
144     * @param obj
145     */
146    public abstract void save(T obj);
147
148    /**
149     * Remove the object from the stash and the underlying data store
150     * @param obj
151     */
152    public abstract void hardDelete(T obj);
153
154    /**
155     * Load all items from the datastore into the stash.
156     */
157    public abstract void loadAll();
158
159    /**
160     * Re-load the given object from the datastore into the stash
161     * @param obj
162     */
163    public abstract boolean loadItem(T obj);
164
165    /**
166     * Load or reload the item with the given id from the datastore into the stash
167     * @param id
168     */
169    public abstract void loadForId(Long id);
170
171    /**
172     * All the items in the stash.
173     *
174     * @return
175     */
176    public abstract List<T> getItems();
177
178    /**
179     * Reset the cache, nulling out all existing fields, and then reloading everything from
180     * the database.
181     */
182    public abstract void reset();
183
184    /**
185     * Called before any of the data access methods run
186     */
187    public abstract void onPreRead();
188
189    /**
190     * Reload from the underlying datastore if the stashed version is older
191     * than the version in the datastore.
192     *
193     * @param obj
194     * @return
195     */
196    public T reloadIfNewer(T obj) {
197        return obj;
198    }
199
200    /**
201     * Get a cloned/detached object by id
202     *
203     * @param id
204     * @return
205     */
206    public abstract T forId(Long id);
207
208    /**
209     * Get the original object by id, if modified, the object in the stash
210     * will be modified, so be careful.
211     *
212     * @param id
213     * @return
214     */
215    public abstract T originalForId(Long id);
216
217    /**
218     * Retrieve an object via unique key.
219     *
220     * @param keyName
221     * @param value
222     * @return
223     */
224    public abstract T forUniqueKey(String keyName, Object value);
225
226    /**
227     * Retrieve all objects for a given alternative key
228     *
229     * @param keyName
230     * @param value
231     * @return
232     */
233    public abstract List<T> listForKey(String keyName, Object value);
234
235    /**
236     * Count the number of objects associated with an alternative key
237     *
238     * @param keyName
239     * @param value
240     * @return
241     */
242    public abstract int countForKey(String keyName, Object value);
243
244    /**
245     * Create a new FilterChain for this stash
246     *
247     * @return
248     */
249    public abstract FilterChain<T> filterChain();
250
251    /**
252     * Create a new filterChain, restricting it to items matching the lookupValue for the key
253     *
254     * @param key - a model field that has been defined as a key
255     * @param lookupValue
256     * @return
257     */
258    public abstract FilterChain<T> filterByKey(String key, Object lookupValue);
259
260    /**
261     * Create a new filter chain using a subset of items
262     *
263     * @param subset
264     * @return
265     */
266    public abstract FilterChain<T> filterChain(List<T> subset);
267
268
269
270}