First pass creating the BeanModel and Commons packages. Lots of stuff moved 
around, but no actual code changes so far


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/3d4de7e1
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/3d4de7e1
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/3d4de7e1

Branch: refs/heads/master
Commit: 3d4de7e112d5ba040171d380e1c041372556769d
Parents: 9b5e190
Author: Thiago H. de Paula Figueiredo <thiag...@apache.org>
Authored: Sat Dec 6 15:16:02 2014 -0200
Committer: Thiago H. de Paula Figueiredo <thiag...@apache.org>
Committed: Sat Dec 6 20:32:39 2014 -0200

----------------------------------------------------------------------
 beanmodel/build.gradle                          |   27 +
 .../org/apache/tapestry5/PropertyConduit.java   |   45 +
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 +
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 ++
 .../tapestry5/beaneditor/PropertyModel.java     |   97 ++
 .../internal/InternalPropertyConduit.java       |   37 +
 .../internal/beaneditor/BeanModelImpl.java      |  289 ++++
 .../internal/beaneditor/PropertyModelImpl.java  |  139 ++
 .../CoercingPropertyConduitWrapper.java         |   67 +
 .../services/PropertyConduitDelegate.java       |   53 +
 .../services/PropertyConduitSourceImpl.java     | 1563 ++++++++++++++++++
 .../tapestry5/services/BeanModelSource.java     |   70 +
 .../services/PropertyConduitSource.java         |   41 +
 commons/build.gradle                            |   18 +
 .../tapestry5/internal/util/IntegerRange.java   |  125 ++
 .../tapestry5/internal/util/MultiKey.java       |   86 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 +
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 +
 .../java/org/apache/tapestry5/ioc/Location.java |   38 +
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 +
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 +
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 ++
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 ++
 .../ioc/internal/NullAnnotationProvider.java    |   35 +
 .../ioc/internal/util/CollectionFactory.java    |  139 ++
 .../ioc/internal/util/GenericsUtils.java        |  615 +++++++
 .../ioc/internal/util/TapestryException.java    |   75 +
 .../ioc/services/ClassPropertyAdapter.java      |   79 +
 .../apache/tapestry5/ioc/services/Coercion.java |   31 +
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 ++
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 +
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 ++
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 +
 .../tapestry5/ioc/util/AvailableValues.java     |   87 +
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ++++++
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 ++
 .../ioc/util/UnknownValueException.java         |   47 +
 .../services/InvalidationEventHub.java          |   60 +
 .../services/InvalidationListener.java          |   33 +
 settings.gradle                                 |    2 +-
 tapestry-core/build.gradle                      |    6 +-
 .../org/apache/tapestry5/PropertyConduit.java   |   45 -
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 -
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 --
 .../tapestry5/beaneditor/PropertyModel.java     |   97 --
 .../internal/InternalPropertyConduit.java       |   37 -
 .../internal/beaneditor/BeanModelImpl.java      |  289 ----
 .../internal/beaneditor/PropertyModelImpl.java  |  139 --
 .../CoercingPropertyConduitWrapper.java         |   67 -
 .../services/PropertyConduitDelegate.java       |   53 -
 .../services/PropertyConduitSourceImpl.java     | 1563 ------------------
 .../tapestry5/internal/util/IntegerRange.java   |  125 --
 .../tapestry5/internal/util/MultiKey.java       |   86 -
 .../tapestry5/services/BeanModelSource.java     |   70 -
 .../tapestry5/services/ComponentClasses.java    |   35 -
 .../tapestry5/services/ComponentLayer.java      |   37 -
 .../services/InvalidationEventHub.java          |   60 -
 .../services/InvalidationListener.java          |   33 -
 .../services/PropertyConduitSource.java         |   41 -
 tapestry-ioc/build.gradle                       |    1 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 -
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 -
 .../java/org/apache/tapestry5/ioc/Location.java |   38 -
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 -
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 -
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 --
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 --
 .../ioc/annotations/UsesConfiguration.java      |   34 -
 .../ioc/internal/NullAnnotationProvider.java    |   35 -
 .../ioc/internal/util/CollectionFactory.java    |  139 --
 .../ioc/internal/util/GenericsUtils.java        |  615 -------
 .../ioc/internal/util/TapestryException.java    |   75 -
 .../ioc/services/ClassPropertyAdapter.java      |   79 -
 .../apache/tapestry5/ioc/services/Coercion.java |   31 -
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 --
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 -
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 --
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 -
 .../tapestry5/ioc/util/AvailableValues.java     |   87 -
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ------
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 --
 .../ioc/util/UnknownValueException.java         |   47 -
 tapestry5-annotations/build.gradle              |    2 +-
 .../ioc/annotations/UsesConfiguration.java      |   34 +
 .../tapestry5/services/ComponentClasses.java    |   35 +
 .../tapestry5/services/ComponentLayer.java      |   37 +
 86 files changed, 5664 insertions(+), 5622 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
