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;
021import io.stallion.dataAccess.filtering.FilterOperator;
022import io.stallion.reflection.PropertyUtils;
023import io.stallion.services.Log;
024import io.stallion.settings.Settings;
025
026
027import java.util.*;
028
029import static io.stallion.utils.Literals.or;
030import static io.stallion.utils.Literals.set;
031
032/**
033 * The standard implementation of a ModelController. You should almost certainly
034 * use this as the base for your own model controllers.
035 *
036 * @param <T>
037 */
038public class StandardModelController<T extends Model> implements ModelController<T> {
039    private String bucket;
040    private Stash<T> stash;
041    private Persister persister;
042    private Boolean writable;
043    private ReadOnlyWrapper<T> readOnlyWrapper;
044    private Class<T> modelClass;
045
046    public StandardModelController() {
047    }
048
049
050
051    protected void preInitialize(DataAccessRegistration registration) {
052
053    }
054
055    protected void postInitialize(DataAccessRegistration registration) {
056
057    }
058
059
060    @Override
061    public void init(DataAccessRegistration registration, Persister<T> persister, Stash<T> stash) {
062        this.bucket = registration.getBucket();
063        this.persister = persister;
064        this.stash = stash;
065        this.writable = registration.isWritable();
066        this.modelClass = (Class<T>)registration.getModelClass();
067        if (this instanceof DisplayableModelController) {
068            DisplayableModelController c = (DisplayableModelController)this;
069            c.setDefaultTemplate(or(registration.getTemplatePath(), Settings.instance().getPageTemplate()));
070        }
071    }
072
073    @Override
074    public String getBucket() {
075        return this.bucket;
076    }
077
078    /**
079     * Instantiates a new item instance from the model class.
080     *
081     * @return
082     */
083    public T newModel() {
084        return newModel(null);
085    }
086
087    /**
088     * Instantiates a new item instance, assigning the values passed in with the map
089     * @param o
090     * @return
091     */
092    public T newModel(Map o) {
093        return newModel(o, new String[]{});
094    }
095
096    public T newModel(Map o, String ...fields) {
097        Set fieldSet = null;
098        if (fields != null && fields.length > 0) {
099            fieldSet = set(fields);
100        }
101
102        try {
103            T model = getModelClass().newInstance();
104            if (o != null && o.size() > 0) {
105                for(Object key: o.keySet()) {
106                    if (fieldSet != null && !fieldSet.contains(key)) {
107                        continue;
108                    }
109                    Object value = o.get(key);
110                    PropertyUtils.setProperty(model, key.toString(), value);
111                }
112            }
113            return model;
114        } catch (InstantiationException e) {
115            throw new RuntimeException(e);
116        } catch (IllegalAccessException e) {
117            throw new RuntimeException(e);
118        }
119    }
120
121    @Override
122    public T detach(T obj) {
123        return getStash().detach(obj);
124    }
125
126
127
128    @Override
129    public void save(T obj)  {
130        T existing = this.forIdWithDeleted(obj.getId());
131        if (existing == null) {
132            Log.finer("Existing object not found. {0} new={1} id={2}", getBucket(), obj.hashCode(), obj.getId());
133            onPreCreatePrepare(obj);
134            onPreSavePrepare(obj);
135            onPreCreateValidate(obj);
136            onPreSaveValidate(obj);
137            getStash().save(obj);
138            onPostCreate(obj);
139        } else {
140            Log.finer("Existing found. {0} existing={1} new={2} id={3}", getBucket(), existing.hashCode(), obj.hashCode(), obj.getId());
141            onPreSavePrepare(obj);
142            onPreSaveValidate(obj);
143            getStash().save(obj);
144            onPostSave(obj);
145        }
146    }
147
148    @Override
149    public void softDelete(T obj)  {
150        obj.setDeleted(true);
151        this.save(obj);
152    }
153
154    @Override
155    public void hardDelete(T obj)  {
156        getStash().hardDelete(obj);
157    }
158
159
160    @Override
161    public void onPreSavePrepare(T obj) {
162
163    }
164
165    @Override
166    public void onPreSaveValidate(T obj) {
167
168    }
169
170    @Override
171    public void onPreCreatePrepare(T obj) {
172
173    }
174
175    @Override
176    public void onPreCreateValidate(T obj) {
177
178    }
179
180    @Override
181    public void onPostSave(T obj) {
182
183    }
184
185    @Override
186    public void onPostCreate(T obj) {
187
188    }
189
190
191    @Override
192    @Deprecated
193    public void onPreRead() {
194
195    }
196
197
198    public void onPostLoadItem(T item) {
199
200    }
201
202    @Override
203    public FilterChain<T> filterChain() {
204        return getStash().filterChain();
205    }
206
207    @Override
208    public FilterChain<T> filter(String name, Object value)  {
209        return filterChain().filter(name, value);
210    }
211
212    @Override
213    public FilterChain<T> filter(String name, Object value, String op)  {
214        return filterChain().filter(name, value, op);
215    }
216
217    @Override
218    public FilterChain<T> filterBy(String name, Object value, FilterOperator op)  {
219        return filterChain().filterBy(name, value, op);
220    }
221
222    @Override
223    public FilterChain<T> filterByKey(String keyName, Object value)  {
224        return getStash().filterByKey(keyName, value);
225    }
226
227
228    @Override
229    public T originalForId(T id) {
230        return null;
231    }
232
233
234    @Override
235    public T forId(Long id) {
236        T o = getStash().forId(id);
237        if (o == null) {
238            return o;
239        }
240        if (o.getDeleted() != null && o.getDeleted() == true) {
241            return null;
242        }
243        return o;
244    }
245
246    @Override
247    public T forIdWithDeleted(Long id) {
248        return getStash().forId(id);
249    }
250
251    @Override
252    public T originalForId(Long id) {
253        return getStash().originalForId(id);
254    }
255
256    @Override
257    public T forUniqueKey(String keyName, Object keyValue)  {
258        return getStash().forUniqueKey(keyName, keyValue);
259    }
260
261    @Override
262    public List<T> listForKey(String keyName, Object value) {
263        return getStash().listForKey(keyName, value);
264    }
265
266    @Override
267    public int countForKey(String keyName, Object value)  {
268        return getStash().countForKey(keyName, value);
269    }
270
271
272    @Override
273    public List<T> all()  {
274        return filterChain().all();
275    }
276
277    @Override
278    public void reset() {
279        getStash().reset();
280    }
281
282    public Persister getPersister() {
283        return this.persister;
284    }
285
286    @Override
287    public Stash<T> getStash() {
288        return this.stash;
289    }
290
291    @Override
292    public Class<T> getModelClass() {
293        return this.modelClass;
294    }
295
296    public void setPersister(Persister persister) {
297        this.persister = persister;
298    }
299
300    @Override
301    public Set<String> getKeyFields() {
302        return getStash().getKeyFields();
303    }
304
305    @Override
306    public Set<String> getUniqueFields() {
307        return getStash().getUniqueFields();
308    }
309
310    @Override
311    public Boolean isWritable() {
312        return writable;
313    }
314
315
316    public void setWritable(Boolean writable) {
317        this.writable = writable;
318    }
319
320    public ReadOnlyWrapper<T> getReadonlyWrapper() {
321        if (readOnlyWrapper == null) {
322            readOnlyWrapper = new ReadOnlyWrapper<>(this);
323        }
324        return readOnlyWrapper;
325    }
326}