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 com.fasterxml.jackson.annotation.JsonIgnore;
021import io.stallion.reflection.PropertyUtils;
022//import org.apache.commons.beanutils.PropertyUtils;
023
024import java.math.BigInteger;
025import java.util.Collection;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.Set;
029
030
031/**
032 * A Model subclass that implements the Map interface and accepts arbitrary
033 * key/value data. This is used by server-side Javascript plugins, which
034 * cannot define standard Java pojos, and this is used to add custom data
035 * to pages, posts, or other objects that are created via text files,
036 * without having go into creating a Java project and writing out classes
037 * that contain the fields.
038 *
039 */
040public interface MappedModel extends Map<String, Object>  {
041    //private Map<String, Object> attributes = new HashMap<String, Object>();
042
043    public default int size() {
044        return toCompleteMap().size();
045    }
046
047    @JsonIgnore
048    public default boolean isEmpty() {
049        return toCompleteMap().isEmpty();
050    }
051
052
053    public default boolean containsKey(String key) {
054        return getAttributes().containsKey(key) || PropertyUtils.isReadable(this, key);
055    }
056
057    public default boolean containsKey(Object key) {
058        return getAttributes().containsKey(key) || PropertyUtils.isReadable(this, key.toString());
059    }
060
061
062    public default boolean containsValue(Object value) {
063        return getAttributes().containsValue(value);
064    }
065
066
067    public default Object get(Object key) {
068        try {
069            if (PropertyUtils.isReadable(this, key.toString())) {
070
071                return PropertyUtils.getProperty(this, key.toString());
072            }
073
074            return getAttributes().get(key);
075        } catch (Exception ex) {
076            throw new RuntimeException(ex);
077        }
078    }
079
080    public default Object put(String key, Object value) {
081        try {
082            if (key.equals("id") || key.equals("lastModifiedMillis") && !(value instanceof Long)) {
083                if (value instanceof Double) {
084                    value = ((Double) value).longValue();
085                } else if (value instanceof Integer) {
086                    value = ((Integer) value).longValue();
087                } else if (value instanceof Float) {
088                    value = ((Float) value).longValue();
089                } else if (value instanceof BigInteger) {
090                    value = ((BigInteger) value).longValue();
091                }
092
093            }
094            if (PropertyUtils.isWriteable(this, key)) {
095                Class cls = null;
096                if (value != null) {
097                    cls = value.getClass();
098                }
099                PropertyUtils.setProperty(this, key, value);
100                return null;
101            } else {
102                return getAttributes().put(key, value);
103            }
104        } catch (Exception ex) {
105            throw new RuntimeException(ex);
106        }
107    }
108
109
110    public default Object remove(Object obj) {
111        return getAttributes().remove(obj);
112    }
113
114
115    public default void putAll(Map<? extends String, ? extends Object> m) {
116        getAttributes().putAll(m);
117    }
118
119
120    public default void clear() {
121
122    }
123
124    public default Set<String> keySet() {
125        return toCompleteMap().keySet();
126    }
127
128
129    public default Collection<Object> values() {
130        return toCompleteMap().values();
131    }
132
133
134    public default Set<Map.Entry<String, Object>> entrySet() {
135        return toCompleteMap().entrySet();
136    }
137
138    default Map<String, Object> toCompleteMap() {
139        Map map = PropertyUtils.getProperties(this, JsonIgnore.class);
140        for(Map.Entry<String, Object> entry: getAttributes().entrySet()) {
141            map.put(entry.getKey(), entry.getValue());
142        }
143        return map;
144    }
145
146    @JsonIgnore
147    public Map<String, Object> getAttributes();
148
149    public void setAttributes(Map<String, Object> attributes);
150
151}