new file mode 100644
index 0000000..ccdeb37
--- /dev/null
+++ b/beanmodel/build.gradle
@@ -0,0 +1,27 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Fast class property discovery, reading and writing library 
based on bytecode generation. Extracted from Apache Tapestry, but not dependent 
on the Web framework (tapestry-core) not the IoC one (tapestry-ioc)."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+       
+project.ext.libraryVersions = [
+       jcache: '1.0.0',
+]
+
+dependencies {
+       compile project(":plastic")
+       compile project(":tapestry5-annotations")
+       compile project(":commons")
+       // Transitive will bring in the unwanted string template library as well
+       compile "org.antlr:antlr-runtime:3.5.2", {
+               exclude group: "org.antlr", module: "stringtemplate"
+       }
+}
+
+jar {  
+       manifest {      
+       }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java 
b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
new file mode 100644
index 0000000..3dbb0c0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
@@ -0,0 +1,45 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Used to read or update the value associated with a property. A 
PropertyConduit provides access to the annotations on
+ * the underlying getter and/or setter methods.
+ */
+public interface PropertyConduit extends AnnotationProvider
+{
+    /**
+     * Reads the property from the instance.
+     *
+     * @param instance object containing the property
+     * @return the current value of the property
+     */
+    Object get(Object instance);
+
+    /**
+     * Changes the current value of the property.
+     *
+     * @param instance object containing the property
+     * @param value    to change the property to
+     */
+    void set(Object instance, Object value);
+
+    /**
+     * Returns the type of the property read or updated by the conduit.
+     */
+    Class getPropertyType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java 
b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
new file mode 100644
index 0000000..839d70f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -0,0 +1,40 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+
+/**
+ * Extension to {@link PropertyConduit} that adds a method to access the 
generic property type.
+ * {@link PropertyConduitSource} instances should ideally return 
PropertyConduit2 objects, not PropertyConduit.
+ * This is only primarily of interest to {@link Binding2}.
+ * 
+ * @since 5.4
+ */
+public interface PropertyConduit2 extends PropertyConduit
+{
+    /**
+     * Returns the generic type of the property
+     * 
+     * @see Method#getGenericReturnType()
+     * @see java.lang.reflect.Field#getGenericType()
+     * 
+     */
+       Type getPropertyGenericType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java 
b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
new file mode 100644
index 0000000..0a60fd7
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
@@ -0,0 +1,169 @@
+// Copyright 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+
+import java.util.List;
+
+/**
+ * Provides the information necessary to build a user interface to view, 
create or edit an instance of a particular
+ * type.
+ * <p/>
+ * BeanModels are not thread-safe, they are also not serializable.
+ * <p/>
+ * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the 
term "propertyName" is used for simplicitly.
+ * However, a full {@linkplain 
org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) 
property
+ * expression} may be utilized when {@linkplain #add(String) adding new 
properties to an existing BeanModel}.
+ *
+ * @see org.apache.tapestry5.services.BeanModelSource
+ */
+public interface BeanModel<T>
+{
+    /**
+     * Returns the type of bean for which this model was initially created.
+     */
+    Class<T> getBeanType();
+
+
+    /**
+     * Creates a new bean instance.  This is based on {@link 
org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
+     * so a public constructor will be used, and dependencies injected.
+     *
+     * @return new instance of the bean
+     */
+    T newInstance();
+
+    /**
+     * Returns a list of the editable properties of the bean, in 
<em>presentation</em> order.
+     */
+    List<String> getPropertyNames();
+
+    /**
+     * Returns the named model.
+     *
+     * @param propertyName name of property to retrieve model for (case is 
ignored)
+     * @return the model for the property
+     * @throws RuntimeException if the bean editor model does not have a 
property model for the provided name
+     */
+    PropertyModel get(String propertyName);
+
+    /**
+     * Returns the identified model.  Property ids are a stripped version of 
the property name. Case is ignored.
+     *
+     * @param propertyId matched caselessly against {@link 
org.apache.tapestry5.beaneditor.PropertyModel#getId()}
+     * @throws RuntimeException if the bean editor model does not have a 
property model with the indicated id
+     */
+    PropertyModel getById(String propertyId);
+
+    /**
+     * Adds a new property to the model, returning its mutable model for 
further refinement. The property is added to
+     * the <em>end</em> of the list of properties. The property must be real 
(but may have been excluded if there was no
+     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} 
associated with the property). To add a synthetic
+     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     */
+    PropertyModel add(String propertyName);
+
+
+    /**
+     * Adds a new synthetic property to the model, returning its mutable model 
for further refinement. The property is added to
+     * the <em>end</em> of the list of properties.
+     *
+     * @param propertyName name of property to add
+     * @param expression   expression for the property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addExpression(String propertyName, String expression);
+
+    /**
+     * Adds an empty property (one with no property conduit).
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addEmpty(String propertyName);
+
+    /**
+     * Adds a new property to the model (as with {@link #add(String)}), 
ordered before or after an existing property.
+     *
+     * @param position             controls whether the new property is 
ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must 
exist)
+     * @param propertyName         the new property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, 
String propertyName);
+
+    /**
+     * Adds a new property to the model, ordered before or after an existing 
property.
+     *
+     * @param position             controls whether the new property is 
ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must 
exist)
+     * @param propertyName         the new property to add
+     * @param conduit              conduit used to read or update the 
property; this may be null for a synthetic or
+     *                             placeholder property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, 
String propertyName,
+                      PropertyConduit conduit);
+
+    /**
+     * Adds a new, synthetic property to the model, returning its mutable 
model for further refinement.
+     *
+     * @param propertyName name of property to add
+     * @param conduit      the conduit used to read or update the property; 
this may be null for a synthetic or
+     *                     placeholder property.  Instead of passing null, 
please invoke {@link #addEmpty(String)}.
+     * @return the model for the property
+     * @throws RuntimeException if the property already exists
+     * @see #addExpression(String, String)
+     */
+    PropertyModel add(String propertyName, PropertyConduit conduit);
+
+    /**
+     * Removes the named properties from the model, if present. It is not 
considered an error to remove a property that
+     * does not exist.
+     *
+     * @param propertyNames the names of properties to be removed (case 
insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> exclude(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. 
Existing properties that are not indicated are
+     * retained, but ordered to the end of the list.
+     *
+     * @param propertyNames property names in order they should be displayed 
(case insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> reorder(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. 
Existing properties that are not indicated are
+     * <<removed>>.
+     *
+     * @param propertyNames the names of properties to be retained
+     * @return the model for further modifications
+     */
+    BeanModel<T> include(String... propertyNames);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java 
b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
new file mode 100644
index 0000000..6095fb9
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
@@ -0,0 +1,97 @@
+// Copyright 2007, 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Part of a {@link org.apache.tapestry5.beaneditor.BeanModel} that defines 
the attributes of a single property of a
+ * bean.
+ * <p/>
+ * <p/>
+ * A PropertyModel is also an {@link AnnotationProvider}, as long as the 
{@link org.apache.tapestry5.PropertyConduit} is
+ * non-null.  When there is no property conduit, then {@link 
org.apache.tapestry5.ioc.AnnotationProvider#getAnnotation(Class)}
+ * will return null.
+ */
+public interface PropertyModel extends AnnotationProvider
+{
+    /**
+     * Returns the name of the property (which may, in fact, be a property 
expression).
+     */
+    String getPropertyName();
+
+    /**
+     * Returns the id used to access other resources (this is based on the 
property name, but with any excess
+     * punctuation stripped out).
+     */
+    String getId();
+
+    /**
+     * Returns a user-presentable label for the property.
+     */
+    String getLabel();
+
+    /**
+     * Returns the type of the property.
+     */
+    Class getPropertyType();
+
+    /**
+     * Returns a logical name for the type of UI needed to view or edit the 
property. This is initially determined from
+     * the property type.
+     */
+    String getDataType();
+
+    /**
+     * Changes the data type for the property.
+     *
+     * @param dataType
+     * @return the property model, for further changes
+     */
+    PropertyModel dataType(String dataType);
+
+    /**
+     * Returns an object used to read or update the property. For virtual 
properties (properties that do not actually
+     * exist on the bean), the conduit may be null.
+     */
+    PropertyConduit getConduit();
+
+    /**
+     * Changes the label for the property to the provided value.
+     *
+     * @param label new label for property
+     * @return the property model, for further changes
+     */
+    PropertyModel label(String label);
+
+    /**
+     * Returns the containing model, often used for "fluent" construction of 
the model.
+     */
+    BeanModel model();
+
+    /**
+     * Returns true if the property can be used for sorting. By default, this 
is true only if the property type
+     * implements Comparable.
+     */
+    boolean isSortable();
+
+    /**
+     * Updates sortable and returns the model for further changes.
+     *
+     * @return the property model, for further changes
+     */
+    PropertyModel sortable(boolean sortable);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
new file mode 100644
index 0000000..315b372
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
@@ -0,0 +1,37 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal;
+
+import org.apache.tapestry5.PropertyConduit2;
+
+
+/**
+ * Extension to {@link org.apache.tapestry5.PropertyConduit2} that adds a 
method to determine the name of the property.
+ * 
+ * @since 5.2.0
+ *
+ */
+public interface InternalPropertyConduit extends PropertyConduit2
+{
+    /**
+     * Returns the name of the property read or updated by the conduit or 
null. 
+     * If the expression points to a property on a bean (e.g. user.name) this 
method returns the last property in the chain. 
+     * Otherwise this method returns {@code null}.
+     * 
+     * @return property name or {@code null}
+     * 
+     */
+    String getPropertyName();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
new file mode 100644
index 0000000..26eb309
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -0,0 +1,289 @@
+// Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.PropertyModel;
+import org.apache.tapestry5.beaneditor.RelativePosition;
+import org.apache.tapestry5.internal.services.CoercingPropertyConduitWrapper;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.util.List;
+import java.util.Map;
+
+public class BeanModelImpl<T> implements BeanModel<T>
+{
+    private final Class<T> beanType;
+
+    private final PropertyConduitSource propertyConduitSource;
+
+    private final TypeCoercer typeCoercer;
+
+    private final Messages messages;
+
+    private final ObjectLocator locator;
+
+    private final Map<String, PropertyModel> properties = 
CollectionFactory.newCaseInsensitiveMap();
+
+    // The list of property names, in desired order (generally not 
alphabetical order).
+
+    private final List<String> propertyNames = CollectionFactory.newList();
+
+    private static PropertyConduit NULL_PROPERTY_CONDUIT = null;
+
+    public BeanModelImpl(Class<T> beanType, PropertyConduitSource 
propertyConduitSource, TypeCoercer typeCoercer,
+                         Messages messages, ObjectLocator locator)
+
+    {
+        this.beanType = beanType;
+        this.propertyConduitSource = propertyConduitSource;
+        this.typeCoercer = typeCoercer;
+        this.messages = messages;
+        this.locator = locator;
+    }
+
+    public Class<T> getBeanType()
+    {
+        return beanType;
+    }
+
+    public T newInstance()
+    {
+        return locator.autobuild("Instantiating new instance of " + 
beanType.getName(), beanType);
+    }
+
+    public PropertyModel add(String propertyName)
+    {
+        return addExpression(propertyName, propertyName);
+    }
+
+    public PropertyModel addEmpty(String propertyName)
+    {
+        return add(propertyName, NULL_PROPERTY_CONDUIT);
+    }
+
+    public PropertyModel addExpression(String propertyName, String expression)
+    {
+        PropertyConduit conduit = createConduit(expression);
+
+        return add(propertyName, conduit);
+
+    }
+
+    private void validateNewPropertyName(String propertyName)
+    {
+        assert InternalUtils.isNonBlank(propertyName);
+        if (properties.containsKey(propertyName))
+            throw new RuntimeException(String.format(
+                    "Bean editor model for %s already contains a property 
model for property '%s'.",
+                    beanType.getName(), propertyName));
+    }
+
+    public PropertyModel add(RelativePosition position, String 
existingPropertyName, String propertyName,
+                             PropertyConduit conduit)
+    {
+        assert position != null;
+        validateNewPropertyName(propertyName);
+
+        // Locate the existing one.
+
+        PropertyModel existing = get(existingPropertyName);
+
+        // Use the case normalized property name.
+
+        int pos = propertyNames.indexOf(existing.getPropertyName());
+
+        PropertyModel newModel = new PropertyModelImpl(this, propertyName, 
conduit, messages);
+
+        properties.put(propertyName, newModel);
+
+        int offset = position == RelativePosition.AFTER ? 1 : 0;
+
+        propertyNames.add(pos + offset, propertyName);
+
+        return newModel;
+    }
+
+    public PropertyModel add(RelativePosition position, String 
existingPropertyName, String propertyName)
+    {
+        PropertyConduit conduit = createConduit(propertyName);
+
+        return add(position, existingPropertyName, propertyName, conduit);
+    }
+
+    public PropertyModel add(String propertyName, PropertyConduit conduit)
+    {
+        validateNewPropertyName(propertyName);
+
+        PropertyModel propertyModel = new PropertyModelImpl(this, 
propertyName, conduit, messages);
+
+        properties.put(propertyName, propertyModel);
+
+        // Remember the order in which the properties were added.
+
+        propertyNames.add(propertyName);
+
+        return propertyModel;
+    }
+
+    private CoercingPropertyConduitWrapper createConduit(String propertyName)
+    {
+        return new 
CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType, 
propertyName), typeCoercer);
+    }
+
+    public PropertyModel get(String propertyName)
+    {
+        PropertyModel propertyModel = properties.get(propertyName);
+
+        if (propertyModel == null)
+            throw new UnknownValueException(String.format(
+                    "Bean editor model for %s does not contain a property 
named '%s'.", beanType.getName(),
+                    propertyName), new AvailableValues("Defined properties", 
propertyNames));
+
+        return propertyModel;
+    }
+
+    public PropertyModel getById(String propertyId)
+    {
+        for (PropertyModel model : properties.values())
+        {
+            if (model.getId().equalsIgnoreCase(propertyId))
+                return model;
+        }
+
+        // Not found, so we throw an exception. A bit of work to set
+        // up the exception however.
+
+        List<String> ids = CollectionFactory.newList();
+
+        for (PropertyModel model : properties.values())
+        {
+            ids.add(model.getId());
+        }
+
+        throw new UnknownValueException(String.format(
+                "Bean editor model for %s does not contain a property with id 
'%s'.", beanType.getName(), propertyId),
+                new AvailableValues("Defined property ids", ids));
+    }
+
+    public List<String> getPropertyNames()
+    {
+        return CollectionFactory.newList(propertyNames);
+    }
+
+    public BeanModel<T> exclude(String... propertyNames)
+    {
+        for (String propertyName : propertyNames)
+        {
+            PropertyModel model = properties.get(propertyName);
+
+            if (model == null)
+                continue;
+
+            // De-referencing from the model is needed because the name 
provided may not be a
+            // case-exact match, so we get the normalized or canonical name 
from the model because
+            // that's the one in propertyNames.
+
+            this.propertyNames.remove(model.getPropertyName());
+
+            properties.remove(propertyName);
+        }
+
+        return this;
+    }
+
+    public BeanModel<T> reorder(String... propertyNames)
+    {
+        List<String> remainingPropertyNames = 
CollectionFactory.newList(this.propertyNames);
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyModel model = get(name);
+
+            // Get the canonical form (which may differ from name in terms of 
case)
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+
+            remainingPropertyNames.remove(canonical);
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        // Any unspecified names are ordered to the end. Don't want them? 
Remove them instead.
+        this.propertyNames.addAll(remainingPropertyNames);
+
+        return this;
+    }
+
+    public BeanModel<T> include(String... propertyNames)
+    {
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+        Map<String, PropertyModel> reduced = 
CollectionFactory.newCaseInsensitiveMap();
+
+        for (String name : propertyNames)
+        {
+
+            PropertyModel model = get(name);
+
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+            reduced.put(canonical, model);
+
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        properties.clear();
+        properties.putAll(reduced);
+
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("BeanModel[");
+        builder.append(PlasticUtils.toTypeName(beanType));
+
+        builder.append(" properties:");
+        String sep = "";
+
+        for (String name : propertyNames)
+        {
+            builder.append(sep);
+            builder.append(name);
+
+            sep = ", ";
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
new file mode 100644
index 0000000..703ce44
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -0,0 +1,139 @@
+// Copyright 2007, 2008, 2010, 2011, 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.PropertyModel;
+import org.apache.tapestry5.beaneditor.Sortable;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.lang.annotation.Annotation;
+
+@SuppressWarnings("all")
+public class PropertyModelImpl implements PropertyModel
+{
+    private final BeanModel model;
+
+    private final String name;
+
+    private final PropertyConduit conduit;
+
+    private final String id;
+
+    private String label;
+
+    private String dataType;
+
+    private boolean sortable;
+
+    public PropertyModelImpl(BeanModel model, String name, PropertyConduit 
conduit, Messages messages)
+    {
+        this.model = model;
+        this.name = name;
+        this.conduit = conduit;
+
+        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+
+        label = TapestryInternalUtils.defaultLabel(id, messages, name);
+
+        // TAP5-2305
+        if (conduit != null)
+        {
+            Sortable sortableAnnotation = 
conduit.getAnnotation(Sortable.class);
+            if (sortableAnnotation != null)
+            {
+                sortable = sortableAnnotation.value();
+            }
+            else
+            {
+                // Primitive types need to be converted to wrapper types 
before checking to see
+                // if they are sortable.
+                Class wrapperType = 
PlasticUtils.toWrapperType(getPropertyType());
+                sortable = Comparable.class.isAssignableFrom(wrapperType);
+            }
+        }
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit == null ? Object.class : conduit.getPropertyType();
+    }
+
+    public PropertyConduit getConduit()
+    {
+        return conduit;
+    }
+
+    public PropertyModel label(String label)
+    {
+        assert InternalUtils.isNonBlank(label);
+        this.label = label;
+
+        return this;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public String getPropertyName()
+    {
+        return name;
+    }
+
+    public BeanModel model()
+    {
+        return model;
+    }
+
+    public PropertyModel dataType(String dataType)
+    {
+        this.dataType = dataType;
+
+        return this;
+    }
+
+    public String getDataType()
+    {
+        return dataType;
+    }
+
+    public boolean isSortable()
+    {
+        return sortable;
+    }
+
+    public PropertyModel sortable(boolean sortable)
+    {
+        this.sortable = sortable;
+
+        return this;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit == null ? null : conduit.getAnnotation(annotationClass);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
new file mode 100644
index 0000000..4dbfb2d
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -0,0 +1,67 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+public class CoercingPropertyConduitWrapper implements PropertyConduit2
+{
+    private final PropertyConduit conduit;
+
+    private final TypeCoercer coercer;
+
+    public CoercingPropertyConduitWrapper(final PropertyConduit conduit, final 
TypeCoercer coercer)
+    {
+        this.conduit = conduit;
+        this.coercer = coercer;
+    }
+
+    public Object get(Object instance)
+    {
+        return conduit.get(instance);
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit.getAnnotation(annotationClass);
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit.getPropertyType();
+    }
+    
+    public Type getPropertyGenericType()
+    {
+       if (conduit instanceof PropertyConduit2) {
+               return ((PropertyConduit2) conduit).getPropertyGenericType();
+       }
+       return conduit.getPropertyType();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void set(Object instance, Object value)
+    {
+        Object coerced = coercer.coerce(value, getPropertyType());
+
+        conduit.set(instance, coerced);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
new file mode 100644
index 0000000..1242031
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -0,0 +1,53 @@
+// Copyright 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * Companion class for {@link org.apache.tapestry5.PropertyConduit} instances 
created by the
+ * {@link org.apache.tapestry5.services.PropertyConduitSource}.
+ */
+@SuppressWarnings("all")
+public class PropertyConduitDelegate
+{
+    private final TypeCoercer typeCoercer;
+
+    public PropertyConduitDelegate(TypeCoercer typeCoercer)
+    {
+        this.typeCoercer = typeCoercer;
+    }
+
+    public final IntegerRange range(int from, int to)
+    {
+        return new IntegerRange(from, to);
+    }
+
+    public final <T> T coerce(Object value, Class<T> type)
+    {
+        return typeCoercer.coerce(value, type);
+    }
+
+    public final boolean invert(Object value)
+    {
+        return coerce(value, Boolean.class).equals(Boolean.FALSE);
+    }
+}

Reply via email to