001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005//     http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.beanmodel;
014
015import java.util.List;
016
017import org.apache.tapestry5.beaneditor.DataType;
018import org.apache.tapestry5.beaneditor.RelativePosition;
019
020/**
021 * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
022 * type.
023 *
024 * BeanModels are not thread-safe, they are also not serializable.
025 *
026 * Here, and in {@link org.apache.tapestry5.beanmodel.PropertyModel}, the term "propertyName" is used for simplicitly.
027 * However, a full {@linkplain org.apache.tapestry5.beanmodel.services.PropertyConduitSource#create(Class, String) property
028 * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
029 *
030 * @see org.apache.tapestry5.beanmodel.services.BeanModelSource
031 */
032public interface BeanModel<T>
033{
034    /**
035     * Returns the type of bean for which this model was initially created.
036     */
037    Class<T> getBeanType();
038
039
040    /**
041     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.commons.ObjectLocator#autobuild(Class)},
042     * so a public constructor will be used, and dependencies injected.
043     *
044     * @return new instance of the bean
045     */
046    T newInstance();
047
048    /**
049     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
050     */
051    List<String> getPropertyNames();
052
053    /**
054     * Returns the named model.
055     *
056     * @param propertyName name of property to retrieve model for (case is ignored)
057     * @return the model for the property
058     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
059     */
060    PropertyModel get(String propertyName);
061
062    /**
063     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
064     *
065     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beanmodel.PropertyModel#getId()}
066     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
067     */
068    PropertyModel getById(String propertyId);
069
070    /**
071     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
072     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
073     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
074     * property, use {@link #add(String, org.apache.tapestry5.beanmodel.PropertyConduit)}
075     *
076     * @param propertyName name of property to add
077     * @return the new property model (for further configuration)
078     * @throws RuntimeException if the property already exists
079     */
080    PropertyModel add(String propertyName);
081
082
083    /**
084     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
085     * the <em>end</em> of the list of properties.
086     *
087     * @param propertyName name of property to add
088     * @param expression   expression for the property
089     * @return the new property model (for further configuration)
090     * @throws RuntimeException if the property already exists
091     * @since 5.3
092     */
093    PropertyModel addExpression(String propertyName, String expression);
094
095    /**
096     * Adds an empty property (one with no property conduit).
097     *
098     * @param propertyName name of property to add
099     * @return the new property model (for further configuration)
100     * @throws RuntimeException if the property already exists
101     * @since 5.3
102     */
103    PropertyModel addEmpty(String propertyName);
104
105    /**
106     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
107     *
108     * @param position             controls whether the new property is ordered before or after the existing property
109     * @param existingPropertyName the name of an existing property (this must exist)
110     * @param propertyName         the new property to add
111     * @return the new property model (for further configuration)
112     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
113     */
114    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
115
116    /**
117     * Adds a new property to the model, ordered before or after an existing property.
118     *
119     * @param position             controls whether the new property is ordered before or after the existing property
120     * @param existingPropertyName the name of an existing property (this must exist)
121     * @param propertyName         the new property to add
122     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
123     *                             placeholder property
124     * @return the new property model (for further configuration)
125     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
126     */
127    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
128                      PropertyConduit conduit);
129
130    /**
131     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
132     *
133     * @param propertyName name of property to add
134     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
135     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
136     * @return the model for the property
137     * @throws RuntimeException if the property already exists
138     * @see #addExpression(String, String)
139     */
140    PropertyModel add(String propertyName, PropertyConduit conduit);
141
142    /**
143     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
144     * does not exist.
145     *
146     * @param propertyNames the names of properties to be removed (case insensitive)
147     * @return the model for further modifications
148     */
149    BeanModel<T> exclude(String... propertyNames);
150
151    /**
152     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
153     * retained, but ordered to the end of the list.
154     *
155     * @param propertyNames property names in order they should be displayed (case insensitive)
156     * @return the model for further modifications
157     */
158    BeanModel<T> reorder(String... propertyNames);
159
160    /**
161     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
162     * removed.
163     *
164     * @param propertyNames the names of properties to be retained
165     * @return the model for further modifications
166     */
167    BeanModel<T> include(String... propertyNames);
168}