001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.model;
018
019import java.io.Serializable;
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.wicket.model.util.CollectionModel;
027import org.apache.wicket.model.util.ListModel;
028import org.apache.wicket.model.util.MapModel;
029import org.apache.wicket.model.util.SetModel;
030import org.apache.wicket.util.lang.Objects;
031
032
033/**
034 * <code>Model</code> is the basic implementation of an <code>IModel</code>. It just wraps a simple
035 * model object. The model object must be serializable, as it is stored in the session. If you have
036 * large objects to store, consider using {@link org.apache.wicket.model.LoadableDetachableModel}
037 * instead of this class.
038 * 
039 * @author Chris Turner
040 * @author Eelco Hillenius
041 * 
042 * @param <T>
043 *            The type of the Model Object
044 */
045public class Model<T extends Serializable> implements IObjectClassAwareModel<T>
046{
047        private static final long serialVersionUID = 1L;
048
049        /** Backing object. */
050        private T object;
051
052        /**
053         * Construct the model without providing an object.
054         */
055        public Model()
056        {
057        }
058
059        /**
060         * Construct the model, setting the given object as the wrapped object.
061         * 
062         * @param object
063         *            The model object proper
064         */
065        public Model(final T object)
066        {
067                setObject(object);
068        }
069
070        /**
071         * Factory method for models that contain lists. This factory method will automatically rebuild
072         * a non-serializable <code>list</code> into a serializable one.
073         * 
074         * @param <C>
075         *            model type
076         * @param list
077         *            The List, which may or may not be Serializable
078         * @return A Model object wrapping the List
079         */
080        public static <C> IModel<List<C>> ofList(final List<C> list)
081        {
082                return new ListModel<>(list);
083        }
084
085        /**
086         * Factory method for models that contain maps. This factory method will automatically rebuild a
087         * non-serializable <code>map</code> into a serializable one.
088         * 
089         * @param <K>
090         *            key type in map
091         * @param <V>
092         *            value type in map
093         * @param map
094         *            The Map, which may or may not be Serializable
095         * @return A Model object wrapping the Map
096         */
097        public static <K, V> IModel<Map<K, V>> ofMap(final Map<K, V> map)
098        {
099                return new MapModel<>(map);
100        }
101
102        /**
103         * Factory method for models that contain sets. This factory method will automatically rebuild a
104         * non-serializable <code>set</code> into a serializable one.
105         * 
106         * @param <C>
107         *            model type
108         * @param set
109         *            The Set, which may or may not be Serializable
110         * @return A Model object wrapping the Set
111         */
112        public static <C> IModel<Set<C>> ofSet(final Set<C> set)
113        {
114                return new SetModel<>(set);
115        }
116
117        /**
118         * Factory method for models that contain collections. This factory method will automatically
119         * rebuild a non-serializable <code>collection</code> into a serializable {@link ArrayList}.
120         * 
121         * @param <C>
122         *            model type
123         * @param collection
124         *            The Collection, which may or may not be Serializable
125         * @return A Model object wrapping the Set
126         */
127        public static <C> IModel<Collection<C>> of(final Collection<C> collection)
128        {
129                return new CollectionModel<>(collection);
130        }
131
132
133        /**
134         * Factory methods for Model which uses type inference to make code shorter. Equivalent to
135         * <code>new Model<TypeOfObject>(object)</code>.
136         * 
137         * @param <T>
138         * @param object
139         * @return Model that contains <code>object</code>
140         */
141        public static <T extends Serializable> Model<T> of(T object)
142        {
143                return new Model<>(object);
144        }
145
146        /**
147         * Factory methods for Model which uses type inference to make code shorter. Equivalent to
148         * <code>new Model<TypeOfObject>()</code>.
149         * 
150         * @param <T>
151         * @return Model that contains <code>object</code>
152         */
153        public static <T extends Serializable> Model<T> of()
154        {
155                return new Model<>();
156        }
157
158        @Override
159        public T getObject()
160        {
161                return object;
162        }
163
164        /**
165         * Set the model object; calls setObject(java.io.Serializable). The model object must be
166         * serializable, as it is stored in the session
167         * 
168         * @param object
169         *            the model object
170         * @see org.apache.wicket.model.IModel#setObject(Object)
171         */
172        @Override
173        public void setObject(final T object)
174        {
175                this.object = object;
176        }
177
178        @Override
179        public void detach()
180        {
181                if (object instanceof IDetachable)
182                {
183                        ((IDetachable)object).detach();
184                }
185        }
186
187        @Override
188        public String toString()
189        {
190                StringBuilder sb = new StringBuilder("Model:classname=[");
191                sb.append(getClass().getName()).append(']');
192                sb.append(":object=[").append(object).append(']');
193                return sb.toString();
194        }
195
196        @Override
197        public int hashCode()
198        {
199                return Objects.hashCode(object);
200        }
201
202        @Override
203        public boolean equals(Object obj)
204        {
205                if (this == obj)
206                {
207                        return true;
208                }
209                if (!(obj instanceof Model<?>))
210                {
211                        return false;
212                }
213                Model<?> that = (Model<?>)obj;
214                return Objects.equal(object, that.object);
215        }
216
217        @SuppressWarnings("unchecked")
218        @Override
219        public Class<T> getObjectClass()
220        {
221                return object != null ? (Class<T>) object.getClass() : null;
222        }
223}